PR c++/93804 - exempt extern C headers from -Wredundant-tags
authorMartin Sebor <msebor@redhat.com>
Mon, 24 Feb 2020 17:14:16 +0000 (10:14 -0700)
committerMartin Sebor <msebor@redhat.com>
Mon, 24 Feb 2020 17:14:16 +0000 (10:14 -0700)
gcc/cp/ChangeLog:

PR c++/93804
* parser.c (cp_parser_check_class_key): Avoid issuing -Wredundant-tags
in shared C/C++ code in headers.

gcc/testsuite/ChangeLog:

PR c++/93804
* g++.dg/warn/Wredundant-tags-4.C: New test.
* g++.dg/warn/Wredundant-tags-5.C: New test.
* g++.dg/warn/Wredundant-tags-5.h: New test.

gcc/cp/ChangeLog
gcc/cp/parser.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/warn/Wredundant-tags-4.C [new file with mode: 0644]
gcc/testsuite/g++.dg/warn/Wredundant-tags-5.C [new file with mode: 0644]
gcc/testsuite/g++.dg/warn/Wredundant-tags-5.h [new file with mode: 0644]

index cc0929a..9c212d9 100644 (file)
@@ -1,3 +1,9 @@
+2020-02-24  Martin Sebor  <msebor@redhat.com>
+
+       PR c++/93804
+       * parser.c (cp_parser_check_class_key): Avoid issuing -Wredundant-tags
+       in shared C/C++ code in headers.
+
 2020-02-24  Marek Polacek  <polacek@redhat.com>
 
        PR c++/93869 - ICE with -Wmismatched-tags.
index 01936e8..8e52fef 100644 (file)
@@ -30837,15 +30837,31 @@ cp_parser_maybe_warn_enum_key (cp_parser *parser, location_t key_loc,
   /* The enum-key is redundant for uses of the TYPE that are not
      declarations and for which name lookup returns just the type
      itself.  */
-  if (decl == type_decl)
-    {
-      gcc_rich_location richloc (key_loc);
-      richloc.add_fixit_remove (key_loc);
-      warning_at (&richloc, OPT_Wredundant_tags,
-                 "redundant enum-key %<enum%s%> in reference to %q#T",
-                 (scoped_key == RID_CLASS ? " class"
-                  : scoped_key == RID_STRUCT ? " struct" : ""), type);
+  if (decl != type_decl)
+    return;
+
+  if (scoped_key != RID_CLASS
+      && scoped_key != RID_STRUCT
+      && current_lang_name != lang_name_cplusplus
+      && current_namespace == global_namespace)
+    {
+      /* Avoid issuing the diagnostic for apparently redundant (unscoped)
+        enum tag in shared C/C++ code in files (such as headers) included
+        in the main source file.  */
+      const line_map_ordinary *map = NULL;
+      linemap_resolve_location (line_table, key_loc,
+                               LRK_MACRO_DEFINITION_LOCATION,
+                               &map);
+      if (!MAIN_FILE_P (map))
+       return;
     }
+
+  gcc_rich_location richloc (key_loc);
+  richloc.add_fixit_remove (key_loc);
+  warning_at (&richloc, OPT_Wredundant_tags,
+             "redundant enum-key %<enum%s%> in reference to %q#T",
+             (scoped_key == RID_CLASS ? " class"
+              : scoped_key == RID_STRUCT ? " struct" : ""), type);
 }
 
 /* Describes the set of declarations of a struct, class, or class template
@@ -31005,6 +31021,13 @@ cp_parser_check_class_key (cp_parser *parser, location_t key_loc,
       && class_key != union_type)
     return;
 
+  /* Only consider the true class-keys below and ignore typename_type,
+     etc. that are not C++ class-keys.  */
+  if (class_key != class_type
+      && class_key != record_type
+      && class_key != union_type)
+    return;
+
   tree type_decl = TYPE_MAIN_DECL (type);
   tree name = DECL_NAME (type_decl);
   /* Look up the NAME to see if it unambiguously refers to the TYPE
@@ -31017,15 +31040,32 @@ cp_parser_check_class_key (cp_parser *parser, location_t key_loc,
      neither definitions of it nor declarations, and for which name
      lookup returns just the type itself.  */
   bool key_redundant = !def_p && !decl_p && decl == type_decl;
+
+  if (key_redundant
+      && class_key != class_type
+      && current_lang_name != lang_name_cplusplus
+      && current_namespace == global_namespace)
+    {
+      /* Avoid issuing the diagnostic for apparently redundant struct
+        and union class-keys in shared C/C++ code in files (such as
+        headers) included in the main source file.  */
+      const line_map_ordinary *map = NULL;
+      linemap_resolve_location (line_table, key_loc,
+                               LRK_MACRO_DEFINITION_LOCATION,
+                               &map);
+      if (!MAIN_FILE_P (map))
+       key_redundant = false;
+    }
+
   if (key_redundant)
     {
       gcc_rich_location richloc (key_loc);
       richloc.add_fixit_remove (key_loc);
       warning_at (&richloc, OPT_Wredundant_tags,
-               "redundant class-key %qs in reference to %q#T",
-               class_key == union_type ? "union"
-               : class_key == record_type ? "struct" : "class",
-               type);
+                 "redundant class-key %qs in reference to %q#T",
+                 class_key == union_type ? "union"
+                 : class_key == record_type ? "struct" : "class",
+                 type);
     }
 
   if (seen_as_union || !warn_mismatched_tags)
