From: Martin Sebor Date: Fri, 27 Mar 2020 16:07:45 +0000 (-0400) Subject: c++: avoid -Wredundant-tags on a first declaration in use [PR 93824] X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=04dd734b52de121853e1ea6b3c197a598b294e23;p=gcc.git c++: avoid -Wredundant-tags on a first declaration in use [PR 93824] -Wredundant-tags doesn't consider type declarations that are also the first uses of the type, such as in 'void f (struct S);' and issues false positives for those. According to the reported that's making it harder to use the warning to clean up LibreOffice. The attached patch extends -Wredundant-tags to avoid these false positives by relying on the same class_decl_loc_t::class2loc mapping as -Wmismatched-tags. The patch also improves the detection of both issues in template declarations. gcc/cp/ChangeLog 2020-03-27 Martin Sebor PR c++/94078 PR c++/93824 PR c++/93810 * cp-tree.h (most_specialized_partial_spec): Declare. * parser.c (cp_parser_elaborated_type_specifier): Distinguish alias from declarations. (specialization_of): New function. (cp_parser_check_class_key): Move code... (class_decl_loc_t::add): ...to here. Add parameters. Avoid issuing -Wredundant-tags on first-time declarations in other declarators. Correct handling of template specializations. (class_decl_loc_t::diag_mismatched_tags): Also expect to be called when -Wredundant-tags is enabled. Use primary template or partial specialization as the guide for uses of implicit instantiations. * pt.c (most_specialized_partial_spec): Declare extern. gcc/testsuite/ChangeLog 2020-03-27 Martin Sebor 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/ChangeLog b/gcc/cp/ChangeLog index 7224ff195d6..2a2e6eac7bf 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,21 @@ +2020-03-27 Martin Sebor + + 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 PR c++/94257 diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 4e1d0f1d42e..af773458413 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -6947,6 +6947,7 @@ extern int comp_template_args (tree, tree, tree * = NULL, extern int template_args_equal (tree, tree, bool = false); extern tree maybe_process_partial_specialization (tree); extern tree most_specialized_instantiation (tree); +extern tree most_specialized_partial_spec (tree, tsubst_flags_t); extern void print_candidates (tree); extern void instantiate_pending_templates (int); extern tree tsubst_default_argument (tree, int, tree, tree, diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 1afd03d3863..3ca8eb9baf8 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -19006,9 +19006,12 @@ cp_parser_elaborated_type_specifier (cp_parser* parser, cp_parser_maybe_warn_enum_key (parser, key_loc, type, scoped_key); else { - /* Diagnose class/struct/union mismatches. */ + /* Diagnose class/struct/union mismatches. IS_DECLARATION is false + for alias definition. */ + bool decl_class = (is_declaration + && cp_parser_declares_only_class_p (parser)); cp_parser_check_class_key (parser, key_loc, tag_type, type, false, - cp_parser_declares_only_class_p (parser)); + decl_class); /* Indicate whether this class was declared as a `class' or as a `struct'. */ @@ -30991,8 +30994,9 @@ class class_decl_loc_t /* Issues -Wmismatched-tags for all classes. */ static void diag_mismatched_tags (); - /* Adds TYPE_DECL to the collection of class decls. */ - static void add (tree, tag_types, bool, bool); + /* Adds TYPE_DECL to the collection of class decls and diagnoses + redundant tags (if -Wredundant-tags is enabled). */ + static void add (cp_parser *, location_t, tag_types, tree, bool, bool); /* Either adds this decl to the collection of class decls or diagnoses it, whichever is appropriate. */ @@ -31020,12 +31024,19 @@ private: return locvec[i].class_key; } + /* True if a definition for the class has been seen. */ + bool def_p () const + { + return idxdef < locvec.length (); + } + /* The location of a single mention of a class type with the given class-key. */ struct class_key_loc_t { class_key_loc_t (tree func, location_t loc, tag_types key, bool redundant) - : func (func), loc (loc), class_key (key), key_redundant (redundant) { } + : func (func), loc (loc), class_key (key), key_redundant (redundant) + { } /* The function the type is mentioned in. */ tree func; @@ -31088,6 +31099,40 @@ cp_parser_check_class_key (cp_parser *parser, location_t key_loc, && class_key != union_type) return; + class_decl_loc_t::add (parser, key_loc, class_key, type, def_p, decl_p); +} + +/* Returns the template or specialization of one to which the RECORD_TYPE + TYPE corresponds. */ + +static tree +specialization_of (tree type) +{ + tree ret = type; + + /* Determine the template or its partial specialization to which TYPE + corresponds. */ + if (tree spec = most_specialized_partial_spec (type, tf_none)) + if (spec != error_mark_node) + ret = TREE_TYPE (TREE_VALUE (spec)); + + if (ret == type) + ret = CLASSTYPE_PRIMARY_TEMPLATE_TYPE (type); + + return TYPE_MAIN_DECL (ret); +} + + +/* Adds the class TYPE to the collection of class decls and diagnoses + redundant tags (if -Wredundant-tags is enabled). + DEF_P is expected to be set for a definition of class TYPE. DECL_P + is set for a (likely, based on syntactic context) declaration of class + TYPE and clear for a reference to it that is not a declaration of it. */ + +void +class_decl_loc_t::add (cp_parser *parser, location_t key_loc, + tag_types class_key, tree type, bool def_p, bool decl_p) +{ tree type_decl = TYPE_MAIN_DECL (type); tree name = DECL_NAME (type_decl); /* Look up the NAME to see if it unambiguously refers to the TYPE @@ -31099,7 +31144,10 @@ cp_parser_check_class_key (cp_parser *parser, location_t key_loc, /* The class-key is redundant for uses of the CLASS_TYPE that are neither definitions of it nor declarations, and for which name lookup returns just the type itself. */ - bool key_redundant = !def_p && !decl_p && decl == type_decl; + bool key_redundant = (!def_p && !decl_p + && (decl == type_decl + || TREE_CODE (decl) == TEMPLATE_DECL + || TYPE_BEING_DEFINED (type))); if (key_redundant && class_key != class_type @@ -31117,29 +31165,8 @@ cp_parser_check_class_key (cp_parser *parser, location_t key_loc, key_redundant = false; } - if (key_redundant) - { - gcc_rich_location richloc (key_loc); - richloc.add_fixit_remove (key_loc); - warning_at (&richloc, OPT_Wredundant_tags, - "redundant class-key %qs in reference to %q#T", - class_key == union_type ? "union" - : class_key == record_type ? "struct" : "class", - type); - } - - if (seen_as_union || !warn_mismatched_tags) - return; - - class_decl_loc_t::add (type_decl, class_key, key_redundant, def_p); -} - -/* Adds TYPE_DECL to the collection of class decls. */ - -void -class_decl_loc_t::add (tree type_decl, tag_types class_key, bool redundant, - bool def_p) -{ + /* Set if a declaration of TYPE has previously been seen or if it must + exist in a precompiled header. */ bool exist; class_decl_loc_t *rdl = &class2loc.get_or_insert (type_decl, &exist); if (!exist) @@ -31149,30 +31176,52 @@ class_decl_loc_t::add (tree type_decl, tag_types class_key, bool redundant, { /* TYPE_DECL is the first declaration or definition of the type (outside precompiled headers -- see below). Just create - a new entry for it. */ + a new entry for it and return unless it's a declaration + involving a template that may need to be diagnosed by + -Wredundant-tags. */ *rdl = class_decl_loc_t (class_key, false, def_p); - return; + if (TREE_CODE (decl) != TEMPLATE_DECL) + return; + } + else + { + /* TYPE was previously defined in some unknown precompiled hdeader. + Simply add a record of its definition at an unknown location and + proceed below to add a reference to it at the current location. + (Declarations in precompiled headers that are not definitions + are ignored.) */ + tag_types def_key + = CLASSTYPE_DECLARED_CLASS (type) ? class_type : record_type; + location_t def_loc = DECL_SOURCE_LOCATION (type_decl); + *rdl = class_decl_loc_t (def_key, false, true, def_loc); + exist = true; } - - /* TYPE was previously defined in some unknown precompiled hdeader. - Simply add a record of its definition at an unknown location and - proceed below to add a reference to it at the current location. - (Declarations in precompiled headers that are not definitions - are ignored.) */ - tag_types def_key - = CLASSTYPE_DECLARED_CLASS (type) ? class_type : record_type; - location_t def_loc = DECL_SOURCE_LOCATION (type_decl); - *rdl = class_decl_loc_t (def_key, false, true, def_loc); } /* A prior declaration of TYPE_DECL has been seen. */ + if (key_redundant) + { + gcc_rich_location richloc (key_loc); + richloc.add_fixit_remove (key_loc); + warning_at (&richloc, OPT_Wredundant_tags, + "redundant class-key %qs in reference to %q#T", + class_key == union_type ? "union" + : class_key == record_type ? "struct" : "class", + type); + } + + if (!exist) + /* Do nothing if this is the first declaration of the type. */ + return; + if (rdl->idxdef != UINT_MAX && rdl->def_class_key == class_key) /* Do nothing if the class-key in this declaration matches the definition. */ return; - rdl->add_or_diag_mismatched_tag (type_decl, class_key, redundant, def_p); + rdl->add_or_diag_mismatched_tag (type_decl, class_key, key_redundant, + def_p); } /* Either adds this DECL corresponding to the TYPE_DECL to the collection @@ -31225,35 +31274,70 @@ class_decl_loc_t::add_or_diag_mismatched_tag (tree type_decl, void class_decl_loc_t::diag_mismatched_tags (tree type_decl) { - unsigned ndecls = locvec.length (); - - /* Skip a declaration that consistently uses the same class-key - or one with just a solitary declaration (i.e., TYPE_DECL). */ - if (def_class_key != none_type || ndecls < 2) + if (!warn_mismatched_tags) return; - /* Save the current function before changing it below. */ - tree save_func = current_function_decl; - /* Set if a class definition for RECLOC has been seen. */ - bool def_p = idxdef < ndecls; - unsigned idxguide = def_p ? idxdef : 0; + /* Number of uses of the class. */ + const unsigned ndecls = locvec.length (); + + /* The class (or template) declaration guiding the decisions about + the diagnostic. For ordinary classes it's the same as THIS. For + uses of instantiations of templates other than their declarations + it points to the record for the declaration of the corresponding + primary template or partial specialization. */ + class_decl_loc_t *cdlguide = this; + + tree type = TREE_TYPE (type_decl); + if (CLASSTYPE_IMPLICIT_INSTANTIATION (type)) + { + /* For implicit instantiations of a primary template look up + the primary or partial specialization and use it as + the expected class-key rather than using the class-key of + the first reference to the instantiation. The primary must + be (and inevitably is) at index zero. */ + tree spec = specialization_of (type); + cdlguide = class2loc.get (spec); + gcc_assert (cdlguide != NULL); + } + else + { + /* Skip declarations that consistently use the same class-key. */ + if (def_class_key != none_type) + return; + } + + /* Set if a definition for the class has been seen. */ + const bool def_p = cdlguide->def_p (); + + /* The index of the declaration whose class-key this declaration + is expected to match. It's either the class-key of the class + definition if one exists or the first declaration otherwise. */ + const unsigned idxguide = def_p ? cdlguide->idxdef : 0; + + /* The class-key the class is expected to be declared with: it's + either the key used in its definition or the first declaration + if no definition has been provided. + For implicit instantiations of a primary template it's + the class-key used to declare the primary with. The primary + must be at index zero. */ + const tag_types xpect_key = cdlguide->class_key (idxguide); + unsigned idx = 0; /* Advance IDX to the first declaration that either is not a definition or that doesn't match the first declaration if no definition is provided. */ - while (class_key (idx) == class_key (idxguide)) + while (class_key (idx) == xpect_key) if (++idx == ndecls) return; - /* The class-key the class is expected to be declared with: it's - either the key used in its definition or the first declaration - if no definition has been provided. */ - tag_types xpect_key = class_key (def_p ? idxguide : 0); - const char *xmatchkstr = xpect_key == record_type ? "class" : "struct"; - const char *xpectkstr = xpect_key == record_type ? "struct" : "class"; + /* Save the current function before changing it below. */ + tree save_func = current_function_decl; /* Set the function declaration to print in diagnostic context. */ current_function_decl = function (idx); + const char *xmatchkstr = xpect_key == record_type ? "class" : "struct"; + const char *xpectkstr = xpect_key == record_type ? "struct" : "class"; + location_t loc = location (idx); bool key_redundant_p = key_redundant (idx); auto_diagnostic_group d; @@ -31274,7 +31358,7 @@ class_decl_loc_t::diag_mismatched_tags (tree type_decl) /* Also point to the first declaration or definition that guided the decision to issue the warning above. */ - inform (location (idxguide), + inform (cdlguide->location (idxguide), (def_p ? G_("%qT defined as %qs here") : G_("%qT first declared as %qs here")), @@ -31316,25 +31400,29 @@ class_decl_loc_t::diag_mismatched_tags (tree type_decl) void class_decl_loc_t::diag_mismatched_tags () { - /* CLASS2LOC should be empty if -Wmismatched-tags is disabled. */ - gcc_assert (warn_mismatched_tags || class2loc.is_empty ()); + /* CLASS2LOC should be empty if both -Wmismatched-tags and + -Wredundant-tags are disabled. */ + gcc_assert (warn_mismatched_tags + || warn_redundant_tags + || class2loc.is_empty ()); - /* Save the current function before changing it below. It should + /* Save the current function before changing on return. It should be null at this point. */ - tree save_func = current_function_decl; + temp_override 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 7ea8ce4cbc3..15b54396ed3 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/ChangeLog b/gcc/testsuite/ChangeLog index 2baa6e800cb..1de6c7ab235 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,16 @@ +2020-03-27 Martin Sebor + + 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 * gcc.dg/analyzer/data-model-5b.c: Add xfail for new false diff --git a/gcc/testsuite/g++.dg/warn/Wmismatched-tags-3.C b/gcc/testsuite/g++.dg/warn/Wmismatched-tags-3.C new file mode 100644 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 S1; +template <> struct S1; + +template class S1; +template struct S1; // { dg-warning "\\\[-Wmismatched-tags" } + +template <> class S1; +template <> struct S1; // { dg-warning "\\\[-Wmismatched-tags" } + +template <> class S1; // { dg-warning "\\\[-Wmismatched-tags" } +template <> struct S1; + +extern S1 s1v; +extern class S1 s1v; +extern struct S1 s1v; // { dg-warning "\\\[-Wmismatched-tags" } + +extern S1 s1i; +extern class S1 s1i; // { dg-warning "\\\[-Wmismatched-tags" } +extern struct S1 s1i; + +extern S1 s1c; +extern class S1 s1c; +extern struct S1 s1c; // { dg-warning "\\\[-Wmismatched-tags" } + + +// Exercise partial specialization. +template struct S2; +template class S2; + +template class S2; // { dg-warning "\\\[-Wmismatched-tags" } +template struct S2; + +template class S2; +template struct S2;// { dg-warning "\\\[-Wmismatched-tags" } + +extern S2 s2i; +extern class S2 s2i; // { dg-warning "\\\[-Wmismatched-tags" } +extern struct S2 s2i; + +extern S2 s2ci; +extern class S2 s2ci; +extern struct S2 s2ci; // { dg-warning "\\\[-Wmismatched-tags" } + + +template struct S3; +template class S3; +template struct S3; + +template class S3; // { dg-warning "\\\[-Wmismatched-tags" } +template struct S3; + +template class S3; +template struct S3; // { dg-warning "\\\[-Wmismatched-tags" } + +template class S3; // { dg-warning "\\\[-Wmismatched-tags" } +template struct S3; + +extern S3 s3i; +extern class S3 s3i; // { dg-warning "\\\[-Wmismatched-tags" } +extern struct S3 s3i; + +extern S3 s3p; +extern class S3 s3p; +extern struct S3 s3p; // { dg-warning "\\\[-Wmismatched-tags" } + +extern S3 s3r; +extern class S3 s3r; // { dg-warning "\\\[-Wmismatched-tags" } +extern struct S3 s3r; + +// Repeat exactly the same as above. +extern S3 s3i; +extern class S3 s3i; // { dg-warning "\\\[-Wmismatched-tags" } +extern struct S3 s3i; + +extern S3 s3p; +extern class S3 s3p; +extern struct S3 s3p; // { dg-warning "\\\[-Wmismatched-tags" } + +extern S3 s3r; +extern class S3 s3r; // { dg-warning "\\\[-Wmismatched-tags" } +extern struct S3 s3r; + +// Repeat the same as above just with different type. +extern S3 s3l; +extern class S3 s3l; // { dg-warning "\\\[-Wmismatched-tags" } +extern struct S3 s3l; + +extern S3 s3lp; +extern class S3 s3lp; +extern struct S3 s3lp; // { dg-warning "\\\[-Wmismatched-tags" } + +extern S3 s3lr; +extern class S3 s3lr; // { dg-warning "\\\[-Wmismatched-tags" } +extern struct S3 s3lr; + +// Repeat with the class-keys swapped. +extern S3 s3l; +extern struct S3 s3l; +extern class S3 s3l; // { dg-warning "\\\[-Wmismatched-tags" } + +extern S3 s3lp; +extern struct S3 s3lp; // { dg-warning "\\\[-Wmismatched-tags" } +extern class S3 s3lp; + +extern S3 s3lr; +extern struct S3 s3lr; +extern class S3 s3lr; // { dg-warning "\\\[-Wmismatched-tags" } + + +namespace N +{ +template struct A; + +extern class A ai; // { dg-warning "\\\[-Wmismatched-tags" } +extern struct A ai; + +typedef class A AI; // { dg-warning "\\\[-Wmismatched-tags" } +typedef struct A AI; + +template struct B; +template <> class B; +template <> struct B; + +extern class B bi; +extern struct B bi; // { dg-warning "\\\[-Wmismatched-tags" } + +extern class B bc; // { dg-warning "\\\[-Wmismatched-tags" } +extern struct B bc; + +typedef class B BC; // { dg-warning "\\\[-Wmismatched-tags" } +typedef struct B 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 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 struct CN; // { dg-message "declared as 'struct'" } + +template +struct X_CNp1 { + typedef CN CNp1; +}; + +template +struct X_class_CNp1 { + typedef class CN CNp1; // { dg-warning "-Wmismatched-tags" } +}; + +template +struct X_struct_CNp1 { + typedef struct CN CNp1; +}; + + +// Exercise partial specialization of templates with member types. +template class CT1; +template struct CT1 { }; +template struct CT1 { }; +template class CT1 { }; + +template struct CT2; +template struct CT2 { + // Expect class-key to match the primary. + CT1 ct1_0; + class CT1 ct1_1; + struct CT1 ct1_2; // { dg-warning "-Wmismatched-tags" } + + // Expect class-key to match the CT1 partial specialization. + CT1 ct1p1_0; + class CT1 ct1p1_1; // { dg-warning "-Wmismatched-tags" } + struct CT1 ct1p1_2; + + // Expect class-key to match the CT1 partial specialization. + CT1 ct1p2_0; + class CT1 ct1p2_1; // { dg-warning "-Wmismatched-tags" } + struct CT1 ct1p2_2; + + // Expect class-key to match the CT1 partial specialization. + CT1 ct1p3_0; + class CT1 ct1p3_1; + struct CT1 ct1p3_2; // { dg-warning "-Wmismatched-tags" } + + // Expect class-key to still match the CT1 partial specialization. + CT1 ct1p4_0; + class CT1 ct1p4_1; + struct CT1 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 D; +template struct D; +template class D; +template struct D; +template class D; +template struct D; +template class D; +template struct D; +template class D; + +typedef class D DIP; // { dg-warning "-Wmismatched-tags" } +typedef struct D DIP; +typedef class D DIP; // { dg-warning "-Wmismatched-tags" } +typedef struct D DIP; + +typedef class D DIR; +typedef struct D DIR; // { dg-warning "-Wmismatched-tags" } +typedef class D DIR; + + +typedef struct D DCIP; +typedef class D DCIP; // { dg-warning "-Wmismatched-tags" } +typedef struct D DCIP; + +typedef struct D DCIR; // { dg-warning "-Wmismatched-tags" } +typedef class D DCIR; +typedef struct D DCIR; // { dg-warning "-Wmismatched-tags" } + + +typedef struct D DVIP; +typedef class D DVIP; // { dg-warning "-Wmismatched-tags" } +typedef struct D DVIP; + +typedef struct D DVIR; // { dg-warning "-Wmismatched-tags" } +typedef class D DVIR; +typedef struct D DVIR; // { dg-warning "-Wmismatched-tags" } + + +typedef struct D DCVIP; +typedef class D DCVIP; // { dg-warning "-Wmismatched-tags" } +typedef struct D DCVIP; + +typedef struct D DCVIR; // { dg-warning "-Wmismatched-tags" } +typedef class D DCVIR; +typedef struct D 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 B; // { dg-message "declared as 'class'" } + +using Bi = B; +using Bi = class B; +using Bi = struct B; // { dg-warning "-Wmismatched-tags" } +using Bi = class B; +using Bi = struct B; // { dg-warning "-Wmismatched-tags" } + + +template class C; // { dg-message "declared as 'class'" } + +template using Cp = C; +template using Cp = class C; +template +using Cp = struct C; // { dg-warning "-Wmismatched-tags" } + +template using Cp = class C; +template +using Cp = struct C; // { 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 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 struct TS2; +template struct TS2; +template struct TS2; + +template +struct TS4 +{ + typedef struct TS2 TS2_CT1; // { dg-warning "\\\[-Wredundant-tags" } + typedef TS2 TS2_CT2; + + typedef struct TS2 TS2_T1; // { dg-warning "\\\[-Wredundant-tags" } + typedef TS2 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 B; + +using Bi = B; +using Bi = class B; // { dg-warning "-Wredundant-tags" } +using Bi = struct B; // { dg-warning "-Wredundant-tags" } + + +template class C; + +template +using Cp = C; +template +using Cp = class C; // { dg-warning "-Wredundant-tags" } +template +using Cp = struct C; // { dg-warning "-Wredundant-tags" }