Line data Source code
1 : /* A rich_location subclass that lazily populates a diagnostic_path
2 : with diagnostic context events, but only if the path is actually to be
3 : used.
4 :
5 : Copyright (C) 2025-2026 Free Software Foundation, Inc.
6 : Contributed by Qing Zhao<qing.zhao@oracle.com>
7 :
8 : This file is part of GCC.
9 :
10 : GCC is free software; you can redistribute it and/or modify it under
11 : the terms of the GNU General Public License as published by the Free
12 : Software Foundation; either version 3, or (at your option) any later
13 : version.
14 :
15 : GCC is distributed in the hope that it will be useful, but WITHOUT ANY
16 : WARRANTY; without even the implied warranty of MERCHANTABILITY or
17 : FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
18 : for more details.
19 :
20 : You should have received a copy of the GNU General Public License
21 : along with GCC; see the file COPYING3. If not see
22 : <http://www.gnu.org/licenses/>. */
23 :
24 : #define INCLUDE_MEMORY
25 : #include "config.h"
26 : #include "system.h"
27 : #include "coretypes.h"
28 : #include "backend.h"
29 : #include "tree.h"
30 : #include "gimple.h"
31 : #include "gimple-iterator.h"
32 : #include "cfganal.h"
33 : #include "tree-cfg.h"
34 : #include "simple-diagnostic-path.h"
35 : #include "diagnostic-context-rich-location.h"
36 :
37 : /* Implemenation of the method make_inner_path of the class
38 : lazy_diagnostic_context_path. */
39 :
40 : std::unique_ptr<diagnostics::paths::path>
41 5750 : lazy_diagnostic_context_path::make_inner_path () const
42 : {
43 5750 : auto path = std::make_unique<simple_diagnostic_path>
44 : (m_logical_loc_mgr,
45 5750 : global_dc->get_reference_printer ());
46 5750 : if (!flag_diagnostics_show_context)
47 5735 : return path;
48 15 : if (!m_stmt)
49 0 : return path;
50 :
51 : /* For the following more complicated code:
52 : if (i < 10) // B2
53 : {
54 : if (is_day) // B3
55 : __builtin_printf ("day"); // B4
56 : else
57 : __builtin_printf ("night"); // B5
58 :
59 : if (i == -1) // B6
60 : {
61 : if (is_dollar) // B7
62 : __builtin_printf ("dollar");// B8
63 : else
64 : __builtin_printf ("euro"); // B9
65 : a[i] = -1; // B10 (warning here)
66 : }
67 : else
68 : a[i] = i; // B11
69 : }
70 : else
71 : a[i] = i + 1; // B12
72 :
73 : it has the following CFG:
74 :
75 : B2
76 : / \
77 : V \
78 : B3 \
79 : / \ \
80 : V V \
81 : B4 B5 V
82 : \ / B12
83 : V
84 : B6
85 : / \
86 : V V
87 : B7 B11
88 : / \
89 : V V
90 : B8 B9
91 : \ /
92 : V
93 : B10 (warning here)
94 :
95 : If the STMT that has warning is in B10, the interesting conditions for
96 : the diagnostic are:
97 : depth=1: the condition stmt at B6, the edge from B6->B7;
98 : depth=2: the condition stmt at B2, the edge from B2->B3;
99 :
100 : In order to get the interesting conditions, the key to the heuristic
101 : is to backtrace the immediate dominator block chain of the current
102 : block B10, such as, B7, then B6, B3, B2.
103 :
104 : In this basic block dominator chain, identify the single predecessor
105 : edges, such as B6->B7, and B2->B3.
106 :
107 : For each of the single predecessor edge, the interesting condition is
108 : embedded in the single predecessor block, and the TRUE/FALSE of this
109 : condition is embedded in the edge.
110 :
111 : FIXME: We currently only handle GIMPLE_COND, might extend to GIMPLE_SWITCH
112 : later. */
113 :
114 15 : basic_block cur_bb = gimple_bb (m_stmt);
115 15 : if (!cur_bb)
116 0 : return path;
117 : basic_block cond_bb = NULL;
118 : int depth = 0;
119 27 : do
120 : {
121 : /* Step 1. locate the immediate dominator of cur_bb. */
122 27 : if (dom_info_available_p (cfun, CDI_DOMINATORS))
123 27 : cond_bb = get_immediate_dominator (CDI_DOMINATORS, cur_bb);
124 :
125 27 : if (!cond_bb)
126 0 : return path;
127 :
128 : /* Step 2. identify the single predecessor edge to locate the
129 : conditional statement. */
130 27 : if (single_pred_p (cur_bb))
131 : {
132 21 : gcc_assert (cond_bb == single_pred (cur_bb));
133 21 : gimple *cond_stmt = NULL;
134 21 : gimple_stmt_iterator gsi = gsi_last_bb (cond_bb);
135 :
136 : /* Currently, we only hanlde GIMPLE_COND.
137 : FIXME, will handle GIMPLE_SWITCH and other ctrl stmt later. */
138 21 : if (gsi_stmt (gsi) && stmt_ends_bb_p (gsi_stmt (gsi)))
139 17 : if (gimple_code (gsi_stmt (gsi)) == GIMPLE_COND)
140 17 : cond_stmt = gsi_stmt (gsi);
141 :
142 : /* If there is no conditional statement in the cond_bb, continue. */
143 21 : if (!cond_stmt)
144 : {
145 4 : cur_bb = cond_bb;
146 4 : continue;
147 : }
148 :
149 17 : depth++;
150 :
151 : /* if there is no location information for the cond_stmt, we should
152 : not add this event to confuse end user. */
153 17 : if (cond_stmt
154 17 : && LOCATION_LOCUS (gimple_location (cond_stmt))
155 : != UNKNOWN_LOCATION)
156 : {
157 : /* Get the edge from the cond_bb to cur_bb, to determine whether
158 : the stmt is on the taken path of the conditional statement. */
159 17 : edge e = find_edge (cond_bb, cur_bb);
160 17 : bool is_branch_taken = e->flags & EDGE_TRUE_VALUE;
161 22 : path->add_event (gimple_location (cond_stmt), cfun->decl, 1,
162 : "when the condition is evaluated to %s",
163 : is_branch_taken ? "true" : "false");
164 : }
165 : }
166 : cur_bb = cond_bb;
167 : }
168 27 : while (cond_bb != ENTRY_BLOCK_PTR_FOR_FN (cfun)
169 27 : && depth < flag_diagnostics_show_context);
170 :
171 : /* Add an end of path warning event in the end of the path. */
172 15 : if (path->num_events () > 0)
173 15 : path->add_event (m_location, cfun->decl, 1,
174 : "warning happens here");
175 15 : return path;
176 5750 : }
|