From: Marek Polacek Date: Thu, 5 Dec 2019 20:13:03 +0000 (+0000) Subject: PR c++/91353 - P1331R2: Allow trivial default init in constexpr contexts. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=7906797ebec6881d7d90165340f51efcf447d716;p=gcc.git PR c++/91353 - P1331R2: Allow trivial default init in constexpr contexts. This patch implements C++20 P1331, allowing trivial default initialization in constexpr contexts. * c-cppbuiltin.c (c_cpp_builtins): Adjust the value of __cpp_constexpr. * class.c (trivial_default_constructor_is_constexpr): Return true in C++20. * constexpr.c (cx_check_missing_mem_inits): Allow missing field initializers in C++20. (cxx_eval_call_expression): Don't clear CONSTRUCTOR_NO_CLEARING for constexpr constructors in C++20. (reduced_constant_expression_p): Don't set FIELD for union and array types. Skip empty class fields without initializers. * decl.c (check_for_uninitialized_const_var): Permit trivial default initialization in constexpr. (next_initializable_field): Don't skip vptr fields. * method.c (walk_field_subobs): Still consider a constructor that doesn't initialize all the members constexpr. * g++.dg/cpp0x/constexpr-array6.C: Adjust dg-error. * g++.dg/cpp0x/constexpr-ctor.C: Likewise. * g++.dg/cpp0x/constexpr-diag3.C: Likewise. * g++.dg/cpp0x/constexpr-diag4.C: Likewise. * g++.dg/cpp0x/constexpr-ex3.C: Likewise. * g++.dg/cpp0x/constexpr-template2.C: Likewise. * g++.dg/cpp0x/constexpr-union2.C: Likewise. * g++.dg/cpp0x/lambda/lambda-mangle.C: Rip out a piece of code ... * g++.dg/cpp0x/lambda/lambda-mangle6.C: ... and put it here. * g++.dg/cpp0x/pr79118.C: Adjust dg-error. * g++.dg/cpp1y/constexpr-83921-3.C: Likewise. * g++.dg/cpp1y/constexpr-neg1.C: Likewise. * g++.dg/cpp1z/constexpr-lambda12.C: Likewise. * g++.dg/cpp1z/feat-cxx1z.C: Use -std=c++17. * g++.dg/cpp2a/constexpr-init1.C: New test. * g++.dg/cpp2a/constexpr-init2.C: New test. * g++.dg/cpp2a/constexpr-init3.C: New test. * g++.dg/cpp2a/constexpr-init4.C: New test. * g++.dg/cpp2a/constexpr-init5.C: New test. * g++.dg/cpp2a/constexpr-init6.C: New test. * g++.dg/cpp2a/constexpr-init7.C: New test. * g++.dg/cpp2a/constexpr-init8.C: New test. * g++.dg/cpp2a/constexpr-init9.C: New test. * g++.dg/cpp2a/constexpr-init10.C: New test. * g++.dg/cpp2a/constexpr-init11.C: New test. * g++.dg/cpp2a/constexpr-init12.C: New test. * g++.dg/cpp2a/constexpr-init13.C: New test. * g++.dg/cpp2a/constexpr-init14.C: New test. * g++.dg/cpp2a/constexpr-init15.C: New test. * g++.dg/cpp2a/constexpr-try5.C: Adjust dg-error. * g++.dg/cpp2a/feat-cxx2a.C: Test __cpp_constexpr. * g++.dg/cpp2a/lambda-mangle.C: New test. * g++.dg/debug/dwarf2/pr44641.C: Skip for c++2a. * g++.dg/ext/stmtexpr21.C: Adjust dg-error. Co-Authored-By: Jakub Jelinek From-SVN: r279019 --- diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index 82a62b82749..bcbb999dcbf 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,9 @@ +2019-12-05 Marek Polacek + Jakub Jelinek + + PR c++/91353 - P1331R2: Allow trivial default init in constexpr contexts. + * c-cppbuiltin.c (c_cpp_builtins): Adjust the value of __cpp_constexpr. + 2019-12-05 Marek Polacek PR c++/92271 - make __is_same alias for __is_same_as. diff --git a/gcc/c-family/c-cppbuiltin.c b/gcc/c-family/c-cppbuiltin.c index c7f4659456a..5ad626d7f24 100644 --- a/gcc/c-family/c-cppbuiltin.c +++ b/gcc/c-family/c-cppbuiltin.c @@ -975,7 +975,8 @@ c_cpp_builtins (cpp_reader *pfile) cpp_define (pfile, "__cpp_fold_expressions=201603L"); cpp_define (pfile, "__cpp_nontype_template_args=201411L"); cpp_define (pfile, "__cpp_range_based_for=201603L"); - cpp_define (pfile, "__cpp_constexpr=201603L"); + if (cxx_dialect <= cxx17) + cpp_define (pfile, "__cpp_constexpr=201603L"); cpp_define (pfile, "__cpp_if_constexpr=201606L"); cpp_define (pfile, "__cpp_capture_star_this=201603L"); cpp_define (pfile, "__cpp_inline_variables=201606L"); @@ -997,6 +998,7 @@ c_cpp_builtins (cpp_reader *pfile) cpp_define (pfile, "__cpp_init_captures=201803L"); cpp_define (pfile, "__cpp_generic_lambdas=201707L"); cpp_define (pfile, "__cpp_designated_initializers=201707L"); + cpp_define (pfile, "__cpp_constexpr=201907L"); cpp_define (pfile, "__cpp_constexpr_in_decltype=201711L"); cpp_define (pfile, "__cpp_conditional_explicit=201806L"); cpp_define (pfile, "__cpp_consteval=201811L"); diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 4e88ed828f6..b5c2d1baf34 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,21 @@ +2019-12-05 Marek Polacek + Jakub Jelinek + + PR c++/91353 - P1331R2: Allow trivial default init in constexpr contexts. + * class.c (trivial_default_constructor_is_constexpr): Return true in + C++20. + * constexpr.c (cx_check_missing_mem_inits): Allow missing field + initializers in C++20. + (cxx_eval_call_expression): Don't clear CONSTRUCTOR_NO_CLEARING for + constexpr constructors in C++20. + (reduced_constant_expression_p): Don't set FIELD for union and array + types. Skip empty class fields without initializers. + * decl.c (check_for_uninitialized_const_var): Permit trivial default + initialization in constexpr. + (next_initializable_field): Don't skip vptr fields. + * method.c (walk_field_subobs): Still consider a constructor that + doesn't initialize all the members constexpr. + 2019-12-05 Marek Polacek PR c++/92271 - make __is_same alias for __is_same_as. diff --git a/gcc/cp/class.c b/gcc/cp/class.c index f36f75fa0db..d8bb44990b7 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -5288,8 +5288,14 @@ trivial_default_constructor_is_constexpr (tree t) /* A defaulted trivial default constructor is constexpr if there is nothing to initialize. */ gcc_assert (!TYPE_HAS_COMPLEX_DFLT (t)); - /* A class with a vptr doesn't have a trivial default ctor. */ - return is_really_empty_class (t, /*ignore_vptr*/true); + /* A class with a vptr doesn't have a trivial default ctor. + In C++20, a class can have transient uninitialized members, e.g.: + + struct S { int i; constexpr S() = default; }; + + should work. */ + return (cxx_dialect >= cxx2a + || is_really_empty_class (t, /*ignore_vptr*/true)); } /* Returns true iff class T has a constexpr default constructor. */ diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index 370633467ab..19e09c74760 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -767,6 +767,10 @@ massage_constexpr_body (tree fun, tree body) static bool cx_check_missing_mem_inits (tree ctype, tree body, bool complain) { + /* We allow uninitialized bases/fields in C++20. */ + if (cxx_dialect >= cxx2a) + return false; + unsigned nelts = 0; if (body) @@ -815,7 +819,7 @@ cx_check_missing_mem_inits (tree ctype, tree body, bool complain) continue; if (ANON_AGGR_TYPE_P (TREE_TYPE (field))) { - /* Recurse to check the anonummous aggregate member. */ + /* Recurse to check the anonymous aggregate member. */ bad |= cx_check_missing_mem_inits (TREE_TYPE (field), NULL_TREE, complain); if (bad && !complain) @@ -2179,15 +2183,26 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, entry->result = result; } - /* The result of a constexpr function must be completely initialized. */ - if (TREE_CODE (result) == CONSTRUCTOR) + /* The result of a constexpr function must be completely initialized. + + However, in C++20, a constexpr constructor doesn't necessarily have + to initialize all the fields, so we don't clear CONSTRUCTOR_NO_CLEARING + in order to detect reading an unitialized object in constexpr instead + of value-initializing it. (reduced_constant_expression_p is expected to + take care of clearing the flag.) */ + if (TREE_CODE (result) == CONSTRUCTOR + && (cxx_dialect < cxx2a + || !DECL_CONSTRUCTOR_P (fun))) clear_no_implicit_zero (result); pop_cx_call_context (); return result; } -/* FIXME speed this up, it's taking 16% of compile time on sieve testcase. */ +/* Return true if T is a valid constant initializer. If a CONSTRUCTOR + initializes all the members, the CONSTRUCTOR_NO_CLEARING flag will be + cleared. + FIXME speed this up, it's taking 16% of compile time on sieve testcase. */ bool reduced_constant_expression_p (tree t) @@ -2209,6 +2224,12 @@ reduced_constant_expression_p (tree t) if (TREE_CODE (TREE_TYPE (t)) == VECTOR_TYPE) /* An initialized vector would have a VECTOR_CST. */ return false; + else if (cxx_dialect >= cxx2a + /* An ARRAY_TYPE doesn't have any TYPE_FIELDS. */ + && (TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE + /* A union only initializes one member. */ + || TREE_CODE (TREE_TYPE (t)) == UNION_TYPE)) + field = NULL_TREE; else field = next_initializable_field (TYPE_FIELDS (TREE_TYPE (t))); } @@ -2222,14 +2243,20 @@ reduced_constant_expression_p (tree t) return false; if (field) { - if (idx != field) - return false; + /* Empty class field may or may not have an initializer. */ + for (; idx != field; + field = next_initializable_field (DECL_CHAIN (field))) + if (!is_really_empty_class (TREE_TYPE (field), + /*ignore_vptr*/false)) + return false; field = next_initializable_field (DECL_CHAIN (field)); } } - if (field) - return false; - else if (CONSTRUCTOR_NO_CLEARING (t)) + /* There could be a non-empty field at the end. */ + for (; field; field = next_initializable_field (DECL_CHAIN (field))) + if (!is_really_empty_class (TREE_TYPE (field), /*ignore_vptr*/false)) + return false; + if (CONSTRUCTOR_NO_CLEARING (t)) /* All the fields are initialized. */ CONSTRUCTOR_NO_CLEARING (t) = false; return true; diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 7897327ad9a..a44f1721ea2 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -5858,8 +5858,12 @@ check_for_uninitialized_const_var (tree decl, bool constexpr_context_p, 7.1.6 */ if (VAR_P (decl) && !TYPE_REF_P (type) - && (constexpr_context_p - || CP_TYPE_CONST_P (type) || var_in_constexpr_fn (decl)) + && (CP_TYPE_CONST_P (type) + /* C++20 permits trivial default initialization in constexpr + context (P1331R2). */ + || (cxx_dialect < cxx2a + && (constexpr_context_p + || var_in_constexpr_fn (decl)))) && !DECL_NONTRIVIALLY_INITIALIZED_P (decl)) { tree field = default_init_uninitialized_part (type); @@ -5868,7 +5872,7 @@ check_for_uninitialized_const_var (tree decl, bool constexpr_context_p, bool show_notes = true; - if (!constexpr_context_p) + if (!constexpr_context_p || cxx_dialect >= cxx2a) { if (CP_TYPE_CONST_P (type)) { @@ -5938,7 +5942,11 @@ next_initializable_field (tree field) && (TREE_CODE (field) != FIELD_DECL || DECL_UNNAMED_BIT_FIELD (field) || (DECL_ARTIFICIAL (field) - && !(cxx_dialect >= cxx17 && DECL_FIELD_IS_BASE (field))))) + /* In C++17, don't skip base class fields. */ + && !(cxx_dialect >= cxx17 && DECL_FIELD_IS_BASE (field)) + /* Don't skip vptr fields. We might see them when we're + called from reduced_constant_expression_p. */ + && !DECL_VIRTUAL_P (field)))) field = DECL_CHAIN (field); return field; diff --git a/gcc/cp/method.c b/gcc/cp/method.c index a707940cacc..d2aed473d77 100644 --- a/gcc/cp/method.c +++ b/gcc/cp/method.c @@ -1985,10 +1985,12 @@ walk_field_subobs (tree fields, special_function_kind sfk, tree fnname, if (bad && deleted_p) *deleted_p = true; - /* For an implicitly-defined default constructor to be constexpr, - every member must have a user-provided default constructor or - an explicit initializer. */ - if (constexpr_p && !CLASS_TYPE_P (mem_type) + /* Before C++20, for an implicitly-defined default constructor to + be constexpr, every member must have a user-provided default + constructor or an explicit initializer. */ + if (constexpr_p + && cxx_dialect < cxx2a + && !CLASS_TYPE_P (mem_type) && TREE_CODE (DECL_CONTEXT (field)) != UNION_TYPE) { *constexpr_p = false; diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index e1692fae10d..6d4c403e129 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,42 @@ +2019-12-05 Marek Polacek + Jakub Jelinek + + PR c++/91353 - P1331R2: Allow trivial default init in constexpr contexts. + * g++.dg/cpp0x/constexpr-array6.C: Adjust dg-error. + * g++.dg/cpp0x/constexpr-ctor.C: Likewise. + * g++.dg/cpp0x/constexpr-diag3.C: Likewise. + * g++.dg/cpp0x/constexpr-diag4.C: Likewise. + * g++.dg/cpp0x/constexpr-ex3.C: Likewise. + * g++.dg/cpp0x/constexpr-template2.C: Likewise. + * g++.dg/cpp0x/constexpr-union2.C: Likewise. + * g++.dg/cpp0x/lambda/lambda-mangle.C: Rip out a piece of code ... + * g++.dg/cpp0x/lambda/lambda-mangle6.C: ... and put it here. + * g++.dg/cpp0x/pr79118.C: Adjust dg-error. + * g++.dg/cpp1y/constexpr-83921-3.C: Likewise. + * g++.dg/cpp1y/constexpr-neg1.C: Likewise. + * g++.dg/cpp1z/constexpr-lambda12.C: Likewise. + * g++.dg/cpp1z/feat-cxx1z.C: Use -std=c++17. + * g++.dg/cpp2a/constexpr-init1.C: New test. + * g++.dg/cpp2a/constexpr-init2.C: New test. + * g++.dg/cpp2a/constexpr-init3.C: New test. + * g++.dg/cpp2a/constexpr-init4.C: New test. + * g++.dg/cpp2a/constexpr-init5.C: New test. + * g++.dg/cpp2a/constexpr-init6.C: New test. + * g++.dg/cpp2a/constexpr-init7.C: New test. + * g++.dg/cpp2a/constexpr-init8.C: New test. + * g++.dg/cpp2a/constexpr-init9.C: New test. + * g++.dg/cpp2a/constexpr-init10.C: New test. + * g++.dg/cpp2a/constexpr-init11.C: New test. + * g++.dg/cpp2a/constexpr-init12.C: New test. + * g++.dg/cpp2a/constexpr-init13.C: New test. + * g++.dg/cpp2a/constexpr-init14.C: New test. + * g++.dg/cpp2a/constexpr-init15.C: New test. + * g++.dg/cpp2a/constexpr-try5.C: Adjust dg-error. + * g++.dg/cpp2a/feat-cxx2a.C: Test __cpp_constexpr. + * g++.dg/cpp2a/lambda-mangle.C: New test. + * g++.dg/debug/dwarf2/pr44641.C: Skip for c++2a. + * g++.dg/ext/stmtexpr21.C: Adjust dg-error. + 2019-12-05 Marek Polacek PR c++/92271 - make __is_same alias for __is_same_as. diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-array6.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-array6.C index 16eacdde440..48dae5d9609 100644 --- a/gcc/testsuite/g++.dg/cpp0x/constexpr-array6.C +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-array6.C @@ -4,7 +4,7 @@ struct A { int i; - constexpr A() {} // { dg-error "A::i" } + constexpr A() {} // { dg-error "A::i" "" { target c++17_down } } }; struct B @@ -12,4 +12,5 @@ struct B A a; }; -constexpr B b[] = { {} }; // { dg-error "A::A" } +constexpr B b[] = { {} }; // { dg-error "A::A" "" { target c++17_down } } +// { dg-error "is not a constant expression" "" { target c++2a } .-1 } diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-ctor.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-ctor.C index 55beda7c49f..1d0fa479cbc 100644 --- a/gcc/testsuite/g++.dg/cpp0x/constexpr-ctor.C +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-ctor.C @@ -3,5 +3,5 @@ struct A { int i; - constexpr A() { } // { dg-error "A::i" } + constexpr A() { } // { dg-error "A::i" "" { target c++17_down } } }; diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-diag3.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-diag3.C index e54b26c7f6a..1c43569615c 100644 --- a/gcc/testsuite/g++.dg/cpp0x/constexpr-diag3.C +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-diag3.C @@ -48,7 +48,7 @@ struct Def { int _M_i; // { dg-message "does not initialize" } - constexpr Def() = default; // { dg-error "implicit declaration is not .constexpr." } + constexpr Def() = default; // { dg-error "implicit declaration is not .constexpr." "" { target c++17_down } } }; constexpr Def defobj; // { dg-error "uninitialized" } diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-diag4.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-diag4.C index 13ca6fa2390..c603bdd1a00 100644 --- a/gcc/testsuite/g++.dg/cpp0x/constexpr-diag4.C +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-diag4.C @@ -21,5 +21,5 @@ struct A1 struct B1 { A1 a1; - constexpr B1() {} // { dg-error "B1::a1" } + constexpr B1() {} // { dg-error "B1::a1" "" { target c++17_down } } }; diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-ex3.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-ex3.C index a5893563eec..9d6d5ff587c 100644 --- a/gcc/testsuite/g++.dg/cpp0x/constexpr-ex3.C +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-ex3.C @@ -6,7 +6,7 @@ struct A { int i; - constexpr A(int _i) { i = _i; } // { dg-error "empty body|A::i" } + constexpr A(int _i) { i = _i; } // { dg-error "empty body|A::i" "" { target c++17_down } } }; template diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-template2.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-template2.C index 12a8d42b31f..71eb559a24c 100644 --- a/gcc/testsuite/g++.dg/cpp0x/constexpr-template2.C +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-template2.C @@ -3,7 +3,7 @@ template struct A { T t; - constexpr A() { } // { dg-error "::t" } + constexpr A() { } // { dg-error "::t" "" { target c++17_down } } }; int main() diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-union2.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-union2.C index 1a5e832ac34..c22ecc99efb 100644 --- a/gcc/testsuite/g++.dg/cpp0x/constexpr-union2.C +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-union2.C @@ -14,5 +14,5 @@ union bar int x; short y; - constexpr bar() = default; // { dg-error "constexpr" } + constexpr bar() = default; // { dg-error "constexpr" "" { target c++17_down } } }; diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-mangle.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-mangle.C index 15b8b79ecbc..7894ef3051e 100644 --- a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-mangle.C +++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-mangle.C @@ -47,17 +47,6 @@ struct S { []{return 3;}()); }; -template struct R { - static int x; -}; -// "int i;" makes the op() non-constexpr in C++17. -template int R::x = []{int i; return 1;}(); -template int R::x; -// Type of lambda in intializer of R::x: N1RIiE1xMUlvE_E -// Corresponding operator(): _ZNK1RIiE1xMUlvE_clEv -// { dg-final { scan-assembler "_ZNK1RIiE1xMUlvE_clEv" } } -// { dg-final { scan-assembler "weak\[^\n\r\]*_?_ZNK1RIiE1xMUlvE_clEv" { target { ! { *-*-mingw* *-*-cygwin } } } } } - void bar() { // lambdas in non-vague linkage functions have internal linkage. diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-mangle6.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-mangle6.C new file mode 100644 index 00000000000..9ec13e79bbf --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-mangle6.C @@ -0,0 +1,15 @@ +// Test lambda mangling +// { dg-do compile { target { c++11 && c++17_down } } } +// { dg-require-weak "" } +// { dg-options "-fno-inline" } + +template struct R { + static int x; +}; +// "int i;" makes the op() non-constexpr in C++17. In C++20, it does not. +template int R::x = []{int i; return 1;}(); +template int R::x; +// Type of lambda in intializer of R::x: N1RIiE1xMUlvE_E +// Corresponding operator(): _ZNK1RIiE1xMUlvE_clEv +// { dg-final { scan-assembler "_ZNK1RIiE1xMUlvE_clEv" } } +// { dg-final { scan-assembler "weak\[^\n\r\]*_?_ZNK1RIiE1xMUlvE_clEv" { target { ! { *-*-mingw* *-*-cygwin } } } } } diff --git a/gcc/testsuite/g++.dg/cpp0x/pr79118.C b/gcc/testsuite/g++.dg/cpp0x/pr79118.C index 5db22a96dd4..616b51ea29a 100644 --- a/gcc/testsuite/g++.dg/cpp0x/pr79118.C +++ b/gcc/testsuite/g++.dg/cpp0x/pr79118.C @@ -13,7 +13,7 @@ struct One constexpr One () : a(), b() {} // { dg-error "multiple" } constexpr One (int) : a() {} constexpr One (unsigned) : b () {} - constexpr One (void *) {} // { dg-error "exactly one" } + constexpr One (void *) {} // { dg-error "exactly one" "" { target c++17_down } } }; One a (); @@ -30,10 +30,10 @@ struct Two }; constexpr Two () : a(), b() {} - constexpr Two (int) : a() {} // { dg-error "b' must be initialized" } - constexpr Two (unsigned) : b () {} // { dg-error "a' must be initialized" } - constexpr Two (void *) {} // { dg-error "a' must be initialized" } - // { dg-error "b' must be initialized" "" { target *-*-* } .-1 } + constexpr Two (int) : a() {} // { dg-error "b' must be initialized" "" { target c++17_down } } + constexpr Two (unsigned) : b () {} // { dg-error "a' must be initialized" "" { target c++17_down } } + constexpr Two (void *) {} // { dg-error "a' must be initialized" "" { target c++17_down } } + // { dg-error "b' must be initialized" "" { target c++17_down } .-1 } }; Two e (); diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-83921-3.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-83921-3.C index 4b1ed5c3a87..2f1218693e0 100644 --- a/gcc/testsuite/g++.dg/cpp1y/constexpr-83921-3.C +++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-83921-3.C @@ -2,4 +2,4 @@ // { dg-do compile { target c++14 } } struct Foo { int m; }; -constexpr void test() { Foo f; } // { dg-error "uninitialized" } +constexpr void test() { Foo f; } // { dg-error "uninitialized" "" { target c++17_down } } diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-neg1.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-neg1.C index d82dbada1bf..53f0f1f7a2b 100644 --- a/gcc/testsuite/g++.dg/cpp1y/constexpr-neg1.C +++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-neg1.C @@ -8,7 +8,7 @@ constexpr int f(int i) { goto foo; // { dg-error "goto" } foo: asm("foo"); // { dg-error "asm" "" { target c++17_down } } - int k; // { dg-error "uninitialized" } + int k; // { dg-error "uninitialized" "" { target c++17_down } } A a; // { dg-error "non-literal" } return i; } diff --git a/gcc/testsuite/g++.dg/cpp1z/constexpr-lambda12.C b/gcc/testsuite/g++.dg/cpp1z/constexpr-lambda12.C index a59bf497b30..93b53273741 100644 --- a/gcc/testsuite/g++.dg/cpp1z/constexpr-lambda12.C +++ b/gcc/testsuite/g++.dg/cpp1z/constexpr-lambda12.C @@ -3,7 +3,7 @@ void f(int i) { [i]() constexpr { - int j; // { dg-error "uninitialized" } + int j; // { dg-error "uninitialized" "" { target c++17_down } } j = i; return j; }(); diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-init1.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-init1.C new file mode 100644 index 00000000000..ab7b89da9e8 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-init1.C @@ -0,0 +1,99 @@ +// PR c++/91353 - P1331R2: Allow trivial default init in constexpr contexts. +// { dg-do compile { target c++2a } } +// Test basic use. + +struct S { + int i; + constexpr S(bool b) { + if (b) + i = 42; + } +}; +constexpr S s1(true); +constexpr S s2(false); // { dg-error "not a constant expression" } + +constexpr int +fn1 (int x) +{ + int a; + a = 5; + return x + a; +} + +static_assert (fn1 (2) == 7); + +constexpr int +fn2 (int x) +{ + const int a; // { dg-error "uninitialized .const a." } + constexpr int b; // { dg-error "uninitialized .const b." } + return x; +} + +constexpr int +fn3 (int x) +{ + int a; // { dg-message ".int a. is not const" } + return x + a; // { dg-error "the value of .a. is not usable in a constant expression" } +} + +constexpr int a = fn3 (5); // { dg-message "in .constexpr. expansion of" } + +constexpr int +fn4 () +{ + struct S { int a = -5; int b; } s; + return s.a; +} + +static_assert (fn4 () == -5); + +constexpr int +fn5 () +{ + struct S { int a = 9; int b; } s; + return s.b; +} + +constexpr int b = fn5 (); // { dg-error "accessing uninitialized member" } +// { dg-message "in .constexpr. expansion of" "" { target *-*-* } .-1 } + +constexpr int +fn6 () +{ + int a; + return 42; +} + +static_assert (fn6 () == 42); + +constexpr int +fn7 (bool b) +{ + int a; // { dg-message ".int a. is not const" } + if (b) + a = 42; + return a; +} + +static_assert (fn7 (true) == 42); +static_assert (fn7 (false) == 42); // { dg-error "non-constant condition|the value of .a. is not usable" } +// { dg-message "in .constexpr. expansion of" "" { target *-*-* } .-1 } + +constexpr int +fn8 (int n) +{ + int r; + switch (n) + { + case 1: + r = n; + return r; + case 42: + r = n; + return r; + } +} + +static_assert (fn8 (1) == 1); +static_assert (fn8 (42) == 42); diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-init10.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-init10.C new file mode 100644 index 00000000000..74bf8e6677b --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-init10.C @@ -0,0 +1,11 @@ +// PR c++/91353 - P1331R2: Allow trivial default init in constexpr contexts. +// { dg-do compile { target c++2a } } +// In c++2a we don't emit a call to _ZN3FooI3ArgEC1Ev. + +struct Arg; +struct Base { + int i; + virtual ~Base(); +}; +template struct Foo : Base { }; +Foo a; diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-init11.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-init11.C new file mode 100644 index 00000000000..1c7836a674a --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-init11.C @@ -0,0 +1,16 @@ +// PR c++/91353 - P1331R2: Allow trivial default init in constexpr contexts. +// { dg-do compile { target c++2a } } + +struct S { + int i; + constexpr S(int) : i(10) {} +}; + +struct W { + constexpr W(int) : s(8), p() {} + + S s; + int *p; +}; + +constexpr auto a = W(42); diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-init12.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-init12.C new file mode 100644 index 00000000000..7d3d3729b31 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-init12.C @@ -0,0 +1,16 @@ +// PR c++/91353 - P1331R2: Allow trivial default init in constexpr contexts. +// { dg-do compile { target c++2a } } + +struct S { + int uninit; + constexpr S(int) {} +}; + +struct W { + constexpr W(int) : s(8), p() {} + + S s; + int *p; +}; + +constexpr auto a = W(42); // { dg-error "not a constant expression" } diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-init13.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-init13.C new file mode 100644 index 00000000000..3d4460a0eb8 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-init13.C @@ -0,0 +1,37 @@ +// PR c++/91353 - P1331R2: Allow trivial default init in constexpr contexts. +// { dg-do compile { target c++2a } } + +struct E { }; + +struct S { + E e; + constexpr S() {} +}; + +constexpr S s; +constexpr S s2[4]; + +struct W { + [[no_unique_address]] E e1, e2; + constexpr W() {} +}; + +constexpr W w; +constexpr W w2[4]; + +struct Y { + [[no_unique_address]] E e; + __extension__ char a[0]; + constexpr Y() {} +}; + +constexpr Y y; +constexpr Y y2[4]; + +struct Z { + [[no_unique_address]] E e; + int i; + constexpr Z(int n) :i(n) { } +}; + +constexpr Z z(42); diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-init14.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-init14.C new file mode 100644 index 00000000000..6ab6abf1505 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-init14.C @@ -0,0 +1,28 @@ +// PR c++/91353 - P1331R2: Allow trivial default init in constexpr contexts. +// { dg-do compile { target c++2a } } + +struct E { + constexpr E() = default; + constexpr E(int) {} +}; + +struct W { + [[no_unique_address]] E e; + constexpr W(int) : e(8) {} +}; + +constexpr W w = W(42); + +struct S { + E e; + constexpr S() : e{} { } +}; + +constexpr S s; + +struct S2 { + [[no_unique_address]] E e; + constexpr S2() : e{} { } +}; + +constexpr S2 s2; diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-init15.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-init15.C new file mode 100644 index 00000000000..f80d3f2c27c --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-init15.C @@ -0,0 +1,31 @@ +// PR c++/91353 - P1331R2: Allow trivial default init in constexpr contexts. +// { dg-do compile { target c++2a } } + +struct E { + constexpr E() = default; + constexpr E(int) {} +}; + +struct W { + [[no_unique_address]] E e; + int i; + constexpr W(int) : e(8), i(11) {} +}; + +constexpr W w = W(42); + +struct S { + E e; + int i; + constexpr S() : e{}, i(11) { } +}; + +constexpr S s; + +struct S2 { + [[no_unique_address]] E e; + int i; + constexpr S2() : e{}, i(11) { } +}; + +constexpr S2 s2; diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-init2.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-init2.C new file mode 100644 index 00000000000..541da1c023f --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-init2.C @@ -0,0 +1,15 @@ +// PR c++/91353 - P1331R2: Allow trivial default init in constexpr contexts. +// { dg-do compile { target c++2a } } + +struct A +{ + int i; + constexpr A() : i{} {} +}; + +struct B +{ + A a; +}; + +constexpr B b[] = { {} }; diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-init3.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-init3.C new file mode 100644 index 00000000000..dd2735289cb --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-init3.C @@ -0,0 +1,16 @@ +// PR c++/91353 - P1331R2: Allow trivial default init in constexpr contexts. +// { dg-do compile { target c++2a } } + +struct A +{ + int i; + constexpr A() {} +}; + +struct B +{ + A a; +}; + +// A::i not initialized. +constexpr B b[] = { {} }; // { dg-error "is not a constant expression" } diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-init4.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-init4.C new file mode 100644 index 00000000000..dd614ede2c6 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-init4.C @@ -0,0 +1,61 @@ +// PR c++/91353 - P1331R2: Allow trivial default init in constexpr contexts. +// { dg-do compile { target c++2a } } + +// This bullet in [dcl.constexpr] is now gone: +// - every non-static data member and base class sub-object shall be initialized + +struct A { + int i; + constexpr A(int _i) { i = _i; } +}; + +struct B { + int i; + constexpr B() { } +}; + +// Anonymous members. +struct E { + int a; + union { + char b; + __extension__ struct { + double c; + long d; + }; + union { + char e; + void *f; + }; + }; + __extension__ struct { + long long g; + __extension__ struct { + int h; + double i; + }; + union { + char *j; + E *k; + }; + }; + + // Completely initialized. + constexpr E(int(&)[1]) : a(), b(), g(), h(), i(), j() {} + constexpr E(int(&)[3]) : a(), e(), g(), h(), i(), k() {} + constexpr E(int(&)[7]) : a(), b(), g(), h(), i(), j() {} + constexpr E(int(&)[8]) : a(), f(), g(), h(), i(), k() {} + constexpr E(int(&)[9]) : a(), c(), d(), g(), h(), i(), k() {} + + // Missing d, i, j/k union init. + constexpr E(int(&)[2]) : a(), c(), g(), h() {} + + // Missing h, j/k union init. + constexpr E(int(&)[4]) : a(), c(), d(), g(), i() {} + + // Missing b/c/d/e/f union init. + constexpr E(int(&)[5]) : a(), g(), h(), i(), k() {} + + // Missing a, b/c/d/e/f union, g/h/i/j/k struct init. + constexpr E(int(&)[6]) {} +}; diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-init5.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-init5.C new file mode 100644 index 00000000000..0d21f26da0e --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-init5.C @@ -0,0 +1,22 @@ +// PR c++/91353 - P1331R2: Allow trivial default init in constexpr contexts. +// { dg-do compile { target c++2a } } + +struct S { int i; }; + +constexpr void +fn () +{ + S s; + + []() constexpr { + int i; + }(); +} + +constexpr int +fn2 () +{ + return __extension__ ({ int n; n; }); // { dg-error "not usable in a constant expression" } +} + +constexpr int i = fn2 (); // { dg-message "in .constexpr. expansion of" } diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-init6.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-init6.C new file mode 100644 index 00000000000..a2994f5272c --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-init6.C @@ -0,0 +1,26 @@ +// PR c++/91353 - P1331R2: Allow trivial default init in constexpr contexts. +// { dg-do compile { target c++2a } } + +/* We used to get the "constexpr constructor for union S:: + must initialize exactly one non-static data member" error, but not anymore + in C++20. */ + +struct S { + union { + int i; + double d; + }; + constexpr S() { } +}; + +union U { + int a; + constexpr U() { } +}; + +struct W { + union { + int a; + }; + constexpr W() { } +}; diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-init7.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-init7.C new file mode 100644 index 00000000000..dd2741efa8c --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-init7.C @@ -0,0 +1,63 @@ +// PR c++/91353 - P1331R2: Allow trivial default init in constexpr contexts. +// { dg-do compile { target c++2a } } + +struct S { + int a = 1; + constexpr S() = default; +}; + +constexpr S s; + +union U { + int a = 1; + constexpr U() = default; +}; + +constexpr U u; + +struct S2 { + int a; + constexpr S2() = default; +}; + +constexpr S2 s2; // { dg-error "uninitialized .const s2." } + +union U2 { + int a; + constexpr U2() = default; +}; + +constexpr U2 u2; // { dg-error "uninitialized .const u2." } + +struct S3 { + // FIXME if it's anonymous union, we don't give the error below + union { + int a; + } u; + constexpr S3() = default; +}; + +constexpr S3 s3; // { dg-error "uninitialized .const s3." } + +struct S4 { + // FIXME if it's anonymous union, we don't give the error below + union { + int n; + } u; + constexpr S4() = default; +}; + +constexpr S4 s4; // { dg-error "uninitialized .const s4." } + +struct S5 { + union { + int n = 0; + }; + // FIXME if it's anonymous union, we don't give the error below + union { + int m; + } u; + constexpr S5() = default; +}; + +constexpr S5 s5; // { dg-error "uninitialized .const s5.|not a constant expression" } diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-init8.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-init8.C new file mode 100644 index 00000000000..0d5a4a79c90 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-init8.C @@ -0,0 +1,15 @@ +// PR c++/91353 - P1331R2: Allow trivial default init in constexpr contexts. +// { dg-do compile { target c++2a } } + +struct S { + constexpr S(int) {} +}; + +struct W { + constexpr W(int) : s(8), p() {} + + S s; + int *p; +}; + +constexpr auto a = W(42); diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-init9.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-init9.C new file mode 100644 index 00000000000..b44098cc89b --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-init9.C @@ -0,0 +1,17 @@ +// PR c++/91353 - P1331R2: Allow trivial default init in constexpr contexts. +// { dg-do compile { target c++2a } } + +struct S { + constexpr S(int) {} +}; + +struct W { + constexpr W(int (&)[8]) : W(8) { } + constexpr W(int) : s(8), p() {} + + S s; + int *p; +}; + +int arr[8]; +constexpr auto a = W(arr); diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-try5.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-try5.C index 47cdce88e36..3b51bf7c901 100644 --- a/gcc/testsuite/g++.dg/cpp2a/constexpr-try5.C +++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-try5.C @@ -4,13 +4,13 @@ constexpr int foo () try { // { dg-warning "function-try-block body of 'constexpr' function only available with" "" { target c++17_down } } - int a; // { dg-error "uninitialized variable 'a' in 'constexpr' function" } + int a; // { dg-error "uninitialized variable 'a' in 'constexpr' function" "" { target c++17_down } } static double b = 1.0;// { dg-error "'b' declared 'static' in 'constexpr' function" } goto l; // { dg-error "'goto' in 'constexpr' function" } l:; return 0; } catch (...) { - long int c; // { dg-error "uninitialized variable 'c' in 'constexpr' function" } + long int c; // { dg-error "uninitialized variable 'c' in 'constexpr' function" "" { target c++17_down } } static float d = 2.0f;// { dg-error "'d' declared 'static' in 'constexpr' function" } goto l2; // { dg-error "'goto' in 'constexpr' function" } l2:; @@ -19,19 +19,19 @@ try { // { dg-warning "function-try-block body of 'constexpr' function only av constexpr int bar () { - int a; // { dg-error "uninitialized variable 'a' in 'constexpr' function" } + int a; // { dg-error "uninitialized variable 'a' in 'constexpr' function" "" { target c++17_down } } static long double b = 3.0;// { dg-error "'b' declared 'static' in 'constexpr' function" } goto l; // { dg-error "'goto' in 'constexpr' function" } l:; try { // { dg-warning "'try' in 'constexpr' function only available with" "" { target c++17_down } } - short c; // { dg-error "uninitialized variable 'c' in 'constexpr' function" } + short c; // { dg-error "uninitialized variable 'c' in 'constexpr' function" "" { target c++17_down } } static float d; // { dg-error "'d' declared 'static' in 'constexpr' function" } - // { dg-error "uninitialized variable 'd' in 'constexpr' function" "" { target *-*-* } .-1 } + // { dg-error "uninitialized variable 'd' in 'constexpr' function" "" { target c++17_down } .-1 } goto l2; // { dg-error "'goto' in 'constexpr' function" } l2:; return 0; } catch (int) { - char e; // { dg-error "uninitialized variable 'e' in 'constexpr' function" } + char e; // { dg-error "uninitialized variable 'e' in 'constexpr' function" "" { target c++17_down } } static int f = 5; // { dg-error "'f' declared 'static' in 'constexpr' function" } goto l3; // { dg-error "'goto' in 'constexpr' function" } l3:; diff --git a/gcc/testsuite/g++.dg/cpp2a/feat-cxx2a.C b/gcc/testsuite/g++.dg/cpp2a/feat-cxx2a.C index 389b25e16ea..c86aead79af 100644 --- a/gcc/testsuite/g++.dg/cpp2a/feat-cxx2a.C +++ b/gcc/testsuite/g++.dg/cpp2a/feat-cxx2a.C @@ -134,8 +134,8 @@ #ifndef __cpp_constexpr # error "__cpp_constexpr" -#elif __cpp_constexpr != 201603 -# error "__cpp_constexpr != 201603" +#elif __cpp_constexpr != 201907 +# error "__cpp_constexpr != 201907" #endif #ifndef __cpp_decltype_auto diff --git a/gcc/testsuite/g++.dg/cpp2a/lambda-mangle.C b/gcc/testsuite/g++.dg/cpp2a/lambda-mangle.C new file mode 100644 index 00000000000..8ee9b0327a5 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/lambda-mangle.C @@ -0,0 +1,15 @@ +// Test lambda mangling +// { dg-do compile { target c++2a } } +// { dg-require-weak "" } +// { dg-options "-fno-inline" } + +template struct R { + static int x; +}; +// "int i;" makes the op() non-constexpr in C++17. In C++20, it does not. +template int R::x = []{int i; return 1;}(); +template int R::x; +// Type of lambda in intializer of R::x: N1RIiE1xMUlvE_E +// Corresponding operator(): _ZNK1RIiE1xMUlvE_clEv +// { dg-final { scan-assembler-not "_ZNK1RIiE1xMUlvE_clEv" } } +// { dg-final { scan-assembler-not "weak\[^\n\r\]*_?_ZNK1RIiE1xMUlvE_clEv" } } diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/pr44641.C b/gcc/testsuite/g++.dg/debug/dwarf2/pr44641.C index d50df25f693..1139f412fda 100644 --- a/gcc/testsuite/g++.dg/debug/dwarf2/pr44641.C +++ b/gcc/testsuite/g++.dg/debug/dwarf2/pr44641.C @@ -1,5 +1,5 @@ // Origin: PR 44641 -// { dg-do compile } +// { dg-do compile { target c++17_down } } // { dg-options "-gdwarf-2 -O0 -dA" } template struct MisplacedDbg; @@ -40,3 +40,11 @@ struct MisplacedDbg // { dg-function-on-line {_ZN12MisplacedDbgI3ArgEC[12]Ev} { static MisplacedDbg static_var1; static MisplacedDbg static_var2; static MisplacedDbg static_var3; + +// This test is skipped in C++20 because we consider the default constructor +// MisplacedDbg() constexpr despite the uninitialized member "int i;". So +// the calls to +// MisplacedDbg::MisplacedDbg() +// MisplacedDbg::MisplacedDbg() +// MisplacedDbg::MisplacedDbg() +// are elided. (This comment is here not to mess up the line numbers.) diff --git a/gcc/testsuite/g++.dg/ext/stmtexpr21.C b/gcc/testsuite/g++.dg/ext/stmtexpr21.C index 259cb2f1913..97052a117a7 100644 --- a/gcc/testsuite/g++.dg/ext/stmtexpr21.C +++ b/gcc/testsuite/g++.dg/ext/stmtexpr21.C @@ -7,7 +7,7 @@ struct test { const int *addr; }; const test* setup() { static constexpr test atest = - { ({ int inner; (const int*)(0); }) }; // { dg-error "uninitialized" } + { ({ int inner; (const int*)(0); }) }; // { dg-error "uninitialized" "" { target c++17_down } } return &atest; }