index 6d5abbb..fae86eb 100644 (file)
@@ -1,3 +1,10 @@
+2020-02-24  Martin Sebor  <msebor@redhat.com>
+
+       PR c++/93804
+       * g++.dg/warn/Wredundant-tags-4.C: New test.
+       * g++.dg/warn/Wredundant-tags-5.C: New test.
+       * g++.dg/warn/Wredundant-tags-5.h: New test.
+
 2020-02-24  David Malcolm  <dmalcolm@redhat.com>
 
        * gcc.dg/analyzer/analyzer-verbosity-2a.c: New test.
diff --git a/gcc/testsuite/g++.dg/warn/Wredundant-tags-4.C b/gcc/testsuite/g++.dg/warn/Wredundant-tags-4.C
new file mode 100644 (file)
index 0000000..c56153a
--- /dev/null
@@ -0,0 +1,142 @@
+/* PR c++/93804 - exempt extern "C" headers from -Wredundant-tags
+   Verify that -Wredundant-tags is not issued for redundant class-key
+   in extern "C" references in a header file.
+   { dg-do compile }
+   { dg-options "-Wredundant-tags -ftrack-macro-expansion=0" }  */
+
+# 1 "Wredundant-tags-4.C"
+# 1 "Wredundant-tags-4.h" 1
+# line 10
+
+#if __cplusplus >= 201103L
+#  define enum_struct   enum struct
+#else
+#  define enum_struct   class
+#endif
+
+extern "C" {
+
+  class C1 { };
+  enum E1 { };
+  enum_struct ES1 { };
+  struct S1 { enum E1 e1; };
+  union U1 { enum E1 e1; struct S1 s1; };
+
+  /* The warning should be issued for the class-key class even in
+     an extern "C" block.  */
+  void f0 (class C1);                   // { dg-warning "\\\[-Wredundant-tags" }
+  void f1 (enum E1);                    // { dg-bogus "\\\[-Wredundant-tags" }
+
+  /* Ditto for a scoped enum.  */
+  void f2 (enum_struct ES1);            // { dg-warning "\\\[-Wredundant-tags" }
+                                        // { dg-warning "must not use the 'struct' keyword" "enum struct" { target { c++11 } } .-1 }
+
+  void f3 (struct S1);                  // { dg-bogus "\\\[-Wredundant-tags" }
+  void f4 (union U1);                   // { dg-bogus "\\\[-Wredundant-tags" }
+
+  inline int
+  finline1 (class C1)                   // { dg-warning "\\\[-Wredundant-tags" }
+  { return sizeof (class C1); }         // { dg-warning "\\\[-Wredundant-tags" }
+
+  inline int
+  finline2 (enum E1)                    // { dg-bogus "\\\[-Wredundant-tags" }
+  { return sizeof (enum E1); }          // { dg-bogus "\\\[-Wredundant-tags" }
+
+  inline int
+  finline3 (enum_struct ES1)            // { dg-warning "\\\[-Wredundant-tags" }
+  { return sizeof (ES1); }
+
+  inline int
+  finline4 (struct S1)                  // { dg-bogus "\\\[-Wredundant-tags" }
+  { return sizeof (struct S1); }
+
+  inline int
+  finline5 (union U1)                   // { dg-bogus "\\\[-Wredundant-tags" }
+  { return sizeof (union U1); }
+
+  extern class C1 c1;                   // { dg-warning "\\\[-Wredundant-tags" }
+  extern enum E1 e1;                    // { dg-bogus "\\\[-Wredundant-tags" }
+  extern enum_struct ES1 es1;           // { dg-warning "\\\[-Wredundant-tags" }
+  extern struct S1 s1;                  // { dg-bogus "\\\[-Wredundant-tags" }
+  extern union U1 u1;                   // { dg-bogus "\\\[-Wredundant-tags" }
+
+  namespace N1 {
+  /* Verify that -Wredundant-tags is issued in a namespace enclosed
+     in an extern "C" block.  (Such code cannot be shared with C.)  */
+  extern class C1 n1c1;                 // { dg-warning "\\\[-Wredundant-tags" }
+  extern enum E1 n1e1;                  // { dg-warning "\\\[-Wredundant-tags" }
+  extern enum_struct ES1 n1es1;         // { dg-warning "\\\[-Wredundant-tags" }
+  extern struct S1 n1s1;                // { dg-warning "\\\[-Wredundant-tags" }
+  extern union U1 n1u1;                 // { dg-warning "\\\[-Wredundant-tags" }
+  }
+}   // extern "C"
+
+
+extern "C++" {
+
+  class C2 { };
+  enum E2 { };
+  enum_struct ES2 { };
+  struct S2 {
+    enum E2 e21;                        // { dg-warning "\\\[-Wredundant-tags" }
+    E2 e22;
+    enum_struct ES2 es21;               // { dg-warning "\\\[-Wredundant-tags" }
+    ES2 es22;
+  };
+  union U2 { };
+
+  void f5 (class C2);                   // { dg-warning "\\\[-Wredundant-tags" }
+  void f6 (enum E2);                    // { dg-warning "\\\[-Wredundant-tags" }
+  void f7 (enum_struct ES2);            // { dg-warning "\\\[-Wredundant-tags" }
+  void f8 (struct S2);                  // { dg-warning "\\\[-Wredundant-tags" }
+  void f9 (union U2);                   // { dg-warning "\\\[-Wredundant-tags" }
+
+  extern class C2 c2;                   // { dg-warning "\\\[-Wredundant-tags" }
+  extern enum E2 e2;                    // { dg-warning "\\\[-Wredundant-tags" }
+  extern enum_struct ES2 es2;           // { dg-warning "\\\[-Wredundant-tags" }
+  extern struct S2 s2;                  // { dg-warning "\\\[-Wredundant-tags" }
+  extern union U2 u2;                   // { dg-warning "\\\[-Wredundant-tags" }
+}   // extern "C++"
+
+
+namespace N {
+
+class C3 { };
+enum E3 { };
+enum_struct ES3 { };
+struct S3 { };
+union U3 { };
+
+void f10 (class C3);                    // { dg-warning "\\\[-Wredundant-tags" }
+void f11 (enum E3);                     // { dg-warning "\\\[-Wredundant-tags" }
+void f12 (enum_struct ES3);             // { dg-warning "\\\[-Wredundant-tags" }
+void f13 (struct S3);                   // { dg-warning "\\\[-Wredundant-tags" }
+void f14 (union U3);                    // { dg-warning "\\\[-Wredundant-tags" }
+
+extern class C3 c3;                     // { dg-warning "\\\[-Wredundant-tags" }
+extern enum E3 e3;                      // { dg-warning "\\\[-Wredundant-tags" }
+extern enum_struct ES3 es3;             // { dg-warning "\\\[-Wredundant-tags" }
+extern struct S3 s3;                    // { dg-warning "\\\[-Wredundant-tags" }
+extern union U3 u3;                     // { dg-warning "\\\[-Wredundant-tags" }
+
+extern "C" {
+
+  /* Verify that -Wredundant-tags is issued in an extern "C" block
+     enclosed within a namespace.  (Such code cannot be shared with
+     C.)  */
+  class C4 { };
+  enum E4 { };
+  enum_struct ES4 { };
+  struct S4 { };
+  union U4 { };
+
+  extern class C4 c4;                   // { dg-warning "\\\[-Wredundant-tags" }
+  extern enum E4 e4;                    // { dg-warning "\\\[-Wredundant-tags" }
+  extern enum_struct ES4 es4;           // { dg-warning "\\\[-Wredundant-tags" }
+  extern struct S4 s4;                  // { dg-warning "\\\[-Wredundant-tags" }
+  extern union U4 u4;                   // { dg-warning "\\\[-Wredundant-tags" }
+}
+
+}   // namespace N
+
+// { dg-prune-output "must not use the 'struct' keyword" }
diff --git a/gcc/testsuite/g++.dg/warn/Wredundant-tags-5.C b/gcc/testsuite/g++.dg/warn/Wredundant-tags-5.C
new file mode 100644 (file)
index 0000000..a3676d8
--- /dev/null
@@ -0,0 +1,109 @@
+// PR c++/93804 - exempt extern "C" headers from -Wredundant-tags
+// Verify that -Wredundant-tags is issued even for redundant class-key
+// in references in the main source file to extern "C" classes defined
+// in headers.
+// { dg-do compile }
+// { dg-options "-Wredundant-tags -ftrack-macro-expansion=0" }
+
+#include "Wredundant-tags-5.h"
+
+extern "C" {
+
+  class C1                    // { dg-warning "\\\[-Wredundant-tags" }
+  fc1 (C1)
+  {
+    return C1 ();
+  }
+
+  EC1
+  fce1 (enum_class EC1)       // { dg-warning "\\\[-Wredundant-tags" }
+  {
+    return EC1 ();
+  }
+
+  E1
+  fe1 (E1)
+  {
+    return (enum E1)0;        // { dg-warning "\\\[-Wredundant-tags" }
+  }
+
+  struct S1                   // { dg-warning "\\\[-Wredundant-tags" }
+  fs1 (S1)
+  {
+    return S1 ();
+  }
+
+  U1
+  fu1 (union U1)              // { dg-warning "\\\[-Wredundant-tags" }
+  {
+    return U1 ();
+  }
+
+}   // extern "C"
+
+
+extern "C++" {
+
+  class C2                    // { dg-warning "\\\[-Wredundant-tags" }
+  fc2 (C2)
+  {
+    return C2 ();
+  }
+
+  EC2
+  fce2 (enum_class EC2)       // { dg-warning "\\\[-Wredundant-tags" }
+  {
+    return EC2 ();
+  }
+
+  E2
+  fe2 (E2)
+  {
+    return (enum E2)0;        // { dg-warning "\\\[-Wredundant-tags" }
+  }
+
+  struct S2                   // { dg-warning "\\\[-Wredundant-tags" }
+  fs2 (S2)
+  {
+    return S2 ();
+  }
+
+  U2
+  fu2 (union U2)              // { dg-warning "\\\[-Wredundant-tags" }
+  {
+    return U2 ();
+  }
+
+}   // extern "C++"
+
+
+class C3                      // { dg-warning "\\\[-Wredundant-tags" }
+fc3 (C3)
+{
+  return C3 ();
+}
+
+EC3
+fce3 (enum_class EC3)         // { dg-warning "\\\[-Wredundant-tags" }
+{
+  return EC3 ();
+}
+
+E3 fe3 (E3)
+{
+  return (enum E3)0;          // { dg-warning "\\\[-Wredundant-tags" }
+}
+
+struct S3                      // { dg-warning "\\\[-Wredundant-tags" }
+fs3 (S3)
+{
+  return S3 ();
+}
+
+U3
+fu3 (union U3)                // { dg-warning "\\\[-Wredundant-tags" }
+{
+  return U3 ();
+}
+
+// { dg-prune-output "must not use the 'class' keyword" }
diff --git a/gcc/testsuite/g++.dg/warn/Wredundant-tags-5.h b/gcc/testsuite/g++.dg/warn/Wredundant-tags-5.h
new file mode 100644 (file)
index 0000000..c72aee6
--- /dev/null
@@ -0,0 +1,80 @@
+#ifndef WREDUNDANT_TAGS_H
+#define WREDUNDANT_TAGS_H
+
+#if __cplusplus >= 201103L
+# define enum_class   enum class
+#else
+# define enum_class   class
+#endif
+
+extern "C" {
+
+  class C1 { };
+  enum_class EC1 { };
+  enum E1 { };
+  struct S1 { };
+  union U1 { };
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wredundant-tags"
+  class C1 fc1 (class C1);          // -Wredundant-tags
+  enum_class EC1 fce1 (enum_class EC1);
+#pragma GCC diagnostic pop
+
+  enum E1 fe1 (enum E1);
+  struct S1 fs1 (struct S1);
+  union U1 fu1 (union U1);
+
+  C1 fc1 (C1);
+  EC1 fce1 (EC1);
+  E1 fe1 (E1);
+  S1 fs1 (S1);
+  U1 fu1 (U1);
+}
+
+
+extern "C++" {
+
+  class C2 { };
+  enum_class EC2 { };
+  enum E2 { };
+  struct S2 { };
+  union U2 { };
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wredundant-tags"
+  class C2 fc2 (class C2);                // -Wredundant-tags
+  enum_class EC2 fce2 (enum_class EC2);   // -Wredundant-tags
+  struct S2 fs2 (struct S2);              // -Wredundant-tags
+  union U2 fu2 (union U2);                // -Wredundant-tags
+#pragma GCC diagnostic pop
+
+  C2 fc2 (C2);
+  EC2 fce2 (EC2);
+  E2 fe2 (E2);
+  S2 fs2 (S2);
+  U2 fu2 (U2);
+}
+
+
+class C3 { };
+enum_class EC3 { };
+enum E3 { };
+struct S3 { };
+union U3 { };
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wredundant-tags"
+class C3 fc3 (class C3);                  // -Wredundant-tags
+enum_class EC3 fce3 (enum_class EC3);     // -Wredundant-tags
+struct S3 fs3 (struct S3);                // -Wredundant-tags
+union U3 fu3 (union U3);                  // -Wredundant-tags
+#pragma GCC diagnostic pop
+
+C3 fc3 (C3);
+EC3 fce3 (EC3);
+E3 fe3 (E3);
+S3 fs3 (S3);
+U3 fu3 (U3);
+
+#endif   // WREDUNDANT_TAGS_H