On Mon, Dec 02, 2019 at 12:09:17PM -0500, Jason Merrill wrote:
> On 12/1/19 8:09 PM, Marek Polacek wrote:
> > --- gcc/cp/constexpr.c
> > +++ gcc/cp/constexpr.c
> > @@ -779,7 +779,9 @@ cx_check_missing_mem_inits (tree ctype, tree body, bool 
> > complain)
> >     if (TREE_CODE (ctype) == UNION_TYPE)
> >       {
> > -      if (nelts == 0 && next_initializable_field (field))
> > +      if (cxx_dialect < cxx2a
> > +     && nelts == 0
> > +     && next_initializable_field (field))
> 
> Do we want cx_check_missing_mem_inits to do anything in C++20?  Or can we
> return immediately at the beginning?

We can just return right away.  Changed.

> >     {
> >       if (complain)
> >         error ("%<constexpr%> constructor for union %qT must "
> > @@ -2153,15 +2157,27 @@ 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)
> > +     || !DECL_DECLARED_CONSTEXPR_P (fun)))
> 
> How can we get here for a non-constexpr function?

We can't -- I was just being explicit.  I dropped the DECL_DECLARED_CONSTEXPR_P
line.

> >       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)
> > @@ -2183,8 +2199,17 @@ 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)));
> > +       /* In C++20, skip fields that don't actually need initializing,
> > +          like empty bases.  */
> > +       field = next_initializable_field (TYPE_FIELDS (TREE_TYPE (t)),
> > +                                         cxx_dialect >= cxx2a);
> >     }
> >         else
> >     field = NULL_TREE;
> > @@ -2198,7 +2223,8 @@ reduced_constant_expression_p (tree t)
> >         {
> >           if (idx != field)
> >             return false;
> > -         field = next_initializable_field (DECL_CHAIN (field));
> > +         field = next_initializable_field (DECL_CHAIN (field),
> > +                                           cxx_dialect >= cxx2a);
> >         }
> >     }
> >         if (field)
> > diff --git gcc/cp/cp-tree.h gcc/cp/cp-tree.h
> > index 7e810b8ee7b..35f3352bdff 100644
> > --- gcc/cp/cp-tree.h
> > +++ gcc/cp/cp-tree.h
> > @@ -6541,7 +6541,7 @@ extern bool is_direct_enum_init                       
> > (tree, tree);
> >   extern void initialize_artificial_var             (tree, 
> > vec<constructor_elt, va_gc> *);
> >   extern tree check_var_type                        (tree, tree, 
> > location_t);
> >   extern tree reshape_init                        (tree, tree, 
> > tsubst_flags_t);
> > -extern tree next_initializable_field (tree);
> > +extern tree next_initializable_field               (tree, bool = false);
> >   extern tree fndecl_declared_return_type           (tree);
> >   extern bool undeduced_auto_decl                   (tree);
> >   extern bool require_deduced_type          (tree, tsubst_flags_t = 
> > tf_warning_or_error);
> > diff --git gcc/cp/decl.c gcc/cp/decl.c
> > index 81d73433547..9feba7d5b54 100644
> > --- gcc/cp/decl.c
> > +++ gcc/cp/decl.c
> > +next_initializable_field (tree field, bool skip_empty /*=false*/)
> >   {
> >     while (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))
> > +            /* In C++20, don't skip vptr fields.  */
> > +            && !(cxx_dialect >= cxx2a && DECL_VIRTUAL_P (field)))
> 
> I don't think this needs to be specific to C++20; in all language revisions
> a vptr makes a class non-aggregate, so we'd only get here for a use like
> that in reduced_constant_expression_p.

True enough, adjusted.

> > +        || (skip_empty
> > +            && is_really_empty_class (TREE_TYPE (field),
> 
> This should probably check DECL_SIZE (field) == size_zero_node instead,
> since that will properly distinguish between overlapping and non-overlapping
> data members of empty class type.  And please test how this works with data
> members of empty class type both with and without [[no_unique_address]].

I don't think that's possible -- empty classes in C++ have sizeof(char), unless
their only member is char[0], then their DECL_SIZE is 0.

I've added two testcases: constexpr-init13.C and constexpr-init14.C.  Is there
another scenario regarding [[no_unique_address]] that you want me to test?

Bootstrapped/regtested on x86_64-linux, built Boost and cmcstl2.

2019-12-02  Marek Polacek  <pola...@redhat.com>
            Jakub Jelinek  <ja...@redhat.com>

        PR c++/91353 - P1331R2: Allow trivial default init 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.  Adjust calls to next_initializable_field.
        * cp-tree.h (next_initializable_field): Adjust declaration.
        * decl.c (check_for_uninitialized_const_var): Permit trivial default
        initialization in constexpr.
        (next_initializable_field): Add a bool parameter.  Use it.
        * 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-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.

diff --git gcc/c-family/c-cppbuiltin.c gcc/c-family/c-cppbuiltin.c
index 6491545bc3b..680087cd254 100644
--- gcc/c-family/c-cppbuiltin.c
+++ 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 gcc/cp/class.c gcc/cp/class.c
index f36f75fa0db..d8bb44990b7 100644
--- gcc/cp/class.c
+++ 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 gcc/cp/constexpr.c gcc/cp/constexpr.c
index ee3ccb9691c..8952d09f19f 100644
--- gcc/cp/constexpr.c
+++ 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)
@@ -2153,15 +2157,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)
@@ -2183,8 +2198,17 @@ 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)));
+           /* In C++20, skip fields that don't actually need initializing,
+              like empty bases.  */
+           field = next_initializable_field (TYPE_FIELDS (TREE_TYPE (t)),
+                                             cxx_dialect >= cxx2a);
        }
       else
        field = NULL_TREE;
