diagnostics: fix excessive range-printing involving macros [PR97932]

PR c/97932 describes a bug in which diagnostic_show_locus prints most
of a source file.

The issue is that it prints a range in which the start and end locations
are part of the same macro map, but the start location is for a token in
the definition of the macro, whereas the end location is for a token in
an argument of the macro.

This patch extends compatible_locations_p to require that range-printing
of macro maps requires the location to either be both for the definition
of the macro, or both for the arguments of the macro (not one of each),
fixing the issue.

gcc/ChangeLog:
	PR c/97932
	* diagnostic-show-locus.c (compatible_locations_p): Require
	locations in the same macro map to be either both from the
	macro definition, or both from the macro arguments.

gcc/testsuite/ChangeLog:
	PR c/97932
	* gcc.dg/pr97932.c: New test.
This commit is contained in:
David Malcolm 2021-02-04 15:20:59 -05:00
parent 26fd3bf75b
commit 65c1cb3589
2 changed files with 134 additions and 0 deletions

View File

@ -905,6 +905,15 @@ compatible_locations_p (location_t loc_a, location_t loc_b)
/* Are both within the same macro expansion? */
if (linemap_macro_expansion_map_p (map_a))
{
/* If so, then they're only compatible if either both are
from the macro definition, or both from the macro arguments. */
bool loc_a_from_defn
= linemap_location_from_macro_definition_p (line_table, loc_a);
bool loc_b_from_defn
= linemap_location_from_macro_definition_p (line_table, loc_b);
if (loc_a_from_defn != loc_b_from_defn)
return false;
/* Expand each location towards the spelling location, and
recurse. */
const line_map_macro *macro_map = linemap_check_macro (map_a);

View File

@ -0,0 +1,125 @@
/* Verify that we don't emit ranges that span both
a macro definition location and a macro expansion location. */
/* { dg-options "-fdiagnostics-show-caret" } */
/* Various cases involving the ranges of the LHS and RHS operands to "-". */
/* Case 1
start token is in macro definition ("&"),
end token is in macro invocation ("a" and "b"). */
#define M1(A, B) &A - &B /* { dg-error "invalid operands" } */
/* Intervening
material
that
ought
not
to
be
printed. */
int test_1 (float a, int b)
{
return M1(a, b); /* { dg-message "in expansion of macro 'M1'" } */
}
/* { dg-begin-multiline-output "" }
#define M1(A, B) &A - &B
^
{ dg-end-multiline-output "" } */
/* { dg-begin-multiline-output "" }
return M1(a, b);
^~
{ dg-end-multiline-output "" } */
/* Case 2:
start and end tokens are both in macro invocation ("&", and "a"/"b"). */
#define M2(A, B) A - B /* { dg-error "invalid operands" } */
/* Intervening
material
that
ought
not
to
be
printed. */
int test_2 (float a, int b)
{
return M2(&a, &b); /* { dg-message "in expansion of macro 'M2'" } */
}
/* { dg-begin-multiline-output "" }
#define M2(A, B) A - B
^
{ dg-end-multiline-output "" } */
/* { dg-begin-multiline-output "" }
return M2(&a, &b);
^~
{ dg-end-multiline-output "" } */
/* Case 3:
start token is in macro invocation ("&"),
end token is in macro definition ("a"). */
#define M3(OP) OP a - OP b /* { dg-error "invalid operands" } */
/* Intervening
material
that
ought
not
to
be
printed. */
int test_3 (float a, int b)
{
return M3(&); /* { dg-message "in expansion of macro 'M3'" } */
}
/* { dg-begin-multiline-output "" }
#define M3(OP) OP a - OP b
^
{ dg-end-multiline-output "" } */
/* { dg-begin-multiline-output "" }
return M3(&);
^~
{ dg-end-multiline-output "" } */
/* Case 4:
start and end tokens are both in macro definition ("&a"). */
#define M4 &a - &b /* { dg-error "invalid operands" } */
/* Intervening
material
that
ought
not
to
be
printed. */
int test_4 (float a, int b)
{
return M4; /* { dg-message "in expansion of macro 'M4'" } */
}
/* { dg-begin-multiline-output "" }
#define M4 &a - &b
~~ ^ ~~
| |
| int *
float *
{ dg-end-multiline-output "" } */
/* { dg-begin-multiline-output "" }
return M4;
^~
{ dg-end-multiline-output "" } */