Commit e8f1ade2 by Martin Sebor Committed by Martin Sebor

PR c++/61339 - add warning for mismatch between struct and class

gcc/c-family/ChangeLog:

	PR c++/61339
	* c.opt (-Wmismatched-tags, -Wredundant-tags): New options.

gcc/cp/ChangeLog:

	PR c++/61339
	* parser.c (cp_parser_maybe_warn_enum_key): New function.
	(class_decl_loc_t): New class.
	(cp_parser_elaborated_type_specifier): Call
	cp_parser_maybe_warn_enum_key.
	(cp_parser_class_head): Call cp_parser_check_class_key.
	(cp_parser_check_class_key): Add arguments.  Call class_decl_loc_t::add.
	(c_parse_file): Call class_decl_loc_t::diag_mismatched_tags.

gcc/testsuite/ChangeLog:

	PR c++/61339
	* g++.dg/warn/Wmismatched-tags.C: New test.
	* g++.dg/warn/Wredundant-tags.C: New test.
	* g++.dg/pch/Wmismatched-tags.C: New test.
	* g++.dg/pch/Wmismatched-tags.Hs: New test header.

gcc/ChangeLog:

	PR c++/61339
	* doc/invoke.texi (-Wmismatched-tags, -Wredundant-tags): Document
	new C++ options.

