c++: avoid -Wredundant-tags on a first declaration in use [PR 93824]
authorMartin Sebor <msebor@gmail.com>
Fri, 27 Mar 2020 16:07:45 +0000 (12:07 -0400)
committerJason Merrill <jason@redhat.com>
Fri, 27 Mar 2020 16:08:18 +0000 (12:08 -0400)
-Wredundant-tags doesn't consider type declarations that are also
the first uses of the type, such as in 'void f (struct S);' and
issues false positives for those.  According to the reported that's
making it harder to use the warning to clean up LibreOffice.

The attached patch extends -Wredundant-tags to avoid these false
positives by relying on the same class_decl_loc_t::class2loc mapping
as -Wmismatched-tags.  The patch also improves the detection
of both issues in template declarations.

gcc/cp/ChangeLog
2020-03-27  Martin Sebor  <msebor@redhat.com>

PR c++/94078
PR c++/93824
PR c++/93810
* cp-tree.h (most_specialized_partial_spec): Declare.
* parser.c (cp_parser_elaborated_type_specifier): Distinguish alias
from declarations.
(specialization_of): New function.
(cp_parser_check_class_key): Move code...
(class_decl_loc_t::add): ...to here.  Add parameters.  Avoid issuing
-Wredundant-tags on first-time declarations in other declarators.
Correct handling of template specializations.
(class_decl_loc_t::diag_mismatched_tags): Also expect to be called
when -Wredundant-tags is enabled.  Use primary template or partial
specialization as the guide for uses of implicit instantiations.
* pt.c (most_specialized_partial_spec): Declare extern.

gcc/testsuite/ChangeLog
2020-03-27  Martin Sebor  <msebor@redhat.com>

PR c++/94078
PR c++/93824
PR c++/93810
* g++.dg/warn/Wmismatched-tags-3.C: New test.
* g++.dg/warn/Wmismatched-tags-4.C: New test.
* g++.dg/warn/Wmismatched-tags-5.C: New test.
* g++.dg/warn/Wmismatched-tags-6.C: New test.
* g++.dg/warn/Wredundant-tags-3.C: Remove xfails.
* g++.dg/warn/Wredundant-tags-6.C: New test.
* g++.dg/warn/Wredundant-tags-7.C: New test.

12 files changed:
gcc/cp/ChangeLog
gcc/cp/cp-tree.h
gcc/cp/parser.c
gcc/cp/pt.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/warn/Wmismatched-tags-3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/warn/Wmismatched-tags-4.C [new file with mode: 0644]
gcc/testsuite/g++.dg/warn/Wmismatched-tags-5.C [new file with mode: 0644]
gcc/testsuite/g++.dg/warn/Wmismatched-tags-6.C [new file with mode: 0644]
gcc/testsuite/g++.dg/warn/Wredundant-tags-3.C
gcc/testsuite/g++.dg/warn/Wredundant-tags-6.C [new file with mode: 0644]
gcc/testsuite/g++.dg/warn/Wredundant-tags-7.C [new file with mode: 0644]

index 7224ff195d611f0ce43a01f6c415b244dfd5fb2a..2a2e6eac7bf681ccb766afa434248d6e15f52648 100644 (file)
@@ -1,3 +1,21 @@
+2020-03-27  Martin Sebor  <msebor@redhat.com>
+
+       PR c++/94078
+       PR c++/93824
+       PR c++/93810
+       * cp-tree.h (most_specialized_partial_spec): Declare.
+       * parser.c (cp_parser_elaborated_type_specifier): Distinguish alias
+       from declarations.
+       (specialization_of): New function.
+       (cp_parser_check_class_key): Move code...
+       (class_decl_loc_t::add): ...to here.  Add parameters.  Avoid issuing
+       -Wredundant-tags on first-time declarations in other declarators.
+       Correct handling of template specializations.
+       (class_decl_loc_t::diag_mismatched_tags): Also expect to be called
+       when -Wredundant-tags is enabled.  Use primary template or partial
+       specialization as the guide for uses of implicit instantiations.
+       * pt.c (most_specialized_partial_spec): Declare extern.
+
 2020-03-27  Nathan Sidwell  <nathan@acm.org>
 
        PR c++/94257