@@ -2198,7 +2222,8 @@ reduced_constant_expression_p (tree t)
            {
              if (idx != field)
                return false;
-             field = next_initializable_field (DECL_CHAIN (field));
+             field = next_initializable_field (DECL_CHAIN (field),
+                                               cxx_dialect >= cxx2a);
            }
        }
       if (field)
diff --git gcc/cp/cp-tree.h gcc/cp/cp-tree.h
index 7e810b8ee7b..35f3352bdff 100644
--- gcc/cp/cp-tree.h
+++ gcc/cp/cp-tree.h
@@ -6541,7 +6541,7 @@ extern bool is_direct_enum_init                   (tree, 
tree);
 extern void initialize_artificial_var          (tree, vec<constructor_elt, 
va_gc> *);
 extern tree check_var_type                     (tree, tree, location_t);
 extern tree reshape_init                        (tree, tree, tsubst_flags_t);
-extern tree next_initializable_field (tree);
+extern tree next_initializable_field           (tree, bool = false);
 extern tree fndecl_declared_return_type                (tree);
 extern bool undeduced_auto_decl                        (tree);
 extern bool require_deduced_type               (tree, tsubst_flags_t = 
tf_warning_or_error);
diff --git gcc/cp/decl.c gcc/cp/decl.c
index 81d73433547..0ee68d3bf27 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))
            {
@@ -5906,16 +5910,23 @@ static tree reshape_init_r (tree, reshape_iter *, bool, 
tsubst_flags_t);
 /* FIELD is a FIELD_DECL or NULL.  In the former case, the value
    returned is the next FIELD_DECL (possibly FIELD itself) that can be
    initialized.  If there are no more such fields, the return value
-   will be NULL.  */
+   will be NULL.  If SKIP_EMPTY, skips empty classes.  */
 
 tree
-next_initializable_field (tree field)
+next_initializable_field (tree field, bool skip_empty /*=false*/)
 {
   while (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))
+            || (skip_empty
+                && is_really_empty_class (TREE_TYPE (field),
+                                          /*ignore_vptr=*/false))))
     field = DECL_CHAIN (field);
 
   return field;
diff --git gcc/cp/method.c gcc/cp/method.c
index a707940cacc..d2aed473d77 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;
diff --git gcc/testsuite/g++.dg/cpp0x/constexpr-array6.C 
gcc/testsuite/g++.dg/cpp0x/constexpr-array6.C
index 16eacdde440..48dae5d9609 100644
--- gcc/testsuite/g++.dg/cpp0x/constexpr-array6.C
+++ 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 gcc/testsuite/g++.dg/cpp0x/constexpr-ctor.C 
gcc/testsuite/g++.dg/cpp0x/constexpr-ctor.C
index 55beda7c49f..1d0fa479cbc 100644
--- gcc/testsuite/g++.dg/cpp0x/constexpr-ctor.C
+++ 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 gcc/testsuite/g++.dg/cpp0x/constexpr-diag3.C 
gcc/testsuite/g++.dg/cpp0x/constexpr-diag3.C
index e54b26c7f6a..1c43569615c 100644
--- gcc/testsuite/g++.dg/cpp0x/constexpr-diag3.C
+++ 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 gcc/testsuite/g++.dg/cpp0x/constexpr-diag4.C 
gcc/testsuite/g++.dg/cpp0x/constexpr-diag4.C
index 13ca6fa2390..c603bdd1a00 100644
--- gcc/testsuite/g++.dg/cpp0x/constexpr-diag4.C
+++ 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 gcc/testsuite/g++.dg/cpp0x/constexpr-ex3.C 
gcc/testsuite/g++.dg/cpp0x/constexpr-ex3.C
index a5893563eec..9d6d5ff587c 100644
--- gcc/testsuite/g++.dg/cpp0x/constexpr-ex3.C
+++ 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 <class T>
diff --git gcc/testsuite/g++.dg/cpp0x/constexpr-template2.C 
gcc/testsuite/g++.dg/cpp0x/constexpr-template2.C
index 12a8d42b31f..71eb559a24c 100644
--- gcc/testsuite/g++.dg/cpp0x/constexpr-template2.C
+++ gcc/testsuite/g++.dg/cpp0x/constexpr-template2.C
@@ -3,7 +3,7 @@
 template <class T> struct A
 {
   T t;
-  constexpr A() { }            // { dg-error "::t" }
+  constexpr A() { }            // { dg-error "::t" "" { target c++17_down } }
 };
 
 int main()
