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: Thu, 26 Mar 2020 12:58:33 -0600	[thread overview]
Message-ID: <fc41057b-515d-2e79-e90e-09715397077a@gmail.com> (raw)
In-Reply-To: <3636dd58-f935-bd92-4b20-003950980b46@redhat.com>

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

On 3/25/20 11:36 PM, Jason Merrill wrote:
> On 3/23/20 12:50 PM, Martin Sebor wrote:
>> 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).
> 
> Sure, at this point in the cycle there's always a tradeoff between 
> better functionality and risk from ballooning changes.  It looks like 
> the improved template handling could still be split out into a separate 
> patch, if you'd prefer.

I would prefer to get this patch committed as is now.  I appreciate
there are improvements that can be made to the code (there always
are) but, unlike the bugs it fixes, they are invisible to users and
so don't seem essential at this point.

>> +  /* Number of usesn of the class.  */
> Typo.
> 
>> +     definintion if one exists or the first declaration otherwise.  */
> typo.
> 
>> +  if (CLASSTYPE_USE_TEMPLATE (type) == 1 && !is_decl (0))
> ...
>> +     the first reference to the instantiation.  The primary must
>> +     be (and inevitably is) at index zero.  */
> 
> I think CLASSTYPE_IMPLICIT_INSTANTIATION is more readable than testing 
> the value 1.

Okay.

> 
> What is the !is_decl (0) intended to do?  Changing it to an assert 
> inside the 'if' doesn't seem to affect any of the testcases.

Looks like the test is an unnecessary remnant and can be removed.
In fact, both is_decl() and decl_p member don't appear necessary
anymore so I've removed them too.

>> +     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);
> 
> A template can also be declared before it's defined;

Obviously, just like a class.  Is there something you expect me to
change in response to this point?

> I think you want to 
> move the def_p/idxdef/idxguide logic into another member function that 
> you invoke on cdlguide to perhaps get the class_key_loc_t that you want 
> to use as the pattern.

I'm not quite sure what you have in mind here.  I agree the cdlcode
code looks a little cumbersome and perhaps could be restructured but
it's not obvious to me how.  Nothing I tried looked like a clear win
so unless you consider changing how this is done a prerequisite for
accepting the whole patch I'd rather not spend any more time at this
stage iterating over refinements of it.  Please let me know soon.

Attached is a revised patch with the other changes above.

Martin

[-- Attachment #2: gcc-93824.diff --]
[-- Type: text/x-patch, Size: 33021 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.
	(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..94e45627cc7 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'.  */
@@ -30922,8 +30925,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.  */
@@ -30956,7 +30960,8 @@ private:
   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;
@@ -31019,6 +31024,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 +31069,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 +31090,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 +31101,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
@@ -31156,35 +31199,74 @@ 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 ();
+  if (!warn_mismatched_tags)
+    return;
 
-  /* 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)
+  /* Number of uses of the class.  */
+  const unsigned ndecls = locvec.length ();
+  if (ndecls < 2)
     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;
+  /* Set if a definition for the class has been seen.  */
+  const bool def_p = idxdef < ndecls;
+
+  /* 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;
+    }
+
+  /* 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 ? 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 +31287,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 +31329,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-26 18:58 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
2020-03-26  5:36                                     ` Jason Merrill
2020-03-26 18:58                                       ` Martin Sebor [this message]
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=fc41057b-515d-2e79-e90e-09715397077a@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).