From patchwork Wed Oct 8 19:47:38 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paolo Carlini X-Patchwork-Id: 397711 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 230BA1400AA for ; Thu, 9 Oct 2014 06:47:58 +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=u8yME01iStg+15qMwk9Ridmt0v3ufLH66TlRnbYqrPh NBbcRtBR1r9csFYry/uQrJaHbNIcm6CHnNZWk4KfM7iLX+s1Arg7APVqRZlkCwle MydoJxPDxsLbEjFKd7YMtsGq0fOPWW+SJ1+4eJYs7p2KyAllPa1qk6c48LzZS0IE = 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=+G2Tsb+xhv+fKsvYs0HvgSwt+yM=; b=to+tWLu1UgsYrU2uZ r/qGb7jACHPyPpzG57kxtNC8yVclw3Q9/wwIb7NEJKJelCzf/n2gtU4N6JAA/8NE QLreEBn6wgUsEtQRielAOqgkpeVdDmmI5FLAacm08ejeMEOKwAMD2oZc2Sbmrcl6 h79hG2gC9Hqq67fx0PC3L8BGxg= Received: (qmail 8080 invoked by alias); 8 Oct 2014 19:47:50 -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 8000 invoked by uid 89); 8 Oct 2014 19:47:50 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-3.2 required=5.0 tests=AWL, BAYES_00, SPF_PASS, T_RP_MATCHES_RCVD autolearn=ham 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; Wed, 08 Oct 2014 19:47:47 +0000 Received: from acsinet21.oracle.com (acsinet21.oracle.com [141.146.126.237]) by aserp1040.oracle.com (Sentrion-MTA-4.3.2/Sentrion-MTA-4.3.2) with ESMTP id s98Jli5P003158 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Wed, 8 Oct 2014 19:47:45 GMT Received: from userz7021.oracle.com (userz7021.oracle.com [156.151.31.85]) by acsinet21.oracle.com (8.14.4+Sun/8.14.4) with ESMTP id s98Jlh67013045 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=FAIL); Wed, 8 Oct 2014 19:47:44 GMT Received: from abhmp0013.oracle.com (abhmp0013.oracle.com [141.146.116.19]) by userz7021.oracle.com (8.14.4+Sun/8.14.4) with ESMTP id s98Jlh2V011103; Wed, 8 Oct 2014 19:47:43 GMT Received: from [192.168.1.4] (/87.10.208.239) by default (Oracle Beehive Gateway v4.0) with ESMTP ; Wed, 08 Oct 2014 12:47:42 -0700 Message-ID: <543594DA.1000304@oracle.com> Date: Wed, 08 Oct 2014 21:47:38 +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] More C++11 and C++14 constexpr work X-IsSubscribed: yes Hi, the below tries to make progress on some relatively easy issues I noticed while working on c++/55250. At least: 1- We rejected using declarations and using directives in constructors. 2- In C++14 mode we rejected compound-statements both in constructors and elsewhere (and in C++11 we provided both the pedwarn and then an hard error) 3- In C++14 mode we rejected local variables in constructors. The patch itself uses quite straightforward strategies: check_constexpr_ctor_body is extended via the new check_constexpr_ctor_body_1; recursion on BIND_EXPRs takes care of compound-statements; the parser is tweaked to suppress the "compound-statement in constexpr function" pedwarn in C++14 mode. Tested x86_64-linux. Thanks, Paolo. ////////////////////// /cp 2014-10-08 Paolo Carlini * semantics.c (check_constexpr_ctor_body_1): New. (check_constexpr_ctor_body): Use it; add bool parameter. (build_data_member_initialization): Handle BIND_EXPR and USING_STMT in the main conditional. (build_constexpr_constructor_member_initializers): Do not handle BIND_EXPR here. (constexpr_fn_retval): Handle BIND_EXPR in the switch. (massage_constexpr_body): Don't do it here. * parser.c (cp_parser_ctor_initializer_opt_and_function_body): Adjust check_constexpr_ctor_body call. (cp_parser_compound_statement): Do not pedwarn for compound-statement in constexpr function in C++14 mode. * cp-tree.h (check_constexpr_ctor_body): Update declaration. /testsuite 2014-10-08 Paolo Carlini * g++.dg/cpp0x/constexpr-using3.C: New. * g++.dg/cpp1y/constexpr-local-compound1.C: Likewise. * g++.dg/cpp1y/constexpr-type-def-compound1.C: Likewise. * g++.dg/cpp1y/constexpr-local1.C: Extend. * g++.dg/cpp0x/constexpr-compound.C: Specify expected error. Index: cp/cp-tree.h =================================================================== --- cp/cp-tree.h (revision 216010) +++ cp/cp-tree.h (working copy) @@ -5822,7 +5822,7 @@ extern void finish_handler (tree); extern void finish_cleanup (tree, tree); extern bool literal_type_p (tree); extern tree register_constexpr_fundef (tree, tree); -extern bool check_constexpr_ctor_body (tree, tree); +extern bool check_constexpr_ctor_body (tree, tree, bool); extern tree ensure_literal_type_for_constexpr_object (tree); extern bool potential_constant_expression (tree); extern bool potential_rvalue_constant_expression (tree); Index: cp/parser.c =================================================================== --- cp/parser.c (revision 216010) +++ cp/parser.c (working copy) @@ -9891,7 +9891,7 @@ cp_parser_compound_statement (cp_parser *parser, t if (!cp_parser_require (parser, CPP_OPEN_BRACE, RT_OPEN_BRACE)) return error_mark_node; if (DECL_DECLARED_CONSTEXPR_P (current_function_decl) - && !function_body) + && !function_body && cxx_dialect < cxx14) pedwarn (input_location, OPT_Wpedantic, "compound-statement in constexpr function"); /* Begin the compound-statement. */ @@ -19015,7 +19015,7 @@ cp_parser_ctor_initializer_opt_and_function_body ( /* Parse the function-body. */ cp_parser_function_body (parser, in_function_try_block); if (check_body_p) - check_constexpr_ctor_body (last, list); + check_constexpr_ctor_body (last, list, /*complain=*/true); /* Finish the function body. */ finish_function_body (body); Index: cp/semantics.c =================================================================== --- cp/semantics.c (revision 216010) +++ cp/semantics.c (working copy) @@ -7779,8 +7779,12 @@ build_data_member_initialization (tree t, vec= cxx14) + return true; + return false; + + case CLEANUP_POINT_EXPR: + return check_constexpr_ctor_body (last, TREE_OPERAND (list, 0), + /*complain=*/false); + + case BIND_EXPR: + if (!check_constexpr_bind_expr_vars (list) + || !check_constexpr_ctor_body (last, BIND_EXPR_BODY (list), + /*complain=*/false)) + return false; + return true; + + case USING_STMT: + case STATIC_ASSERT: + return true; + + default: + return false; + } +} + /* Make sure that there are no statements after LAST in the constructor body represented by LIST. */ bool -check_constexpr_ctor_body (tree last, tree list) +check_constexpr_ctor_body (tree last, tree list, bool complain) { bool ok = true; if (TREE_CODE (list) == STATEMENT_LIST) @@ -7867,20 +7905,8 @@ bool tree t = tsi_stmt (i); if (t == last) break; - if (TREE_CODE (t) == BIND_EXPR) + if (!check_constexpr_ctor_body_1 (last, t)) { - if (!check_constexpr_bind_expr_vars (t)) - { - ok = false; - break; - } - if (!check_constexpr_ctor_body (last, BIND_EXPR_BODY (t))) - return false; - else - continue; - } - if (TREE_CODE (t) != STATIC_ASSERT) - { ok = false; break; } @@ -7887,11 +7913,12 @@ bool } } else if (list != last - && TREE_CODE (list) != STATIC_ASSERT) + && !check_constexpr_ctor_body_1 (last, list)) ok = false; if (!ok) { - error ("constexpr constructor does not have empty body"); + if (complain) + error ("constexpr constructor does not have empty body"); DECL_DECLARED_CONSTEXPR_P (current_function_decl) = false; } return ok; @@ -7981,8 +8008,6 @@ 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 @@ -8050,6 +8075,11 @@ constexpr_fn_retval (tree body) case CLEANUP_POINT_EXPR: return constexpr_fn_retval (TREE_OPERAND (body, 0)); + case BIND_EXPR: + if (!check_constexpr_bind_expr_vars (body)) + return error_mark_node; + return constexpr_fn_retval (BIND_EXPR_BODY (body)); + case USING_STMT: return NULL_TREE; @@ -8074,9 +8104,6 @@ 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 - && check_constexpr_bind_expr_vars (body)) - body = BIND_EXPR_BODY (body); body = constexpr_fn_retval (body); } return body; Index: testsuite/g++.dg/cpp0x/constexpr-compound.C =================================================================== --- testsuite/g++.dg/cpp0x/constexpr-compound.C (revision 216010) +++ testsuite/g++.dg/cpp0x/constexpr-compound.C (working copy) @@ -2,8 +2,8 @@ constexpr int f() { - { // { dg-error "" } + { // { dg-error "compound-statement" "" { target { c++11_only } } } return 1; } - { } // { dg-error "" } + { } // { dg-error "compound-statement" "" { target { c++11_only } } } } Index: testsuite/g++.dg/cpp0x/constexpr-using3.C =================================================================== --- testsuite/g++.dg/cpp0x/constexpr-using3.C (revision 0) +++ testsuite/g++.dg/cpp0x/constexpr-using3.C (working copy) @@ -0,0 +1,29 @@ +// { dg-do compile { target c++11 } } +// { dg-options "-pedantic" } + +namespace ns { typedef int T; } + +constexpr int Test1(int x) { using ns::T; typedef T U; return U(x); } +constexpr int Test2(int x) { using namespace ns; typedef T U; return U(x); } +constexpr int Test3(int x) { { using ns::T; typedef T U; return U(x); } } // { dg-warning "compound-statement" "" { target { c++11_only } } } +constexpr int Test4(int x) { { using namespace ns; typedef T U; return T(x); } } // { dg-warning "compound-statement" "" { target { c++11_only } } } + +struct S1 +{ + constexpr S1() { using ns::T; typedef T U; } +}; + +struct S2 +{ + constexpr S2() { using namespace ns; typedef T U; } +}; + +struct S3 +{ + constexpr S3() { { using ns::T; typedef T U; } } // { dg-warning "compound-statement" "" { target { c++11_only } } } +}; + +struct S4 +{ + constexpr S4() { { using namespace ns; typedef T U; } } // { dg-warning "compound-statement" "" { target { c++11_only } } } +}; Index: testsuite/g++.dg/cpp1y/constexpr-local-compound1.C =================================================================== --- testsuite/g++.dg/cpp1y/constexpr-local-compound1.C (revision 0) +++ testsuite/g++.dg/cpp1y/constexpr-local-compound1.C (working copy) @@ -0,0 +1,14 @@ +// { dg-do compile { target c++14 } } + +#define SA(X) static_assert((X),#X) + +constexpr int f(int i) { { int j = i+1; return j; } } + +constexpr int i = f(41); + +struct S +{ + constexpr S() { { constexpr int j = 17; SA(j == 17); } } +}; + +SA(i==42); Index: testsuite/g++.dg/cpp1y/constexpr-local1.C =================================================================== --- testsuite/g++.dg/cpp1y/constexpr-local1.C (revision 216010) +++ testsuite/g++.dg/cpp1y/constexpr-local1.C (working copy) @@ -1,9 +1,14 @@ // { dg-do compile { target c++14 } } +#define SA(X) static_assert((X),#X) + constexpr int f(int i) { int j = i+1; return j; } constexpr int i = f(41); -#define SA(X) static_assert((X),#X) +struct S +{ + constexpr S() { constexpr int j = 17; SA(j == 17); } +}; SA(i==42); Index: testsuite/g++.dg/cpp1y/constexpr-type-def-compound1.C =================================================================== --- testsuite/g++.dg/cpp1y/constexpr-type-def-compound1.C (revision 0) +++ testsuite/g++.dg/cpp1y/constexpr-type-def-compound1.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;