From patchwork Mon Jul 8 22:00:18 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Martin Sebor X-Patchwork-Id: 1129378 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=gcc.gnu.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-504657-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="GPzzQtro"; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="YBae0/Wp"; dkim-atps=neutral Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 45jKC360rRz9sMr for ; Tue, 9 Jul 2019 08:00:47 +1000 (AEST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :subject:from:to:references:message-id:date:mime-version :in-reply-to:content-type; q=dns; s=default; b=kQOF98O2kzgjXPicO sMX4lh7jM63JBsb/y3y4vYEjvbw+RrHcMIVGRsmnw5fYpkYj0bibbe3IZmrr2ev/ AH45atkNUkhCMC++OTf0g9eagrSWdUPCIxdoShhadaOKgk8jZB5/oftt5mIpwnUT ARshqlNiCOX040Gp538in8pJo0= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :subject:from:to:references:message-id:date:mime-version :in-reply-to:content-type; s=default; bh=fAI9fflubg1vEIMw00ofMMf n+yw=; b=GPzzQtrocir7c+gccoTK7kQxPvWbV5c8F0EWlp33Iwq2YJR3svn2fHp KbgNEMt+TdW2pEuIc7Ty0QRHmWgtL2O8+JbWXAel6P1bY3uPJajmjRQIFvqrqJjK DXrENKFIkmP6zY/kuTYhnk1Nq2uAQdK76NGq0vzBHITB3lVCJomc= Received: (qmail 17726 invoked by alias); 8 Jul 2019 22:00:39 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 17543 invoked by uid 89); 8 Jul 2019 22:00:30 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-18.6 required=5.0 tests=AWL, BAYES_00, FREEMAIL_FROM, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, RCVD_IN_DNSWL_NONE, SPF_PASS autolearn=ham version=3.3.1 spammy= X-HELO: mail-qt1-f174.google.com Received: from mail-qt1-f174.google.com (HELO mail-qt1-f174.google.com) (209.85.160.174) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Mon, 08 Jul 2019 22:00:26 +0000 Received: by mail-qt1-f174.google.com with SMTP id k10so12002731qtq.1 for ; Mon, 08 Jul 2019 15:00:22 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=subject:from:to:references:message-id:date:user-agent:mime-version :in-reply-to:content-language; bh=6TeH4CXCCvg/PFhOM8d7bL9Hk5nVP+hTtGCscIwOIHo=; b=YBae0/Wpr+uIh4/LVpU1dc9N8TSnMJws1aViWhCgTH0sVnumRaxscHWCMi49Zb1EOL D9n28FEkcSWDKmMTEzbzzPU2bbc3sXW+S9mW338x/6tafqBxzJmP2EmhWExhAkjj9Tqx BQxjVlGY+uHdEfdlQS3meHCsY3pN2WxKkKPUH9U6Vq8fgZuTXKKwQr2l8QOwT7IkqHdW uY0QA61PGb2OSYDmWYzsQSHOKh2ywMG/jF7UxEwOTf+zQwNpmbSWn9+rjeKPsXT/oGYd PrFF4molKoxSqS0eBjllxpc8o+4S0IQgw7Q9G7ItugHqseJ/m/K+JATCXt9FKZRfzbz1 BuWg== Received: from [192.168.0.41] (174-16-116-9.hlrn.qwest.net. [174.16.116.9]) by smtp.gmail.com with ESMTPSA id u19sm8469866qka.35.2019.07.08.15.00.18 for (version=TLS1_3 cipher=AEAD-AES128-GCM-SHA256 bits=128/128); Mon, 08 Jul 2019 15:00:19 -0700 (PDT) Subject: [PATCH 2/3] change class-key of PODs to struct and others to class (PR 61339) From: Martin Sebor To: gcc-patches References: Message-ID: <05c26a42-d2ed-493c-441d-5325dafa6e53@gmail.com> Date: Mon, 8 Jul 2019 16:00:18 -0600 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Thunderbird/60.6.1 MIME-Version: 1.0 In-Reply-To: X-IsSubscribed: yes 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 A // { dg-warning "\\\[-Wclass-is-pod" } +{ }; +template +class B // { dg-warning "\\\[-Wclass-is-pod" } +{ public: int i; }; +template +class C // { dg-warning "\\\[-Wclass-is-pod" } +{ public: void f (); }; +template +class D // { dg-warning "\\\[-Wclass-is-pod" } +{ void operator= (int); }; + +#if __cplusplus > 199711L +template +class E // { dg-warning "\\\[-Wclass-is-pod" "" { target c++11 } } + : A { }; +template +class F // { dg-warning "\\\[-Wclass-is-pod" "" { target c++11 } } + : E { }; +template +class G // { dg-warning "\\\[-Wclass-is-pod" "" { target c++11 } } + : private A { }; +#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 A +{ public: T &r; }; + +class B { public: B (); }; + +template +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 struct A { }; +template struct A { }; + +template struct B { int i; }; +template struct B { }; + +template struct C { void f (); }; +template struct C { }; + +template struct D { void operator= (int); }; +template struct D { }; + +#if __cplusplus > 199711L +template struct E: A { }; +template struct E; + +template struct F: E { }; +template struct F; + +template struct G: private A { }; +template struct G; +#endif + +template struct H { public: int i; }; +template struct H; + +#if __cplusplus > 199711L +template struct I { protected: int i; protected: int j; }; +template struct I; +#endif + +// This is considered a POD even though instantiating it on a non-POD +// will prevent it from being one. +template struct J { T i; }; +template struct J; + +template struct K { + /* Template ctor and assignment operator are not special members. */ + template K (const K&); + template K& operator= (const K&); +}; +ASSERT_POD (K); +} + + +namespace PodExplicitSpecialization +{ +template class A; +template <> struct A { }; + +template class B; +template <> struct B { int i; }; +template class C; +template <> struct C { void f (); }; +template class D; +template <> struct D { void operator= (int); }; + +#if __cplusplus > 199711L +template class E; +template <> struct E: A { }; + +template class F; +template <> struct F: E { }; + +template class G; +template <> struct G: private A { }; +#endif + +template class H; +template <> struct H { public: int i; }; + +#if __cplusplus > 199711L +template class I; +template <> struct I { protected: int i; protected: int j; }; +#endif + +} + + +namespace PodPartialSpecialization +{ +template class A; +template struct A { }; +template struct A; + +template class B; +template struct B { int i; }; +template struct B; + +template class C; +template struct C { void f (); }; +template struct C; + +template class D; +template struct D { void operator= (int); }; +template struct D; + +#if __cplusplus > 199711L +template class E; +template struct E: A { }; +template struct E; + +template class F; +template struct F: E { }; +template struct F; + +template class G; +template struct G: private A { }; +template struct G; +#endif + +template class H; +template struct H { public: int i; }; +template struct H; + +#if __cplusplus > 199711L +template class I; +template struct I { protected: int i; protected: int j; }; +template struct I; +#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 J; +template struct J { T i; }; +template struct J; +} + + +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 +struct A // { dg-warning "\\\[-Wstruct-not-pod" } +{ A (); }; + +template +struct B // { dg-warning "\\\[-Wstruct-not-pod" } +{ B (int); }; + +template +struct C // { dg-warning "\\\[-Wstruct-not-pod" } +{ C (C&); }; + +template +struct D // { dg-warning "\\\[-Wstruct-not-pod" "FIXME" { xfail *-*-* } } +{ ~D (); }; + +template +struct E // { dg-warning "\\\[-Wstruct-not-pod" } +{ void operator= (E&); }; +} + + +namespace NonPodExplicitSpecializationDueToSpecialFunctions +{ +template class A; +template <> +struct A // { dg-warning "\\\[-Wstruct-not-pod" } +{ A (); }; + +template class B; +template <> +struct B // { dg-warning "\\\[-Wstruct-not-pod" } +{ B (int); }; + +template class C; +template <> +struct C // { dg-warning "\\\[-Wstruct-not-pod" } +{ C (C&); }; + +template class D; +template <> +struct D // { dg-warning "\\\[-Wstruct-not-pod" } +{ ~D (); }; + +template class E; +template <> +struct E // { dg-warning "\\\[-Wstruct-not-pod" } +{ void operator= (E&); }; +} + + +namespace NonPodPartialSpecializationDueToSpecialFunctions +{ +template class A; +template +struct A // { dg-warning "\\\[-Wstruct-not-pod" } +{ A (); }; +template struct A; + +template class B; +template +struct B // { dg-warning "\\\[-Wstruct-not-pod" } +{ B (int); }; +template struct B; + +template class C; +template +struct C // { dg-warning "\\\[-Wstruct-not-pod" } +{ C (C&); }; +template struct C; + +template class D; +template +struct D // { dg-warning "\\\[-Wstruct-not-pod" "FIXME" { xfail *-*-* } } +{ ~D (); }; +template struct D; + +template class E; +template +struct E // { dg-warning "\\\[-Wstruct-not-pod" } +{ void operator= (E&); }; +template struct E; +} + + +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 +struct A // { dg-warning "\\\[-Wstruct-not-pod" } +{ int &r; }; + +class B { public: B (); }; + +template +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 +struct A // { dg-warning "\\\[-Wstruct-not-pod" } +{ int i; private: int j; }; + +template +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" } +{ }; +}