Here is the diagnostic that we want the compiler to generate:
- test.c: In function 'g':
- test.c:5:14: error: invalid operands to binary << (have 'double' and 'int')
- test.c:2:9: note: in expansion of macro 'OPERATE'
- test.c:5:3: note: expanded from here
- test.c:5:14: note: in expansion of macro 'SHIFTL'
- test.c:8:3: note: expanded from here
- test.c:8:3: note: in expansion of macro 'MULT'
- test.c:13:3: note: expanded from here
-
- The part that goes from the third to the eighth line of this
+ test.c: In function ‘g’:
+ test.c:5:14: error: invalid operands to binary << (have ‘double’ and ‘int’)
+ test.c:2:9: note: in definition of macro 'OPERATE'
+ test.c:8:3: note: in expansion of macro 'SHIFTL'
+ test.c:13:3: note: in expansion of macro 'MULT'
+
+ The part that goes from the third to the fifth line of this
diagnostic (the lines containing the 'note:' string) is called the
unwound macro expansion trace. That's the part generated by this
function. */
if (!LINEMAP_SYSP (map))
FOR_EACH_VEC_ELT (loc_map_pair, loc_vec, ix, iter)
{
- source_location resolved_def_loc = 0, resolved_exp_loc = 0;
+ source_location resolved_def_loc = 0, resolved_exp_loc = 0,
+ saved_location = 0;
+ int resolved_def_loc_line = 0, saved_location_line = 0;
diagnostic_t saved_kind;
const char *saved_prefix;
- source_location saved_location;
+ /* Sometimes, in the unwound macro expansion trace, we want to
+ print a part of the context that shows where, in the
+ definition of the relevant macro, is the token (we are
+ looking at) used. That is the case in the introductory
+ comment of this function, where we print:
+
+ test.c:2:9: note: in definition of macro 'OPERATE'.
+
+ We print that "macro definition context" because the
+ diagnostic line (emitted by the call to
+ pp_ouput_formatted_text in diagnostic_report_diagnostic):
+
+ test.c:5:14: error: invalid operands to binary << (have ‘double’ and ‘int’)
+
+ does not point into the definition of the macro where the
+ token '<<' (that is an argument to the function-like macro
+ OPERATE) is used. So we must "display" the line of that
+ macro definition context to the user somehow.
+
+ A contrario, when the first interesting diagnostic line
+ points into the definition of the macro, we don't need to
+ display any line for that macro definition in the trace
+ anymore, otherwise it'd be redundant.
+
+ This flag is true when we need to display the context of
+ the macro definition. */
+ bool print_definition_context_p = false;
/* Okay, now here is what we want. For each token resulting
from macro expansion we want to show: 1/ where in the
if (l < RESERVED_LOCATION_COUNT
|| LINEMAP_SYSP (m))
continue;
+
+ resolved_def_loc_line = SOURCE_LINE (m, l);
}
/* Resolve the location of the expansion point of the macro
saved_kind = diagnostic->kind;
saved_prefix = pp_get_prefix (context->printer);
saved_location = diagnostic->location;
+ saved_location_line =
+ expand_location_to_spelling_point (saved_location).line;
diagnostic->kind = DK_NOTE;
- diagnostic->location = resolved_def_loc;
- pp_set_prefix (context->printer,
- diagnostic_build_prefix (context, diagnostic));
- pp_newline (context->printer);
- pp_printf (context->printer, "in expansion of macro '%s'",
- linemap_map_get_macro_name (iter->map));
- pp_destroy_prefix (context->printer);
- diagnostic_show_locus (context, diagnostic);
- diagnostic->location = resolved_exp_loc;
- pp_set_prefix (context->printer,
+ /* We need to print the context of the macro definition only
+ when the locus of the first displayed diagnostic (displayed
+ before this trace) was inside the definition of the
+ macro. */
+ print_definition_context_p =
+ (ix == 0 && (saved_location_line != resolved_def_loc_line));
+
+ if (print_definition_context_p)
+ {
+ diagnostic->location = resolved_def_loc;
+ pp_set_prefix (context->printer,
+ diagnostic_build_prefix (context, diagnostic));
+ pp_newline (context->printer);
+ pp_printf (context->printer, "in definition of macro '%s'",
+ linemap_map_get_macro_name (iter->map));
+ pp_destroy_prefix (context->printer);
+ diagnostic_show_locus (context, diagnostic);
+ /* At this step, as we've printed the context of the macro
+ definition, we don't want to print the context of its
+ expansion, otherwise, it'd be redundant. */
+ continue;
+ }
+
+ diagnostic->location = resolved_exp_loc;
+ pp_set_prefix (context->printer,
diagnostic_build_prefix (context, diagnostic));
- pp_newline (context->printer);
- pp_string (context->printer, "expanded from here");
+ pp_newline (context->printer);
+ pp_printf (context->printer, "in expansion of macro '%s'",
+ linemap_map_get_macro_name (iter->map));
pp_destroy_prefix (context->printer);
diagnostic_show_locus (context, diagnostic);