From patchwork Mon Oct 6 08:56:55 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paolo Carlini X-Patchwork-Id: 396754 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]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 67F001400E0 for ; Mon, 6 Oct 2014 19:57:11 +1100 (EST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :message-id:date:from:mime-version:to:cc:subject:content-type; q=dns; s=default; b=W2l2DZSWL4H+fvql7jsj0WUwAIIRTFtW8nM+Crdru7O R2Gjdb0hGElq674JTU0iPbclUy/rXv3mHyKbJsZbusUdcC83Yuub/a4xsFhy2Mmr +K/gaDR2DS9r3UzbaA44uye4IFJRzUVgQPcMjBjOvp1VnsOCDSnnoT4n6+UkhDQ0 = 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 :message-id:date:from:mime-version:to:cc:subject:content-type; s=default; bh=XclBiiYifH5GgKKnfp8W40NLQlc=; b=cjH5a46OsWF2ZTsCo efBUGnuK5VJEeKr+j/gjlXhte6StG5WRvuFHQZI9W+VpDLgfQGOUW8Y21tyH7yxM /kx3DHbXIf/oYngNkf//sH/eqL+HcnLkHPEMnQbjTrmCu555fbHdeEUU8z76yrbp xnTZyw/BjcOBd0fqIHnzty3jpo= Received: (qmail 32304 invoked by alias); 6 Oct 2014 08:57:05 -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 32292 invoked by uid 89); 6 Oct 2014 08:57:04 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-2.4 required=5.0 tests=AWL, BAYES_00, SPF_PASS, T_RP_MATCHES_RCVD, URIBL_RHS_DOB autolearn=no version=3.3.2 X-HELO: aserp1040.oracle.com Received: from aserp1040.oracle.com (HELO aserp1040.oracle.com) (141.146.126.69) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES256-SHA encrypted) ESMTPS; Mon, 06 Oct 2014 08:57:03 +0000 Received: from ucsinet21.oracle.com (ucsinet21.oracle.com [156.151.31.93]) by aserp1040.oracle.com (Sentrion-MTA-4.3.2/Sentrion-MTA-4.3.2) with ESMTP id s968v0d4007068 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Mon, 6 Oct 2014 08:57:00 GMT Received: from aserz7022.oracle.com (aserz7022.oracle.com [141.146.126.231]) by ucsinet21.oracle.com (8.14.4+Sun/8.14.4) with ESMTP id s968uxHk020870 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Mon, 6 Oct 2014 08:56:59 GMT Received: from abhmp0012.oracle.com (abhmp0012.oracle.com [141.146.116.18]) by aserz7022.oracle.com (8.14.4+Sun/8.14.4) with ESMTP id s968uwTu025862; Mon, 6 Oct 2014 08:56:58 GMT Received: from [192.168.1.4] (/87.6.20.22) by default (Oracle Beehive Gateway v4.0) with ESMTP ; Mon, 06 Oct 2014 01:56:58 -0700 Message-ID: <54325957.9030708@oracle.com> Date: Mon, 06 Oct 2014 10:56:55 +0200 From: Paolo Carlini User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:31.0) Gecko/20100101 Thunderbird/31.1.0 MIME-Version: 1.0 To: "gcc-patches@gcc.gnu.org" CC: Jason Merrill Subject: [C++ Patch] PR 55250 X-IsSubscribed: yes Hi, the second half of the bug report is about C++14 variable declarations in constexpr functions, an implementation request which should be already done by Jason's recent commit. The first half is about us not rejecting in C++11 mode type declarations in constexpr functions outside, per 7.1.5/3/4: "typedef declarations and alias-declarations that do not define classes or enumerations," In fact, however, while working on the issue, I noticed that conversely we reject *all* type declarations in constructors (actually we used to ICE on those, which a while ago I turned to reject valid), eg: struct S { constexpr S() { typedef int T; } }; Thus I prepared the below, which in C++11 mode checks the exact requirements above, both for constructors and all the other functions. I had to add handling of BIND_EXPRs to the main conditional of build_constexpr_constructor_member_initializers, otherwise we ICE immediately on something as simple as the snippet above: I think all is fine because we get to the conditional having checked the BIND_EXPR_VARS part with the new checking function. Tested x86_64-linux. Thanks! Paolo. ///////////////////// /cp 2014-10-06 Paolo Carlini PR c++/55250 * semantics.c (check_constexpr_bind_expr_vars): New. (check_constexpr_ctor_body, massage_constexpr_body): Use it. (build_constexpr_constructor_member_initializers): Handle BIND_EXPR in the main conditional. /testsuite 2014-10-06 Paolo Carlini PR c++/55250 * g++.dg/cpp0x/constexpr-type-decl1.C: New. * g++.dg/cpp0x/constexpr-type-def1.C: Likewise. * g++.dg/cpp1y/constexpr-type-def1.C: Likewise. Index: cp/semantics.c =================================================================== --- cp/semantics.c (revision 215914) +++ cp/semantics.c (working copy) @@ -7833,6 +7833,26 @@ build_data_member_initialization (tree t, vec= cxx14) + return true; + + for (tree var = BIND_EXPR_VARS (t); var; var = DECL_CHAIN (var)) + if (TREE_CODE (var) == TYPE_DECL + && ! is_typedef_decl (var) + && ! TYPE_DECL_ALIAS_P (var)) + return false; + return true; +} + /* Make sure that there are no statements after LAST in the constructor body represented by LIST. */ @@ -7850,7 +7870,7 @@ check_constexpr_ctor_body (tree last, tree list) break; if (TREE_CODE (t) == BIND_EXPR) { - if (BIND_EXPR_VARS (t)) + if (!check_constexpr_bind_expr_vars (t)) { ok = false; break; @@ -7860,8 +7880,6 @@ check_constexpr_ctor_body (tree last, tree list) else continue; } - /* We currently allow typedefs and static_assert. - FIXME allow them in the standard, too. */ if (TREE_CODE (t) != STATIC_ASSERT) { ok = false; @@ -7964,6 +7982,8 @@ build_constexpr_constructor_member_initializers (t "a function-try-block"); return error_mark_node; } + else if (TREE_CODE (body) == BIND_EXPR) + ok = build_data_member_initialization (BIND_EXPR_BODY (body), &vec); else if (EXPR_P (body)) ok = build_data_member_initialization (body, &vec); else @@ -8055,7 +8075,8 @@ massage_constexpr_body (tree fun, tree body) body = EH_SPEC_STMTS (body); if (TREE_CODE (body) == MUST_NOT_THROW_EXPR) body = TREE_OPERAND (body, 0); - if (TREE_CODE (body) == BIND_EXPR) + if (TREE_CODE (body) == BIND_EXPR + && check_constexpr_bind_expr_vars (body)) body = BIND_EXPR_BODY (body); body = constexpr_fn_retval (body); } Index: testsuite/g++.dg/cpp0x/constexpr-type-decl1.C =================================================================== --- testsuite/g++.dg/cpp0x/constexpr-type-decl1.C (revision 0) +++ testsuite/g++.dg/cpp0x/constexpr-type-decl1.C (working copy) @@ -0,0 +1,58 @@ +// PR c++/55250 +// { dg-do compile { target c++11 } } + +#define SA(X) static_assert((X),#X) + +struct GS { constexpr operator int() { return 1; } }; +enum GE { y = 1 }; + +constexpr int Test1(int x) { typedef int T; return T(x) + 1; } +constexpr int Test2(int x) { using T = int; return T(x) + 1; } +constexpr int Test3(int x) { typedef GS T; return x + T(); } +constexpr int Test4(int x) { using T = GS; return x + T(); } +constexpr int Test5(int x) { typedef GE T; return x + T::y; } +constexpr int Test6(int x) { using T = GE; return x + T::y; } + +SA(Test1(2) == 3); +SA(Test2(2) == 3); +SA(Test3(2) == 3); +SA(Test4(2) == 3); +SA(Test5(2) == 3); +SA(Test6(2) == 3); + +struct S1 +{ + constexpr S1() { typedef int T; SA(T(1) == 1); } +}; + +struct S2 +{ + constexpr S2() { using T = int; SA(T(1) == 1); } +}; + +struct S3 +{ + constexpr S3() { typedef GS T; SA(T() == 1); } +}; + +struct S4 +{ + constexpr S4() { using T = GS; SA(T() == 1); } +}; + +struct S5 +{ + constexpr S5() { typedef GE T; SA(T::y == 1); } +}; + +struct S6 +{ + constexpr S6() { using T = GE; SA(T::y == 1); } +}; + +S1 s1; +S2 s2; +S3 s3; +S4 s4; +S5 s5; +S6 s6; Index: testsuite/g++.dg/cpp0x/constexpr-type-def1.C =================================================================== --- testsuite/g++.dg/cpp0x/constexpr-type-def1.C (revision 0) +++ testsuite/g++.dg/cpp0x/constexpr-type-def1.C (working copy) @@ -0,0 +1,44 @@ +// PR c++/55250 +// { dg-do compile { target c++11 } } + +constexpr int Test1(int x) { enum E { y = 1 }; return x; } // { dg-error "not a return-statement" "" { target { c++11_only } } } + +constexpr int Test2(int x) { struct T { }; return x; } // { dg-error "not a return-statement" "" { target { c++11_only } } } + +constexpr int Test3(int x) { typedef enum E { y = 1 } EE; return x; } // { dg-error "not a return-statement" "" { target { c++11_only } } } + +constexpr int Test4(int x) { typedef struct T { } TT; return x; } // { dg-error "not a return-statement" "" { target { c++11_only } } } + +constexpr int Test5(int x) { using EE = enum E { y = 1 }; return x; } // { dg-error "not a return-statement" "" { target { c++11_only } } } + +constexpr int Test6(int x) { using TT = struct T { }; return x; } // { dg-error "not a return-statement" "" { target { c++11_only } } } + +struct S1 +{ + constexpr S1() { enum E { y = 1 }; } // { dg-error "does not have empty body" "" { target { c++11_only } } } +}; + +struct S2 +{ + constexpr S2() { struct T { }; } // { dg-error "does not have empty body" "" { target { c++11_only } } } +}; + +struct S3 +{ + constexpr S3() { typedef enum E { y = 1 } EE; } // { dg-error "does not have empty body" "" { target { c++11_only } } } +}; + +struct S4 +{ + constexpr S4() { typedef struct T { } TT; } // { dg-error "does not have empty body" "" { target { c++11_only } } } +}; + +struct S5 +{ + constexpr S5() { using EE = enum E { y = 1 }; } // { dg-error "does not have empty body" "" { target { c++11_only } } } +}; + +struct S6 +{ + constexpr S6() { using TT = struct T { }; } // { dg-error "does not have empty body" "" { target { c++11_only } } } +}; Index: testsuite/g++.dg/cpp1y/constexpr-type-def1.C =================================================================== --- testsuite/g++.dg/cpp1y/constexpr-type-def1.C (revision 0) +++ testsuite/g++.dg/cpp1y/constexpr-type-def1.C (working copy) @@ -0,0 +1,60 @@ +// PR c++/55250 +// { dg-do compile { target c++14 } } + +#define SA(X) static_assert((X),#X) + +constexpr int Test1(int x) { enum E { y = 1 }; return x + y; } + +constexpr int Test2(int x) { struct T { constexpr operator int() { return 1; } }; return x + T(); } + +constexpr int Test3(int x) { typedef enum E { y = 1 } EE; return x + EE::y; } + +constexpr int Test4(int x) { typedef struct T { constexpr operator int() { return 1; } } TT; return x + TT(); } + +constexpr int Test5(int x) { using EE = enum E { y = 1 }; return x + EE::y; } + +constexpr int Test6(int x) { using TT = struct T { constexpr operator int() { return 1; } }; return x + TT(); } + +SA(Test1(2) == 3); +SA(Test2(2) == 3); +SA(Test3(2) == 3); +SA(Test4(2) == 3); +SA(Test5(2) == 3); +SA(Test6(2) == 3); + +struct S1 +{ + constexpr S1() { enum E { y = 1 }; SA(y == 1); } +}; + +struct S2 +{ + constexpr S2() { struct T { constexpr operator int() { return 1; } }; SA(T() == 1); } +}; + +struct S3 +{ + constexpr S3() { typedef enum E { y = 1} EE; SA(EE::y == 1); } +}; + +struct S4 +{ + constexpr S4() { typedef struct T { constexpr operator int() { return 1; } } TT; SA(TT() == 1); } +}; + +struct S5 +{ + constexpr S5() { using EE = enum E { y = 1}; SA(EE::y == 1); } +}; + +struct S6 +{ + constexpr S6() { using TT = struct T { constexpr operator int() { return 1; } }; SA(TT() == 1); } +}; + +S1 s1; +S2 s2; +S3 s3; +S4 s4; +S5 s5; +S6 s6;