https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91353
Bug ID: 91353 Summary: Implement P1331R2: Permitting trivial default initialization in constexprcontexts Product: gcc Version: 9.1.1 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: jakub at gcc dot gnu.org Target Milestone: --- Out of curiousity, I've played with this a little bit. Given constexpr int foo (int x) { int a; a = 5; return x + a; } static_assert (foo (2) == 7); constexpr int bar (int x) { const int a; // { dg-error "" } constexpr int b; // { dg-error "" } return x; } constexpr int baz (int x) { int a; return x + a; // { dg-error "" } } constexpr int a = baz (5); constexpr int qux () { struct S { int a = -5; int b; } s; return s.a; } static_assert (qux () == -5); constexpr int quux () { struct S { int a = 9; int b; } s; return s.b; // { dg-error "" } } constexpr int b = quux (); the following patch doesn't diagnose the quux bug of using uninitialized s.b. For some reason CONSTRUCTOR_NO_CLEARING is not set and thus we value-initialize instead of diagnosing. --- gcc/cp/decl.c.jj 2019-08-05 09:58:07.713491022 +0200 +++ gcc/cp/decl.c 2019-08-05 10:22:28.534127984 +0200 @@ -5742,8 +5742,10 @@ check_for_uninitialized_const_var (tree 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) + || (cxx_dialect < cxx2a + && (constexpr_context_p + || var_in_constexpr_fn (decl)))) && !DECL_NONTRIVIALLY_INITIALIZED_P (decl)) { tree field = default_init_uninitialized_part (type); @@ -5752,7 +5754,7 @@ check_for_uninitialized_const_var (tree bool show_notes = true; - if (!constexpr_context_p) + if (!constexpr_context_p || cxx_dialect >= cxx2a) { if (CP_TYPE_CONST_P (type)) { --- gcc/cp/constexpr.c.jj 2019-08-05 09:57:55.147683227 +0200 +++ gcc/cp/constexpr.c 2019-08-05 10:51:56.954215860 +0200 @@ -814,13 +814,15 @@ cx_check_missing_mem_inits (tree ctype, 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) return true; continue; } + if (cxx_dialect >= cxx2a) + continue; ftype = strip_array_types (TREE_TYPE (field)); if (type_has_constexpr_default_constructor (ftype)) { @@ -6617,8 +6619,9 @@ potential_constant_expression_1 (tree t, "%<thread_local%> in %<constexpr%> context", tmp); return false; } - else if (!check_for_uninitialized_const_var - (tmp, /*constexpr_context_p=*/true, flags)) + else if (cxx_dialect < cxx2a + && !check_for_uninitialized_const_var + (tmp, /*constexpr_context_p=*/true, flags)) return false; } return RECUR (tmp, want_rval); --- gcc/cp/method.c.jj 2019-05-20 23:33:13.818084173 +0200 +++ gcc/cp/method.c 2019-08-05 10:46:07.057545848 +0200 @@ -1410,7 +1410,9 @@ walk_field_subobs (tree fields, special_ /* 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) + if (constexpr_p + && cxx_dialect < cxx2a + && !CLASS_TYPE_P (mem_type) && TREE_CODE (DECL_CONTEXT (field)) != UNION_TYPE) { *constexpr_p = false; Not really sure with the removal of diagnostics for constexpr ctors not initializing all non-static data members for -std=c++2a, shall we diagnose somewhere else if a const or constexpr variable is initialized with such a constructor? And part of this change shall be bumping for cxx_dialect >= cxx2a of __cpp_constexpr value.