Branch data 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 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 : 5726 : lazy_diagnostic_context_path::make_inner_path () const
42 : : {
43 : 5726 : auto path = std::make_unique<simple_diagnostic_path>
44 : : (m_logical_loc_mgr,
45 : 5726 : global_dc->get_reference_printer ());
46 : 5726 : if (!flag_diagnostics_show_context)
47 : 5711 : 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 : 5726 : }
|