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> 2019-12-17 Michael Meissner <meissner@linux.ibm.com>
* config/rs6000/rs6000.c (num_insns_constant_gpr): Return 1 if the * 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> 2019-12-11 David Malcolm <dmalcolm@redhat.com>
* c-pretty-print.c (c_pretty_printer::clone): New vfunc * c-pretty-print.c (c_pretty_printer::clone): New vfunc
......
...@@ -755,6 +755,10 @@ Wmisleading-indentation ...@@ -755,6 +755,10 @@ Wmisleading-indentation
C C++ Common Var(warn_misleading_indentation) Warning LangEnabledBy(C C++,Wall) 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. 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 Wmissing-braces
C ObjC C++ ObjC++ Var(warn_missing_braces) Warning LangEnabledBy(C ObjC,Wall) C ObjC C++ ObjC++ Var(warn_missing_braces) Warning LangEnabledBy(C ObjC,Wall)
Warn about possibly missing braces around initializers. Warn about possibly missing braces around initializers.
...@@ -783,6 +787,10 @@ Wpacked-not-aligned ...@@ -783,6 +787,10 @@ Wpacked-not-aligned
C ObjC C++ ObjC++ Var(warn_packed_not_aligned) Warning LangEnabledBy(C ObjC C++ ObjC++,Wall) 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. 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 Wsized-deallocation
C++ ObjC++ Var(warn_sized_deallocation) Warning EnabledBy(Wextra) C++ ObjC++ Var(warn_sized_deallocation) Warning EnabledBy(Wextra)
Warn about missing sized deallocation functions. 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> 2019-12-17 Jason Merrill <jason@redhat.com>
PR c++/79592 - missing explanation of invalid constexpr. PR c++/79592 - missing explanation of invalid constexpr.
......
...@@ -233,10 +233,10 @@ in the following sections. ...@@ -233,10 +233,10 @@ in the following sections.
-Wabi=@var{n} -Wabi-tag -Wcomma-subscript -Wconversion-null @gol -Wabi=@var{n} -Wabi-tag -Wcomma-subscript -Wconversion-null @gol
-Wctor-dtor-privacy @gol -Wctor-dtor-privacy @gol
-Wdelete-non-virtual-dtor -Wdeprecated-copy -Wdeprecated-copy-dtor @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 -Wmultiple-inheritance -Wno-init-list-lifetime @gol
-Wnamespaces -Wnarrowing @gol -Wnamespaces -Wnarrowing @gol
-Wpessimizing-move -Wredundant-move @gol -Wpessimizing-move -Wredundant-move -Wredundant-tags @gol
-Wnoexcept -Wnoexcept-type -Wclass-memaccess @gol -Wnoexcept -Wnoexcept-type -Wclass-memaccess @gol
-Wnon-virtual-dtor -Wreorder -Wregister @gol -Wnon-virtual-dtor -Wreorder -Wregister @gol
-Weffc++ -Wstrict-null-sentinel -Wtemplates @gol -Weffc++ -Wstrict-null-sentinel -Wtemplates @gol
...@@ -3323,6 +3323,21 @@ treats the return value as if it were designated by an rvalue. ...@@ -3323,6 +3323,21 @@ treats the return value as if it were designated by an rvalue.
This warning is enabled by @option{-Wextra}. 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)} @item -fext-numeric-literals @r{(C++ and Objective-C++ only)}
@opindex fext-numeric-literals @opindex fext-numeric-literals
@opindex fno-ext-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 ...@@ -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 one can still use the STL. One may also instantiate or specialize
templates. 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)} @item -Wmultiple-inheritance @r{(C++ and Objective-C++ only)}
@opindex Wmultiple-inheritance @opindex Wmultiple-inheritance
@opindex Wno-multiple-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> 2019-12-17 Jakub Jelinek <jakub@redhat.com>
PR c++/59655 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