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