+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
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,
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'. */
/* 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. */
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;
&& 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
/* 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
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)
{
/* 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
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;
/* 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")),
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
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);
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;
+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
--- /dev/null
+/* { 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" }
+};
--- /dev/null
+/* 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;
+
+}
--- /dev/null
+/* 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" }
--- /dev/null
+/* 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" }
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" }
--- /dev/null
+/* 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;
+};
--- /dev/null
+/* 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" }