Line data Source code
1 : /* Code for unwinding macro expansions in diagnostics.
2 : Copyright (C) 1999-2026 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 314327 : maybe_unwind_expanded_macro_loc (text_sink &text_output,
79 : location_t where)
80 : {
81 314327 : const struct line_map *map;
82 314327 : auto_vec<loc_map_pair> loc_vec;
83 314327 : unsigned ix;
84 314327 : loc_map_pair loc, *iter;
85 :
86 314327 : const location_t original_loc = where;
87 :
88 314327 : map = linemap_lookup (line_table, where);
89 314327 : if (!linemap_macro_expansion_map_p (map))
90 306258 : 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 14251 : do
101 : {
102 14251 : loc.where = where;
103 14251 : loc.map = linemap_check_macro (map);
104 :
105 14251 : 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 14251 : where = linemap_unwind_toward_expansion (line_table, where, &map);
114 14251 : } 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 8069 : 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 8069 : int saved_location_line =
124 8069 : expand_location_to_spelling_point (original_loc).line;
125 :
126 8069 : if (!LINEMAP_SYSP (ord_map))
127 29844 : 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 13792 : location_t resolved_def_loc =
161 13792 : 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 13792 : const line_map_ordinary *m = nullptr;
167 13792 : location_t l =
168 13792 : linemap_resolve_location (line_table, resolved_def_loc,
169 : LRK_SPELLING_LOCATION, &m);
170 13792 : location_t l0 = l;
171 13792 : if (IS_ADHOC_LOC (l0))
172 0 : l0 = get_location_from_adhoc_loc (line_table, l0);
173 13792 : if (l0 < RESERVED_LOCATION_COUNT || LINEMAP_SYSP (m))
174 2919 : 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 12644 : const int resolved_def_loc_line = SOURCE_LINE (m, l0);
181 12644 : if (ix == 0 && saved_location_line != resolved_def_loc_line)
182 : {
183 1771 : 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 1771 : 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 10873 : location_t resolved_exp_loc =
196 10873 : linemap_resolve_location (line_table,
197 10873 : iter->map->get_expansion_point_location (),
198 : LRK_MACRO_DEFINITION_LOCATION, nullptr);
199 :
200 10873 : text_output.append_note (resolved_exp_loc,
201 : "in expansion of macro %qs",
202 : linemap_map_get_macro_name (iter->map));
203 : }
204 314327 : }
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 314283 : virt_loc_aware_text_finalizer (text_sink &text_output,
221 : const diagnostic_info *diagnostic)
222 : {
223 314283 : maybe_unwind_expanded_macro_loc (text_output,
224 : diagnostic_location (diagnostic));
225 314283 : }
226 :
227 : } // namespace diagnostics
|