public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
From: Martin Sebor <msebor@gmail.com>
To: Jason Merrill <jason@redhat.com>, gcc-patches <gcc-patches@gcc.gnu.org>
Subject: Re: [PATCH] avoid -Wredundant-tags on a first declaration in use (PR 93824)
Date: Mon, 23 Mar 2020 10:50:27 -0600	[thread overview]
Message-ID: <c60dbbe2-1dba-e0f3-620c-4f5f4f8dd567@gmail.com> (raw)
In-Reply-To: <b10a84dc-387a-cbd1-3879-e55eca195083@redhat.com>

[-- Attachment #1: Type: text/plain, Size: 2400 bytes --]

On 3/23/20 8:49 AM, Jason Merrill wrote:
> On 3/21/20 5:59 PM, Martin Sebor wrote:
>> +      /* 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));
> 
> Don't you need to use the new variable?
> 
> Don't your testcases exercise this?

Of course they do.  This was a leftover from an experiment after I put
the initial updated patch together.  On final review I decided to adjust
some comments and forgot to restore the original use of the variable.

>> +      /* When TYPE is the use of an implicit specialization of a 
>> previously
>> +     declared template set TYPE_DECL to the type of the primary template
>> +     for the specialization and look it up in CLASS2LOC below.  For uses
>> +     of explicit or partial specializations TYPE_DECL already points to
>> +     the declaration of the specialization.
>> +     IS_USE is clear so that the type of an implicit instantiation 
>> rather
>> +     than that of a partial specialization is determined.  */
>> +      type_decl = TREE_TYPE (type_decl);
>> +      if (TREE_CODE (type_decl) != TEMPLATE_DECL)
>> +    type_decl = TYPE_MAIN_DECL (type_decl);
> 
> The comment is no longer relevant to the code.  The remaining code also 
> seems like it would have no effect; we already know type_decl is 
> TYPE_MAIN_DECL (type).

I removed the block of code.

Martin

PS I would have preferred to resolve just the reported problem in this
patch and deal with the template specializations more fully (and with
aliases) in a followup.  As it is, it has grown bigger and more complex
than I'm comfortable with, especially with the template specializations,
harder for me to follow, and obviously a lot more time-consuming not
just to put together but also to review.  Although this revision handles
many more template specialization cases correctly, there still are other
(arguably corner) cases that it doesn't.  I suspect getting those right
might even require a design change, which I see as out of scope at this
time (not to mention my ability).

[-- Attachment #2: gcc-93824.diff --]
[-- Type: text/x-patch, Size: 35757 bytes --]

PR c++/94078 - bogus and missing -Wmismatched-tags on an instance of a template
PR c++/93824 - bogus -Wredundant-tags on a first declaration in use
PR c++/93810 - missing -Wmismatched-tags and -Wredundant-tags on a typedef of an implicit class template specialization

gcc/cp/ChangeLog:

	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.
	(class_decl_loc_t::class_decl_loc_t): Add an argument.
	(class_decl_loc_t::add): Same.
	(class_decl_loc_t::add_or_diag_mismatched_tag): Same.
	(class_decl_loc_t::is_decl): New member function.
	(class_decl_loc_t::class_key_loc_t): Add a new member.
	(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:

	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.

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 0783b3114f2..9c4447202fc 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -6944,6 +6944,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,
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index cbd5510a8fb..8851940710e 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -18937,9 +18937,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'.  */
@@ -30883,12 +30886,12 @@ class class_decl_loc_t
      DEF_P is true for a class declaration that is a definition.
      CURLOC is the associated location.  */
   class_decl_loc_t (tag_types class_key, bool key_redundant, bool def_p,
-		    location_t curloc = input_location)
+		    bool decl_p, location_t curloc = input_location)
     : locvec (), idxdef (def_p ? 0 : UINT_MAX), def_class_key (class_key)
   {
     locvec.create (4);
     class_key_loc_t ckl (current_function_decl, curloc, class_key,
-			 key_redundant);
+			 key_redundant, def_p || decl_p);
     locvec.quick_push (ckl);
   }
 
@@ -30922,12 +30925,13 @@ 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.  */
-  void add_or_diag_mismatched_tag (tree, tag_types, bool, bool);
+  void add_or_diag_mismatched_tag (tree, tag_types, bool, bool, bool);
 
 private:
 
@@ -30946,6 +30950,11 @@ private:
     return locvec[i].key_redundant;
   }
 
+  bool is_decl (unsigned i) const
+  {
+    return locvec[i].is_decl;
+  }
+
   tag_types class_key (unsigned i) const
   {
     return locvec[i].class_key;
@@ -30955,8 +30964,10 @@ private:
      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) { }
+    class_key_loc_t (tree func, location_t loc, tag_types key, bool redundant,
+		     bool decl)
+      : func (func), loc (loc), class_key (key), key_redundant (redundant),
+	is_decl (decl) { }
 
     /* The function the type is mentioned in.  */
     tree func;
@@ -30966,7 +30977,11 @@ private:
     tag_types class_key;
     /* True when the class-key could be omitted at this location
        without an ambiguity with another symbol of the same name.  */
