From patchwork Mon Mar 28 16:11:05 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jason Merrill X-Patchwork-Id: 88626 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 2D784B6FB5 for ; Tue, 29 Mar 2011 03:11:34 +1100 (EST) Received: (qmail 17623 invoked by alias); 28 Mar 2011 16:11:30 -0000 Received: (qmail 17601 invoked by uid 22791); 28 Mar 2011 16:11:24 -0000 X-SWARE-Spam-Status: No, hits=-6.2 required=5.0 tests=AWL, BAYES_00, RCVD_IN_DNSWL_HI, SPF_HELO_PASS, TW_TM, T_RP_MATCHES_RCVD X-Spam-Check-By: sourceware.org Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Mon, 28 Mar 2011 16:11:14 +0000 Received: from int-mx09.intmail.prod.int.phx2.redhat.com (int-mx09.intmail.prod.int.phx2.redhat.com [10.5.11.22]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id p2SGBElt029192 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Mon, 28 Mar 2011 12:11:14 -0400 Received: from [127.0.0.1] ([10.3.113.2]) by int-mx09.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id p2SGBAW1015554 for ; Mon, 28 Mar 2011 12:11:11 -0400 Message-ID: <4D90B319.6000000@redhat.com> Date: Mon, 28 Mar 2011 12:11:05 -0400 From: Jason Merrill User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.15) Gecko/20110307 Fedora/3.1.9-0.39.b3pre.fc14 Lightning/1.0b2 Thunderbird/3.1.9 MIME-Version: 1.0 To: gcc-patches List Subject: C++ PATCHes to restrictions on constexpr functions 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 The resolution of core issue 898 ratifies our current behavior of allowing typedefs and static_assert in constexpr functions. It also allows using decls/directives. We discussed allowing unnecessary braces, but decided not to. So these patches 1) allow using and 2) prohibit extra compound-statements. Tested x86_64-pc-linux-gnu, applying to trunk and 4.6. commit 8e9828f2e972534d81a6c409ff68c77faeb99ed6 Author: Jason Merrill Date: Tue Mar 22 18:25:56 2011 +0100 Core 898 * semantics.c (constexpr_fn_retval): New. Allow using-declaration and using-definition. (register_constexpr_fundef): Call it. commit 93ed9ae1cfa1856f713f67c9de812ad7e49e2b66 Author: Jason Merrill Date: Fri Mar 25 17:40:20 2011 +0100 Core 898 * parser.c (cp_parser_compound_statement): Add function_body parm. Complain about non-body compound-stmt in constexpr fn. (cp_parser_primary_expression, cp_parser_statement): Adjust. (cp_parser_implicitly_scoped_statement): Adjust. (cp_parser_function_body, cp_parser_try_block): Adjust. (cp_parser_handler, cp_parser_objc_synchronized_statement): Adjust. (cp_parser_objc_try_catch_finally_statement): Adjust. diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index c7347cf..3a60d0f 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -1590,7 +1590,7 @@ static void cp_parser_label_for_labeled_statement static tree cp_parser_expression_statement (cp_parser *, tree); static tree cp_parser_compound_statement - (cp_parser *, tree, bool); + (cp_parser *, tree, bool, bool); static void cp_parser_statement_seq_opt (cp_parser *, tree); static tree cp_parser_selection_statement @@ -3417,7 +3417,7 @@ cp_parser_primary_expression (cp_parser *parser, /* Start the statement-expression. */ expr = begin_stmt_expr (); /* Parse the compound-statement. */ - cp_parser_compound_statement (parser, expr, false); + cp_parser_compound_statement (parser, expr, false, false); /* Finish up. */ expr = finish_stmt_expr (expr, false); } @@ -7873,7 +7873,7 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr, } /* Anything that starts with a `{' must be a compound-statement. */ else if (token->type == CPP_OPEN_BRACE) - statement = cp_parser_compound_statement (parser, NULL, false); + statement = cp_parser_compound_statement (parser, NULL, false, false); /* CPP_PRAGMA is a #pragma inside a function body, which constitutes a statement all its own. */ else if (token->type == CPP_PRAGMA) @@ -8105,13 +8105,17 @@ cp_parser_expression_statement (cp_parser* parser, tree in_statement_expr) static tree cp_parser_compound_statement (cp_parser *parser, tree in_statement_expr, - bool in_try) + bool in_try, bool function_body) { tree compound_stmt; /* Consume the `{'. */ 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) + pedwarn (input_location, OPT_pedantic, + "compound-statement in constexpr function"); /* Begin the compound-statement. */ compound_stmt = begin_compound_stmt (in_try ? BCS_TRY_BLOCK : 0); /* If the next keyword is `__label__' we have a label declaration. */ @@ -9022,7 +9026,7 @@ cp_parser_implicitly_scoped_statement (cp_parser* parser, bool *if_p) } /* if a compound is opened, we simply parse the statement directly. */ else if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE)) - statement = cp_parser_compound_statement (parser, NULL, false); + statement = cp_parser_compound_statement (parser, NULL, false, false); /* If the token is not a `{', then we must take special action. */ else { @@ -16157,7 +16161,7 @@ cp_parser_default_argument (cp_parser *parser, bool template_parm_p) static void cp_parser_function_body (cp_parser *parser) { - cp_parser_compound_statement (parser, NULL, false); + cp_parser_compound_statement (parser, NULL, false, true); } /* Parse a ctor-initializer-opt followed by a function-body. Return @@ -18255,7 +18259,7 @@ cp_parser_try_block (cp_parser* parser) cp_parser_require_keyword (parser, RID_TRY, RT_TRY); try_block = begin_try_block (); - cp_parser_compound_statement (parser, NULL, true); + cp_parser_compound_statement (parser, NULL, true, false); finish_try_block (try_block); cp_parser_handler_seq (parser); finish_handler_sequence (try_block); @@ -18332,7 +18336,7 @@ cp_parser_handler (cp_parser* parser) declaration = cp_parser_exception_declaration (parser); finish_handler_parms (declaration, handler); cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN); - cp_parser_compound_statement (parser, NULL, false); + cp_parser_compound_statement (parser, NULL, false, false); finish_handler (handler); } @@ -22533,7 +22537,7 @@ cp_parser_objc_try_catch_finally_statement (cp_parser *parser) /* NB: The @try block needs to be wrapped in its own STATEMENT_LIST node, lest it get absorbed into the surrounding block. */ stmt = push_stmt_list (); - cp_parser_compound_statement (parser, NULL, false); + cp_parser_compound_statement (parser, NULL, false, false); objc_begin_try_stmt (location, pop_stmt_list (stmt)); while (cp_lexer_next_token_is_keyword (parser->lexer, RID_AT_CATCH)) @@ -22589,7 +22593,7 @@ cp_parser_objc_try_catch_finally_statement (cp_parser *parser) forget about the closing parenthesis and keep going. */ } objc_begin_catch_clause (parameter_declaration); - cp_parser_compound_statement (parser, NULL, false); + cp_parser_compound_statement (parser, NULL, false, false); objc_finish_catch_clause (); } if (cp_lexer_next_token_is_keyword (parser->lexer, RID_AT_FINALLY)) @@ -22599,7 +22603,7 @@ cp_parser_objc_try_catch_finally_statement (cp_parser *parser) /* NB: The @finally block needs to be wrapped in its own STATEMENT_LIST node, lest it get absorbed into the surrounding block. */ stmt = push_stmt_list (); - cp_parser_compound_statement (parser, NULL, false); + cp_parser_compound_statement (parser, NULL, false, false); objc_build_finally_clause (location, pop_stmt_list (stmt)); } @@ -22630,7 +22634,7 @@ cp_parser_objc_synchronized_statement (cp_parser *parser) /* NB: The @synchronized block needs to be wrapped in its own STATEMENT_LIST node, lest it get absorbed into the surrounding block. */ stmt = push_stmt_list (); - cp_parser_compound_statement (parser, NULL, false); + cp_parser_compound_statement (parser, NULL, false, false); return objc_build_synchronized (location, lock, pop_stmt_list (stmt)); } diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-compound.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-compound.C new file mode 100644 index 0000000..81fcc54 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-compound.C @@ -0,0 +1,9 @@ +// { dg-options "-std=c++0x -pedantic-errors" } + +constexpr int f() +{ + { // { dg-error "" } + return 1; + } + { } // { dg-error "" } +} diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 41ab858..6906c1b 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -5585,6 +5585,52 @@ build_constexpr_constructor_member_initializers (tree type, tree body) return error_mark_node; } +/* Subroutine of register_constexpr_fundef. BODY is the body of a function + declared to be constexpr, or a sub-statement thereof. Returns the + return value if suitable, error_mark_node for a statement not allowed in + a constexpr function, or NULL_TREE if no return value was found. */ + +static tree +constexpr_fn_retval (tree body) +{ + switch (TREE_CODE (body)) + { + case STATEMENT_LIST: + { + tree_stmt_iterator i; + tree expr = NULL_TREE; + for (i = tsi_start (body); !tsi_end_p (i); tsi_next (&i)) + { + tree s = constexpr_fn_retval (tsi_stmt (i)); + if (s == error_mark_node) + return error_mark_node; + else if (s == NULL_TREE) + /* Keep iterating. */; + else if (expr) + /* Multiple return statements. */ + return error_mark_node; + else + expr = s; + } + return expr; + } + + case RETURN_EXPR: + return unshare_expr (TREE_OPERAND (body, 0)); + + case DECL_EXPR: + if (TREE_CODE (DECL_EXPR_DECL (body)) == USING_DECL) + return NULL_TREE; + return error_mark_node; + + case USING_STMT: + return NULL_TREE; + + default: + return error_mark_node; + } +} + /* We are processing the definition of the constexpr function FUN. Check that its BODY fulfills the propriate requirements and enter it in the constexpr function definition table. @@ -5610,13 +5656,13 @@ register_constexpr_fundef (tree fun, tree body) body = TREE_OPERAND (body, 0); if (TREE_CODE (body) == CLEANUP_POINT_EXPR) body = TREE_OPERAND (body, 0); - if (TREE_CODE (body) != RETURN_EXPR) + body = constexpr_fn_retval (body); + if (body == NULL_TREE || body == error_mark_node) { error ("body of constexpr function %qD not a return-statement", fun); DECL_DECLARED_CONSTEXPR_P (fun) = false; return NULL; } - body = unshare_expr (TREE_OPERAND (body, 0)); } if (!potential_rvalue_constant_expression (body)) diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-using.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-using.C new file mode 100644 index 0000000..fc794e9 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-using.C @@ -0,0 +1,27 @@ +// Core issue 898 +// { dg-options -std=c++0x } + +namespace N { const int i = 42; } +namespace M { const int j = 42; } + +constexpr int g() { + using namespace N; + using M::j; + static_assert (i == 42, "i == 42"); + return i + j; +} + +template +constexpr int h() { + using namespace N; + using M::j; + static_assert (i == 42, "i == 42"); + return i + j; +} + +constexpr int i = g(); +constexpr int i2 = h(); + +static_assert (i == 84, "i == 84"); +static_assert (i2 == 84, "i2 == 84"); +