From: Paolo Carlini Date: Thu, 9 Oct 2014 19:22:53 +0000 (+0000) Subject: semantics.c (check_constexpr_ctor_body_1): New. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=3369b9193606b86677e65bc96699939fb6a8d13e;p=gcc.git semantics.c (check_constexpr_ctor_body_1): New. /cp 2014-10-09 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-09 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. From-SVN: r216049 --- diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index cf04f0dd704..84996a45cba 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,19 @@ +2014-10-09 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. + 2014-10-09 Jason Merrill PR c++/63309 diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index cdc892762f7..3787c4a3f25 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -5823,7 +5823,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); diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index a9edcd53df4..c6218af21e9 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -9891,7 +9891,7 @@ cp_parser_compound_statement (cp_parser *parser, tree in_statement_expr, 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 (cp_parser *parser, /* 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); diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index ba09e720573..3ca91d88bfe 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -7781,8 +7781,12 @@ build_data_member_initialization (tree t, vec **vec) wrong type, but cxx_eval_constant_expression doesn't care. */ init = break_out_target_exprs (t); } - else if (TREE_CODE (t) == DECL_EXPR) - /* Declaring a temporary, don't add it to the CONSTRUCTOR. */ + else if (TREE_CODE (t) == BIND_EXPR) + return build_data_member_initialization (BIND_EXPR_BODY (t), vec); + else if (TREE_CODE (t) == DECL_EXPR + || TREE_CODE (t) == USING_STMT) + /* Declaring a temporary, don't add it to the CONSTRUCTOR. + Likewise for using directives. */ return true; else gcc_unreachable (); @@ -7835,7 +7839,7 @@ build_data_member_initialization (tree t, vec **vec) return true; } -/* Subroutine of check_constexpr_ctor_body and massage_constexpr_body. +/* Subroutine of check_constexpr_ctor_body_1 and constexpr_fn_retval. In C++11 mode checks that the TYPE_DECLs in the BIND_EXPR_VARS of a BIND_EXPR conform to 7.1.5/3/4 on typedef and alias declarations. */ @@ -7854,11 +7858,45 @@ check_constexpr_bind_expr_vars (tree t) return true; } +/* Subroutine of check_constexpr_ctor_body. */ + +static bool +check_constexpr_ctor_body_1 (tree last, tree list) +{ + switch (TREE_CODE (list)) + { + case DECL_EXPR: + if (TREE_CODE (DECL_EXPR_DECL (list)) == USING_DECL) + return true; + if (cxx_dialect >= 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) @@ -7869,19 +7907,7 @@ check_constexpr_ctor_body (tree last, tree list) tree t = tsi_stmt (i); if (t == last) break; - if (TREE_CODE (t) == BIND_EXPR) - { - 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) + if (!check_constexpr_ctor_body_1 (last, t)) { ok = false; break; @@ -7889,11 +7915,12 @@ check_constexpr_ctor_body (tree last, tree list) } } 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; @@ -7983,8 +8010,6 @@ build_constexpr_constructor_member_initializers (tree type, tree body) "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 @@ -8052,6 +8077,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; @@ -8076,9 +8106,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; diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index d6b22f22f72..0fb4c9edef5 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,11 @@ +2014-10-09 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. + 2014-10-09 Joseph Myers * gcc.dg/torture/float128-extendxf-underflow.c: New test. diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-compound.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-compound.C index bfe4e13d4a7..c23e1483b4b 100644 --- a/gcc/testsuite/g++.dg/cpp0x/constexpr-compound.C +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-compound.C @@ -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 } } } } diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-using3.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-using3.C new file mode 100644 index 00000000000..88a14fda10e --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-using3.C @@ -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 } } } +}; diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-local-compound1.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-local-compound1.C new file mode 100644 index 00000000000..b72d13569a4 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-local-compound1.C @@ -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); diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-local1.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-local1.C index 39c3ee84de5..8412f63ded6 100644 --- a/gcc/testsuite/g++.dg/cpp1y/constexpr-local1.C +++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-local1.C @@ -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); diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-type-def-compound1.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-type-def-compound1.C new file mode 100644 index 00000000000..aace6102556 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-type-def-compound1.C @@ -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;