index 4e1d0f1d42e127d4166381cae5456890ba6929c6..af7734584136a926f8bec5026b194b2919ef2cac 100644 (file)
@@ -6947,6 +6947,7 @@ extern int comp_template_args                     (tree, tree, tree * = NULL,
 extern int template_args_equal                  (tree, tree, bool = false);
 extern tree maybe_process_partial_specialization (tree);
 extern tree most_specialized_instantiation     (tree);
+extern tree most_specialized_partial_spec       (tree, tsubst_flags_t);
 extern void print_candidates                   (tree);
 extern void instantiate_pending_templates      (int);
 extern tree tsubst_default_argument            (tree, int, tree, tree,
index 1afd03d38635cf93a1528b4e2623243567632e37..3ca8eb9baf8b5249ec107f88fbe88b9e9f33f33d 100644 (file)
@@ -19006,9 +19006,12 @@ cp_parser_elaborated_type_specifier (cp_parser* parser,
     cp_parser_maybe_warn_enum_key (parser, key_loc, type, scoped_key);
   else
     {
-      /* Diagnose class/struct/union mismatches.  */
+      /* Diagnose class/struct/union mismatches.  IS_DECLARATION is false
+        for alias definition.  */
+      bool decl_class = (is_declaration
+                        && cp_parser_declares_only_class_p (parser));
       cp_parser_check_class_key (parser, key_loc, tag_type, type, false,
-                                cp_parser_declares_only_class_p (parser));
+                                decl_class);
 
       /* Indicate whether this class was declared as a `class' or as a
         `struct'.  */
@@ -30991,8 +30994,9 @@ class class_decl_loc_t
   /* Issues -Wmismatched-tags for all classes.  */
   static void diag_mismatched_tags ();
 
-  /* Adds TYPE_DECL to the collection of class decls.  */
-  static void add (tree, tag_types, bool, bool);
+  /* Adds TYPE_DECL to the collection of class decls and diagnoses
+     redundant tags (if -Wredundant-tags is enabled).  */
+  static void add (cp_parser *, location_t, tag_types, tree, bool, bool);
 
   /* Either adds this decl to the collection of class decls
      or diagnoses it, whichever is appropriate.  */
@@ -31020,12 +31024,19 @@ private:
     return locvec[i].class_key;
   }
 
+  /* True if a definition for the class has been seen.  */
+  bool def_p () const
+  {
+    return idxdef < locvec.length ();
+  }
+
   /* The location of a single mention of a class type with the given
      class-key.  */
   struct class_key_loc_t
   {
     class_key_loc_t (tree func, location_t loc, tag_types key, bool redundant)
-      : func (func), loc (loc), class_key (key), key_redundant (redundant) { }
+      : func (func), loc (loc), class_key (key), key_redundant (redundant)
+    { }
 
     /* The function the type is mentioned in.  */
     tree func;
@@ -31088,6 +31099,40 @@ cp_parser_check_class_key (cp_parser *parser, location_t key_loc,
       && class_key != union_type)
     return;
 
+  class_decl_loc_t::add (parser, key_loc, class_key, type, def_p, decl_p);
+}
+
+/* Returns the template or specialization of one to which the RECORD_TYPE
+   TYPE corresponds.  */
+
+static tree
+specialization_of (tree type)
+{
+  tree ret = type;
+
+  /* Determine the template or its partial specialization to which TYPE
+     corresponds.  */
+  if (tree spec = most_specialized_partial_spec (type, tf_none))
+    if (spec != error_mark_node)
+      ret = TREE_TYPE (TREE_VALUE (spec));
+
+  if (ret == type)
+    ret = CLASSTYPE_PRIMARY_TEMPLATE_TYPE (type);
+
+  return TYPE_MAIN_DECL (ret);
+}
+
+
+/* Adds the class TYPE to the collection of class decls and diagnoses
+   redundant tags (if -Wredundant-tags is enabled).
+   DEF_P is expected to be set for a definition of class TYPE.  DECL_P
+   is set for a (likely, based on syntactic context) declaration of class
+   TYPE and clear for a reference to it that is not a declaration of it.  */
+
+void
+class_decl_loc_t::add (cp_parser *parser, location_t key_loc,
+                      tag_types class_key, tree type, bool def_p, bool decl_p)
+{
   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
@@ -31099,7 +31144,10 @@ cp_parser_check_class_key (cp_parser *parser, location_t key_loc,
   /* The class-key is redundant for uses of the CLASS_TYPE that are
      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;
+  bool key_redundant = (!def_p && !decl_p
+                       && (decl == type_decl
+                           || TREE_CODE (decl) == TEMPLATE_DECL
+                           || TYPE_BEING_DEFINED (type)));
 
   if (key_redundant
       && class_key != class_type
@@ -31117,29 +31165,8 @@ cp_parser_check_class_key (cp_parser *parser, location_t key_loc,
        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);
-    }
-
-  if (seen_as_union || !warn_mismatched_tags)
-    return;
-
-  class_decl_loc_t::add (type_decl, class_key, key_redundant, def_p);
-}
-
-/* Adds TYPE_DECL to the collection of class decls.  */
-
-void
-class_decl_loc_t::add (tree type_decl, tag_types class_key, bool redundant,
-                      bool def_p)
-{
+  /* Set if a declaration of TYPE has previously been seen or if it must
+     exist in a precompiled header.  */
   bool exist;
   class_decl_loc_t *rdl = &class2loc.get_or_insert (type_decl, &exist);
   if (!exist)
@@ -31149,30 +31176,52 @@ class_decl_loc_t::add (tree type_decl, tag_types class_key, bool redundant,
        {
          /* TYPE_DECL is the first declaration or definition of the type
             (outside precompiled headers -- see below).  Just create
-            a new entry for it.  */
+            a new entry for it and return unless it's a declaration
+            involving a template that may need to be diagnosed by
+            -Wredundant-tags.  */
          *rdl = class_decl_loc_t (class_key, false, def_p);
-         return;
+         if (TREE_CODE (decl) != TEMPLATE_DECL)
+           return;
+       }
+      else
+       {
+         /* TYPE was previously defined in some unknown precompiled hdeader.
+            Simply add a record of its definition at an unknown location and
+            proceed below to add a reference to it at the current location.
+            (Declarations in precompiled headers that are not definitions
+            are ignored.)  */
+         tag_types def_key
+           = CLASSTYPE_DECLARED_CLASS (type) ? class_type : record_type;
+         location_t def_loc = DECL_SOURCE_LOCATION (type_decl);
+         *rdl = class_decl_loc_t (def_key, false, true, def_loc);
+         exist = true;
        }
-
-      /* TYPE was previously defined in some unknown precompiled hdeader.
-        Simply add a record of its definition at an unknown location and
-        proceed below to add a reference to it at the current location.
-        (Declarations in precompiled headers that are not definitions
-        are ignored.)  */
-      tag_types def_key
-       = CLASSTYPE_DECLARED_CLASS (type) ? class_type : record_type;
-      location_t def_loc = DECL_SOURCE_LOCATION (type_decl);
-      *rdl = class_decl_loc_t (def_key, false, true, def_loc);
     }
 
   /* A prior declaration of TYPE_DECL has been seen.  */
 
+  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);
+    }
+
+  if (!exist)
+    /* Do nothing if this is the first declaration of the type.  */
+    return;
+
   if (rdl->idxdef != UINT_MAX && rdl->def_class_key == class_key)
     /* Do nothing if the class-key in this declaration matches
        the definition.  */
     return;
 
-  rdl->add_or_diag_mismatched_tag (type_decl, class_key, redundant, def_p);
+  rdl->add_or_diag_mismatched_tag (type_decl, class_key, key_redundant,
+                                  def_p);
 }
 
 /* Either adds this DECL corresponding to the TYPE_DECL to the collection
@@ -31225,35 +31274,70 @@ class_decl_loc_t::add_or_diag_mismatched_tag (tree type_decl,
 void
 class_decl_loc_t::diag_mismatched_tags (tree type_decl)
 {
-  unsigned ndecls = locvec.length ();
-
-  /* Skip a declaration that consistently uses the same class-key
-     or one with just a solitary declaration (i.e., TYPE_DECL).  */
-  if (def_class_key != none_type || ndecls < 2)
+  if (!warn_mismatched_tags)
     return;
 
-  /* Save the current function before changing it below.  */
-  tree save_func = current_function_decl;
-  /* Set if a class definition for RECLOC has been seen.  */
-  bool def_p = idxdef < ndecls;
-  unsigned idxguide = def_p ? idxdef : 0;
+  /* Number of uses of the class.  */
+  const unsigned ndecls = locvec.length ();
+
+  /* The class (or template) declaration guiding the decisions about
+     the diagnostic.  For ordinary classes it's the same as THIS.  For
+     uses of instantiations of templates other than their declarations
+     it points to the record for the declaration of the corresponding
+     primary template or partial specialization.  */
+  class_decl_loc_t *cdlguide = this;
+
+  tree type = TREE_TYPE (type_decl);
+  if (CLASSTYPE_IMPLICIT_INSTANTIATION (type))
+    {
+      /* For implicit instantiations of a primary template look up
+        the primary or partial specialization and use it as
+        the expected class-key rather than using the class-key of
+        the first reference to the instantiation.  The primary must
+        be (and inevitably is) at index zero.  */
+      tree spec = specialization_of (type);
+      cdlguide = class2loc.get (spec);
+      gcc_assert (cdlguide != NULL);
+    }
+  else
+    {
+      /* Skip declarations that consistently use the same class-key.  */
+      if (def_class_key != none_type)
+       return;
+    }
+
+  /* Set if a definition for the class has been seen.  */
+  const bool def_p = cdlguide->def_p ();
+
+  /* The index of the declaration whose class-key this declaration
+     is expected to match.  It's either the class-key of the class
+     definition if one exists or the first declaration otherwise.  */
+  const unsigned idxguide = def_p ? cdlguide->idxdef : 0;
+
+  /* The class-key the class is expected to be declared with: it's
+     either the key used in its definition or the first declaration
+     if no definition has been provided.
+     For implicit instantiations of a primary template it's
+     the class-key used to declare the primary with.  The primary
+     must be at index zero.  */
+  const tag_types xpect_key = cdlguide->class_key (idxguide);
+
   unsigned idx = 0;
   /* Advance IDX to the first declaration that either is not
      a definition or that doesn't match the first declaration
      if no definition is provided.  */
-  while (class_key (idx) == class_key (idxguide))
+  while (class_key (idx) == xpect_key)
     if (++idx == ndecls)
       return;
 
-  /* The class-key the class is expected to be declared with: it's
-     either the key used in its definition or the first declaration
-     if no definition has been provided.  */
-  tag_types xpect_key = class_key (def_p ? idxguide : 0);
-  const char *xmatchkstr = xpect_key == record_type ? "class" : "struct";
-  const char *xpectkstr = xpect_key == record_type ? "struct" : "class";
+  /* Save the current function before changing it below.  */
+  tree save_func = current_function_decl;
   /* Set the function declaration to print in diagnostic context.  */
   current_function_decl = function (idx);
 
+  const char *xmatchkstr = xpect_key == record_type ? "class" : "struct";
+  const char *xpectkstr = xpect_key == record_type ? "struct" : "class";
+
   location_t loc = location (idx);
   bool key_redundant_p = key_redundant (idx);
   auto_diagnostic_group d;
@@ -31274,7 +31358,7 @@ class_decl_loc_t::diag_mismatched_tags (tree type_decl)
 
   /* Also point to the first declaration or definition that guided
      the decision to issue the warning above.  */
-  inform (location (idxguide),
+  inform (cdlguide->location (idxguide),
          (def_p
           ? G_("%qT defined as %qs here")
           : G_("%qT first declared as %qs here")),
@@ -31316,25 +31400,29 @@ class_decl_loc_t::diag_mismatched_tags (tree type_decl)
 void
 class_decl_loc_t::diag_mismatched_tags ()
 {
-  /* CLASS2LOC should be empty if -Wmismatched-tags is disabled.  */
-  gcc_assert (warn_mismatched_tags || class2loc.is_empty ());
+  /* CLASS2LOC should be empty if both -Wmismatched-tags and
+     -Wredundant-tags are disabled.  */
+  gcc_assert (warn_mismatched_tags
+             || warn_redundant_tags
+             || class2loc.is_empty ());
 
-  /* Save the current function before changing it below.  It should
+  /* Save the current function before changing on return.  It should
      be null at this point.  */
-  tree save_func = current_function_decl;
+  temp_override<tree> cleanup (current_function_decl);
 
-  /* Iterate over the collected class/struct declarations.  */
-  typedef class_to_loc_map_t::iterator iter_t;
-  for (iter_t it = class2loc.begin (); it != class2loc.end (); ++it)
+  if (warn_mismatched_tags)
     {
-      tree type_decl = (*it).first;
-      class_decl_loc_t &recloc = (*it).second;
-      recloc.diag_mismatched_tags (type_decl);
+      /* Iterate over the collected class/struct/template declarations.  */
+      typedef class_to_loc_map_t::iterator iter_t;
+      for (iter_t it = class2loc.begin (); it != class2loc.end (); ++it)
+       {
+         tree type_decl = (*it).first;
+         class_decl_loc_t &recloc = (*it).second;
+         recloc.diag_mismatched_tags (type_decl);
+       }
     }
 
   class2loc.empty ();
-  /* Restore the current function.  */
-  current_function_decl = save_func;
 }
 
 /* Issue an error message if DECL is redeclared with different
index 7ea8ce4cbc351033fa3cdd29d9922cbccc011fd9..15b54396ed3103d941038a2e74ce623be6a73054 100644 (file)
@@ -185,7 +185,7 @@ static int unify_pack_expansion (tree, tree, tree,
                                 tree, unification_kind_t, bool, bool);
 static tree copy_template_args (tree);
 static tree tsubst_template_parms (tree, tree, tsubst_flags_t);
-static tree most_specialized_partial_spec (tree, tsubst_flags_t);
+tree most_specialized_partial_spec (tree, tsubst_flags_t);
 static tree tsubst_aggr_type (tree, tree, tsubst_flags_t, tree, int);
 static tree tsubst_arg_types (tree, tree, tree, tsubst_flags_t, tree);
 static tree tsubst_function_type (tree, tree, tsubst_flags_t, tree);
@@ -24332,7 +24332,7 @@ most_general_template (tree decl)
    partial specializations matching TARGET, then NULL_TREE is
    returned, indicating that the primary template should be used.  */
 
-static tree
+tree
 most_specialized_partial_spec (tree target, tsubst_flags_t complain)
 {
   tree list = NULL_TREE;
index 2baa6e800cbafe4f146409854bbad3e436e35915..1de6c7ab2351491afd5266066af81b0d2405e287 100644 (file)
@@ -1,3 +1,16 @@
+2020-03-27  Martin Sebor  <msebor@redhat.com>
+
+       PR c++/94078
+       PR c++/93824
+       PR c++/93810
+       * g++.dg/warn/Wmismatched-tags-3.C: New test.
+       * g++.dg/warn/Wmismatched-tags-4.C: New test.
+       * g++.dg/warn/Wmismatched-tags-5.C: New test.
+       * g++.dg/warn/Wmismatched-tags-6.C: New test.
+       * g++.dg/warn/Wredundant-tags-3.C: Remove xfails.
+       * g++.dg/warn/Wredundant-tags-6.C: New test.
+       * g++.dg/warn/Wredundant-tags-7.C: New test.
+
 2020-03-27  David Malcolm  <dmalcolm@redhat.com>
 
        * gcc.dg/analyzer/data-model-5b.c: Add xfail for new false
diff --git a/gcc/testsuite/g++.dg/warn/Wmismatched-tags-3.C b/gcc/testsuite/g++.dg/warn/Wmismatched-tags-3.C
new file mode 100644 (file)
index 0000000..ecbe66d
--- /dev/null
@@ -0,0 +1,14 @@
+/* { dg-do compile }
+   { dg-options "-Wall -Wmismatched-tags" } */
+
+extern class C1 c1;             // { dg-message "declared as 'class'" }
+extern struct C1 c1;            // { dg-warning "\\\[-Wmismatched-tags" }
+
+void fs1 (struct S1);           // { dg-message "declared as 'struct'" }
+void fs1 (class S1);            // { dg-warning "\\\[-Wmismatched-tags" }
+
+enum
+{
+  ec2 = sizeof (struct C2*),    // { dg-message "declared as 'struct'" }
+  fc2 = sizeof (class C2*)      // { dg-warning "\\\[-Wmismatched-tags" }
+};
diff --git a/gcc/testsuite/g++.dg/warn/Wmismatched-tags-4.C b/gcc/testsuite/g++.dg/warn/Wmismatched-tags-4.C
new file mode 100644 (file)
index 0000000..7570264
--- /dev/null
@@ -0,0 +1,141 @@
+/* PR c++/94078 - bogus and missing -Wmismatched-tags on an instance
+   of a template
+   Verify that -Wmismatched-tags is issued for redeclarations and
+   instances of the appropriate primary template or specialization.
+  { dg-do compile }
+  { dg-options "-Wmismatched-tags" } */
+
+// Exercise explicit specialization.
+template <class> class S1;
+template <>      struct S1<int>;
+
+template <class> class S1;
+template <class> struct S1;           // { dg-warning "\\\[-Wmismatched-tags" }
+
+template <>      class S1<char>;
+template <>      struct S1<char>;     // { dg-warning "\\\[-Wmismatched-tags" }
+
+template <>      class S1<int>;       // { dg-warning "\\\[-Wmismatched-tags" }
+template <>      struct S1<int>;
+
+extern        S1<void> s1v;
+extern class  S1<void> s1v;
+extern struct S1<void> s1v;           // { dg-warning "\\\[-Wmismatched-tags" }
+
+extern        S1<int> s1i;
+extern class  S1<int> s1i;            // { dg-warning "\\\[-Wmismatched-tags" }
+extern struct S1<int> s1i;
+
+extern        S1<char> s1c;
+extern class  S1<char> s1c;
+extern struct S1<char> s1c;           // { dg-warning "\\\[-Wmismatched-tags" }
+
+
+// Exercise partial specialization.
+template <class>   struct S2;
+template <class T> class S2<const T>;
+
+template <class>   class S2;          // { dg-warning "\\\[-Wmismatched-tags" }
+template <class>   struct S2;
+
+template <class T> class S2<const T>;
+template <class T> struct S2<const T>;// { dg-warning "\\\[-Wmismatched-tags" }
+
+extern        S2<int> s2i;
+extern class  S2<int> s2i;            // { dg-warning "\\\[-Wmismatched-tags" }
+extern struct S2<int> s2i;
+
+extern        S2<const int> s2ci;
+extern class  S2<const int> s2ci;
+extern struct S2<const int> s2ci;     // { dg-warning "\\\[-Wmismatched-tags" }
+
+
+template <class>   struct S3;
+template <class T> class S3<T*>;
+template <class T> struct S3<T&>;
+
+template <class>   class S3;          // { dg-warning "\\\[-Wmismatched-tags" }
+template <class>   struct S3;
+
+template <class T> class S3<T*>;
+template <class T> struct S3<T*>;     // { dg-warning "\\\[-Wmismatched-tags" }
+
+template <class T> class S3<T&>;      // { dg-warning "\\\[-Wmismatched-tags" }
+template <class T> struct S3<T&>;
+
+extern        S3<int> s3i;
+extern class  S3<int> s3i;            // { dg-warning "\\\[-Wmismatched-tags" }
+extern struct S3<int> s3i;
+
+extern        S3<int*> s3p;
+extern class  S3<int*> s3p;
+extern struct S3<int*> s3p;           // { dg-warning "\\\[-Wmismatched-tags" }
+
+extern        S3<int&> s3r;
+extern class  S3<int&> s3r;           // { dg-warning "\\\[-Wmismatched-tags" }
+extern struct S3<int&> s3r;
+
+// Repeat exactly the same as above.
+extern        S3<int> s3i;
+extern class  S3<int> s3i;            // { dg-warning "\\\[-Wmismatched-tags" }
+extern struct S3<int> s3i;
+
+extern        S3<int*> s3p;
+extern class  S3<int*> s3p;
+extern struct S3<int*> s3p;           // { dg-warning "\\\[-Wmismatched-tags" }
+
+extern        S3<int&> s3r;
+extern class  S3<int&> s3r;           // { dg-warning "\\\[-Wmismatched-tags" }
+extern struct S3<int&> s3r;
+
+// Repeat the same as above just with different type.
+extern        S3<long> s3l;
+extern class  S3<long> s3l;           // { dg-warning "\\\[-Wmismatched-tags" }
+extern struct S3<long> s3l;
+
+extern        S3<long*> s3lp;
+extern class  S3<long*> s3lp;
+extern struct S3<long*> s3lp;         // { dg-warning "\\\[-Wmismatched-tags" }
+
+extern        S3<long&> s3lr;
+extern class  S3<long&> s3lr;         // { dg-warning "\\\[-Wmismatched-tags" }
+extern struct S3<long&> s3lr;
+
+// Repeat with the class-keys swapped.
+extern        S3<long> s3l;
+extern struct S3<long> s3l;
+extern class  S3<long> s3l;          // { dg-warning "\\\[-Wmismatched-tags" }
+
+extern        S3<long*> s3lp;
+extern struct S3<long*> s3lp;        // { dg-warning "\\\[-Wmismatched-tags" }
+extern class  S3<long*> s3lp;
+
+extern        S3<long&> s3lr;
+extern struct S3<long&> s3lr;
+extern class  S3<long&> s3lr;        // { dg-warning "\\\[-Wmismatched-tags" }
+
+
+namespace N
+{
+template <class> struct A;
+
+extern class A<int> ai;               // { dg-warning "\\\[-Wmismatched-tags" }
+extern struct A<int> ai;
+
+typedef class A<int> AI;              // { dg-warning "\\\[-Wmismatched-tags" }
+typedef struct A<int> AI;
+
+template <class> struct B;
+template <> class B<int>;
+template <> struct B<char>;
+
+extern class B<int> bi;
+extern struct B<int> bi;              // { dg-warning "\\\[-Wmismatched-tags" }
+
+extern class B<char> bc;              // { dg-warning "\\\[-Wmismatched-tags" }
+extern struct B<char> bc;
+
+typedef class B<char> BC;             // { dg-warning "\\\[-Wmismatched-tags" }
+typedef struct B<char> BC;
+
+}
diff --git a/gcc/testsuite/g++.dg/warn/Wmismatched-tags-5.C b/gcc/testsuite/g++.dg/warn/Wmismatched-tags-5.C
new file mode 100644 (file)
index 0000000..622b9e3
--- /dev/null
@@ -0,0 +1,117 @@
+/* PR c++/93810 - missing -Wmismatched-tags and -Wredundant-tags on a typedef
+   of an implicit class template specialization
+  { dg-do compile }
+  { dg-options "-Wall -Wmismatched-tags" }
+  { dg-require-effective-target c++11 } */
+
+class A;                                // { dg-message "declared as 'class'" }
+typedef        A A0;
+typedef class  A A0;
+typedef struct A A0;                    // { dg-warning "-Wmismatched-tags" }
+
+template <int> struct B;                // { dg-message "declared as 'struct'" }
+typedef        B<0> B0;
+typedef class  B<0> B0;                 // { dg-warning "-Wmismatched-tags" }
+typedef struct B<0> B0;
+
+
+// Exercise member types of templates with non-type arguments.
+template <int> struct CN;               // { dg-message "declared as 'struct'" }
+
+template <int N>
+struct X_CNp1 {
+  typedef CN<N + 1> CNp1;
+};
+
+template <int N>
+struct X_class_CNp1 {
+  typedef class CN<N + 1> CNp1;         // { dg-warning "-Wmismatched-tags" }
+};
+
+template <int N>
+struct X_struct_CNp1 {
+  typedef struct CN<N + 1> CNp1;
+};
+
+
+// Exercise partial specialization of templates with member types.
+template <class> class CT1;
+template <class T> struct CT1<T*> { };
+template <class T> struct CT1<T**> { };
+template <class T> class  CT1<T***> { };
+
+template <class> struct CT2;
+template <class T> struct CT2<T*> {
+  // Expect class-key to match the primary.
+         CT1<T> ct1_0;
+  class  CT1<T> ct1_1;
+  struct CT1<T> ct1_2;                  // { dg-warning "-Wmismatched-tags" }
+
+  // Expect class-key to match the CT1<T*> partial specialization.
+         CT1<T*> ct1p1_0;
+  class  CT1<T*> ct1p1_1;               // { dg-warning "-Wmismatched-tags" }
+  struct CT1<T*> ct1p1_2;
+
+  // Expect class-key to match the CT1<T**> partial specialization.
+         CT1<T**> ct1p2_0;
+  class  CT1<T**> ct1p2_1;              // { dg-warning "-Wmismatched-tags" }
+  struct CT1<T**> ct1p2_2;
+
+  // Expect class-key to match the CT1<T***> partial specialization.
+         CT1<T***> ct1p3_0;
+  class  CT1<T***> ct1p3_1;
+  struct CT1<T***> ct1p3_2;             // { dg-warning "-Wmismatched-tags" }
+
+  // Expect class-key to still match the CT1<T***> partial specialization.
+         CT1<T****> ct1p4_0;
+  class  CT1<T****> ct1p4_1;
+  struct CT1<T****> ct1p4_2;            // { dg-warning "-Wmismatched-tags" }
+};
+
+// Exercise many partial specializations (since the class-key for each
+// must be tracked separately from the others).
+template <class>   class  D;
+template <class T> struct D<T*>;
+template <class T> class  D<T&>;
+template <class T> struct D<const T*>;
+template <class T> class  D<const T&>;
+template <class T> struct D<volatile T*>;
+template <class T> class  D<volatile T&>;
+template <class T> struct D<const volatile T*>;
+template <class T> class  D<const volatile T&>;
+
+typedef class  D<int*> DIP;             // { dg-warning "-Wmismatched-tags" }
+typedef struct D<int*> DIP;
+typedef class  D<int*> DIP;             // { dg-warning "-Wmismatched-tags" }
+typedef struct D<int*> DIP;
+
+typedef class  D<int&>  DIR;
+typedef struct D<int&> DIR;             // { dg-warning "-Wmismatched-tags" }
+typedef class  D<int&>  DIR;
+
+
+typedef struct D<const int*> DCIP;
+typedef class  D<const int*> DCIP;      // { dg-warning "-Wmismatched-tags" }
+typedef struct D<const int*> DCIP;
+
+typedef struct D<const int&> DCIR;      // { dg-warning "-Wmismatched-tags" }
+typedef class  D<const int&>  DCIR;
+typedef struct D<const int&> DCIR;      // { dg-warning "-Wmismatched-tags" }
+
+
+typedef struct D<volatile int*> DVIP;
+typedef class  D<volatile int*> DVIP;   // { dg-warning "-Wmismatched-tags" }
+typedef struct D<volatile int*> DVIP;
+
+typedef struct D<volatile int&> DVIR;   // { dg-warning "-Wmismatched-tags" }
+typedef class  D<volatile int&> DVIR;
+typedef struct D<volatile int&> DVIR;   // { dg-warning "-Wmismatched-tags" }
+
+
+typedef struct D<const volatile int*> DCVIP;
+typedef class  D<const volatile int*> DCVIP;    // { dg-warning "-Wmismatched-tags" }
+typedef struct D<const volatile int*> DCVIP;
+
+typedef struct D<const volatile int&> DCVIR;    // { dg-warning "-Wmismatched-tags" }
+typedef class  D<const volatile int&> DCVIR;
+typedef struct D<const volatile int&> DCVIR;    // { dg-warning "-Wmismatched-tags" }
diff --git a/gcc/testsuite/g++.dg/warn/Wmismatched-tags-6.C b/gcc/testsuite/g++.dg/warn/Wmismatched-tags-6.C
new file mode 100644 (file)
index 0000000..d9d644c
--- /dev/null
@@ -0,0 +1,29 @@
+/* Verify -Wmismatched-tags on alias definitions.
+   { dg-do compile { target c++11 } }
+   { dg-options "-Wall -Wmismatched-tags" } */
+
+class A;                      // { dg-message "declared as 'class'" }
+using AA =        A;
+using AA = class  A;
+using AA = struct A;          // { dg-warning "-Wmismatched-tags" }
+
+
+template <class> class B;     // { dg-message "declared as 'class'" }
+
+using Bi =        B<int>;
+using Bi = class  B<int>;
+using Bi = struct B<int>;     // { dg-warning "-Wmismatched-tags" }
+using Bi = class  B<int>;
+using Bi = struct B<int>;     // { dg-warning "-Wmismatched-tags" }
+
+
+template <class> class C;     // { dg-message "declared as 'class'" }
+
+template <class T> using Cp = C<T*>;
+template <class T> using Cp = class C<T*>;
+template <class T>
+using Cp = struct C<T*>;      // { dg-warning "-Wmismatched-tags" }
+
+template <class T> using Cp = class  C<T*>;
+template <class T>
+using Cp = struct C<T*>;      // { dg-warning "-Wmismatched-tags" }
index 7b30e949d0c76392e85c003efebf5407f022a91b..0eeee34dae7525f8d818788ca9e408239e022328 100644 (file)
@@ -34,12 +34,12 @@ union N::U u3;        // { dg-warning "-Wredundant-tags" }
 
 typedef N::TC<0> TC0;
 typedef typename N::TC<0> TC0;
-typedef class N::TC<0> TC0;   // { dg-warning "-Wredundant-tags" "pr93809" { xfail *-*-*} .-1 }
+typedef class N::TC<0> TC0;   // { dg-warning "-Wredundant-tags" }
 
 typedef N::TS<0> TS0;
 typedef typename N::TS<0> TS0;
-typedef struct N::TS<0> TS0;  // { dg-warning "-Wredundant-tags" "pr93809" { xfail *-*-*} .-1 }
+typedef struct N::TS<0> TS0;  // { dg-warning "-Wredundant-tags" }
 
 typedef N::TS<0> TS0;
 typedef typename N::TS<0> TS0;
-typedef struct N::TS<0> TS0;  // { dg-warning "-Wredundant-tags" "pr93809" { xfail *-*-*} .-1 }
+typedef struct N::TS<0> TS0;  // { dg-warning "-Wredundant-tags" }
diff --git a/gcc/testsuite/g++.dg/warn/Wredundant-tags-6.C b/gcc/testsuite/g++.dg/warn/Wredundant-tags-6.C
new file mode 100644 (file)
index 0000000..ce5cb96
--- /dev/null
@@ -0,0 +1,91 @@
+/* PR c++/93824 - bogus -Wredundant-tags on a first declaration in use
+   { dg-do compile }
+   { dg-options "-Wredundant-tags" } */
+
+extern class C1 &c1;              // { dg-bogus "\\\[-Wredundant-tags" }
+extern class C1 &c1;              // { dg-warning "\\\[-Wredundant-tags" }
+
+void fc2 (class C2);              // { dg-bogus "\\\[-Wredundant-tags" }
+void fc2 (class C2);              // { dg-warning "\\\[-Wredundant-tags" }
+
+const int
+npc3 = sizeof (class C3*);        // { dg-bogus "\\\[-Wredundant-tags" }
+const int
+nppc3 = sizeof (class C3**);      // { dg-warning "\\\[-Wredundant-tags" }
+
+extern struct S1 *s1p;            // { dg-bogus "\\\[-Wredundant-tags" }
+extern struct S1 s1a[];           // { dg-warning "\\\[-Wredundant-tags" }
+
+struct S3
+{
+  struct S3 *p1s3;                // { dg-warning "\\\[-Wredundant-tags" }
+  S3 *p2s3;
+
+  union U1 *p1u1;                 // { dg-bogus "\\\[-Wredundant-tags" }
+  union U1 *p2u1;                 // { dg-warning "\\\[-Wredundant-tags" }
+} s3;
+
+typedef struct S3 T_S3;           // { dg-warning "\\\[-Wredundant-tags" }
+
+typedef struct S4 T_S4;
+
+struct S5
+{
+  struct S6
+  {
+  private:
+    // 'struct' is redundant in a declaration of a pointer to ::S5;
+    struct S5 *ps5;               // { dg-warning "\\\[-Wredundant-tags" }
+    // 'struct' is required in a definition of a new type.
+    struct S5 { } *ps5_2;
+    struct S5 *p2s5_2;            // { dg-warning "\\\[-Wredundant-tags" }
+  };
+};
+
+
+template <int> struct TS1;
+
+// Verify redeclaration with no definition.
+template <> struct TS1<0>;
+template <> struct TS1<0>;
+
+// Verify definition after a declaration and vice versa.
+template <> struct TS1<1>;
+template <> struct TS1<1> { };
+template <> struct TS1<1>;
+
+// Verify typedefs of an explicit specialization with a definition.
+typedef struct TS1<1> TS1_1;      // { dg-warning "\\\[-Wredundant-tags" }
+typedef        TS1<1> TS1_1;
+typedef struct TS1<1> TS1_1;      // { dg-warning "\\\[-Wredundant-tags" }
+
+// Verify object declarations of an expplicit specialization.
+extern struct TS1<1> ts1_1;      // { dg-warning "\\\[-Wredundant-tags" }
+extern        TS1<1> ts1_1;
+extern struct TS1<1> ts1_1;      // { dg-warning "\\\[-Wredundant-tags" }
+
+// Verify typedefs of an implicit specialization without a definition.
+typedef struct TS1<2> TS1_2;      // { dg-warning "\\\[-Wredundant-tags" }
+typedef        TS1<2> TS1_2;
+typedef struct TS1<2> TS1_2;      // { dg-warning "\\\[-Wredundant-tags" }
+
+// Verify object declarations of an implicit specialization.
+extern struct TS1<2> ts1_2;       // { dg-warning "\\\[-Wredundant-tags" }
+extern        TS1<2> ts1_2;
+extern struct TS1<2> ts1_2;       // { dg-warning "\\\[-Wredundant-tags" }
+
+
+// Verify partial template specialization.
+template <class> struct TS2;
+template <class T> struct TS2<const T>;
+template <class T> struct TS2<volatile T>;
+
+template <class T>
+struct TS4
+{
+  typedef struct TS2<const T> TS2_CT1;   // { dg-warning "\\\[-Wredundant-tags" }
+  typedef        TS2<const T> TS2_CT2;
+
+  typedef struct TS2<T> TS2_T1;   // { dg-warning "\\\[-Wredundant-tags" }
+  typedef        TS2<T> TS2_T2;
+};
diff --git a/gcc/testsuite/g++.dg/warn/Wredundant-tags-7.C b/gcc/testsuite/g++.dg/warn/Wredundant-tags-7.C
new file mode 100644 (file)
index 0000000..872535b
--- /dev/null
@@ -0,0 +1,25 @@
+/* Verify -Wmismatched-tags on alias definitions.
+   { dg-do compile { target c++11 } }
+   { dg-options "-Wall -Wredundant-tags" } */
+
+class A;
+using AA =        A;
+using AA = class  A;          // { dg-warning "-Wredundant-tags" }
+using AA = struct A;          // { dg-warning "-Wredundant-tags" }
+
+
+template <class> class B;
+
+using Bi =        B<int>;
+using Bi = class  B<int>;     // { dg-warning "-Wredundant-tags" }
+using Bi = struct B<int>;     // { dg-warning "-Wredundant-tags" }
+
+
+template <class> class C;
+
+template <class T>
+using Cp = C<T*>;
+template <class T>
+using Cp = class C<T*>;       // { dg-warning "-Wredundant-tags" }
+template <class T>
+using Cp = struct C<T*>;      // { dg-warning "-Wredundant-tags" }