Commit 04dd734b by Martin Sebor Committed by Jason Merrill

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  <msebor@redhat.com>

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

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

	PR c++/94078
	PR c++/93824
	PR c++/93810
	* g++.dg/warn/Wmismatched-tags-3.C: New test.
	* g++.dg/warn/Wmismatched-tags-4.C: New test.
	* g++.dg/warn/Wmismatched-tags-5.C: New test.
	* g++.dg/warn/Wmismatched-tags-6.C: New test.
	* g++.dg/warn/Wredundant-tags-3.C: Remove xfails.
	* g++.dg/warn/Wredundant-tags-6.C: New test.
	* g++.dg/warn/Wredundant-tags-7.C: New test.
parent 9dba6013
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> 2020-03-27 Nathan Sidwell <nathan@acm.org>
PR c++/94257 PR c++/94257
......
...@@ -6947,6 +6947,7 @@ extern int comp_template_args (tree, tree, tree * = NULL, ...@@ -6947,6 +6947,7 @@ extern int comp_template_args (tree, tree, tree * = NULL,
extern int template_args_equal (tree, tree, bool = false); extern int template_args_equal (tree, tree, bool = false);
extern tree maybe_process_partial_specialization (tree); extern tree maybe_process_partial_specialization (tree);
extern tree most_specialized_instantiation (tree); extern tree most_specialized_instantiation (tree);
extern tree most_specialized_partial_spec (tree, tsubst_flags_t);
extern void print_candidates (tree); extern void print_candidates (tree);
extern void instantiate_pending_templates (int); extern void instantiate_pending_templates (int);
extern tree tsubst_default_argument (tree, int, tree, tree, extern tree tsubst_default_argument (tree, int, tree, tree,
......
...@@ -185,7 +185,7 @@ static int unify_pack_expansion (tree, tree, tree, ...@@ -185,7 +185,7 @@ static int unify_pack_expansion (tree, tree, tree,
tree, unification_kind_t, bool, bool); tree, unification_kind_t, bool, bool);
static tree copy_template_args (tree); static tree copy_template_args (tree);
static tree tsubst_template_parms (tree, tree, tsubst_flags_t); 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_aggr_type (tree, tree, tsubst_flags_t, tree, int);
static tree tsubst_arg_types (tree, tree, tree, tsubst_flags_t, tree); static tree tsubst_arg_types (tree, tree, tree, tsubst_flags_t, tree);
static tree tsubst_function_type (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) ...@@ -24332,7 +24332,7 @@ most_general_template (tree decl)
partial specializations matching TARGET, then NULL_TREE is partial specializations matching TARGET, then NULL_TREE is
returned, indicating that the primary template should be used. */ returned, indicating that the primary template should be used. */
static tree tree
most_specialized_partial_spec (tree target, tsubst_flags_t complain) most_specialized_partial_spec (tree target, tsubst_flags_t complain)
{ {
tree list = NULL_TREE; 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> 2020-03-27 David Malcolm <dmalcolm@redhat.com>
* gcc.dg/analyzer/data-model-5b.c: Add xfail for new false * gcc.dg/analyzer/data-model-5b.c: Add xfail for new false
......
/* { 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" }
};
/* 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;
}
/* 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" }
/* 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" }
...@@ -34,12 +34,12 @@ union N::U u3; // { dg-warning "-Wredundant-tags" } ...@@ -34,12 +34,12 @@ union N::U u3; // { dg-warning "-Wredundant-tags" }
typedef N::TC<0> TC0; typedef N::TC<0> TC0;
typedef typename 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 N::TS<0> TS0;
typedef typename 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 N::TS<0> TS0;
typedef typename 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" }
/* 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;
};
/* 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" }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment