The attached patch changes the class-key of class definitions that satisfy the requirements on a POD struct to 'struct', and that of struct definitions that aren't POD to class, according to the GCC coding convention. The patch is also prerequisite for GCC being able to compile cleanly with -Wmismatched-tags.
I made the changes building GCC with -Wstruct-not-pod and -Wclass-is-pod enabled, scanning the build log for instances of each warning, and using a script replacing the class-key as necessary and adjusting the access of the members declared immediately after the class-head. Martin
PR c++/61339 - add mismatch between struct and class [-Wmismatched-tags] to non-bugs gcc/c-family/ChangeLog: PR c++/61339 * c.opt: gcc/cp/ChangeLog: PR c++/61339 * parser.c (cp_parser_type_specifier): (cp_parser_function_definition_after_declarator): (cp_parser_template_declaration_after_parameters): gcc/testsuite/ChangeLog: PR c++/61339 * g++.dg/warn/Wclass-is-pod.C: New test. * g++.dg/warn/Wstruct-not-pod.C: New test. diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt index 080066fa608..27b413115e3 100644 --- a/gcc/c-family/c.opt +++ b/gcc/c-family/c.opt @@ -794,6 +794,14 @@ Wstringop-truncation C ObjC C++ LTO ObjC++ Var(warn_stringop_truncation) Warning Init (1) LangEnabledBy(C ObjC C++ LTO ObjC++, Wall) Warn about truncation in string manipulation functions like strncat and strncpy. +Wstruct-not-pod +C++ ObjC++ Var(warn_struct_not_pod) Init (1) LangEnabledBy(C++ ObjC++, Wall) +Warn about structs that are not POD. + +Wclass-is-pod +C++ ObjC++ Var(warn_class_is_pod) Init (1) LangEnabledBy(C++ ObjC++, Wall) +Warn about classes that are POD. + Wsuggest-attribute=format C ObjC C++ ObjC++ Var(warn_suggest_attribute_format) Warning Warn about functions which might be candidates for format attributes. diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 12814102465..e20c26b7ecd 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -262,6 +262,8 @@ static bool cp_parser_omp_declare_reduction_exprs static void cp_finalize_oacc_routine (cp_parser *, tree, bool); +static void maybe_warn_struct_vs_class (location_t, tree); + /* Manifest constants. */ #define CP_LEXER_BUFFER_SIZE ((256 * 1024) / sizeof (cp_token)) #define CP_SAVED_TOKEN_STACK 5 @@ -17442,6 +17444,8 @@ cp_parser_type_specifier (cp_parser* parser, type_spec, token, /*type_definition_p=*/true); + + maybe_warn_struct_vs_class (token->location, type_spec); return type_spec; } @@ -28039,6 +28043,118 @@ cp_parser_function_definition_after_declarator (cp_parser* parser, return fn; } +/* Return true if the template TYPE appears to meet the requirements + of a POD type even if some of its instantiations may not. */ + +static bool +template_pod_p (tree type) +{ + if (TYPE_HAS_USER_CONSTRUCTOR (type) + || TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type) + || (TYPE_HAS_COPY_ASSIGN (type) + && (cxx_dialect != cxx98 + || !TYPE_HAS_TRIVIAL_COPY_ASSIGN (type)))) + return false; + + for (tree fld = TYPE_FIELDS (type); fld; fld = TREE_CHAIN (fld)) + { + if (TREE_CODE (fld) == FIELD_DECL + && !TREE_STATIC (fld) + && TREE_TYPE (fld)) + { + tree fldtype = TREE_TYPE (fld); + if (TREE_CODE (fldtype) == REFERENCE_TYPE) + return false; + if (TREE_CODE (fldtype) == RECORD_TYPE + && !template_pod_p (fldtype)) + return false; + } + else if (TREE_CODE (fld) == FUNCTION_DECL + && DECL_NONSTATIC_MEMBER_FUNCTION_P (fld) + && DECL_VIRTUAL_P (fld)) + return false; + } + + return true; +} + +/* For a DECL of class type, issue a warning when it is a POD type + and is declared with the class-key class, or when it is not a POD + type and is declared withe the class-key struct. When DECL refers + to a class template, consider instead whether it has a ctor, dtor, + or copy assignment operator as a proxy. */ + +static void +maybe_warn_struct_vs_class (location_t loc, tree type) +{ + if (TREE_CODE (type) != RECORD_TYPE) + return; + + const char *key = class_key_or_enum_as_string (type); + if (processing_template_decl) + { + if (template_pod_p (type)) + { + if (!strcmp (key, "class")) + warning_at (loc, OPT_Wclass_is_pod, + "POD-like template %qT declared with class-key %qs; " + "use %qs instead", + type, key, "struct"); + else + inform (loc, + "POD-like template %qT declared with class-key %qs " + "as expected", + type, key); + } + else if (strcmp (key, "class")) + warning_at (loc, OPT_Wstruct_not_pod, + "non-POD-like template %qT declared with class-key %qs; " + "use %qs instead", + type, key, "class"); + else + inform (loc, + "non-POD-like template %qT declared with class-key %qs " + "as expected", + type, key); + } + else + { + if (pod_type_p (type)) + { + if (!strcmp (key, "class")) + warning_at (loc, OPT_Wclass_is_pod, + "POD type %qT declared with class-key %qs; " + "use %qs instead", + type, key, "struct"); + else + inform (loc, + "POD type %qT declared with class-key %qs as expected", + type, key); + } + else if (cxx_dialect == cxx98 && template_pod_p (type)) + { + if (!strcmp (key, "class")) + warning_at (loc, OPT_Wstruct_not_pod, + "C++11 POD type %qT declared with class-key %qs; " + "use %qs instead", + type, key, "struct"); + else + inform (loc, + "C++11 POD type %qT declared with class-key %qs as expected", + type, key); + } + else if (strcmp (key, "class")) + warning_at (loc, OPT_Wstruct_not_pod, + "non-POD type %qT declared with class-key %qs; " + "use %qs instead", + type, key, "class"); + else + inform (loc, + "non-POD type %qT declared with class-key %qs as expected", + type, key); + } +} + /* Parse a template-declaration body (following argument list). */ static void @@ -28076,6 +28192,8 @@ cp_parser_template_declaration_after_parameters (cp_parser* parser, member_p, /*explicit_specialization_p=*/false, &friend_p); + // maybe_warn_struct_vs_class (token->location, TREE_TYPE (decl)); + pop_deferring_access_checks (); /* If this is a member template declaration, let the front diff --git a/gcc/testsuite/g++.dg/warn/Wclass-is-pod.C b/gcc/testsuite/g++.dg/warn/Wclass-is-pod.C new file mode 100644 index 00000000000..c276b469783 --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wclass-is-pod.C @@ -0,0 +1,127 @@ +// { dg-do compile } +// { dg-options "-Wclass-is-pod" } + +namespace Pod +{ +class A // { dg-warning "POD type 'Pod::A' declared with class-key 'class'; use 'struct' instead" } +{ }; +class B // { dg-warning "\\\[-Wclass-is-pod" } +{ public: int i; }; +class C // { dg-warning "\\\[-Wclass-is-pod" } +{ public: void f (); }; +class D // { dg-warning "\\\[-Wclass-is-pod" } +{ void operator= (int); }; + +#if __cplusplus > 199711L +class E // { dg-warning "\\\[-Wclass-is-pod" "" { target c++11 } } + : A { }; +class F // { dg-warning "\\\[-Wclass-is-pod" "" { target c++11 } } + : E { }; +class G // { dg-warning "\\\[-Wclass-is-pod" "" { target c++11 } } + : private A { }; +#endif +} + + +namespace PodTemplate +{ +template <class> +class A // { dg-warning "\\\[-Wclass-is-pod" } +{ }; +template <class> +class B // { dg-warning "\\\[-Wclass-is-pod" } +{ public: int i; }; +template <class> +class C // { dg-warning "\\\[-Wclass-is-pod" } +{ public: void f (); }; +template <class> +class D // { dg-warning "\\\[-Wclass-is-pod" } +{ void operator= (int); }; + +#if __cplusplus > 199711L +template <class T> +class E // { dg-warning "\\\[-Wclass-is-pod" "" { target c++11 } } + : A<T> { }; +template <class T> +class F // { dg-warning "\\\[-Wclass-is-pod" "" { target c++11 } } + : E<T> { }; +template <class T> +class G // { dg-warning "\\\[-Wclass-is-pod" "" { target c++11 } } + : private A<T> { }; +#endif +} + + +namespace NonPodDueToSpecialFunctions +{ +class A +{ public: A (); }; +class B +{ public: B (int); }; + +class C +{ public: C (C&); }; + +class D +{ public: ~D (); }; + +class E +{ public: void operator= (E&); }; +} + + +namespace NonPodDueToVirtuals +{ +class A +{ public: virtual void f (); }; + +} + + +namespace NonPodDueToNonPodMembers +{ +class A +{ public: int &r; }; + +class B { public: B (); }; + +class C +{ public: B b; }; +} + + +namespace NonPodTemplateDueToNonPodMembers +{ +template <class T> +class A +{ public: T &r; }; + +class B { public: B (); }; + +template <class> +class C +{ public: B b; }; +} + + + +namespace NonPodDueToAccess +{ +class A +{ int i; public: int j; }; + +class B +{ int i; protected: int j; }; +} + + +namespace NonPodDueToBases +{ +struct A { }; +struct B { }; +class C: A, B // { dg-bogus "\\\[-Wclass-is-pod" "pr91064" { xfail c++11 } } +{ }; + +class D: virtual A +{ }; +} diff --git a/gcc/testsuite/g++.dg/warn/Wstruct-not-pod.C b/gcc/testsuite/g++.dg/warn/Wstruct-not-pod.C new file mode 100644 index 00000000000..3e238eedef3 --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wstruct-not-pod.C @@ -0,0 +1,336 @@ +// Test to verify that -Wstruct-not-pod is issued for struct definitions +// that don't meet the requirements for a POD class. +// { dg-do compile } +// { dg-options "-Wstruct-not-pod" } + +#define ASSERT_POD(T) static_assert (__is_pod (T), #T "is pod") + +namespace PodStruct +{ +struct A { }; ASSERT_POD (A); +struct B { int i; const int j; }; ASSERT_POD (B); +struct C { void f (); }; ASSERT_POD (C); +struct D { void operator= (int); }; ASSERT_POD (D); + +#if __cplusplus > 199711L +struct E: A { }; +struct F: E { }; +struct G: private A { }; ASSERT_POD (G); +#endif + +struct H { public: int i; }; ASSERT_POD (H); + +#if __cplusplus > 199711L +struct I { protected: int i; protected: int j; }; ASSERT_POD (J); +#endif + +class J { J (); ~J (); }; +struct K { static const int i; static int &r; static J j; int k; }; +ASSERT_POD (K); +} + + +namespace PodTemplate +{ +template <class> struct A { }; +template struct A<int> { }; + +template <class> struct B { int i; }; +template struct B<int> { }; + +template <class> struct C { void f (); }; +template struct C<int> { }; + +template <class> struct D { void operator= (int); }; +template struct D<int> { }; + +#if __cplusplus > 199711L +template <class T> struct E: A<T> { }; +template struct E<int>; + +template <class T> struct F: E<T> { }; +template struct F<int>; + +template <class T> struct G: private A<T> { }; +template struct G<int>; +#endif + +template <class> struct H { public: int i; }; +template struct H<int>; + +#if __cplusplus > 199711L +template <class> struct I { protected: int i; protected: int j; }; +template struct I<int>; +#endif + +// This is considered a POD even though instantiating it on a non-POD +// will prevent it from being one. +template <class T> struct J { T i; }; +template struct J<int>; + +template <class> struct K { + /* Template ctor and assignment operator are not special members. */ + template <class T> K (const K<T>&); + template <class T> K& operator= (const K<T>&); +}; +ASSERT_POD (K<int>); +} + + +namespace PodExplicitSpecialization +{ +template <class> class A; +template <> struct A<int> { }; + +template <class> class B; +template <> struct B<int> { int i; }; +template <class> class C; +template <> struct C<int> { void f (); }; +template <class> class D; +template <> struct D<int> { void operator= (int); }; + +#if __cplusplus > 199711L +template <class> class E; +template <> struct E<int>: A<int> { }; + +template <class> class F; +template <> struct F<int>: E<int> { }; + +template <class> class G; +template <> struct G<int>: private A<int> { }; +#endif + +template <class> class H; +template <> struct H<int> { public: int i; }; + +#if __cplusplus > 199711L +template <class> class I; +template <> struct I<int> { protected: int i; protected: int j; }; +#endif + +} + + +namespace PodPartialSpecialization +{ +template <class> class A; +template <class T> struct A<const T> { }; +template struct A<const int>; + +template <class> class B; +template <class T> struct B<const T> { int i; }; +template struct B<const int>; + +template <class> class C; +template <class T> struct C<const T> { void f (); }; +template struct C<const int>; + +template <class> class D; +template <class T> struct D<const T> { void operator= (int); }; +template struct D<const int>; + +#if __cplusplus > 199711L +template <class> class E; +template <class T> struct E<const T>: A<const T> { }; +template struct E<const int>; + +template <class> class F; +template <class T> struct F<const T>: E<const T> { }; +template struct F<const int>; + +template <class> class G; +template <class T> struct G<const T>: private A<const T> { }; +template struct G<const int>; +#endif + +template <class> class H; +template <class T> struct H<const T> { public: int i; }; +template struct H<const int>; + +#if __cplusplus > 199711L +template <class> class I; +template <class T> struct I<const T> { protected: int i; protected: int j; }; +template struct I<const int>; +#endif + +// Similar to the case of the primary template, this is considered a POD +// even though instantiating it on a non-POD will prevent it from being +// one. +template <class T> class J; +template <class T> struct J<const T> { T i; }; +template struct J<const int>; +} + + +namespace NonPodStructDueToSpecialFunctions +{ +struct A // { dg-warning "non-POD type '\[A-Za-z\]\*::A' declared with class-key 'struct'; use 'class' instead" } +{ A (); }; + +struct B // { dg-warning "\\\[-Wstruct-not-pod" } +{ B (int); }; + +struct C // { dg-warning "\\\[-Wstruct-not-pod" } +{ C (C&); }; + +struct D // { dg-warning "\\\[-Wstruct-not-pod" } +{ ~D (); }; + +struct E // { dg-warning "\\\[-Wstruct-not-pod" } +{ void operator= (E&); }; +} + + +namespace NonPodTemplateDueToSpecialFunctions +{ +template <class> +struct A // { dg-warning "\\\[-Wstruct-not-pod" } +{ A (); }; + +template <class> +struct B // { dg-warning "\\\[-Wstruct-not-pod" } +{ B (int); }; + +template <class> +struct C // { dg-warning "\\\[-Wstruct-not-pod" } +{ C (C&); }; + +template <class> +struct D // { dg-warning "\\\[-Wstruct-not-pod" "FIXME" { xfail *-*-* } } +{ ~D (); }; + +template <class> +struct E // { dg-warning "\\\[-Wstruct-not-pod" } +{ void operator= (E&); }; +} + + +namespace NonPodExplicitSpecializationDueToSpecialFunctions +{ +template <class> class A; +template <> +struct A<int> // { dg-warning "\\\[-Wstruct-not-pod" } +{ A (); }; + +template <class> class B; +template <> +struct B<int> // { dg-warning "\\\[-Wstruct-not-pod" } +{ B (int); }; + +template <class> class C; +template <> +struct C<int> // { dg-warning "\\\[-Wstruct-not-pod" } +{ C (C&); }; + +template <class> class D; +template <> +struct D<int> // { dg-warning "\\\[-Wstruct-not-pod" } +{ ~D (); }; + +template <class> class E; +template <> +struct E<int> // { dg-warning "\\\[-Wstruct-not-pod" } +{ void operator= (E&); }; +} + + +namespace NonPodPartialSpecializationDueToSpecialFunctions +{ +template <class> class A; +template <class T> +struct A<T*> // { dg-warning "\\\[-Wstruct-not-pod" } +{ A (); }; +template struct A<int*>; + +template <class> class B; +template <class T> +struct B<T*> // { dg-warning "\\\[-Wstruct-not-pod" } +{ B (int); }; +template struct B<int*>; + +template <class> class C; +template <class T> +struct C<T*> // { dg-warning "\\\[-Wstruct-not-pod" } +{ C (C&); }; +template struct C<int*>; + +template <class> class D; +template <class T> +struct D<T*> // { dg-warning "\\\[-Wstruct-not-pod" "FIXME" { xfail *-*-* } } +{ ~D (); }; +template struct D<int*>; + +template <class> class E; +template <class T> +struct E<T*> // { dg-warning "\\\[-Wstruct-not-pod" } +{ void operator= (E&); }; +template struct E<int*>; +} + + +namespace NonPodDueToVirtuals +{ +struct A // { dg-warning "\\\[-Wstruct-not-pod" } +{ virtual void f (); }; + +} + + +namespace NonPodDueToNonPodMembers +{ +struct A // { dg-warning "\\\[-Wstruct-not-pod" } +{ int &r; }; + +class B { public: B (); }; + +struct C // { dg-warning "\\\[-Wstruct-not-pod" } +{ B b; }; +} + + +namespace NonPodTemplateDueToNonPodMembers +{ +template <class> +struct A // { dg-warning "\\\[-Wstruct-not-pod" } +{ int &r; }; + +class B { public: B (); }; + +template <class> +struct C // { dg-warning "\\\[-Wstruct-not-pod" } +{ B b; }; +} + + +namespace NonPodDueToAccess +{ +struct A // { dg-warning "\\\[-Wstruct-not-pod" } +{ int i; private: int j; }; + +struct B // { dg-warning "\\\[-Wstruct-not-pod" } +{ int i; protected: int j; }; +} + + +namespace NonPodTemplateDueToAccess +{ +template <class> +struct A // { dg-warning "\\\[-Wstruct-not-pod" } +{ int i; private: int j; }; + +template <class> +struct B // { dg-warning "\\\[-Wstruct-not-pod" } +{ int i; protected: int j; }; +} + + +namespace NonPodDueToBases +{ +struct A { }; +struct B { }; +struct C: A, B // { dg-warning "\\\[-Wstruct-not-pod" "pr91064" { xfail c++11 } } +{ }; + +struct D: virtual A // { dg-warning "\\\[-Wstruct-not-pod" } +{ }; +}