diff --git gcc/testsuite/g++.dg/cpp0x/constexpr-union2.C 
gcc/testsuite/g++.dg/cpp0x/constexpr-union2.C
index 1a5e832ac34..c22ecc99efb 100644
--- gcc/testsuite/g++.dg/cpp0x/constexpr-union2.C
+++ 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 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-mangle.C 
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-mangle.C
index 15b8b79ecbc..7894ef3051e 100644
--- gcc/testsuite/g++.dg/cpp0x/lambda/lambda-mangle.C
+++ gcc/testsuite/g++.dg/cpp0x/lambda/lambda-mangle.C
@@ -47,17 +47,6 @@ struct S {
         []{return 3;}());
 };
 
-template<typename T> struct R {
-  static int x;
-};
-// "int i;" makes the op() non-constexpr in C++17.
-template<typename T> int R<T>::x = []{int i; return 1;}();
-template int R<int>::x;
-// Type of lambda in intializer of R<int>::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 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-mangle6.C 
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-mangle6.C
new file mode 100644
index 00000000000..9ec13e79bbf
--- /dev/null
+++ 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<typename T> struct R {
+  static int x;
+};
+// "int i;" makes the op() non-constexpr in C++17.  In C++20, it does not.
+template<typename T> int R<T>::x = []{int i; return 1;}();
+template int R<int>::x;
+// Type of lambda in intializer of R<int>::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 gcc/testsuite/g++.dg/cpp0x/pr79118.C 
gcc/testsuite/g++.dg/cpp0x/pr79118.C
index 5db22a96dd4..616b51ea29a 100644
--- gcc/testsuite/g++.dg/cpp0x/pr79118.C
+++ 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 gcc/testsuite/g++.dg/cpp1y/constexpr-83921-3.C 
gcc/testsuite/g++.dg/cpp1y/constexpr-83921-3.C
index 4b1ed5c3a87..2f1218693e0 100644
--- gcc/testsuite/g++.dg/cpp1y/constexpr-83921-3.C
+++ 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 gcc/testsuite/g++.dg/cpp1y/constexpr-neg1.C 
gcc/testsuite/g++.dg/cpp1y/constexpr-neg1.C
index d82dbada1bf..53f0f1f7a2b 100644
--- gcc/testsuite/g++.dg/cpp1y/constexpr-neg1.C
+++ 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 gcc/testsuite/g++.dg/cpp1z/constexpr-lambda12.C 
gcc/testsuite/g++.dg/cpp1z/constexpr-lambda12.C
index a59bf497b30..93b53273741 100644
--- gcc/testsuite/g++.dg/cpp1z/constexpr-lambda12.C
+++ 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 gcc/testsuite/g++.dg/cpp2a/constexpr-init1.C 
gcc/testsuite/g++.dg/cpp2a/constexpr-init1.C
new file mode 100644
index 00000000000..ab7b89da9e8
--- /dev/null
+++ 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 gcc/testsuite/g++.dg/cpp2a/constexpr-init10.C 
gcc/testsuite/g++.dg/cpp2a/constexpr-init10.C
new file mode 100644
index 00000000000..74bf8e6677b
--- /dev/null
+++ 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 <class> struct Foo : Base { };
+Foo<Arg> a;
diff --git gcc/testsuite/g++.dg/cpp2a/constexpr-init11.C 
gcc/testsuite/g++.dg/cpp2a/constexpr-init11.C
new file mode 100644
index 00000000000..1c7836a674a
--- /dev/null
+++ 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 gcc/testsuite/g++.dg/cpp2a/constexpr-init12.C 
gcc/testsuite/g++.dg/cpp2a/constexpr-init12.C
new file mode 100644
index 00000000000..7d3d3729b31
--- /dev/null
+++ 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 gcc/testsuite/g++.dg/cpp2a/constexpr-init13.C 
gcc/testsuite/g++.dg/cpp2a/constexpr-init13.C
new file mode 100644
index 00000000000..3d4460a0eb8
--- /dev/null
+++ 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 gcc/testsuite/g++.dg/cpp2a/constexpr-init14.C 
gcc/testsuite/g++.dg/cpp2a/constexpr-init14.C
new file mode 100644
index 00000000000..6ab6abf1505
--- /dev/null
+++ 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 gcc/testsuite/g++.dg/cpp2a/constexpr-init2.C 
gcc/testsuite/g++.dg/cpp2a/constexpr-init2.C
new file mode 100644
index 00000000000..541da1c023f
--- /dev/null
+++ 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 gcc/testsuite/g++.dg/cpp2a/constexpr-init3.C 
gcc/testsuite/g++.dg/cpp2a/constexpr-init3.C
new file mode 100644
index 00000000000..dd2735289cb
--- /dev/null
+++ 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 gcc/testsuite/g++.dg/cpp2a/constexpr-init4.C 
gcc/testsuite/g++.dg/cpp2a/constexpr-init4.C
new file mode 100644
index 00000000000..dd614ede2c6
--- /dev/null
+++ 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 gcc/testsuite/g++.dg/cpp2a/constexpr-init5.C 
gcc/testsuite/g++.dg/cpp2a/constexpr-init5.C
new file mode 100644
index 00000000000..0d21f26da0e
--- /dev/null
+++ 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 gcc/testsuite/g++.dg/cpp2a/constexpr-init6.C 
gcc/testsuite/g++.dg/cpp2a/constexpr-init6.C
new file mode 100644
index 00000000000..a2994f5272c
--- /dev/null
+++ 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::<unnamed union>
+   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 gcc/testsuite/g++.dg/cpp2a/constexpr-init7.C 
gcc/testsuite/g++.dg/cpp2a/constexpr-init7.C
new file mode 100644
index 00000000000..dd2741efa8c
--- /dev/null
+++ 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 gcc/testsuite/g++.dg/cpp2a/constexpr-init8.C 
gcc/testsuite/g++.dg/cpp2a/constexpr-init8.C
new file mode 100644
index 00000000000..0d5a4a79c90
--- /dev/null
+++ 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 gcc/testsuite/g++.dg/cpp2a/constexpr-init9.C 
gcc/testsuite/g++.dg/cpp2a/constexpr-init9.C
new file mode 100644
index 00000000000..b44098cc89b
--- /dev/null
+++ 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 gcc/testsuite/g++.dg/cpp2a/constexpr-try5.C 
gcc/testsuite/g++.dg/cpp2a/constexpr-try5.C
index 47cdce88e36..3b51bf7c901 100644
--- gcc/testsuite/g++.dg/cpp2a/constexpr-try5.C
+++ 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 gcc/testsuite/g++.dg/cpp2a/feat-cxx2a.C 
gcc/testsuite/g++.dg/cpp2a/feat-cxx2a.C
index 9b6e2f59d2c..c5c16b6bcc7 100644
--- gcc/testsuite/g++.dg/cpp2a/feat-cxx2a.C
+++ 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 gcc/testsuite/g++.dg/cpp2a/lambda-mangle.C 
gcc/testsuite/g++.dg/cpp2a/lambda-mangle.C
new file mode 100644
index 00000000000..8ee9b0327a5
--- /dev/null
+++ 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<typename T> struct R {
+  static int x;
+};
+// "int i;" makes the op() non-constexpr in C++17.  In C++20, it does not.
+template<typename T> int R<T>::x = []{int i; return 1;}();
+template int R<int>::x;
+// Type of lambda in intializer of R<int>::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 gcc/testsuite/g++.dg/debug/dwarf2/pr44641.C 
gcc/testsuite/g++.dg/debug/dwarf2/pr44641.C
index d50df25f693..1139f412fda 100644
--- gcc/testsuite/g++.dg/debug/dwarf2/pr44641.C
+++ 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 <class A> struct MisplacedDbg;
@@ -40,3 +40,11 @@ struct MisplacedDbg  // { dg-function-on-line 
{_ZN12MisplacedDbgI3ArgEC[12]Ev} {
 static MisplacedDbg<Arg> static_var1;
 static MisplacedDbg<Arg*> static_var2;
 static MisplacedDbg<Full> 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<Arg>::MisplacedDbg()
+//    MisplacedDbg<Full>::MisplacedDbg()
+//    MisplacedDbg<Arg*>::MisplacedDbg()
+// are elided.  (This comment is here not to mess up the line numbers.)
diff --git gcc/testsuite/g++.dg/ext/stmtexpr21.C 
gcc/testsuite/g++.dg/ext/stmtexpr21.C
index 259cb2f1913..97052a117a7 100644
--- gcc/testsuite/g++.dg/ext/stmtexpr21.C
+++ 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;
 }

Reply via email to