Branch data Line data Source code
1 : : /* Code for unwinding macro expansions in diagnostics.
2 : : Copyright (C) 1999-2025 Free Software Foundation, Inc.
3 : :
4 : : This file is part of GCC.
5 : :
6 : : GCC is free software; you can redistribute it and/or modify it under
7 : : the terms of the GNU General Public License as published by the Free
8 : : Software Foundation; either version 3, or (at your option) any later
9 : : version.
10 : :
11 : : GCC is distributed in the hope that it will be useful, but WITHOUT ANY
12 : : WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 : : FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 : : for more details.
15 : :
16 : : You should have received a copy of the GNU General Public License
17 : : along with GCC; see the file COPYING3. If not see
18 : : <http://www.gnu.org/licenses/>. */
19 : :
20 : : #define INCLUDE_VECTOR
21 : : #include "config.h"
22 : : #include "system.h"
23 : : #include "coretypes.h"
24 : : #include "tree.h"
25 : : #include "diagnostics/macro-unwinding.h"
26 : : #include "diagnostics/text-sink.h"
27 : : #include "intl.h"
28 : :
29 : : namespace diagnostics {
30 : :
31 : : /* This is a pair made of a location and the line map it originated
32 : : from. It's used in the maybe_unwind_expanded_macro_loc function
33 : : below. */
34 : : struct loc_map_pair
35 : : {
36 : : const line_map_macro *map;
37 : : location_t where;
38 : : };
39 : :
40 : :
41 : : /* Unwind the different macro expansions that lead to the token which
42 : : location is WHERE and emit diagnostics showing the resulting
43 : : unwound macro expansion trace. Let's look at an example to see how
44 : : the trace looks like. Suppose we have this piece of code,
45 : : artificially annotated with the line numbers to increase
46 : : legibility:
47 : :
48 : : $ cat -n test.c
49 : : 1 #define OPERATE(OPRD1, OPRT, OPRD2) \
50 : : 2 OPRD1 OPRT OPRD2;
51 : : 3
52 : : 4 #define SHIFTL(A,B) \
53 : : 5 OPERATE (A,<<,B)
54 : : 6
55 : : 7 #define MULT(A) \
56 : : 8 SHIFTL (A,1)
57 : : 9
58 : : 10 void
59 : : 11 g ()
60 : : 12 {
61 : : 13 MULT (1.0);// 1.0 << 1; <-- so this is an error.
62 : : 14 }
63 : :
64 : : Here is the diagnostic that we want the compiler to generate:
65 : :
66 : : test.c: In function ‘g’:
67 : : test.c:5:14: error: invalid operands to binary << (have ‘double’ and ‘int’)
68 : : test.c:2:9: note: in definition of macro 'OPERATE'
69 : : test.c:8:3: note: in expansion of macro 'SHIFTL'
70 : : test.c:13:3: note: in expansion of macro 'MULT'
71 : :
72 : : The part that goes from the third to the fifth line of this
73 : : diagnostic (the lines containing the 'note:' string) is called the
74 : : unwound macro expansion trace. That's the part generated by this
75 : : function. */
76 : :
77 : : void
78 : 313079 : maybe_unwind_expanded_macro_loc (text_sink &text_output,
79 : : location_t where)
80 : : {
81 : 313079 : const struct line_map *map;
82 : 313079 : auto_vec<loc_map_pair> loc_vec;
83 : 313079 : unsigned ix;
84 : 313079 : loc_map_pair loc, *iter;
85 : :
86 : 313079 : const location_t original_loc = where;
87 : :
88 : 313079 : map = linemap_lookup (line_table, where);
89 : 313079 : if (!linemap_macro_expansion_map_p (map))
90 : 304937 : return;
91 : :
92 : : /* Let's unwind the macros that got expanded and led to the token
93 : : which location is WHERE. We are going to store these macros into
94 : : LOC_VEC, so that we can later walk it at our convenience to
95 : : display a somewhat meaningful trace of the macro expansion
96 : : history to the user. Note that the first macro of the trace
97 : : (which is OPERATE in the example above) is going to be stored at
98 : : the beginning of LOC_VEC. */
99 : :
100 : 14309 : do
101 : : {
102 : 14309 : loc.where = where;
103 : 14309 : loc.map = linemap_check_macro (map);
104 : :
105 : 14309 : loc_vec.safe_push (loc);
106 : :
107 : : /* WHERE is the location of a token inside the expansion of a
108 : : macro. MAP is the map holding the locations of that macro
109 : : expansion. Let's get the location of the token inside the
110 : : context that triggered the expansion of this macro.
111 : : This is basically how we go "down" in the trace of macro
112 : : expansions that led to WHERE. */
113 : 14309 : where = linemap_unwind_toward_expansion (line_table, where, &map);
114 : 14309 : } while (linemap_macro_expansion_map_p (map));
115 : :
116 : : /* Now map is set to the map of the location in the source that
117 : : first triggered the macro expansion. This must be an ordinary map. */
118 : 8142 : const line_map_ordinary *ord_map = linemap_check_ordinary (map);
119 : :
120 : : /* Walk LOC_VEC and print the macro expansion trace, unless the
121 : : first macro which expansion triggered this trace was expanded
122 : : inside a system header. */
123 : 8142 : int saved_location_line =
124 : 8142 : expand_location_to_spelling_point (original_loc).line;
125 : :
126 : 8142 : if (!LINEMAP_SYSP (ord_map))
127 : 30048 : FOR_EACH_VEC_ELT (loc_vec, ix, iter)
128 : : {
129 : : /* Sometimes, in the unwound macro expansion trace, we want to
130 : : print a part of the context that shows where, in the
131 : : definition of the relevant macro, is the token (we are
132 : : looking at) used. That is the case in the introductory
133 : : comment of this function, where we print:
134 : :
135 : : test.c:2:9: note: in definition of macro 'OPERATE'.
136 : :
137 : : We print that "macro definition context" because the
138 : : diagnostic line (emitted by the call to
139 : : pp_ouput_formatted_text in diagnostic_report_diagnostic):
140 : :
141 : : test.c:5:14: error: invalid operands to binary << (have ‘double’ and ‘int’)
142 : :
143 : : does not point into the definition of the macro where the
144 : : token '<<' (that is an argument to the function-like macro
145 : : OPERATE) is used. So we must "display" the line of that
146 : : macro definition context to the user somehow.
147 : :
148 : : A contrario, when the first interesting diagnostic line
149 : : points into the definition of the macro, we don't need to
150 : : display any line for that macro definition in the trace
151 : : anymore, otherwise it'd be redundant. */
152 : :
153 : : /* Okay, now here is what we want. For each token resulting
154 : : from macro expansion we want to show: 1/ where in the
155 : : definition of the macro the token comes from; 2/ where the
156 : : macro got expanded. */
157 : :
158 : : /* Resolve the location iter->where into the locus 1/ of the
159 : : comment above. */
160 : 13850 : location_t resolved_def_loc =
161 : 13850 : linemap_resolve_location (line_table, iter->where,
162 : : LRK_MACRO_DEFINITION_LOCATION, nullptr);
163 : :
164 : : /* Don't print trace for locations that are reserved or from
165 : : within a system header. */
166 : 13850 : const line_map_ordinary *m = nullptr;
167 : 13850 : location_t l =
168 : 13850 : linemap_resolve_location (line_table, resolved_def_loc,
169 : : LRK_SPELLING_LOCATION, &m);
170 : 13850 : location_t l0 = l;
171 : 13850 : if (IS_ADHOC_LOC (l0))
172 : 0 : l0 = get_location_from_adhoc_loc (line_table, l0);
173 : 13850 : if (l0 < RESERVED_LOCATION_COUNT || LINEMAP_SYSP (m))
174 : 2931 : continue;
175 : :
176 : : /* We need to print the context of the macro definition only
177 : : when the locus of the first displayed diagnostic (displayed
178 : : before this trace) was inside the definition of the
179 : : macro. */
180 : 12719 : const int resolved_def_loc_line = SOURCE_LINE (m, l0);
181 : 12719 : if (ix == 0 && saved_location_line != resolved_def_loc_line)
182 : : {
183 : 1800 : text_output.append_note (resolved_def_loc,
184 : : "in definition of macro %qs",
185 : : linemap_map_get_macro_name (iter->map));
186 : : /* At this step, as we've printed the context of the macro
187 : : definition, we don't want to print the context of its
188 : : expansion, otherwise, it'd be redundant. */
189 : 1800 : continue;
190 : : }
191 : :
192 : : /* Resolve the location of the expansion point of the macro
193 : : which expansion gave the token represented by def_loc.
194 : : This is the locus 2/ of the earlier comment. */
195 : 10919 : location_t resolved_exp_loc =
196 : 10919 : linemap_resolve_location (line_table,
197 : 10919 : iter->map->get_expansion_point_location (),
198 : : LRK_MACRO_DEFINITION_LOCATION, nullptr);
199 : :
200 : 10919 : text_output.append_note (resolved_exp_loc,
201 : : "in expansion of macro %qs",
202 : : linemap_map_get_macro_name (iter->map));
203 : : }
204 : 313079 : }
205 : :
206 : : /* This is a diagnostic finalizer implementation that is aware of
207 : : virtual locations produced by libcpp.
208 : :
209 : : It has to be called by the diagnostic finalizer of front ends that
210 : : uses libcpp and wish to get diagnostics involving tokens resulting
211 : : from macro expansion.
212 : :
213 : : For a given location, if said location belongs to a token
214 : : resulting from a macro expansion, this starter prints the context
215 : : of the token. E.g, for multiply nested macro expansion, it
216 : : unwinds the nested macro expansions and prints them in a manner
217 : : that is similar to what is done for function call stacks, or
218 : : template instantiation contexts. */
219 : : void
220 : 313035 : virt_loc_aware_text_finalizer (text_sink &text_output,
221 : : const diagnostic_info *diagnostic)
222 : : {
223 : 313035 : maybe_unwind_expanded_macro_loc (text_output,
224 : : diagnostic_location (diagnostic));
225 : 313035 : }
226 : :
227 : : } // namespace diagnostics
|