-    bool key_redundant;
+    bool key_redundant: 1;
+    /* True for an entry that corresponds to a dedicated declaration
+       (including a definition) of a class, false for its other uses
+       (such as in declarations of other entities).  */
+    bool is_decl: 1;
   };
   /* Avoid using auto_vec here since it's not safe to copy due to pr90904.  */
   vec <class_key_loc_t> locvec;
@@ -31019,6 +31034,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
@@ -31030,7 +31079,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
@@ -31048,29 +31100,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)
@@ -31080,30 +31111,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.  */
-	  *rdl = class_decl_loc_t (class_key, false, def_p);
-	  return;
+	     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, decl_p);
+	  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, decl_p);
 }
 
 /* Either adds this DECL corresponding to the TYPE_DECL to the collection
@@ -31113,7 +31166,7 @@ void
 class_decl_loc_t::add_or_diag_mismatched_tag (tree type_decl,
 					      tag_types class_key,
 					      bool redundant,
-					      bool def_p)
+					      bool def_p, bool decl_p)
 {
   /* Reset the CLASS_KEY associated with this type on mismatch.
      This is an optimization that lets the diagnostic code skip
@@ -31128,7 +31181,7 @@ class_decl_loc_t::add_or_diag_mismatched_tag (tree type_decl,
 
   /* Append a record of this declaration to the vector.  */
   class_key_loc_t ckl (current_function_decl, input_location, class_key,
-		       redundant);
+		       redundant, def_p || decl_p);
   locvec.safe_push (ckl);
 
   if (idxdef == UINT_MAX)
@@ -31156,35 +31209,73 @@ 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.  */
+  /* Number of usesn of the class.  */
+  unsigned ndecls = locvec.length ();
+
+  /* Set if a definition for the class has been seen.  */
   bool def_p = idxdef < ndecls;
-  unsigned idxguide = def_p ? idxdef : 0;
+
+  /* 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_USE_TEMPLATE (type) == 1 && !is_decl (0))
+    {
+      /* 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 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)
+	return;
+    }
+
+  /* The index of the declaration whose class-key this declaration
+     is expected to match.  It's either the class-key of the class
+     definintion if one exists or the first declaration otherwise.  */
+  const unsigned idxguide = def_p ? idxdef : 0;
   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) == cdlguide->class_key (idxguide))
     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";
+     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 (cdlguide == this ? idxguide : 0);
+  if (cdlguide != this && xpect_key == class_key (idx))
+    return;
+
+  /* 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;
@@ -31205,7 +31296,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")),
@@ -31247,25 +31338,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
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 03a8dfbd37c..0a2c4c86088 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -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;
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
index 00000000000..ecbe66d037e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Wmismatched-tags-3.C
@@ -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
index 00000000000..7570264b1d3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Wmismatched-tags-4.C
@@ -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
index 00000000000..622b9e386ab
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Wmismatched-tags-5.C
@@ -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
index 00000000000..d9d644c4226
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Wmismatched-tags-6.C
@@ -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" }
diff --git a/gcc/testsuite/g++.dg/warn/Wredundant-tags-3.C b/gcc/testsuite/g++.dg/warn/Wredundant-tags-3.C
index 7b30e949d0c..0eeee34dae7 100644
--- a/gcc/testsuite/g++.dg/warn/Wredundant-tags-3.C
+++ b/gcc/testsuite/g++.dg/warn/Wredundant-tags-3.C
@@ -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
index 00000000000..ce5cb967b79
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Wredundant-tags-6.C
@@ -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
index 00000000000..872535b9221
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Wredundant-tags-7.C
@@ -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" }

  reply	other threads:[~2020-03-23 16:50 UTC|newest]

Thread overview: 26+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-02-24 23:58 Martin Sebor
2020-02-28 16:59 ` Jason Merrill
2020-02-28 17:45   ` Martin Sebor
2020-02-28 20:24     ` Jason Merrill
2020-03-09 16:31       ` Martin Sebor
2020-03-09 19:40         ` Jason Merrill
2020-03-09 21:39           ` Martin Sebor
2020-03-10  0:08             ` Jason Merrill
2020-03-11 16:57               ` Martin Sebor
2020-03-11 20:10                 ` Jason Merrill
2020-03-11 21:30                   ` Martin Sebor
2020-03-12 17:03                     ` Martin Sebor
2020-03-12 22:38                       ` Martin Sebor
2020-03-18 22:09                         ` [PING][PATCH] " Martin Sebor
2020-03-19  3:07                         ` [PATCH] " Jason Merrill
2020-03-19 23:55                           ` Martin Sebor
2020-03-20 21:53                             ` Jason Merrill
2020-03-21 21:59                               ` Martin Sebor
2020-03-23 14:49                                 ` Jason Merrill
2020-03-23 16:50                                   ` Martin Sebor [this message]
2020-03-26  5:36                                     ` Jason Merrill
2020-03-26 18:58                                       ` Martin Sebor
2020-03-26 22:16                                         ` Jason Merrill
2020-03-26 22:51                                           ` Martin Sebor
2020-03-27 16:33                                             ` Jason Merrill
2020-03-25 20:54                                 ` Martin Sebor

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=c60dbbe2-1dba-e0f3-620c-4f5f4f8dd567@gmail.com \
    --to=msebor@gmail.com \
    --cc=gcc-patches@gcc.gnu.org \
    --cc=jason@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).