From fbf833b776811b8ac22c79ee52ff46d578da755b Mon Sep 17 00:00:00 2001 From: Paolo Carlini Date: Mon, 6 Oct 2014 16:13:41 +0000 Subject: [PATCH] re PR c++/55250 ([C++0x] enum declarations within constexpr function are allowed, constexpr declarations are not) /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. From-SVN: r215954 --- gcc/cp/ChangeLog | 8 +++ gcc/cp/semantics.c | 28 +++++++-- gcc/testsuite/ChangeLog | 7 +++ .../g++.dg/cpp0x/constexpr-type-decl1.C | 58 ++++++++++++++++++ .../g++.dg/cpp0x/constexpr-type-def1.C | 44 ++++++++++++++ .../g++.dg/cpp1y/constexpr-type-def1.C | 60 +++++++++++++++++++ 6 files changed, 201 insertions(+), 4 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/constexpr-type-decl1.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/constexpr-type-def1.C create mode 100644 gcc/testsuite/g++.dg/cpp1y/constexpr-type-def1.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 5cb8203a636..6405be09475 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,11 @@ +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. + 2014-10-02 Mark Wielaard PR debug/63239 diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 5d1aafc1f2c..b11ec0905cb 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -7833,6 +7833,25 @@ build_data_member_initialization (tree t, vec **vec) return true; } +/* Subroutine of check_constexpr_ctor_body and massage_constexpr_body. + 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. */ + +static bool +check_constexpr_bind_expr_vars (tree t) +{ + gcc_assert (TREE_CODE (t) == BIND_EXPR); + + if (cxx_dialect >= cxx14) + return true; + + for (tree var = BIND_EXPR_VARS (t); var; var = DECL_CHAIN (var)) + if (TREE_CODE (var) == TYPE_DECL + && DECL_IMPLICIT_TYPEDEF_P (var)) + return false; + return true; +} + /* Make sure that there are no statements after LAST in the constructor body represented by LIST. */ @@ -7850,7 +7869,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 +7879,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 +7981,8 @@ 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 @@ -8055,7 +8074,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); } diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 154a7702d3c..582f1890220 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,10 @@ +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. + 2014-10-06 Marek Polacek * c-c++-common/raw-string-3.c: Use -std=gnu89 for C. diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-type-decl1.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-type-decl1.C new file mode 100644 index 00000000000..0ef715e8830 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-type-decl1.C @@ -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; diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-type-def1.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-type-def1.C new file mode 100644 index 00000000000..1a72950b8b1 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-type-def1.C @@ -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 } } } +}; diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-type-def1.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-type-def1.C new file mode 100644 index 00000000000..648e09c9934 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-type-def1.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; -- 2.30.2