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