diagnostics: fix excessive range-printing involving macros [PR97932]
authorDavid Malcolm <dmalcolm@redhat.com>
Thu, 4 Feb 2021 20:20:59 +0000 (15:20 -0500)
committerDavid Malcolm <dmalcolm@redhat.com>
Thu, 4 Feb 2021 20:20:59 +0000 (15:20 -0500)
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.

gcc/diagnostic-show-locus.c
gcc/testsuite/gcc.dg/pr97932.c [new file with mode: 0644]

index 92a07c2f60a034e9716f570df38ff806ac071462..458830aa2a9769b4b31b49e479ac9032a742b458 100644 (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);
diff --git a/gcc/testsuite/gcc.dg/pr97932.c b/gcc/testsuite/gcc.dg/pr97932.c
new file mode 100644 (file)
index 0000000..4a0b304
--- /dev/null
@@ -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 "" } */
+