Prevent erroneous "macro had not yet been defined" messages (PR c++/85385)
authorDavid Malcolm <dmalcolm@redhat.com>
Thu, 12 Apr 2018 23:44:09 +0000 (23:44 +0000)
committerDavid Malcolm <dmalcolm@gcc.gnu.org>
Thu, 12 Apr 2018 23:44:09 +0000 (23:44 +0000)
PR c++/85385 reports an issue where we emit bogus "macro had not yet been
defined" notes when a macro is mis-used:

  $ cat test.c
  #define MACRO(X,Y)

  void test ()
  {
    MACRO(42);
  }

  $ ./xg++ -B. -c test.c
  test.c:5:11: error: macro "MACRO" requires 2 arguments, but only 1 given
     MACRO(42);
             ^
  test.c: In function ‘void test()’:
  test.c:5:3: error: ‘MACRO’ was not declared in this scope
     MACRO(42);
     ^~~~~
  test.c:5:3: note:
  test.c:1: note: it was later defined here
   #define MACRO(X,Y)

The macro *had* been defined, it was merely misused.

This patch fixes the issue by only issuing the note if the use location
is before the definition location (using linemap_location_before_p).

gcc/cp/ChangeLog:
PR c++/85385
* name-lookup.c (macro_use_before_def::maybe_make): New function,
checking that the use is indeed before the definition.
(macro_use_before_def::macro_use_before_def): Make private.
(macro_use_before_def::~macro_use_before_def): Make private.  Move
check for UNKNOWN_LOCATION to macro_use_before_def::maybe_make.
(lookup_name_fuzzy): Call macro_use_before_def::maybe_make rather
than using new directly.

gcc/testsuite/ChangeLog:
PR c++/85385
* g++.dg/diagnostic/macro-arg-count.C: New test.

From-SVN: r259360

gcc/cp/ChangeLog
gcc/cp/name-lookup.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/diagnostic/macro-arg-count.C [new file with mode: 0644]

index 08021dfb1e22a163c324e2efa670351b7bc84053..5f29b0c82502713032893bfe10ef2a4cf19e79de 100644 (file)
@@ -1,3 +1,14 @@
+2018-04-12  David Malcolm  <dmalcolm@redhat.com>
+
+       PR c++/85385
+       * name-lookup.c (macro_use_before_def::maybe_make): New function,
+       checking that the use is indeed before the definition.
+       (macro_use_before_def::macro_use_before_def): Make private.
+       (macro_use_before_def::~macro_use_before_def): Make private.  Move
+       check for UNKNOWN_LOCATION to macro_use_before_def::maybe_make.
+       (lookup_name_fuzzy): Call macro_use_before_def::maybe_make rather
+       than using new directly.
+
 2018-04-12  Jason Merrill  <jason@redhat.com>
 
        PR c++/85356 - ICE with pointer to member function.
