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;

Reply via email to