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 <ja...@redhat.com>
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.
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 <class T>
+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<int>();
+
+static_assert (i == 84, "i == 84");
+static_assert (i2 == 84, "i2 == 84");
+
commit 93ed9ae1cfa1856f713f67c9de812ad7e49e2b66
Author: Jason Merrill <ja...@redhat.com>
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 "" }
+}