index ca776844c9ce302a9e89644a62725b4124f8cf08..3f86cd2f0e2e3c5b5b611540d48e59c15dc6d086 100644 (file)
@@ -5888,6 +5888,27 @@ consider_binding_level (tree name, best_match <tree, const char *> &bm,
 class macro_use_before_def : public deferred_diagnostic
 {
  public:
+  /* Factory function.  Return a new macro_use_before_def instance if
+     appropriate, or return NULL. */
+  static macro_use_before_def *
+  maybe_make (location_t use_loc, cpp_hashnode *macro)
+  {
+    source_location def_loc = cpp_macro_definition_location (macro);
+    if (def_loc == UNKNOWN_LOCATION)
+      return NULL;
+
+    /* We only want to issue a note if the macro was used *before* it was
+       defined.
+       We don't want to issue a note for cases where a macro was incorrectly
+       used, leaving it unexpanded (e.g. by using the wrong argument
+       count).  */
+    if (!linemap_location_before_p (line_table, use_loc, def_loc))
+      return NULL;
+
+    return new macro_use_before_def (use_loc, macro);
+  }
+
+ private:
   /* Ctor.  LOC is the location of the usage.  MACRO is the
      macro that was used.  */
   macro_use_before_def (location_t loc, cpp_hashnode *macro)
@@ -5901,13 +5922,10 @@ class macro_use_before_def : public deferred_diagnostic
     if (is_suppressed_p ())
       return;
 
-    source_location def_loc = cpp_macro_definition_location (m_macro);
-    if (def_loc != UNKNOWN_LOCATION)
-      {
-       inform (get_location (), "the macro %qs had not yet been defined",
-               (const char *)m_macro->ident.str);
-       inform (def_loc, "it was later defined here");
-      }
+    inform (get_location (), "the macro %qs had not yet been defined",
+           (const char *)m_macro->ident.str);
+    inform (cpp_macro_definition_location (m_macro),
+           "it was later defined here");
   }
 
  private:
@@ -5990,12 +6008,13 @@ lookup_name_fuzzy (tree name, enum lookup_name_fuzzy_kind kind, location_t loc)
     bm.consider ((const char *)best_macro->ident.str);
   else if (bmm.get_best_distance () == 0)
     {
-      /* If we have an exact match for a macro name, then the
-        macro has been used before it was defined.  */
+      /* If we have an exact match for a macro name, then either the
+        macro was used with the wrong argument count, or the macro
+        has been used before it was defined.  */
       cpp_hashnode *macro = bmm.blithely_get_best_candidate ();
       if (macro && (macro->flags & NODE_BUILTIN) == 0)
        return name_hint (NULL,
-                         new macro_use_before_def (loc, macro));
+                         macro_use_before_def::maybe_make (loc, macro));
     }
 
   /* Try the "starts_decl_specifier_p" keywords to detect
index 16d39a283cfcf6c9fd4ba522552c9df680aff98d..ce924a3ae5cc5bcf5fed034cb7dbd17a67a75ebf 100644 (file)
@@ -1,3 +1,8 @@
+2018-04-12  David Malcolm  <dmalcolm@redhat.com>
+
+       PR c++/85385
+       * g++.dg/diagnostic/macro-arg-count.C: New test.
+
 2018-04-12  Thomas Koenig  <tkoenig@gcc.gnu.org>
 
        PR fortran/83064
diff --git a/gcc/testsuite/g++.dg/diagnostic/macro-arg-count.C b/gcc/testsuite/g++.dg/diagnostic/macro-arg-count.C
new file mode 100644 (file)
index 0000000..12b2dbd
--- /dev/null
@@ -0,0 +1,51 @@
+// { dg-options "-fdiagnostics-show-caret" }
+
+#define MACRO_1(X,Y)
+void test_1 ()
+{
+  MACRO_1(42); // { dg-line "use_of_MACRO_1" }
+  // { dg-error "macro \"MACRO_1\" requires 2 arguments, but only 1 given" "" { target *-*-* } use_of_MACRO_1 }
+  /* { dg-begin-multiline-output "" }
+   MACRO_1(42);
+             ^
+     { dg-end-multiline-output "" } */
+  // { dg-error "'MACRO_1' was not declared in this scope" "" { target *-*-* } use_of_MACRO_1 }
+  /* { dg-begin-multiline-output "" }
+   MACRO_1(42);
+   ^~~~~~~
+     { dg-end-multiline-output "" } */
+  // { dg-bogus "had not yet been defined" "" { target *-*-* } use_of_MACRO_1 }
+}
+
+#define MACRO_2(X,Y)
+void test_2 ()
+{
+  MACRO_2(1, 2, 3); // { dg-line "use_of_MACRO_2" }
+  // { dg-error "macro \"MACRO_2\" passed 3 arguments, but takes just 2" "" { target *-*-* } use_of_MACRO_2 }
+  /* { dg-begin-multiline-output "" }
+   MACRO_2(1, 2, 3);
+                  ^
+     { dg-end-multiline-output "" } */
+  // { dg-error "'MACRO_2' was not declared in this scope" "" { target *-*-* } use_of_MACRO_2 }
+  /* { dg-begin-multiline-output "" }
+   MACRO_2(1, 2, 3);
+   ^~~~~~~
+     { dg-end-multiline-output "" } */
+  // { dg-bogus "had not yet been defined" "" { target *-*-* } use_of_MACRO_2 }
+}
+
+#define MACRO_3
+void test_3 ()
+{
+  MACRO_3 (42);
+}
+
+#define MACRO_4(X,Y)
+void test_4 ()
+{
+  MACRO_4; // { dg-error "'MACRO_4' was not declared in this scope" }
+  /* { dg-begin-multiline-output "" }
+   MACRO_4;
+   ^~~~~~~
+     { dg-end-multiline-output "" } */
+}