From patchwork Sat Dec 3 12:04:14 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Jonathan Wakely X-Patchwork-Id: 129077 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) by ozlabs.org (Postfix) with SMTP id E0FB9B6F7B for ; Sat, 3 Dec 2011 23:04:34 +1100 (EST) Received: (qmail 20016 invoked by alias); 3 Dec 2011 12:04:31 -0000 Received: (qmail 19997 invoked by uid 22791); 3 Dec 2011 12:04:29 -0000 X-SWARE-Spam-Status: No, hits=-2.4 required=5.0 tests=AWL, BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, FREEMAIL_FROM, RCVD_IN_DNSWL_LOW, TW_CX X-Spam-Check-By: sourceware.org Received: from mail-ww0-f51.google.com (HELO mail-ww0-f51.google.com) (74.125.82.51) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Sat, 03 Dec 2011 12:04:15 +0000 Received: by wgbdr1 with SMTP id dr1so2820732wgb.8 for ; Sat, 03 Dec 2011 04:04:14 -0800 (PST) MIME-Version: 1.0 Received: by 10.180.102.162 with SMTP id fp2mr3273994wib.50.1322913854284; Sat, 03 Dec 2011 04:04:14 -0800 (PST) Received: by 10.216.68.76 with HTTP; Sat, 3 Dec 2011 04:04:14 -0800 (PST) In-Reply-To: References: Date: Sat, 3 Dec 2011 12:04:14 +0000 Message-ID: Subject: Re: [patch] add __is_final trait to fix libstdc++/51365 From: Jonathan Wakely To: gcc-patches Cc: jason@gcc.gnu.org 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 On 3 December 2011 12:00, Jonathan Wakely wrote: > This implements a new C++ trait, __is_final, to query the 'final' > specifier that 4.7 supports. The trait is needed for the library so we > can detect when it's not possible to derive from a type in order to > exploit the empty base-class optimisation.  This affects all > containers, std::shared_ptr, std::future, std::tuple and anywhere else > that tries to use the EBO.  It's not a C++11-only problem because we > support __final in c++98 mode.  See PR libstdc++/51365 for examples of > programs using final classes that cause problems in libstdc++ and for > patches to the library that use this trait to solve the problems. > > I originally thought about naming this __is_final_class, which would > allow a possible __is_final_function in future, but I think > __is_final(type) is pretty clear.  There is a proposal to add > __is_final to Clang with the same spelling and semantics. > > Tested x86_64-linux, ok for trunk? > > c-family/ChangeLog: > >        * c-common.c (RID_IS_FINAL): Add. >        * c-common.h (RID_IS_FINAL): Add. > > cp/ChangeLog: > >        * cp-tree.h (CPTK_IS_FINAL): Add. >        * parser.c (cp_parser_translation_unit): Handle RID_IS_FINAL. >        (cp_parser_primary_expression, cp_parser_trait_expr): Likewise. >        * semantics.c (trait_expr_value, finish_trait_expr): Handle >        CPTK_IS_FINAL. >        * cxx-pretty-print.c (pp_cxx_trait_expression): Likewise. > > ChangeLog: > >        * doc/extend.texi (Type Traits): Add __is_final. > > testsuite/ChangeLog: > >        * g++.dg/ext/is_final.C: New. Oops, there was a stray chunk in that patch: @@ -4923,6 +4924,7 @@ extern bool user_provided_p (tree); extern bool type_has_user_provided_constructor (tree); extern bool type_has_user_provided_default_constructor (tree); extern tree default_init_uninitialized_part (tree); +extern void warn_missing_meminits (tree, tree); extern bool trivial_default_constructor_is_constexpr (tree); extern bool type_has_constexpr_default_constructor (tree); extern bool type_has_virtual_destructor (tree); Here's the correct patch (identical except for removing that piece) Index: c-family/c-common.c =================================================================== --- c-family/c-common.c (revision 181967) +++ c-family/c-common.c (working copy) @@ -462,6 +462,7 @@ const struct c_common_resword c_common_r { "__is_convertible_to", RID_IS_CONVERTIBLE_TO, D_CXXONLY }, { "__is_empty", RID_IS_EMPTY, D_CXXONLY }, { "__is_enum", RID_IS_ENUM, D_CXXONLY }, + { "__is_final", RID_IS_FINAL, D_CXXONLY }, { "__is_literal_type", RID_IS_LITERAL_TYPE, D_CXXONLY }, { "__is_pod", RID_IS_POD, D_CXXONLY }, { "__is_polymorphic", RID_IS_POLYMORPHIC, D_CXXONLY }, Index: c-family/c-common.h =================================================================== --- c-family/c-common.h (revision 181967) +++ c-family/c-common.h (working copy) @@ -134,7 +134,7 @@ enum rid RID_CONSTCAST, RID_DYNCAST, RID_REINTCAST, RID_STATCAST, /* C++ extensions */ - RID_BASES, RID_DIRECT_BASES, + RID_BASES, RID_DIRECT_BASES, RID_HAS_NOTHROW_ASSIGN, RID_HAS_NOTHROW_CONSTRUCTOR, RID_HAS_NOTHROW_COPY, RID_HAS_TRIVIAL_ASSIGN, RID_HAS_TRIVIAL_CONSTRUCTOR, RID_HAS_TRIVIAL_COPY, @@ -142,12 +142,12 @@ enum rid RID_IS_ABSTRACT, RID_IS_BASE_OF, RID_IS_CLASS, RID_IS_CONVERTIBLE_TO, RID_IS_EMPTY, RID_IS_ENUM, - RID_IS_LITERAL_TYPE, RID_IS_POD, - RID_IS_POLYMORPHIC, RID_IS_STD_LAYOUT, - RID_IS_TRIVIAL, RID_IS_UNION, - RID_UNDERLYING_TYPE, + RID_IS_FINAL, RID_IS_LITERAL_TYPE, + RID_IS_POD, RID_IS_POLYMORPHIC, + RID_IS_STD_LAYOUT, RID_IS_TRIVIAL, + RID_IS_UNION, RID_UNDERLYING_TYPE, - /* C++0x */ + /* C++11 */ RID_CONSTEXPR, RID_DECLTYPE, RID_NOEXCEPT, RID_NULLPTR, RID_STATIC_ASSERT, /* Objective-C ("AT" reserved words - they are only keywords when Index: cp/cp-tree.h =================================================================== --- cp/cp-tree.h (revision 181967) +++ cp/cp-tree.h (working copy) @@ -584,6 +584,7 @@ typedef enum cp_trait_kind CPTK_IS_CONVERTIBLE_TO, CPTK_IS_EMPTY, CPTK_IS_ENUM, + CPTK_IS_FINAL, CPTK_IS_LITERAL_TYPE, CPTK_IS_POD, CPTK_IS_POLYMORPHIC, Index: cp/parser.c =================================================================== --- cp/parser.c (revision 181967) +++ cp/parser.c (working copy) @@ -3854,6 +3854,7 @@ cp_parser_translation_unit (cp_parser* p __is_convertible_to ( type-id , type-id ) __is_empty ( type-id ) __is_enum ( type-id ) + __is_final ( type-id ) __is_literal_type ( type-id ) __is_pod ( type-id ) __is_polymorphic ( type-id ) @@ -4199,6 +4200,7 @@ cp_parser_primary_expression (cp_parser case RID_IS_CONVERTIBLE_TO: case RID_IS_EMPTY: case RID_IS_ENUM: + case RID_IS_FINAL: case RID_IS_LITERAL_TYPE: case RID_IS_POD: case RID_IS_POLYMORPHIC: @@ -7868,6 +7870,9 @@ cp_parser_trait_expr (cp_parser* parser, case RID_IS_ENUM: kind = CPTK_IS_ENUM; break; + case RID_IS_FINAL: + kind = CPTK_IS_FINAL; + break; case RID_IS_LITERAL_TYPE: kind = CPTK_IS_LITERAL_TYPE; break; Index: cp/semantics.c =================================================================== --- cp/semantics.c (revision 181967) +++ cp/semantics.c (working copy) @@ -5412,6 +5412,9 @@ trait_expr_value (cp_trait_kind kind, tr case CPTK_IS_ENUM: return (type_code1 == ENUMERAL_TYPE); + case CPTK_IS_FINAL: + return (CLASS_TYPE_P (type1) && CLASSTYPE_FINAL (type1)); + case CPTK_IS_LITERAL_TYPE: return (literal_type_p (type1)); @@ -5471,6 +5474,7 @@ finish_trait_expr (cp_trait_kind kind, t || kind == CPTK_IS_CONVERTIBLE_TO || kind == CPTK_IS_EMPTY || kind == CPTK_IS_ENUM + || kind == CPTK_IS_FINAL || kind == CPTK_IS_LITERAL_TYPE || kind == CPTK_IS_POD || kind == CPTK_IS_POLYMORPHIC @@ -5511,6 +5515,7 @@ finish_trait_expr (cp_trait_kind kind, t case CPTK_HAS_VIRTUAL_DESTRUCTOR: case CPTK_IS_ABSTRACT: case CPTK_IS_EMPTY: + case CPTK_IS_FINAL: case CPTK_IS_LITERAL_TYPE: case CPTK_IS_POD: case CPTK_IS_POLYMORPHIC: Index: cp/cxx-pretty-print.c =================================================================== --- cp/cxx-pretty-print.c (revision 181967) +++ cp/cxx-pretty-print.c (working copy) @@ -2380,6 +2380,9 @@ pp_cxx_trait_expression (cxx_pretty_prin case CPTK_IS_ENUM: pp_cxx_ws_string (pp, "__is_enum"); break; + case CPTK_IS_FINAL: + pp_cxx_ws_string (pp, "__is_final"); + break; case CPTK_IS_POD: pp_cxx_ws_string (pp, "__is_pod"); break; Index: doc/extend.texi =================================================================== --- doc/extend.texi (revision 181967) +++ doc/extend.texi (working copy) @@ -15164,6 +15164,10 @@ of unknown bound. If @code{type} is a cv enumeration type ([basic.compound]) the trait is true, else it is false. +@item __is_final (type) +If @code{type} is a cv class type marked @code{final} ([class]) the trait +is true, else it is false. + @item __is_literal_type (type) If @code{type} is a literal type ([basic.types]) the trait is true, else it is false. Requires: @code{type} shall be a complete type, Index: testsuite/g++.dg/ext/is_final.C =================================================================== --- testsuite/g++.dg/ext/is_final.C (revision 0) +++ testsuite/g++.dg/ext/is_final.C (revision 0) @@ -0,0 +1,46 @@ +// PR c++/51365 +// { dg-do compile } +// { dg-options "-std=c++0x" } + +struct A { }; +static_assert( ! __is_final (A), "A not final" ); + +struct Af final { }; +static_assert( __is_final (Af), "Af is final" ); + +class B { }; +static_assert( ! __is_final (B), "B not final" ); + +class Bf final { }; +static_assert( __is_final (Bf), "Bf is final" ); + +struct C : private A, private B { }; +static_assert( ! __is_final (C), "C not final" ); + +struct Cf final : private A, private B { }; +static_assert( __is_final (Cf), "Cf is final" ); + +struct D { virtual ~D() final { } }; +static_assert( ! __is_final (D), "D not final" ); + +struct Df final { virtual ~Df() final { } }; +static_assert( __is_final (Df), "Df is final" ); + +template struct E { }; +static_assert( ! __is_final (E), "E not final" ); +static_assert( ! __is_final (E), "E not final" ); + +template struct Ef final { }; +static_assert( __is_final (Ef), "Ef is final" ); +static_assert( __is_final (Ef), "Ef is final" ); +static_assert( __is_final (Ef), "Ef is final" ); + +template struct F { virtual ~F() final { }; }; +static_assert( ! __is_final (F), "F not final" ); +static_assert( ! __is_final (F), "F not final" ); + +template struct Ff final { virtual ~Ff() final { }; }; +static_assert( __is_final (Ff), "Ff is final" ); +static_assert( __is_final (Ff), "Ff is final" ); +static_assert( __is_final (Ff), "Ff is final" ); +