From-SVN: r279480
parent 54ba911f
2019-12-17 Martin Sebor <msebor@redhat.com>
PR c++/61339
* doc/invoke.texi (-Wmismatched-tags, -Wredundant-tags): Document
new C++ options.
2019-12-17 Michael Meissner <meissner@linux.ibm.com>
* config/rs6000/rs6000.c (num_insns_constant_gpr): Return 1 if the
2019-12-17 Martin Sebor <msebor@redhat.com>
PR c++/61339
* c.opt (-Wmismatched-tags, -Wredundant-tags): New options.
2019-12-11 David Malcolm <dmalcolm@redhat.com>
* c-pretty-print.c (c_pretty_printer::clone): New vfunc
......
......@@ -755,6 +755,10 @@ Wmisleading-indentation
C C++ Common Var(warn_misleading_indentation) Warning LangEnabledBy(C C++,Wall)
Warn when the indentation of the code does not reflect the block structure.
Wmismatched-tags
C++ ObjC++ Var(warn_mismatched_tags) Warning
Warn when a class is redeclared or referenced using a mismatched class-key.
Wmissing-braces
C ObjC C++ ObjC++ Var(warn_missing_braces) Warning LangEnabledBy(C ObjC,Wall)
Warn about possibly missing braces around initializers.
......@@ -783,6 +787,10 @@ Wpacked-not-aligned
C ObjC C++ ObjC++ Var(warn_packed_not_aligned) Warning LangEnabledBy(C ObjC C++ ObjC++,Wall)
Warn when fields in a struct with the packed attribute are misaligned.
Wredundant-tags
C++ ObjC++ Var(warn_redundant_tags) Warning
Warn when a class or enumerated type is referenced using a redundant class-key.
Wsized-deallocation
C++ ObjC++ Var(warn_sized_deallocation) Warning EnabledBy(Wextra)
Warn about missing sized deallocation functions.
......
2019-12-17 Martin Sebor <msebor@redhat.com>
PR c++/61339
* parser.c (cp_parser_maybe_warn_enum_key): New function.
(class_decl_loc_t): New class.
(cp_parser_elaborated_type_specifier): Call
cp_parser_maybe_warn_enum_key.
(cp_parser_class_head): Call cp_parser_check_class_key.
(cp_parser_check_class_key): Add arguments. Call class_decl_loc_t::add.
(c_parse_file): Call class_decl_loc_t::diag_mismatched_tags.
2019-12-17 Jason Merrill <jason@redhat.com>
PR c++/79592 - missing explanation of invalid constexpr.
......
......@@ -233,10 +233,10 @@ in the following sections.
-Wabi=@var{n} -Wabi-tag -Wcomma-subscript -Wconversion-null @gol
-Wctor-dtor-privacy @gol
-Wdelete-non-virtual-dtor -Wdeprecated-copy -Wdeprecated-copy-dtor @gol
-Wliteral-suffix @gol
-Wliteral-suffix -Wmismatched-tags @gol
-Wmultiple-inheritance -Wno-init-list-lifetime @gol
-Wnamespaces -Wnarrowing @gol
-Wpessimizing-move -Wredundant-move @gol
-Wpessimizing-move -Wredundant-move -Wredundant-tags @gol
-Wnoexcept -Wnoexcept-type -Wclass-memaccess @gol
-Wnon-virtual-dtor -Wreorder -Wregister @gol
-Weffc++ -Wstrict-null-sentinel -Wtemplates @gol
......@@ -3323,6 +3323,21 @@ treats the return value as if it were designated by an rvalue.
This warning is enabled by @option{-Wextra}.
@item -Wredundant-tags @r{(C++ and Objective-C++ only)}
@opindex Wredundant-tags
@opindex Wno-redundant-tags
Warn about redundant class-key and enum-key in references to class types
and enumerated types in contexts where the key can be eliminated without
causing an ambiguity. For example
@smallexample
struct foo;
struct foo *p; // -Wredundant-tags, keyword struct can be eliminated
void foo (); // "hides" struct foo
void bar (struct foo&); // no warning, keyword struct cannot be eliminated
@end smallexample
@item -fext-numeric-literals @r{(C++ and Objective-C++ only)}
@opindex fext-numeric-literals
@opindex fno-ext-numeric-literals
......@@ -3458,6 +3473,32 @@ The warning is inactive inside a system header file, such as the STL, so
one can still use the STL. One may also instantiate or specialize
templates.
@item -Wmismatched-tags @r{(C++ and Objective-C++ only)}
@opindex Wmismatched-tags
@opindex Wno-mismatched-tags
Warn for declarations of structs, classes, and class templates and their
specializations with a class-key that does not match either the definition
or the first declaration if no definition is provided.
For example, the declaration of @code{struct Object} in the argument list
of @code{draw} triggers the warning. To avoid it, either remove the redundant
class-key @code{struct} or replace it with @code{class} to match its definition.
@smallexample
class Object @{
public:
virtual ~Object () = 0;
@};
void draw (struct Object*);
@end smallexample
It is not wrong to declare a class with the class-key @code{struct} as
the example above shows. The @option{-Wmismatched-tags} option is intended
to help achieve a consistent style of class declarations. In code that is
intended to be portable to Windows-based compilers the warning helps prevent
unresolved references due to the difference in the mangling of symbols
declared with different class-keys. The option can be used either on its
own or in conjunction with @option{-Wredundant-tags}.
@item -Wmultiple-inheritance @r{(C++ and Objective-C++ only)}
@opindex Wmultiple-inheritance
@opindex Wno-multiple-inheritance
2019-12-17 Martin Sebor <msebor@redhat.com>
PR c++/61339
* g++.dg/warn/Wmismatched-tags.C: New test.
* g++.dg/warn/Wredundant-tags.C: New test.
* g++.dg/pch/Wmismatched-tags.C: New test.
* g++.dg/pch/Wmismatched-tags.Hs: New test header.
2019-12-17 Jakub Jelinek <jakub@redhat.com>
PR c++/59655
......
/* PR c++/61339 - add mismatch between struct and class
Verify that declarations that don't match definitions in precompiled
headers are diagnosed.
{ dg-options "-Wall -Wmismatched-tags" } */
#include "Wmismatched-tags.H"
class PCHDeclaredClass;
struct PCHDeclaredStruct;
struct PCHDefinedClass; // { dg-warning "declared with a mismatched class-key 'struct'" }
class PCHDefinedStruct; // { dg-warning "declared with a mismatched class-key 'class'" }
class PCHDeclaredClass { };
struct PCHDeclaredStruct { };
class PCHDeclaredClass;
struct PCHDeclaredStruct;
class PCHDefinedClass { };
struct PCHDefinedStruct { };
\ No newline at end of file
/* PR c++/61339 - add mismatch between struct and class
Test to verify that -Wmismatched-tags is issued for declarations
of the same class using different class-ids.
{ dg-do compile }
{ dg-options "-Wmismatched-tags" } */
namespace Classes
{
class A;
class A;
struct B;
struct B;
union C;
union C;
struct D; // { dg-warning "Classes::D' declared with a mismatched class-key 'struct'" }
class D { }; // { dg-message "Classes::D' defined as 'class' here" }
class E; // { dg-warning "Classes::E' declared with a mismatched class-key 'class'" }
struct E { }; // { dg-message "Classes::E' defined as 'struct' here" }
class D;
struct E;
class D;
struct E;
struct D; // { dg-warning "Classes::D' declared with a mismatched class-key" }
class E; // { dg-warning "Classes::E' declared with a mismatched class-key" }
class F; // { dg-message "Classes::F' first declared as 'class' here" }
class F;
struct G { }; // { dg-message "Classes::G' defined as 'struct' here" }
} // namespace Classes
namespace Classes
{
class A;
struct B;
union C;
class D;
struct E;
struct F; // { dg-warning "Classes::F' declared with a mismatched class-key" }
struct G;
}
// Verify that the correct hint is provided, one to remove the class-key
// when it's redundant, and one to (only) replace it with the correct one
// when it's needed to disambiguate the reference to the class type.
namespace RemoveOrReplace
{
struct Func;
class Func; // { dg-warning "RemoveOrReplace::Func' declared with a mismatched class-key 'class'" }
// { dg-message "replace the class-key with 'struct'" "hint to remove" { target *-*-* } .-1 }
void Func ();
class Func; // { dg-warning "RemoveOrReplace::Func' declared with a mismatched class-key 'class'" }
// { dg-message "replace the class-key with 'struct'" "hint to replace" { target *-*-* } .-1 }
class Var;
struct Var; // { dg-warning "RemoveOrReplace::Var' declared with a mismatched class-key 'struct'" }
// { dg-message "replace the class-key with 'class'" "hint to remove" { target *-*-* } .-1 }
void f (struct Var*); // { dg-warning "RemoveOrReplace::Var' declared with a mismatched class-key 'struct'" }
// { dg-message "remove the class-key or replace it with 'class'" "hint to remove" { target *-*-* } .-1 }
int Var;
struct Var; // { dg-warning "RemoveOrReplace::Var' declared with a mismatched class-key 'struct'" }
// { dg-message "replace the class-key with 'class'" "hint to replace" { target *-*-* } .-1 }
}
namespace GlobalObjects
{
class A; // { dg-message "'GlobalObjects::A' first declared as 'class' here" }
struct B; // { dg-message "'GlobalObjects::B' first declared as 'struct' here" }
class C { }; // { dg-message "'GlobalObjects::C' defined as 'class' here" }
extern A a0;
extern class A a1;
extern class A a2;
extern B b0;
extern struct B b1;
extern struct B b2;
extern struct A a3; // { dg-warning "GlobalObjects::A' declared with a mismatched class-key" }
extern class A a4;
extern class B b3; // { dg-warning "GlobalObjects::B' declared with a mismatched class-key" }
extern struct B b4;
extern struct C c[]; // { dg-warning "GlobalObjects::C' declared with a mismatched class-key" }
// { dg-message "remove the class-key or replace it with 'class'" "hint to remove" { target *-*-* } .-1 }
extern char
arr[sizeof (struct C)]; // { dg-warning "GlobalObjects::C' declared with a mismatched class-key" }
// { dg-message "remove the class-key or replace it with 'class'" "hint to remove" { target *-*-* } .-1 }
} // namespace GlobalObjects
namespace LocalObjects
{
class A; // { dg-message "LocalObjects::A' first declared as 'class' here" }
struct B; // { dg-message "LocalObjects::B' first declared as 'struct' here" }
void f (A*, B&)
{
class A *a1;
class A *a2;
struct B *b1;
struct B *b2;
struct A *a3; // { dg-warning "LocalObjects::A' declared with a mismatched class-key" }
class A *a4;
class B *b3; // { dg-warning "LocalObjects::B' declared with a mismatched class-key" }
struct B *b4;
}
void g (struct A*); // { dg-warning "LocalObjects::A' declared with a mismatched class-key" }
} // namespace LocalObjects
namespace MemberClasses
{
struct A { struct B; };
struct C { struct D; struct D; struct D { }; };
struct E { class F; class F { }; class F; };
struct G {
struct H; // { dg-message "MemberClasses::G::H' first declared as 'struct' here" }
class H; // { dg-warning "MemberClasses::G::H' declared with a mismatched class-key" }
class I { }; // { dg-message "MemberClasses::G::I' defined as 'class' here" }
struct I; // { dg-warning "MemberClasses::G::I' declared with a mismatched class-key" }
};
} // namespace MemberClasses
namespace DataMembers
{
struct A { struct B *p; };
struct C { struct D *p; struct D *q; struct D { } d; };
struct E { class F &r; class F { } f; class F *p; };
class G; // { dg-message "DataMembers::G' first declared as 'class' here" }
struct H; // { dg-message "DataMembers::H' first declared as 'struct' here" }
struct I {
struct G *p0; // { dg-warning "DataMembers::G' declared with a mismatched class-key" }
class G *p1;
struct H &r0;
class H &r1; // { dg-warning "DataMembers::H' declared with a mismatched class-key" }
class J { }; // { dg-message "DataMembers::I::J' defined as 'class' here" }
struct K { }; // { dg-message "DataMembers::I::K' defined as 'struct' here" }
class J j0;
class K k0; // { dg-warning "DataMembers::I::K' declared with a mismatched class-key" }
struct J j1; // { dg-warning "DataMembers::I::J' declared with a mismatched class-key" }
struct K k1;
};
} // namespace DataMembers
namespace Templates
{
template <int> class A;
template <int> class A;
template <int> struct B;
template <int> struct B;
template <int> union C;
template <int> union C;
template <int> struct D; // { dg-warning "Templates::D\[^\n\r]*' declared with a mismatched class-key" }
template <int>
class D // { dg-message "Templates::D\[^\n\r]*' defined as 'class' here" }
{ public: D (); };
template <int> class E; // { dg-warning "Templates::E\[^\n\r]*' declared with a mismatched class-key" }
template <int>
struct E // { dg-message "Templates::E\[^\n\r]*' defined as 'struct' here" }
{ int i; };
template <int> class D;
template <int> struct E;
template <int>
struct D; // { dg-warning "Templates::D\[^\n\r]*' declared with a mismatched class-key" }
// { dg-message "replace the class-key with 'class'" "hint" { target *-*-* } .-1 }
} // namespace Templates
namespace ExplicitSpecializations
{
template <int> class A;
template <> class A<0>;
template <> struct A<1>;
template <> struct A<1> { };
template <int> struct B;
template <> struct B<0>;
template <> class B<1>;
template <> class B<2> { public: B (); };
template <int> union C;
template <> union C<0>;
template <int> class D;
template <> class D<0>; // { dg-warning "ExplicitSpecializations::D\[^\n\r]*' declared with a mismatched class-key " }
template <>
struct D<0> { }; // { dg-message "ExplicitSpecializations::D\[^\n\r]*' defined as 'struct' here" }
template <int> struct E;
template <> struct E<0>; // { dg-warning "ExplicitSpecializations::E\[^\n\r]*' declared with a mismatched class-key" }
template <>
class E<0> { }; // { dg-message "ExplicitSpecializations::E\[^\n\r]*' defined as 'class' here" }
template <int> struct F;
template <> class F<0> { }; // { dg-message "ExplicitSpecializations::F\[^\n\r]*' defined as 'class' here" }
template <>
struct F<0>; // { dg-warning "ExplicitSpecializations::F\[^\n\r]*' declared with a mismatched class-key" }
} // namespace ExplicitSpecializations
namespace PartialSpecializations
{
template <class> class A;
template <class T> struct A<const T>;
template <class T> struct A<volatile T>;
template <class> struct B;
template <class T> class B<const T>;
template <class T> class B<volatile T>;
template <class> class C { };
template <class T> struct C<const T> { };
template <class T> struct C<volatile T> { };
template <class> struct D { };
template <class T> class D<const T> { };
template <class T> class D<volatile T> { };
template <class> class E;
template <class T>
struct E<const T>; // { dg-message "PartialSpecializations::E<const T>' first declared as 'struct' here" }
template <class T>
class E<const T>; // { dg-warning "PartialSpecializations::E<const T>' declared with a mismatched class-key" }
template <class> class F;
template <class T>
class F<const T>; // { dg-message "PartialSpecializations::F<const T>' first declared as 'class' here" }
template <class T>
struct F<const T>; // { dg-warning "PartialSpecializations::F<const T>' declared with a mismatched class-key" }
} // namespace PartialSpecializations
namespace Classes
{
struct G;
class G; // { dg-warning "Classes::G' declared with a mismatched class-key 'class'" }
}
/* PR c++/61339 - add mismatch between struct and class
Test to verify that -Wredundant-tags is issued for references to class
types that use the class-key even though they don't need to.
{ dg-do compile }
{ dg-options "-Wredundant-tags" } */
struct A;
extern A *pa;
extern struct A *pa; // { dg-warning "redundant class-key 'struct' in reference to 'struct A'" }
extern A aa[];
extern struct A aa[]; // { dg-warning "redundant class-key 'struct' in reference to 'struct A'" }
void func (A*);
void func (struct A*); // { dg-warning "redundant class-key 'struct' in reference to 'struct A'" }
int A;
extern struct A *pa;
extern struct A aa[];
void func (struct A*);
class B;
extern B *pb;
extern class B *pb; // { dg-warning "redundant class-key 'class' in reference to 'class B'" }
extern B ab[];
extern class B ab[]; // { dg-warning "redundant class-key 'class' in reference to 'class B'" }
void func (B*);
void func (class B*); // { dg-warning "redundant class-key 'class' in reference to 'class B'" }
int B;
extern class B *pb;
extern class B ab[];
void func (class B*);
enum C { c0 };
extern C *pc;
extern enum C *pc; // { dg-warning "redundant enum-key 'enum' in reference to 'enum C'" }
extern C ac[];
extern enum C ac[]; // { dg-warning "redundant enum-key 'enum' in reference to 'enum C'" }
void func (C*);
void func (enum C*); // { dg-warning "redundant enum-key 'enum' in reference to 'enum C'" }
int C;
extern enum C *pc;
extern enum C ac[];
void func (enum C*);
#if __cplusplus > 199711L
enum class D1 { d1 };
enum struct D2 { d2 };
#else
enum D1 { d1 };
enum D2 { d2 };
#endif
extern D1 *pd1;
extern D2 *pd2;
extern enum D1 *pd1; // { dg-warning "redundant enum-key 'enum' in reference to 'enum class D1'" "C++ 11 and above" { target c++11 } }
// { dg-warning "redundant enum-key 'enum' in reference to 'enum D1'" "C++ 98" { target c++98_only } .-1 }
extern enum D2 *pd2; // { dg-warning "redundant enum-key 'enum' in reference to 'enum class D2'" "C++ 11 and above" { target c++11 } }
// { dg-warning "redundant enum-key 'enum' in reference to 'enum D2'" "C++ 98" { target c++98_only } .-1 }
extern D1 ad1[];
extern D2 ad2[];
#if __cplusplus > 199711L
extern enum class D1 ad1[]; // { dg-warning "redundant enum-key 'enum class' in reference to 'enum class D1'" "C++ 11 and above" { target c++11 } }
// { dg-warning "elaborated-type-specifier for a scoped enum must not use the 'class' keyword" "C++ 11 and above" { target c++11 } .-1 }
/* The pretty printer cannot differentiate between enum class and enum struct
because the C++ front-end doesn't encode it so allow for both in the text
of the warning below. */
extern enum struct D2 ad2[]; // { dg-warning "redundant enum-key 'enum struct' in reference to 'enum \(class|struct\) D2'" "C++ 11 and above" { target c++11 } }
// { dg-warning "elaborated-type-specifier for a scoped enum must not use the 'struct' keyword" "C++ 11 and above" { target c++11 } .-1 }
#else
extern enum D1 ad1[]; // { dg-warning "redundant enum-key 'enum' in reference to 'enum D1'" "C++ 98" { target c++98_only } }
#endif
void func (D1*);
void func (enum D1*); // { dg-warning "redundant enum-key 'enum' in reference to 'enum " }
void func (D2*);
void func (enum D2*); // { dg-warning "redundant enum-key 'enum' in reference to 'enum " }
int D1, D2;
extern enum D1 *pd1;
extern enum D1 ad1[];
void func (enum D1*);
extern enum D2 *pd2;
extern enum D2 ad2[];
void func (enum D2*);
union U;
extern U *pu;
extern union U *pu; // { dg-warning "redundant class-key 'union' in reference to 'union U'" }
extern U au[];
extern union U au[]; // { dg-warning "redundant class-key 'union' in reference to 'union U'" }
void func (U*);
void func (union U*); // { dg-warning "redundant class-key 'union' in reference to 'union U'" }
int U;
extern union U *pu;
extern union U au[];
void func (union U*);
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