https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91353
--- Comment #6 from Marek Polacek <mpolacek at gcc dot gnu.org> --- Current patch (modulo testsuite changes) that seems to work pretty well: diff --git gcc/c-family/c-cppbuiltin.c gcc/c-family/c-cppbuiltin.c index 76d1e4a380e..9766d7f96c4 100644 --- gcc/c-family/c-cppbuiltin.c +++ gcc/c-family/c-cppbuiltin.c @@ -972,7 +972,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"); @@ -991,6 +992,7 @@ c_cpp_builtins (cpp_reader *pfile) { /* Set feature test macros for C++2a. */ cpp_define (pfile, "__cpp_conditional_explicit=201806L"); + cpp_define (pfile, "__cpp_constexpr=201907L"); cpp_define (pfile, "__cpp_constinit=201907L"); cpp_define (pfile, "__cpp_nontype_template_parameter_class=201806L"); cpp_define (pfile, "__cpp_impl_destroying_delete=201806L"); diff --git gcc/cp/constexpr.c gcc/cp/constexpr.c index 8c79b0484fc..5bfbc1f7ce5 100644 --- gcc/cp/constexpr.c +++ gcc/cp/constexpr.c @@ -765,7 +765,7 @@ massage_constexpr_body (tree fun, tree body) bases/fields are uninitialized, and complain if COMPLAIN. */ static bool -cx_check_missing_mem_inits (tree ctype, tree body, bool complain) +cx_check_missing_mem_inits (tree ctype, tree body, bool complain, bool allow_missing = true) { unsigned nelts = 0; @@ -815,13 +815,15 @@ 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); + (TREE_TYPE (field), NULL_TREE, complain, allow_missing); if (bad && !complain) return true; continue; } + if (cxx_dialect >= cxx2a && allow_missing) + continue; ftype = strip_array_types (TREE_TYPE (field)); if (type_has_constexpr_default_constructor (ftype)) { @@ -829,6 +831,10 @@ cx_check_missing_mem_inits (tree ctype, tree body, bool complain) A constexpr ctor that isn't trivial should have been added in by now. */ gcc_checking_assert (!TYPE_HAS_COMPLEX_DFLT (ftype) + /* If we're only checking for missing + inits, non-trivial ctors have not been + added yet. */ + || (cxx_dialect >= cxx2a && !allow_missing) || errorcount != 0); continue; } @@ -847,7 +853,7 @@ cx_check_missing_mem_inits (tree ctype, tree body, bool complain) { /* Check the anonymous aggregate initializer is valid. */ bad |= cx_check_missing_mem_inits - (TREE_TYPE (index), CONSTRUCTOR_ELT (body, i)->value, complain); + (TREE_TYPE (index), CONSTRUCTOR_ELT (body, i)->value, complain, allow_missing); if (bad && !complain) return true; } @@ -2150,8 +2156,18 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, } /* The result of a constexpr function must be completely initialized. */ + // XXX not in C++20 constructor + // XXX pedwarn somewhere if (TREE_CODE (result) == CONSTRUCTOR) - clear_no_implicit_zero (result); + { + clear_no_implicit_zero (result); + if (cxx_dialect >= cxx2a + && DECL_CONSTRUCTOR_P (fun) + && DECL_DECLARED_CONSTEXPR_P (fun) + && NON_UNION_CLASS_TYPE_P (TREE_TYPE (result)) + && cx_check_missing_mem_inits (TREE_TYPE (result), result, false, false)) + CONSTRUCTOR_NO_CLEARING (result) = true; + } pop_cx_call_context (); return result; @@ -2903,8 +2919,7 @@ cxx_eval_array_reference (const constexpr_ctx *ctx, tree t, /* Not found. */ - if (TREE_CODE (ary) == CONSTRUCTOR - && CONSTRUCTOR_NO_CLEARING (ary)) + if (TREE_CODE (ary) == CONSTRUCTOR && CONSTRUCTOR_NO_CLEARING (ary)) { /* 'ary' is part of the aggregate initializer we're currently building; if there's no initializer for this element yet, diff --git gcc/cp/decl.c gcc/cp/decl.c index 86e38f4af69..ab6da6080a5 100644 --- gcc/cp/decl.c +++ gcc/cp/decl.c @@ -5835,8 +5835,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); @@ -5845,7 +5849,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)) { diff --git gcc/cp/method.c gcc/cp/method.c index acba6c6da8c..f01ea6a9128 100644 --- gcc/cp/method.c +++ 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;