--- gcc/c-family/c-cppbuiltin.c.jj	2019-09-26 21:34:21.188923996 +0200
+++ gcc/c-family/c-cppbuiltin.c	2019-09-27 18:25:41.346059343 +0200
@@ -989,6 +989,7 @@ c_cpp_builtins (cpp_reader *pfile)
 	  cpp_define (pfile, "__cpp_constinit=201907");
 	  cpp_define (pfile, "__cpp_nontype_template_parameter_class=201806");
 	  cpp_define (pfile, "__cpp_impl_destroying_delete=201806");
+	  cpp_define (pfile, "__cpp_constexpr_dynamic_alloc=201907");
 	}
       if (flag_concepts)
 	cpp_define (pfile, "__cpp_concepts=201507");
--- gcc/cp/cp-tree.h.jj	2019-09-27 12:22:54.042880699 +0200
+++ gcc/cp/cp-tree.h	2019-09-27 18:25:40.903065957 +0200
@@ -172,6 +172,9 @@ enum cp_tree_index
     CPTI_VALUE_IDENTIFIER,
     CPTI_FUN_IDENTIFIER,
     CPTI_CLOSURE_IDENTIFIER,
+    CPTI_HEAP_UNINIT_IDENTIFIER,
+    CPTI_HEAP_IDENTIFIER,
+    CPTI_HEAP_DELETED_IDENTIFIER,
 
     CPTI_LANG_NAME_C,
     CPTI_LANG_NAME_CPLUSPLUS,
@@ -310,6 +313,9 @@ extern GTY(()) tree cp_global_trees[CPTI
 #define value_identifier		cp_global_trees[CPTI_VALUE_IDENTIFIER]
 #define fun_identifier			cp_global_trees[CPTI_FUN_IDENTIFIER]
 #define closure_identifier		cp_global_trees[CPTI_CLOSURE_IDENTIFIER]
+#define heap_uninit_identifier		cp_global_trees[CPTI_HEAP_UNINIT_IDENTIFIER]
+#define heap_identifier			cp_global_trees[CPTI_HEAP_IDENTIFIER]
+#define heap_deleted_identifier		cp_global_trees[CPTI_HEAP_DELETED_IDENTIFIER]
 #define lang_name_c			cp_global_trees[CPTI_LANG_NAME_C]
 #define lang_name_cplusplus		cp_global_trees[CPTI_LANG_NAME_CPLUSPLUS]
 
@@ -6324,6 +6330,7 @@ extern bool vbase_has_user_provided_move
 extern tree default_init_uninitialized_part (tree);
 extern bool trivial_default_constructor_is_constexpr (tree);
 extern bool type_has_constexpr_default_constructor (tree);
+extern bool type_has_constexpr_destructor	(tree);
 extern bool type_has_virtual_destructor		(tree);
 extern bool classtype_has_move_assign_or_move_ctor_p (tree, bool user_declared);
 extern bool classtype_has_non_deleted_move_ctor (tree);
@@ -7729,6 +7736,7 @@ extern bool require_constant_expression
 extern bool require_rvalue_constant_expression (tree);
 extern bool require_potential_rvalue_constant_expression (tree);
 extern tree cxx_constant_value			(tree, tree = NULL_TREE);
+extern void cxx_constant_dtor			(tree, tree);
 extern tree cxx_constant_init			(tree, tree = NULL_TREE);
 extern tree maybe_constant_value		(tree, tree = NULL_TREE, bool = false);
 extern tree maybe_constant_init			(tree, tree = NULL_TREE, bool = false);
--- gcc/cp/class.c.jj	2019-09-26 21:34:21.434920308 +0200
+++ gcc/cp/class.c	2019-09-27 18:25:40.904065942 +0200
@@ -206,6 +206,7 @@ static int empty_base_at_nonzero_offset_
 static tree end_of_base (tree);
 static tree get_vcall_index (tree, tree);
 static bool type_maybe_constexpr_default_constructor (tree);
+static bool type_maybe_constexpr_destructor (tree);
 static bool field_poverlapping_p (tree);
 
 /* Return a COND_EXPR that executes TRUE_STMT if this execution of the
@@ -5242,7 +5243,7 @@ type_has_constexpr_default_constructor (
    without forcing a lazy declaration (which might cause undesired
    instantiations).  */
 
-bool
+static bool
 type_maybe_constexpr_default_constructor (tree t)
 {
   if (CLASS_TYPE_P (t) && CLASSTYPE_LAZY_DEFAULT_CTOR (t)
@@ -5252,6 +5253,34 @@ type_maybe_constexpr_default_constructor
   return type_has_constexpr_default_constructor (t);
 }
 
+/* Returns true iff class T has a constexpr destructor.  */
+
+bool
+type_has_constexpr_destructor (tree t)
+{
+  tree fns;
+
+  if (CLASSTYPE_LAZY_DESTRUCTOR (t))
+    /* Non-trivial, we need to check subobject destructors.  */
+    lazily_declare_fn (sfk_destructor, t);
+  fns = CLASSTYPE_DESTRUCTOR (t);
+  return (fns && DECL_DECLARED_CONSTEXPR_P (fns));
+}
+
+/* Returns true iff class T has a constexpr destructor or has an
+   implicitly declared destructor that we can't tell if it's constexpr
+   without forcing a lazy declaration (which might cause undesired
+   instantiations).  */
+
+static bool
+type_maybe_constexpr_destructor (tree t)
+{
+  if (CLASS_TYPE_P (t) && CLASSTYPE_LAZY_DESTRUCTOR (t))
+    /* Assume it's constexpr.  */
+    return true;
+  return type_has_constexpr_destructor (t);
+}
+
 /* Returns true iff class TYPE has a virtual destructor.  */
 
 bool
@@ -5503,8 +5532,11 @@ finalize_literal_type_property (tree t)
 {
   tree fn;
 
-  if (cxx_dialect < cxx11
-      || TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t))
+  if (cxx_dialect < cxx11)
+    CLASSTYPE_LITERAL_P (t) = false;
+  else if (CLASSTYPE_LITERAL_P (t)
+	   && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t)
+	   && (cxx_dialect < cxx2a || !type_maybe_constexpr_destructor (t)))
     CLASSTYPE_LITERAL_P (t) = false;
   else if (CLASSTYPE_LITERAL_P (t) && LAMBDA_TYPE_P (t))
     CLASSTYPE_LITERAL_P (t) = (cxx_dialect >= cxx17);
@@ -5558,8 +5590,12 @@ explain_non_literal_class (tree t)
     inform (UNKNOWN_LOCATION,
 	    "  %qT is a closure type, which is only literal in "
 	    "C++17 and later", t);
-  else if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t))
+  else if (cxx_dialect < cxx2a && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t))
     inform (UNKNOWN_LOCATION, "  %q+T has a non-trivial destructor", t);
+  else if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t)
+	   && !type_maybe_constexpr_destructor (t))
+    inform (UNKNOWN_LOCATION, "  %q+T does not have %<constexpr%> destructor",
+	    t);
   else if (CLASSTYPE_NON_AGGREGATE (t)
 	   && !TYPE_HAS_TRIVIAL_DFLT (t)
 	   && !LAMBDA_TYPE_P (t)
--- gcc/cp/constexpr.c.jj	2019-09-27 20:33:37.600208356 +0200
+++ gcc/cp/constexpr.c	2019-09-27 20:38:38.203710246 +0200
@@ -34,6 +34,7 @@ along with GCC; see the file COPYING3.
 #include "gimple-fold.h"
 #include "timevar.h"
 #include "fold-const-call.h"
+#include "stor-layout.h"
 
 static bool verify_constant (tree, bool, bool *, bool *);
 #define VERIFY_CONSTANT(X)						\
@@ -1031,6 +1032,9 @@ struct constexpr_ctx {
      on simple constants or location wrappers) encountered during current
      cxx_eval_outermost_constant_expr call.  */
   HOST_WIDE_INT *constexpr_ops_count;
+  /* Heap VAR_DECLs created during the evaluation of the outermost constant
+     expression.  */
+  vec<tree> *heap_vars;
 
   /* Whether we should error on a non-constant expression or fail quietly.  */
   bool quiet;
@@ -1666,6 +1670,58 @@ cxx_eval_call_expression (const constexp
 					   lval, non_constant_p, overflow_p);
   if (!DECL_DECLARED_CONSTEXPR_P (fun))
     {
+      if (cxx_dialect >= cxx2a
+	  && IDENTIFIER_NEWDEL_OP_P (DECL_NAME (fun))
+	  && CP_DECL_CONTEXT (fun) == global_namespace)
+	{
+	  const int nargs = call_expr_nargs (t);
+	  tree arg0 = NULL_TREE;
+	  for (int i = 0; i < nargs; ++i)
+	    {
+	      tree arg = CALL_EXPR_ARG (t, i);
+	      arg = cxx_eval_constant_expression (ctx, arg, false,
+						  non_constant_p, overflow_p);
+	      VERIFY_CONSTANT (arg);
+	      if (i == 0)
+		arg0 = arg;
+	    }
+	  gcc_assert (arg0);
+	  if (IDENTIFIER_NEW_OP_P (DECL_NAME (fun)))
+	    {
+	      tree type = build_array_type_nelts (char_type_node,
+						  tree_to_uhwi (arg0));
+	      tree var = build_decl (loc, VAR_DECL, heap_uninit_identifier,
+				     type);
+	      DECL_ARTIFICIAL (var) = 1;
+	      TREE_STATIC (var) = 1;
+	      ctx->heap_vars->safe_push (var);
+	      return fold_convert (ptr_type_node, build_address (var));
+	    }
+	  else
+	    {
+	      STRIP_NOPS (arg0);
+	      if (TREE_CODE (arg0) == ADDR_EXPR
+		  && VAR_P (TREE_OPERAND (arg0, 0)))
+		{
+		  tree var = TREE_OPERAND (arg0, 0);
+		  if (DECL_NAME (var) == heap_uninit_identifier
+		      || DECL_NAME (var) == heap_identifier)
+		    {
+		      DECL_NAME (var) = heap_deleted_identifier;
+		      ctx->values->remove (var);
+		      return void_node;
+		    }
+		  else if (DECL_NAME (var) == heap_deleted_identifier)
+		    {
+		      if (!ctx->quiet)
+			error_at (loc, "deallocation of already deallocated "
+				       "storage");
+		      *non_constant_p = true;
+		      return t;
+		    }
+		}
+	    }
+	}
       if (!ctx->quiet)
 	{
 	  if (!lambda_static_thunk_p (fun))
@@ -2998,8 +3054,8 @@ base_field_constructor_elt (vec<construc
 }
 
 /* Some of the expressions fed to the constexpr mechanism are calls to
-   constructors, which have type void.  In that case, return the type being
-   initialized by the constructor.  */
+   constructors or destructors, which have type void.  In that case,
+   return the type being initialized by the constructor.  */
 
 static tree
 initialized_type (tree t)
@@ -3011,8 +3067,10 @@ initialized_type (tree t)
     {
       /* A constructor call has void type, so we need to look deeper.  */
       tree fn = get_function_named_in_call (t);
-      if (fn && TREE_CODE (fn) == FUNCTION_DECL
-	  && DECL_CXX_CONSTRUCTOR_P (fn))
+      if (fn
+	  && TREE_CODE (fn) == FUNCTION_DECL
+	  && (DECL_CXX_CONSTRUCTOR_P (fn)
+	      || (cxx_dialect >= cxx2a && DECL_CXX_DESTRUCTOR_P (fn))))
 	type = DECL_CONTEXT (fn);
     }
   else if (TREE_CODE (t) == COMPOUND_EXPR)
@@ -3434,11 +3492,24 @@ cxx_fold_indirect_ref (location_t loc, t
 	{
 	  tree field = TYPE_FIELDS (optype);
 	  for (; field; field = DECL_CHAIN (field))
-	    if (TREE_CODE (field) == FIELD_DECL
-		&& TREE_TYPE (field) != error_mark_node
-		&& integer_zerop (byte_position (field))
-		&& similar_type_p (TREE_TYPE (field), type))
+	    if (TREE_CODE (field) != FIELD_DECL
+		|| TREE_TYPE (field) == error_mark_node
+		|| !integer_zerop (byte_position (field)))
+	      continue;
+	    else if (similar_type_p (TREE_TYPE (field), type))
 	      return fold_build3 (COMPONENT_REF, type, op, field, NULL_TREE);
+	    else if (TREE_CODE (TREE_TYPE (field)) == ARRAY_TYPE
+		     && similar_type_p (TREE_TYPE (TREE_TYPE (field)), type))
+	      {
+		tree type_domain = TYPE_DOMAIN (TREE_TYPE (field));
+		tree min_val = size_zero_node;
+		if (type_domain && TYPE_MIN_VALUE (type_domain))
+		  min_val = TYPE_MIN_VALUE (type_domain);
+		op = fold_build3 (COMPONENT_REF, TREE_TYPE (field),
+				  op, field, NULL_TREE);
+		return build4_loc (loc, ARRAY_REF, type, op, min_val,
+				   NULL_TREE, NULL_TREE);
+	      }
 	}
     }
   else if (TREE_CODE (sub) == POINTER_PLUS_EXPR
@@ -3521,12 +3592,44 @@ cxx_fold_indirect_ref (location_t loc, t
 	    {
 	      tree field = TYPE_FIELDS (op00type);
 	      for (; field; field = DECL_CHAIN (field))
-		if (TREE_CODE (field) == FIELD_DECL
-		    && TREE_TYPE (field) != error_mark_node
-		    && tree_int_cst_equal (byte_position (field), op01)
-		    && similar_type_p (TREE_TYPE (field), type))
+		if (TREE_CODE (field) != FIELD_DECL
+		    || TREE_TYPE (field) == error_mark_node)
+		  continue;
+		else if (tree_int_cst_equal (byte_position (field), op01)
+			 && similar_type_p (TREE_TYPE (field), type))
 		  return fold_build3 (COMPONENT_REF, type, op00,
 				      field, NULL_TREE);
+		else if (TREE_CODE (TREE_TYPE (field)) == ARRAY_TYPE
+			 && tree_int_cst_le (byte_position (field), op01)
+			 && similar_type_p (TREE_TYPE (TREE_TYPE (field)),
+					    type))
+		  {
+		    tree type_domain = TYPE_DOMAIN (TREE_TYPE (field));
+		    tree min_val = size_zero_node;
+		    tree max_val = NULL_TREE;
+		    if (type_domain && TYPE_MIN_VALUE (type_domain))
+		      min_val = TYPE_MIN_VALUE (type_domain);
+		    if (type_domain && TYPE_MAX_VALUE (type_domain))
+		      max_val = TYPE_MAX_VALUE (type_domain);
+		    offset_int off = wi::to_offset (op01);
+		    off -= wi::to_offset (byte_position (field));
+		    offset_int el_sz = wi::to_offset (TYPE_SIZE_UNIT (type));
+		    offset_int remainder;
+		    off = wi::divmod_trunc (off, el_sz, SIGNED, &remainder);
+		    if (remainder == 0
+			&& TREE_CODE (min_val) == INTEGER_CST
+			&& (max_val == NULL_TREE
+			    || (TREE_CODE (max_val) == INTEGER_CST
+				&& off <= wi::to_offset (max_val))))
+		      {
+			off = off + wi::to_offset (min_val);
+			op00 = fold_build3 (COMPONENT_REF, TREE_TYPE (field),
+					    op00, field, NULL_TREE);
+			op01 = wide_int_to_tree (sizetype, off);
+			return build4_loc (loc, ARRAY_REF, type, op00, op01,
+					   NULL_TREE, NULL_TREE);
+		      }
+		  }
 	    }
 	}
     }
@@ -3645,7 +3748,23 @@ cxx_eval_indirect_ref (const constexpr_c
 static void
 non_const_var_error (tree r)
 {
+  auto_diagnostic_group d;
   tree type = TREE_TYPE (r);
+  if (DECL_NAME (r) == heap_uninit_identifier
+      || DECL_NAME (r) == heap_identifier)
+    {
+      error ("the content of uninitialized storage is not usable "
+	     "in a constant expression");
+      inform (DECL_SOURCE_LOCATION (r), "allocated here");
+      return;
+    }
+  if (DECL_NAME (r) == heap_deleted_identifier)
+    {
+      error ("use of allocated storage after deallocation in a "
+	     "constant expression");
+      inform (DECL_SOURCE_LOCATION (r), "allocated here");
+      return;
+    }
   error ("the value of %qD is not usable in a constant "
 	 "expression", r);
   /* Avoid error cascade.  */
@@ -3892,6 +4011,15 @@ cxx_eval_store_expression (const constex
     valp = ctx->values->get (object);
   else
     valp = NULL;
+  if (!valp
+      && VAR_P (object)
+      && DECL_NAME (object) == heap_identifier)
+    {
+      tree ctor = build_constructor (type, NULL);
+      CONSTRUCTOR_NO_CLEARING (ctor) = true;
+      ctx->values->put (object, ctor);
+      valp = ctx->values->get (object);
+    }
   if (!valp)
     {
       /* A constant-expression cannot modify objects from outside the
@@ -3905,7 +4033,7 @@ cxx_eval_store_expression (const constex
   bool no_zero_init = true;
 
   releasing_vec ctors;
-  while (!refs->is_empty())
+  while (!refs->is_empty ())
     {
       if (*valp == NULL_TREE)
 	{
@@ -4046,7 +4174,9 @@ cxx_eval_store_expression (const constex
   if (const_object_being_modified)
     {
       bool fail = false;
-      if (!CLASS_TYPE_P (TREE_TYPE (const_object_being_modified)))
+      tree const_objtype
+	= strip_array_types (TREE_TYPE (const_object_being_modified));
+      if (!CLASS_TYPE_P (const_objtype))
 	fail = true;
       else
 	{
@@ -4365,6 +4495,12 @@ cxx_eval_loop_expr (const constexpr_ctx
 		    tree *jump_target)
 {
   constexpr_ctx new_ctx = *ctx;
+  tree local_target;
+  if (!jump_target)
+    {
+      local_target = NULL_TREE;
+      jump_target = &local_target;
+    }
 
   tree body, cond = NULL_TREE, expr = NULL_TREE;
   int count = 0;
@@ -4907,14 +5043,21 @@ cxx_eval_constant_expression (const cons
       break;
 
     case CLEANUP_STMT:
-      r = cxx_eval_constant_expression (ctx, CLEANUP_BODY (t), lval,
+      {
+	tree initial_jump_target = jump_target ? *jump_target : NULL_TREE;
+	r = cxx_eval_constant_expression (ctx, CLEANUP_BODY (t), lval,
+					  non_constant_p, overflow_p,
+					  jump_target);
+	if (!CLEANUP_EH_ONLY (t) && !*non_constant_p)
+	  /* Also evaluate the cleanup.  If we weren't skipping at the
+	     start of the CLEANUP_BODY, change jump_target temporarily
+	     to &initial_jump_target, so that even a return or break or
+	     continue in the body doesn't skip the cleanup.  */
+	  cxx_eval_constant_expression (ctx, CLEANUP_EXPR (t), true,
 					non_constant_p, overflow_p,
-					jump_target);
-      if (!CLEANUP_EH_ONLY (t) && !*non_constant_p)
-	/* Also evaluate the cleanup.  */
-	cxx_eval_constant_expression (ctx, CLEANUP_EXPR (t), true,
-				      non_constant_p, overflow_p,
-				      jump_target);
+					jump_target ? &initial_jump_target
+					: NULL);
+      }
       break;
 
       /* These differ from cxx_eval_unary_expression in that this doesn't
@@ -5203,8 +5346,7 @@ cxx_eval_constant_expression (const cons
 	if (VOID_TYPE_P (type))
 	  return void_node;
 
-	if (TREE_CODE (op) == PTRMEM_CST
-	    && !TYPE_PTRMEM_P (type))
+	if (TREE_CODE (op) == PTRMEM_CST && !TYPE_PTRMEM_P (type))
 	  op = cplus_expand_constant (op);
 
 	if (TREE_CODE (op) == PTRMEM_CST && tcode == NOP_EXPR)
@@ -5258,6 +5400,81 @@ cxx_eval_constant_expression (const cons
 	      }
 	  }
 
+	if (INDIRECT_TYPE_P (type)
+	    && TREE_CODE (op) == NOP_EXPR
+	    && TREE_TYPE (op) == ptr_type_node
+	    && TREE_CODE (TREE_OPERAND (op, 0)) == ADDR_EXPR
+	    && VAR_P (TREE_OPERAND (TREE_OPERAND (op, 0), 0))
+	    && DECL_NAME (TREE_OPERAND (TREE_OPERAND (op, 0),
+					0)) == heap_uninit_identifier)
+	  {
+	    tree var = TREE_OPERAND (TREE_OPERAND (op, 0), 0);
+	    tree var_type = TREE_TYPE (type);
+	    tree cookie_type = NULL_TREE;
+	    bool array_p = false;
+	    HOST_WIDE_INT cookie_size = 0;
+	    if (TREE_CODE (var_type) == ARRAY_TYPE
+		&& TYPE_DOMAIN (var_type) == NULL_TREE)
+	      {
+		var_type = TREE_TYPE (var_type);
+		array_p = true;
+	      }
+	    else if (TREE_CODE (var_type) == RECORD_TYPE
+		     && TYPE_NAME (var_type) == NULL_TREE)
+	      if (tree fld1 = TYPE_FIELDS (var_type))
+		if (TREE_CODE (fld1) == FIELD_DECL
+		    && DECL_NAME (fld1) == NULL_TREE
+		    && DECL_ARTIFICIAL (fld1)
+		    && TREE_CODE (TREE_TYPE (fld1)) == ARRAY_TYPE
+		    && COMPLETE_TYPE_P (TREE_TYPE (fld1)))
+		  if (tree fld2 = DECL_CHAIN (fld1))
+		    if (TREE_CODE (fld2) == FIELD_DECL
+			&& DECL_NAME (fld2) == NULL_TREE
+			&& DECL_ARTIFICIAL (fld2)
+			&& TREE_CODE (TREE_TYPE (fld2)) == ARRAY_TYPE
+			&& TYPE_DOMAIN (TREE_TYPE (fld2)) == NULL_TREE
+			&& DECL_CHAIN (fld2) == NULL_TREE)
+		      {
+			var_type = TREE_TYPE (TREE_TYPE (fld2));
+			array_p = true;
+			cookie_type = TREE_TYPE (fld1);
+			cookie_size = int_size_in_bytes (TREE_TYPE (fld1));
+		      }
+	    HOST_WIDE_INT sz1 = int_size_in_bytes (var_type);
+	    HOST_WIDE_INT sz2 = int_size_in_bytes (TREE_TYPE (var));
+	    if (sz1 <= sz2 && cookie_size <= sz2)
+	      {
+		DECL_NAME (var) = heap_identifier;
+		if (array_p && sz1 > 0)
+		  {
+		    sz2 -= cookie_size;
+		    sz2 /= sz1;
+		    tree idx_type = build_index_type (size_int (sz2 - 1));
+		    var_type = build_cplus_array_type (var_type, idx_type);
+		    if (cookie_type)
+		      {
+			location_t loc = cp_expr_loc_or_input_loc (t);
+			tree vtype = cxx_make_type (RECORD_TYPE);
+			tree fld1 = build_decl (loc, FIELD_DECL, NULL_TREE,
+						cookie_type);
+			tree fld2 = build_decl (loc, FIELD_DECL, NULL_TREE,
+						var_type);
+			DECL_FIELD_CONTEXT (fld1) = vtype;
+			DECL_FIELD_CONTEXT (fld2) = vtype;
+			DECL_ARTIFICIAL (fld1) = true;
+			DECL_ARTIFICIAL (fld2) = true;
+			TYPE_FIELDS (vtype) = fld1;
+			DECL_CHAIN (fld1) = fld2;
+			layout_type (vtype);
+			var_type = vtype;
+		      }
+		  }
+		TREE_TYPE (var) = var_type;
+		TREE_TYPE (TREE_OPERAND (op, 0))
+		  = build_pointer_type (var_type);
+	      }
+	  }
+
 	if (op == oldop && tcode != UNARY_PLUS_EXPR)
 	  /* We didn't fold at the top so we could check for ptr-int
 	     conversion.  */
@@ -5499,6 +5716,7 @@ instantiate_cx_fn_r (tree *tp, int *walk
 
   return NULL_TREE;
 }
+
 static void
 instantiate_constexpr_fns (tree t)
 {
@@ -5507,17 +5725,36 @@ instantiate_constexpr_fns (tree t)
   input_location = loc;
 }
 
+/* Look for heap variables in the expression *TP.  */
+
+static tree
+find_heap_var_refs (tree *tp, int *walk_subtrees, void */*data*/)
+{
+  if (VAR_P (*tp)
+      && (DECL_NAME (*tp) == heap_uninit_identifier
+	  || DECL_NAME (*tp) == heap_identifier
+	  || DECL_NAME (*tp) == heap_deleted_identifier))
+    return *tp;
+
+  if (TYPE_P (*tp))
+    *walk_subtrees = 0;
+  return NULL_TREE;
+}
+
 /* ALLOW_NON_CONSTANT is false if T is required to be a constant expression.
    STRICT has the same sense as for constant_value_1: true if we only allow
    conforming C++ constant expressions, or false if we want a constant value
    even if it doesn't conform.
    MANIFESTLY_CONST_EVAL is true if T is manifestly const-evaluated as
-   per P0595 even when ALLOW_NON_CONSTANT is true.  */
+   per P0595 even when ALLOW_NON_CONSTANT is true.
+   CONSTEXPR_DTOR is true when evaluating the dtor of a constexpr variable.
+   OBJECT must be non-NULL in that case.  */
 
 static tree
 cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant,
 				  bool strict = true,
 				  bool manifestly_const_eval = false,
+				  bool constexpr_dtor = false,
 				  tree object = NULL_TREE)
 {
   auto_timevar time (TV_CONSTEXPR);
@@ -5525,16 +5762,23 @@ cxx_eval_outermost_constant_expr (tree t
   bool non_constant_p = false;
   bool overflow_p = false;
   hash_map<tree,tree> map;
+  auto_vec<tree, 16> heap_vars;
   HOST_WIDE_INT constexpr_ctx_count = 0;
 
   constexpr_ctx ctx = { NULL, &map, NULL, NULL, NULL, NULL,
-			&constexpr_ctx_count, allow_non_constant, strict,
-			manifestly_const_eval || !allow_non_constant };
+			&constexpr_ctx_count, &heap_vars, allow_non_constant,
+			strict, manifestly_const_eval || !allow_non_constant };
 
   tree type = initialized_type (t);
   tree r = t;
   if (VOID_TYPE_P (type))
-    return t;
+    {
+      if (TREE_CODE (t) == BIND_EXPR && constexpr_dtor)
+	/* Used for destructors of array elements.  */
+	type = TREE_TYPE (object);
+      else
+	return t;
+    }
   if (AGGREGATE_TYPE_P (type) || VECTOR_TYPE_P (type))
     {
       /* In C++14 an NSDMI can participate in aggregate initialization,
@@ -5544,8 +5788,22 @@ cxx_eval_outermost_constant_expr (tree t
 	 update ctx.values for the VAR_DECL.  We use the same strategy
 	 for C++11 constexpr constructors that refer to the object being
 	 initialized.  */
-      ctx.ctor = build_constructor (type, NULL);
-      CONSTRUCTOR_NO_CLEARING (ctx.ctor) = true;
+      if (constexpr_dtor)
+	{
+	  gcc_assert (object && VAR_P (object));
+	  gcc_assert (DECL_DECLARED_CONSTEXPR_P (object));
+	  gcc_assert (DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (object));
+	  ctx.ctor = unshare_expr (DECL_INITIAL (object));
+	  TREE_READONLY (ctx.ctor) = false;
+	  /* Temporarily force decl_really_constant_value to return false
+	     for it, we want to use ctx.ctor for the current value instead.  */
+	  DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (object) = false;
+	}
+      else
+	{
+	  ctx.ctor = build_constructor (type, NULL);
+	  CONSTRUCTOR_NO_CLEARING (ctx.ctor) = true;
+	}
       if (!object)
 	{
 	  if (TREE_CODE (t) == TARGET_EXPR)
@@ -5569,13 +5827,15 @@ cxx_eval_outermost_constant_expr (tree t
   r = cxx_eval_constant_expression (&ctx, r,
 				    false, &non_constant_p, &overflow_p);
 
-  verify_constant (r, allow_non_constant, &non_constant_p, &overflow_p);
+  if (!constexpr_dtor)
+    verify_constant (r, allow_non_constant, &non_constant_p, &overflow_p);
+  else
+    DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (object) = true;
 
   /* Mutable logic is a bit tricky: we want to allow initialization of
      constexpr variables with mutable members, but we can't copy those
      members to another constexpr variable.  */
-  if (TREE_CODE (r) == CONSTRUCTOR
-      && CONSTRUCTOR_MUTABLE_POISON (r))
+  if (TREE_CODE (r) == CONSTRUCTOR && CONSTRUCTOR_MUTABLE_POISON (r))
     {
       if (!allow_non_constant)
 	error ("%qE is not a constant expression because it refers to "
@@ -5583,8 +5843,7 @@ cxx_eval_outermost_constant_expr (tree t
       non_constant_p = true;
     }
 
-  if (TREE_CODE (r) == CONSTRUCTOR
-      && CONSTRUCTOR_NO_CLEARING (r))
+  if (TREE_CODE (r) == CONSTRUCTOR && CONSTRUCTOR_NO_CLEARING (r))
     {
       if (!allow_non_constant)
 	error ("%qE is not a constant expression because it refers to "
@@ -5593,6 +5852,32 @@ cxx_eval_outermost_constant_expr (tree t
       non_constant_p = true;
     }
 
+  if (!heap_vars.is_empty ())
+    {
+      tree heap_var = cp_walk_tree_without_duplicates (&r, find_heap_var_refs,
+						       NULL);
+      unsigned int i;
+      if (heap_var)
+	{
+	  if (!allow_non_constant && !non_constant_p)
+	    error_at (DECL_SOURCE_LOCATION (heap_var),
+		      "%qE is not a constant expression because it refers to "
+		      "a result of %<operator new%>", t);
+	  r = t;
+	  non_constant_p = true;
+	}
+      FOR_EACH_VEC_ELT (heap_vars, i, heap_var)
+	if (DECL_NAME (heap_var) != heap_deleted_identifier)
+	  {
+	    if (!allow_non_constant && !non_constant_p)
+	      error_at (DECL_SOURCE_LOCATION (heap_var),
+			"%qE is not a constant expression because allocated "
+			"storage has not been deallocated", t);
+	    r = t;
+	    non_constant_p = true;
+	  }
+    }
+
   /* Technically we should check this for all subexpressions, but that
      runs into problems with our internal representation of pointer
      subtraction and the 5.19 rules are still in flux.  */
@@ -5618,6 +5903,8 @@ cxx_eval_outermost_constant_expr (tree t
 
   if (non_constant_p && !allow_non_constant)
     return error_mark_node;
+  else if (constexpr_dtor)
+    return r;
   else if (non_constant_p && TREE_CONSTANT (r))
     {
       /* If __builtin_is_constant_evaluated () was evaluated to true
@@ -5625,7 +5912,7 @@ cxx_eval_outermost_constant_expr (tree t
 	 punt.  */
       if (manifestly_const_eval)
 	return cxx_eval_outermost_constant_expr (t, true, strict,
-						 false, object);
+						 false, false, object);
       /* This isn't actually constant, so unset TREE_CONSTANT.
 	 Don't clear TREE_CONSTANT on ADDR_EXPR, as the middle-end requires
 	 it to be set if it is invariant address, even when it is not
@@ -5653,7 +5940,7 @@ cxx_eval_outermost_constant_expr (tree t
 	return t;
       else if (TREE_CODE (t) != CONSTRUCTOR)
 	{
-	  r = get_target_expr (r);
+	  r = get_target_expr_sfinae (r, tf_warning_or_error | tf_no_cleanup);
 	  TREE_CONSTANT (r) = true;
 	}
     }
@@ -5668,7 +5955,16 @@ cxx_eval_outermost_constant_expr (tree t
 tree
 cxx_constant_value (tree t, tree decl)
 {
-  return cxx_eval_outermost_constant_expr (t, false, true, true, decl);
+  return cxx_eval_outermost_constant_expr (t, false, true, true, false, decl);
+}
+
+/* Like cxx_constant_value, but used for evaluation of constexpr destructors
+   of constexpr variables.  The actual initializer of DECL is not modified.  */
+
+void
+cxx_constant_dtor (tree t, tree decl)
+{
+  cxx_eval_outermost_constant_expr (t, false, true, true, true, decl);
 }
 
 /* Helper routine for fold_simple function.  Either return simplified
@@ -5772,14 +6068,14 @@ maybe_constant_value (tree t, tree decl,
     return t;
 
   if (manifestly_const_eval)
-    return cxx_eval_outermost_constant_expr (t, true, true, true, decl);
+    return cxx_eval_outermost_constant_expr (t, true, true, true, false, decl);
 
   if (cv_cache == NULL)
     cv_cache = hash_map<tree, tree>::create_ggc (101);
   if (tree *cached = cv_cache->get (t))
     return *cached;
 
-  r = cxx_eval_outermost_constant_expr (t, true, true, false, decl);
+  r = cxx_eval_outermost_constant_expr (t, true, true, false, false, decl);
   gcc_checking_assert (r == t
 		       || CONVERT_EXPR_P (t)
 		       || TREE_CODE (t) == VIEW_CONVERT_EXPR
@@ -5841,7 +6137,7 @@ fold_non_dependent_expr_template (tree t
 
       tree r = cxx_eval_outermost_constant_expr (t, true, true,
 						 manifestly_const_eval,
-						 NULL_TREE);
+						 false, NULL_TREE);
       /* cp_tree_equal looks through NOPs, so allow them.  */
       gcc_checking_assert (r == t
 			   || CONVERT_EXPR_P (t)
@@ -5945,7 +6241,7 @@ maybe_constant_init_1 (tree t, tree decl
   else
     t = cxx_eval_outermost_constant_expr (t, allow_non_constant,
 					  /*strict*/false,
-					  manifestly_const_eval, decl);
+					  manifestly_const_eval, false, decl);
   if (TREE_CODE (t) == TARGET_EXPR)
     {
       tree init = TARGET_EXPR_INITIAL (t);
@@ -6239,7 +6535,12 @@ potential_constant_expression_1 (tree t,
 		if (!DECL_DECLARED_CONSTEXPR_P (fun)
 		    /* Allow any built-in function; if the expansion
 		       isn't constant, we'll deal with that then.  */
-		    && !fndecl_built_in_p (fun))
+		    && !fndecl_built_in_p (fun)
+		    /* In C++2a, replaceable global allocation functions
+		       are constant expressions.  */
+		    && (cxx_dialect < cxx2a
+			|| !IDENTIFIER_NEWDEL_OP_P (DECL_NAME (fun))
+			|| CP_DECL_CONTEXT (fun) != global_namespace))
 		  {
 		    if (flags & tf_error)
 		      {
@@ -6468,6 +6769,9 @@ potential_constant_expression_1 (tree t,
 	goto fail;
       if (!RECUR (TREE_OPERAND (t, 0), any))
 	return false;
+      /* Just ignore clobbers.  */
+      if (TREE_CLOBBER_P (TREE_OPERAND (t, 1)))
+	return true;
       if (!RECUR (TREE_OPERAND (t, 1), rval))
 	return false;
       return true;
@@ -6937,7 +7241,7 @@ potential_constant_expression_1 (tree t,
      return true;
 
     case COND_EXPR:
-      if (COND_EXPR_IS_VEC_DELETE (t))
+      if (COND_EXPR_IS_VEC_DELETE (t) && cxx_dialect < cxx2a)
 	{
 	  if (flags & tf_error)
 	    error_at (loc, "%<delete[]%> is not a constant expression");
@@ -6983,6 +7287,12 @@ potential_constant_expression_1 (tree t,
       return true;
 
     case CLEANUP_STMT:
+      if (!RECUR (CLEANUP_BODY (t), any))
+	return false;
+      if (!CLEANUP_EH_ONLY (t) && !RECUR (CLEANUP_EXPR (t), any))
+	return false;
+      return true;
+
     case EMPTY_CLASS_EXPR:
     case PREDICT_EXPR:
       return false;
--- gcc/cp/decl.c.jj	2019-09-26 21:34:21.673916726 +0200
+++ gcc/cp/decl.c	2019-09-27 18:25:40.898066032 +0200
@@ -4146,6 +4146,9 @@ initialize_predefined_identifiers (void)
     {"value", &value_identifier, cik_normal},
     {"_FUN", &fun_identifier, cik_normal},
     {"__closure", &closure_identifier, cik_normal},
+    {"heap uninit", &heap_uninit_identifier, cik_normal},
+    {"heap ", &heap_identifier, cik_normal},
+    {"heap deleted", &heap_deleted_identifier, cik_normal},
     {NULL, NULL, cik_normal}
   };
 
@@ -7430,7 +7433,11 @@ cp_finish_decl (tree decl, tree init, bo
 	    TREE_READONLY (decl) = 1;
 
 	  /* Likewise if it needs destruction.  */
-	  if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type))
+	  if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type)
+	      && (cxx_dialect < cxx2a
+		  || !DECL_DECLARED_CONSTEXPR_P (decl)
+		  || !type_has_constexpr_destructor
+						(strip_array_types (type))))
 	    TREE_READONLY (decl) = 0;
 	}
 
@@ -8319,6 +8326,27 @@ register_dtor_fn (tree decl)
   if (TYPE_HAS_TRIVIAL_DESTRUCTOR (type))
     return void_node;
 
+  if (cxx_dialect >= cxx2a
+      && DECL_DECLARED_CONSTEXPR_P (decl)
+      && DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl)
+      && type_has_constexpr_destructor (strip_array_types (type)))
+    {
+      int flags = LOOKUP_NORMAL|LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR;
+      tree addr, call;
+
+      if (TREE_CODE (type) == ARRAY_TYPE)
+	addr = decl;
+      else
+	addr = build_address (decl);
+
+      call = build_delete (TREE_TYPE (addr), addr,
+			   sfk_complete_destructor, flags, 0,
+			   tf_warning_or_error);
+      if (call != error_mark_node)
+	cxx_constant_dtor (call, decl);
+      return void_node;
+    }
+
   /* If we're using "__cxa_atexit" (or "__cxa_thread_atexit" or
      "__aeabi_atexit"), and DECL is a class object, we can just pass the
      destructor to "__cxa_atexit"; we don't have to build a temporary
@@ -8432,11 +8460,15 @@ register_dtor_fn (tree decl)
 static void
 expand_static_init (tree decl, tree init)
 {
+  tree type = TREE_TYPE (decl);
   gcc_assert (VAR_P (decl));
   gcc_assert (TREE_STATIC (decl));
 
   /* Some variables require no dynamic initialization.  */
-  if (TYPE_HAS_TRIVIAL_DESTRUCTOR (TREE_TYPE (decl)))
+  if (TYPE_HAS_TRIVIAL_DESTRUCTOR (TREE_TYPE (decl))
+      || (cxx_dialect >= cxx2a
+	  && DECL_DECLARED_CONSTEXPR_P (decl)
+	  && type_has_constexpr_destructor (strip_array_types (type))))
     {
       /* Make sure the destructor is callable.  */
       cxx_maybe_build_cleanup (decl, tf_warning_or_error);
@@ -12702,12 +12734,13 @@ grokdeclarator (const cp_declarator *dec
 			      "a destructor cannot be %<concept%>");
                     return error_mark_node;
                   }
-                if (constexpr_p)
-                  {
-                    error_at (declspecs->locations[ds_constexpr],
-			      "a destructor cannot be %<constexpr%>");
-                    return error_mark_node;
-                  }
+		if (constexpr_p && cxx_dialect < cxx2a)
+		  {
+		    error_at (declspecs->locations[ds_constexpr],
+			      "%<constexpr%> destructors only available"
+			      " with %<-std=c++2a%> or %<-std=gnu++2a%>");
+		    return error_mark_node;
+		  }
 	      }
 	    else if (sfk == sfk_constructor && friendp && !ctype)
 	      {
@@ -12744,10 +12777,11 @@ grokdeclarator (const cp_declarator *dec
 	      }
 
 	    /* Tell grokfndecl if it needs to set TREE_PUBLIC on the node.  */
-	    function_context = (ctype != NULL_TREE) ?
-	      decl_function_context (TYPE_MAIN_DECL (ctype)) : NULL_TREE;
-	    publicp = (! friendp || ! staticp)
-	      && function_context == NULL_TREE;
+	    function_context
+	      = (ctype != NULL_TREE
+		 ? decl_function_context (TYPE_MAIN_DECL (ctype)) : NULL_TREE);
+	    publicp = ((! friendp || ! staticp)
+		       && function_context == NULL_TREE);
 
 	    decl = grokfndecl (ctype, type,
 			       TREE_CODE (unqualified_id) != TEMPLATE_ID_EXPR
@@ -16752,6 +16786,12 @@ cxx_maybe_build_cleanup (tree decl, tsub
 	cleanup = error_mark_node;
       else if (TYPE_HAS_TRIVIAL_DESTRUCTOR (type))
 	/* Discard the call.  */;
+      else if (cxx_dialect >= cxx2a
+	       && VAR_P (decl)
+	       && DECL_DECLARED_CONSTEXPR_P (decl)
+	       && DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl)
+	       && type_has_constexpr_destructor (strip_array_types (type)))
+	cxx_constant_dtor (call, decl);
       else if (cleanup)
 	cleanup = cp_build_compound_expr (cleanup, call, complain);
       else
--- gcc/cp/init.c.jj	2019-09-26 21:34:21.598917851 +0200
+++ gcc/cp/init.c	2019-09-27 19:15:56.473042238 +0200
@@ -33,6 +33,7 @@ along with GCC; see the file COPYING3.
 #include "stringpool.h"
 #include "attribs.h"
 #include "asan.h"
+#include "stor-layout.h"
 
 static bool begin_init_stmts (tree *, tree *);
 static tree finish_init_stmts (bool, tree, tree);
@@ -3332,6 +3333,48 @@ build_new_1 (vec<tree, va_gc> **placemen
 	}
     }
 
+  tree alloc_call_call = extract_call_expr (alloc_call);
+  tree alloc_call_fndecl = NULL_TREE;
+  if (alloc_call_call != error_mark_node)
+    alloc_call_fndecl = cp_get_callee_fndecl_nofold (alloc_call_call);
+  if (array_p
+      && cxx_dialect >= cxx2a
+      && (current_function_decl == NULL_TREE
+	  || DECL_DECLARED_CONSTEXPR_P (current_function_decl))
+      && alloc_call_fndecl
+      && IDENTIFIER_NEW_OP_P (DECL_NAME (alloc_call_fndecl))
+      && CP_DECL_CONTEXT (alloc_call_fndecl) == global_namespace)
+    {
+      /* Help the constexpr code to find the right type for the heap variable
+	 by adding a NOP_EXPR around alloc_call.
+	 If not using cookies, use array type, otherwise structure with
+	 two array types.  */
+      tree atype = build_cplus_array_type (elt_type, NULL_TREE);
+      if (cookie_size)
+	{
+	  gcc_assert (tree_fits_uhwi_p (cookie_size));
+	  unsigned HOST_WIDE_INT sz = tree_to_uhwi (cookie_size);
+	  sz /= int_size_in_bytes (sizetype);
+	  tree atype2 = build_index_type (size_int (sz - 1));
+	  atype2 = build_cplus_array_type (sizetype, atype2);
+	  tree atype3 = cxx_make_type (RECORD_TYPE);
+	  tree fld1 = build_decl (input_location, FIELD_DECL, NULL_TREE,
+				  atype2);
+	  tree fld2 = build_decl (input_location, FIELD_DECL, NULL_TREE,
+				  atype);
+	  DECL_FIELD_CONTEXT (fld1) = atype3;
+	  DECL_FIELD_CONTEXT (fld2) = atype3;
+	  DECL_ARTIFICIAL (fld1) = true;
+	  DECL_ARTIFICIAL (fld2) = true;
+	  TYPE_FIELDS (atype3) = fld1;
+	  DECL_CHAIN (fld1) = fld2;
+	  layout_type (atype3);
+	  atype = atype3;
+	}
+      pointer_type = build_pointer_type (atype);
+      alloc_call = build_nop (pointer_type, alloc_call);
+    }
+
   /* In the simple case, we can stop now.  */
   pointer_type = build_pointer_type (type);
   if (!cookie_size && !is_initialized)
@@ -3905,17 +3948,11 @@ build_vec_delete_1 (tree base, tree maxi
 			     fold_convert (sizetype, maxindex));
 
   tbase = create_temporary_var (ptype);
-  tbase_init
-    = cp_build_modify_expr (input_location, tbase, NOP_EXPR,
-			    fold_build_pointer_plus_loc (input_location,
-							 fold_convert (ptype,
-								       base),
-							 virtual_size),
-			    complain);
-  if (tbase_init == error_mark_node)
-    return error_mark_node;
-  controller = build3 (BIND_EXPR, void_type_node, tbase,
-		       NULL_TREE, NULL_TREE);
+  DECL_INITIAL (tbase)
+    = fold_build_pointer_plus_loc (input_location, fold_convert (ptype, base),
+				   virtual_size);
+  tbase_init = build_stmt (input_location, DECL_EXPR, tbase);
+  controller = build3 (BIND_EXPR, void_type_node, tbase, NULL_TREE, NULL_TREE);
   TREE_SIDE_EFFECTS (controller) = 1;
 
   body = build1 (EXIT_EXPR, void_type_node,
--- gcc/cp/method.c.jj	2019-09-26 21:34:21.331921851 +0200
+++ gcc/cp/method.c	2019-09-27 18:25:40.902065972 +0200
@@ -30,6 +30,7 @@ along with GCC; see the file COPYING3.
 #include "cgraph.h"
 #include "varasm.h"
 #include "toplev.h"
+#include "intl.h"
 #include "common/common-target.h"
 
 static void do_build_copy_assign (tree);
@@ -1237,12 +1238,24 @@ is_xible (enum tree_code code, tree to,
   return !!expr;
 }
 
+/* Categorize various special_function_kinds.  */
+#define SFK_CTOR_P(sfk) \
+  ((sfk) >= sfk_constructor && (sfk) <= sfk_move_constructor)
+#define SFK_DTOR_P(sfk) \
+  ((sfk) == sfk_destructor || (sfk) == sfk_virtual_destructor)
+#define SFK_ASSIGN_P(sfk) \
+  ((sfk) == sfk_copy_assignment || (sfk) == sfk_move_assignment)
+#define SFK_COPY_P(sfk) \
+  ((sfk) == sfk_copy_constructor || (sfk) == sfk_copy_assignment)
+#define SFK_MOVE_P(sfk) \
+  ((sfk) == sfk_move_constructor || (sfk) == sfk_move_assignment)
+
 /* Subroutine of synthesized_method_walk.  Update SPEC_P, TRIVIAL_P and
    DELETED_P or give an error message MSG with argument ARG.  */
 
 static void
-process_subob_fn (tree fn, tree *spec_p, bool *trivial_p,
-		  bool *deleted_p, bool *constexpr_p,
+process_subob_fn (tree fn, special_function_kind sfk, tree *spec_p,
+		  bool *trivial_p, bool *deleted_p, bool *constexpr_p,
 		  bool diag, tree arg, bool dtor_from_ctor = false)
 {
   if (!fn || fn == error_mark_node)
@@ -1283,24 +1296,15 @@ process_subob_fn (tree fn, tree *spec_p,
       if (diag)
 	{
 	  inform (DECL_SOURCE_LOCATION (fn),
-		  "defaulted constructor calls non-%<constexpr%> %qD", fn);
+		  SFK_DTOR_P (sfk)
+		  ? G_("destructor calls non-%<constexpr%> %qD")
+		  : G_("defaulted constructor calls non-%<constexpr%> %qD"),
+		  fn);
 	  explain_invalid_constexpr_fn (fn);
 	}
     }
 }
 
-/* Categorize various special_function_kinds.  */
-#define SFK_CTOR_P(sfk) \
-  ((sfk) >= sfk_constructor && (sfk) <= sfk_move_constructor)
-#define SFK_DTOR_P(sfk) \
-  ((sfk) == sfk_destructor || (sfk) == sfk_virtual_destructor)
-#define SFK_ASSIGN_P(sfk) \
-  ((sfk) == sfk_copy_assignment || (sfk) == sfk_move_assignment)
-#define SFK_COPY_P(sfk) \
-  ((sfk) == sfk_copy_constructor || (sfk) == sfk_copy_assignment)
-#define SFK_MOVE_P(sfk) \
-  ((sfk) == sfk_move_constructor || (sfk) == sfk_move_assignment)
-
 /* Subroutine of synthesized_method_walk to allow recursion into anonymous
    aggregates.  If DTOR_FROM_CTOR is true, we're walking subobject destructors
    called from a synthesized constructor, in which case we don't consider
@@ -1318,8 +1322,7 @@ walk_field_subobs (tree fields, special_
     {
       tree mem_type, argtype, rval;
 
-      if (TREE_CODE (field) != FIELD_DECL
-	  || DECL_ARTIFICIAL (field))
+      if (TREE_CODE (field) != FIELD_DECL || DECL_ARTIFICIAL (field))
 	continue;
 
       /* Variant members only affect deletedness.  In particular, they don't
@@ -1457,7 +1460,7 @@ walk_field_subobs (tree fields, special_
 
       rval = locate_fn_flags (mem_type, fnname, argtype, flags, complain);
 
-      process_subob_fn (rval, spec_p, trivial_p, deleted_p,
+      process_subob_fn (rval, sfk, spec_p, trivial_p, deleted_p,
 			constexpr_p, diag, field, dtor_from_ctor);
     }
 }
@@ -1510,23 +1513,23 @@ synthesized_method_base_walk (tree binfo
       && DECL_CONTEXT (*inheriting_ctor) == DECL_CONTEXT (rval))
     *inheriting_ctor = DECL_CLONED_FUNCTION (rval);
 
-  process_subob_fn (rval, spec_p, trivial_p, deleted_p,
+  process_subob_fn (rval, sfk, spec_p, trivial_p, deleted_p,
 		    constexpr_p, diag, BINFO_TYPE (base_binfo));
-  if (SFK_CTOR_P (sfk) &&
-      (!BINFO_VIRTUAL_P (base_binfo)
-       || TYPE_HAS_NONTRIVIAL_DESTRUCTOR (BINFO_TYPE (base_binfo))))
+  if (SFK_CTOR_P (sfk)
+      && (!BINFO_VIRTUAL_P (base_binfo)
+	  || TYPE_HAS_NONTRIVIAL_DESTRUCTOR (BINFO_TYPE (base_binfo))))
     {
       /* In a constructor we also need to check the subobject
 	 destructors for cleanup of partially constructed objects.  */
       tree dtor = locate_fn_flags (base_binfo, complete_dtor_identifier,
 				   NULL_TREE, flags,
 				   diag ? tf_warning_or_error : tf_none);
-	  /* Note that we don't pass down trivial_p; the subobject
-	     destructors don't affect triviality of the constructor.  Nor
-	     do they affect constexpr-ness (a constant expression doesn't
-	     throw) or exception-specification (a throw from one of the
-	     dtors would be a double-fault).  */
-      process_subob_fn (dtor, NULL, NULL, deleted_p, NULL, false,
+      /* Note that we don't pass down trivial_p; the subobject
+	 destructors don't affect triviality of the constructor.  Nor
+	 do they affect constexpr-ness (a constant expression doesn't
+	 throw) or exception-specification (a throw from one of the
+	 dtors would be a double-fault).  */
+      process_subob_fn (dtor, sfk, NULL, NULL, deleted_p, NULL, false,
 			BINFO_TYPE (base_binfo), /*dtor_from_ctor*/true);
     }
 
@@ -1608,7 +1611,8 @@ synthesized_method_walk (tree ctype, spe
 	member is a constexpr function.  */
   if (constexpr_p)
     *constexpr_p = (SFK_CTOR_P (sfk)
-		    || (SFK_ASSIGN_P (sfk) && cxx_dialect >= cxx14));
+		    || (SFK_ASSIGN_P (sfk) && cxx_dialect >= cxx14)
+		    || (SFK_DTOR_P (sfk) && cxx_dialect >= cxx2a));
 
   bool expected_trivial = type_has_trivial_fn (ctype, sfk);
   if (trivial_p)
@@ -1704,8 +1708,8 @@ synthesized_method_walk (tree ctype, spe
   else if (vec_safe_is_empty (vbases))
     /* No virtual bases to worry about.  */;
   else if (ABSTRACT_CLASS_TYPE_P (ctype) && cxx_dialect >= cxx14
-	   /* DR 1658 specifis that vbases of abstract classes are
-	      ignored for both ctors and dtors.  Except DR 2338
+	   /* DR 1658 specifies that vbases of abstract classes are
+	      ignored for both ctors and dtors.  Except DR 2336
 	      overrides that skipping when determing the eh-spec of a
 	      virtual destructor.  */
 	   && sfk != sfk_virtual_destructor)
@@ -2046,7 +2050,8 @@ implicitly_declare_fn (special_function_
     constexpr_p = false;
   /* A trivial copy/move constructor is also a constexpr constructor,
      unless the class has virtual bases (7.1.5p4).  */
-  else if (trivial_p && cxx_dialect >= cxx11
+  else if (trivial_p
+	   && cxx_dialect >= cxx11
 	   && (kind == sfk_copy_constructor
 	       || kind == sfk_move_constructor)
 	   && !CLASSTYPE_VBASECLASSES (type))
--- gcc/cp/typeck2.c.jj	2019-09-26 21:34:26.299847376 +0200
+++ gcc/cp/typeck2.c	2019-09-27 18:25:40.899066017 +0200
@@ -902,7 +902,13 @@ store_init_value (tree decl, tree init,
 	    value = oldval;
 	}
     }
-  value = cp_fully_fold_init (value);
+  /* Don't fold initializers of automatic variables in constexpr functions,
+     that might fold away something that needs to be diagnosed at constexpr
+     evaluation time.  */
+  if (!current_function_decl
+      || !DECL_DECLARED_CONSTEXPR_P (current_function_decl)
+      || TREE_STATIC (decl))
+    value = cp_fully_fold_init (value);
 
   /* Handle aggregate NSDMI in non-constant initializers, too.  */
   value = replace_placeholders (value, decl);
--- gcc/testsuite/g++.dg/cpp0x/constexpr-delete2.C.jj	2016-03-05 07:46:49.554128302 +0100
+++ gcc/testsuite/g++.dg/cpp0x/constexpr-delete2.C	2019-09-27 20:26:06.317971681 +0200
@@ -5,8 +5,9 @@ struct A { ~A(); };
 constexpr int f(int i) { return i; }
 constexpr int g(A* ap)
 {
-  return f((delete[] ap, 42)); // { dg-message "" }
+  return f((delete[] ap, 42)); // { dg-message "" "" { target c++17_down } }
 }
 
 A a;
 constexpr int i = g(&a);	// { dg-error "" }
+				// { dg-message "in 'constexpr' expansion of" "" { target c++2a } .-1 }
--- gcc/testsuite/g++.dg/cpp0x/locations1.C.jj	2019-09-26 21:34:22.205908750 +0200
+++ gcc/testsuite/g++.dg/cpp0x/locations1.C	2019-09-27 18:25:41.346059343 +0200
@@ -11,7 +11,7 @@ struct S
 {
   virtual S();  // { dg-error "3:constructors cannot be declared .virtual." }
   constexpr int s = 1;  // { dg-error "3:non-static data member .s. declared .constexpr." }
-  constexpr ~S();  // { dg-error "3:a destructor cannot be .constexpr." }
+  constexpr ~S();  // { dg-error "3:'constexpr' destructors only available with" "" { target c++17_down } }
 };
 
 typedef constexpr int my_int;  // { dg-error "9:.constexpr. cannot appear in a typedef declaration" }
--- gcc/testsuite/g++.dg/cpp1y/constexpr-new.C.jj	2019-09-26 21:34:22.281907610 +0200
+++ gcc/testsuite/g++.dg/cpp1y/constexpr-new.C	2019-09-27 18:25:41.303059984 +0200
@@ -4,7 +4,7 @@ constexpr int *f4(bool b) {
   if (b) {
     return nullptr;
   } else {
-    return new int{42}; // { dg-error "call to non-.constexpr." }
+    return new int{42}; // { dg-error "call to non-.constexpr." "" { target c++17_down } }
   }
 }
 static_assert(f4(true) == nullptr, "");
--- gcc/testsuite/g++.dg/cpp2a/constexpr-dtor1.C.jj	2019-09-27 18:25:41.320059731 +0200
+++ gcc/testsuite/g++.dg/cpp2a/constexpr-dtor1.C	2019-09-27 18:25:41.320059731 +0200
@@ -0,0 +1,9 @@
+// P0784R7
+// { dg-do compile { target c++11 } }
+
+struct S
+{
+  constexpr S () : s (0) {}
+  constexpr ~S () {}	// { dg-error "'constexpr' destructors only available with" "" { target c++17_down } }
+  int s;
+};
--- gcc/testsuite/g++.dg/cpp2a/constexpr-dtor2.C.jj	2019-09-27 18:25:41.303059984 +0200
+++ gcc/testsuite/g++.dg/cpp2a/constexpr-dtor2.C	2019-09-27 18:25:41.303059984 +0200
@@ -0,0 +1,66 @@
+// P0784R7
+// { dg-do compile { target c++2a } }
+
+struct S
+{
+  constexpr S () : r (4), s (3) { --r; s -= 2; }
+  constexpr ~S () { if (s == 1) s = 0; else asm (""); if (s == 0 && r == 3) r = 0; else asm (""); }
+  int r, s;
+};
+struct T : public S
+{
+  constexpr T () : t (2) {}
+  int t;
+  S u;
+};
+struct U : public S
+{
+  constexpr U (int x) : u (x) {}
+  constexpr ~U () = default;
+  int u;
+  S v;
+};
+
+constexpr S a;
+constexpr T b;
+constexpr U c = 3;
+static_assert (a.s == 1 && a.r == 3);
+static_assert (b.s == 1 && b.r == 3 && b.t == 2 && b.u.s == 1 && b.u.r == 3);
+static_assert (c.s == 1 && c.r == 3 && c.u == 3 && c.v.s == 1 && c.v.r == 3);
+
+void
+foo ()
+{
+  static constexpr S d;
+  static constexpr T e;
+  static constexpr U f = 4;
+  static_assert (d.s == 1 && d.r == 3);
+  static_assert (e.s == 1 && e.r == 3 && e.t == 2 && e.u.s == 1 && e.u.r == 3);
+  static_assert (f.s == 1 && f.r == 3 && f.u == 4 && f.v.s == 1 && f.v.r == 3);
+  if (1)
+    {
+      constexpr S g;
+      constexpr T h;
+      constexpr U i = 5;
+      static_assert (g.s == 1 && g.r == 3);
+      static_assert (h.s == 1 && h.r == 3 && h.t == 2 && h.u.s == 1 && h.u.r == 3);
+      static_assert (i.s == 1 && i.r == 3 && i.u == 5 && i.v.s == 1 && i.v.r == 3);
+    }
+}
+
+constexpr bool
+bar ()
+{
+  S j;
+  T k;
+  U l = 6;
+  if (j.s != 1 || j.r != 3)
+    return false;
+  if (k.s != 1 || k.r != 3 || k.t != 2 || k.u.s != 1 || k.u.r != 3)
+    return false;
+  if (l.s != 1 || l.r != 3 || l.u != 6 || l.v.s != 1 || l.v.r != 3)
+    return false;
+  return true;
+}
+
+static_assert (bar ());
--- gcc/testsuite/g++.dg/cpp2a/constexpr-dtor3.C.jj	2019-09-27 18:25:41.303059984 +0200
+++ gcc/testsuite/g++.dg/cpp2a/constexpr-dtor3.C	2019-09-27 18:25:41.303059984 +0200
@@ -0,0 +1,185 @@
+// P0784R7
+// { dg-do compile { target c++2a } }
+
+struct S
+{
+  constexpr S () : s (0) {}
+  constexpr ~S () {}
+  int s;
+};
+struct T	// { dg-message "'T' is not literal because" }
+{		// { dg-message "'T' does not have 'constexpr' destructor" "" { target *-*-* } .-1 }
+  constexpr T () : t (0) {}
+  ~T () {}	// { dg-message "destructor calls non-'constexpr' 'T::~T\\(\\)'" }
+  int t;
+};
+struct U : public S
+{
+  constexpr U () : u (0) {}
+  constexpr ~U () = default;	// { dg-error "explicitly defaulted function 'constexpr U::~U\\(\\)' cannot be declared 'constexpr' because the implicit declaration is not 'constexpr'" }
+  int u;
+  T t;
+};
+struct V : virtual public S
+{
+  V () : v (0) {}
+  constexpr ~V () = default;	// { dg-error "explicitly defaulted function 'constexpr V::~V\\(\\)' cannot be declared 'constexpr' because the implicit declaration is not 'constexpr'" }
+  int v;
+};
+struct W0
+{
+  constexpr W0 () : w (0) {}
+  constexpr W0 (int x) : w (x) {}
+  constexpr ~W0 () { if (w == 5) asm (""); w = 3; }
+  int w;
+};
+struct W1
+{
+  constexpr W1 () : w (0) {}
+  constexpr W1 (int x) : w (x) {}
+  constexpr ~W1 () { if (w == 5) asm (""); w = 3; }	// { dg-error "inline assembly is not a constant expression" }
+							// { dg-message "only unevaluated inline assembly is allowed in a 'constexpr' function" "" { target *-*-* } .-1 }
+  int w;
+};
+struct W2
+{
+  constexpr W2 () : w (0) {}
+  constexpr W2 (int x) : w (x) {}
+  constexpr ~W2 () { if (w == 5) asm (""); w = 3; }	// { dg-error "inline assembly is not a constant expression" }
+							// { dg-message "only unevaluated inline assembly is allowed in a 'constexpr' function" "" { target *-*-* } .-1 }
+  int w;
+};
+struct W3
+{
+  constexpr W3 () : w (0) {}
+  constexpr W3 (int x) : w (x) {}
+  constexpr ~W3 () { if (w == 5) asm (""); w = 3; }	// { dg-error "inline assembly is not a constant expression" }
+							// { dg-message "only unevaluated inline assembly is allowed in a 'constexpr' function" "" { target *-*-* } .-1 }
+  int w;
+};
+struct W4
+{
+  constexpr W4 () : w (0) {}
+  constexpr W4 (int x) : w (x) {}
+  constexpr ~W4 () { if (w == 5) asm (""); w = 3; }	// { dg-error "inline assembly is not a constant expression" }
+							// { dg-message "only unevaluated inline assembly is allowed in a 'constexpr' function" "" { target *-*-* } .-1 }
+  int w;
+};
+struct W5
+{
+  constexpr W5 () : w (0) {}
+  constexpr W5 (int x) : w (x) {}
+  constexpr ~W5 () { if (w == 5) asm (""); w = 3; }	// { dg-error "inline assembly is not a constant expression" }
+							// { dg-message "only unevaluated inline assembly is allowed in a 'constexpr' function" "" { target *-*-* } .-1 }
+  int w;
+};
+struct W6
+{
+  constexpr W6 () : w (0) {}
+  constexpr W6 (int x) : w (x) {}
+  constexpr ~W6 () { if (w == 5) asm (""); w = 3; }	// { dg-error "inline assembly is not a constant expression" }
+							// { dg-message "only unevaluated inline assembly is allowed in a 'constexpr' function" "" { target *-*-* } .-1 }
+  int w;
+};
+struct W7
+{
+  constexpr W7 () : w (0) {}
+  constexpr W7 (int x) : w (x) {}
+  constexpr ~W7 () { if (w == 5) asm (""); w = 3; }	// { dg-error "inline assembly is not a constant expression" }
+							// { dg-message "only unevaluated inline assembly is allowed in a 'constexpr' function" "" { target *-*-* } .-1 }
+  int w;
+};
+struct W8
+{
+  constexpr W8 () : w (0) {}
+  constexpr W8 (int x) : w (x) {}
+  constexpr ~W8 () { if (w == 5) asm (""); w = 3; }	// { dg-error "inline assembly is not a constant expression" }
+							// { dg-message "only unevaluated inline assembly is allowed in a 'constexpr' function" "" { target *-*-* } .-1 }
+  int w;
+};
+struct X : public T
+{
+  constexpr X () : x (0) {}
+  constexpr ~X () = default;	// { dg-error "explicitly defaulted function 'constexpr X::~X\\(\\)' cannot be declared 'constexpr' because the implicit declaration is not 'constexpr'" }
+  int x;
+};
+constexpr S s;
+constexpr T t;	// { dg-error "the type 'const T' of 'constexpr' variable 't' is not literal" }
+constexpr W0 w1;
+constexpr W0 w2 = 12;
+constexpr W1 w3 = 5;	// { dg-message "in 'constexpr' expansion of" }
+constexpr W0 w4[3] = { 1, 2, 3 };
+constexpr W2 w5[3] = { 4, 5, 6 };	// { dg-message "in 'constexpr' expansion of" }
+
+void
+f1 ()
+{
+  constexpr S s2;
+  constexpr W0 w6;
+  constexpr W0 w7 = 12;
+  constexpr W3 w8 = 5;	// { dg-message "in 'constexpr' expansion of" }
+  constexpr W0 w9[3] = { 1, 2, 3 };
+  constexpr W4 w10[3] = { 4, 5, 6 };	// { dg-message "in 'constexpr' expansion of" }
+}
+
+constexpr int
+f2 ()
+{
+  constexpr S s3;
+  constexpr W0 w11;
+  constexpr W0 w12 = 12;
+  constexpr W5 w13 = 5;	// { dg-message "in 'constexpr' expansion of" }
+  constexpr W0 w14[3] = { 1, 2, 3 };
+  constexpr W6 w15[3] = { 4, 5, 6 };	// { dg-message "in 'constexpr' expansion of" }
+  return 0;
+}
+
+constexpr int
+f3 ()
+{
+  S s3;
+  W0 w11;
+  W0 w12 = 12;
+  W0 w14[3] = { 1, 2, 3 };
+  return 0;
+}
+
+constexpr int x3 = f3 ();
+
+constexpr int
+f4 ()
+{
+  W7 w13 = 5;
+  return 0;
+}
+
+constexpr int x4 = f4 ();	// { dg-message "in 'constexpr' expansion of" }
+
+constexpr int
+f5 ()
+{
+  W8 w15[3] = { 4, 5, 6 };	// { dg-message "in 'constexpr' expansion of" }
+  return 0;
+}
+
+constexpr int x5 = f5 ();	// { dg-message "in 'constexpr' expansion of" }
+
+void
+f6 ()
+{
+  constexpr T t2;	// { dg-error "the type 'const T' of 'constexpr' variable 't2' is not literal" }
+}
+
+constexpr int
+f7 ()
+{
+  constexpr T t3;	// { dg-error "the type 'const T' of 'constexpr' variable 't3' is not literal" }
+  return 0;
+}
+
+constexpr int
+f8 ()
+{
+  T t4;			// { dg-error "variable 't4' of non-literal type 'T' in 'constexpr' function" }
+  return 0;
+}
--- gcc/testsuite/g++.dg/cpp2a/constexpr-new1.C.jj	2019-09-27 18:25:41.320059731 +0200
+++ gcc/testsuite/g++.dg/cpp2a/constexpr-new1.C	2019-09-27 20:06:50.047298452 +0200
@@ -0,0 +1,39 @@
+// P0784R7
+// { dg-do compile { target c++2a } }
+
+struct S { constexpr S () : s (5) {} constexpr S (int x) : s (x) {} int s; };
+
+constexpr bool
+foo ()
+{
+  int r = 0;
+  S *p = new S ();
+  p->s += 3;
+  r += p->s;
+  delete p;
+  p = new S (12);
+  p->s = p->s * 2;
+  r += p->s;
+  delete p;
+  int *q = new int;
+  *q = 25;
+  r += *q;
+  delete q;
+  q = new int (1);
+  r += *q;
+  if (!q)
+    return false;
+  delete q;
+  q = new int[5]{1,2,3,4,5};
+  r += q[0] + q[4];
+  delete[] q;
+  q = new int[4];
+  q[0] = 6;
+  q[1] = 7;
+  q[3] = 8;
+  r += q[0] + q[1] + q[3];
+  delete[] q;
+  return r == 5 + 3 + 2 * 12 + 25 + 1 + 1 + 5 + 6 + 7 + 8;
+}
+constexpr bool a = foo ();
+static_assert (a);
--- gcc/testsuite/g++.dg/cpp2a/constexpr-new2.C.jj	2019-09-27 18:25:41.320059731 +0200
+++ gcc/testsuite/g++.dg/cpp2a/constexpr-new2.C	2019-09-27 20:23:16.107524585 +0200
@@ -0,0 +1,21 @@
+// P0784R7
+// { dg-do compile { target c++2a } }
+
+template <int N>
+constexpr bool
+foo (const char (&x)[N])
+{
+  int **p = new int *[N];
+  for (int i = 0; i < N; i++)
+    p[i] = new int (x[i]);
+  for (int i = 0; i < N; i++)
+    if (*p[i] != x[i])
+      return false;
+  for (int i = 0; i < N; ++i)
+    delete p[i];
+  delete[] p;
+  return true;
+}
+
+constexpr bool a = foo ("foobar");
+static_assert (a);
--- gcc/testsuite/g++.dg/cpp2a/constexpr-new3.C.jj	2019-09-27 18:25:41.320059731 +0200
+++ gcc/testsuite/g++.dg/cpp2a/constexpr-new3.C	2019-09-27 18:25:41.320059731 +0200
@@ -0,0 +1,63 @@
+// P0784R7
+// { dg-do compile { target c++2a } }
+
+constexpr int *
+f1 ()
+{
+  return new int (2);		// { dg-error "is not a constant expression because it refers to a result of 'operator new'" }
+}
+
+constexpr auto v1 = f1 ();
+
+constexpr bool
+f2 ()
+{
+  int *p = new int (3);		// { dg-error "is not a constant expression because allocated storage has not been deallocated" }
+  return false;
+}
+
+constexpr auto v2 = f2 ();
+
+constexpr bool
+f3 ()
+{
+  int *p = new int (3);
+  int *q = p;
+  delete p;
+  delete q;			// { dg-error "deallocation of already deallocated storage" }
+  return false;
+}
+
+constexpr auto v3 = f3 ();	// { dg-message "in 'constexpr' expansion of" }
+
+constexpr bool
+f4 (int *p)
+{
+  delete p;			// { dg-error "call to non-'constexpr' function" }
+  return false;
+}
+
+int q;
+constexpr auto v4 = f4 (&q);	// { dg-message "in 'constexpr' expansion of" }
+
+constexpr bool
+f5 ()
+{
+  int *p = new int;		// { dg-message "allocated here" }
+  return *p == 1;
+}
+
+constexpr auto v5 = f5 ();	// { dg-error "the content of uninitialized storage is not usable in a constant expression" }
+				// { dg-message "in 'constexpr' expansion of" "" { target *-*-* } .-1 }
+
+constexpr bool
+f6 ()
+{
+  int *p = new int (2);		// { dg-message "allocated here" }
+  int *q = p;
+  delete p;
+  return *q == 2;
+}
+
+constexpr auto v6 = f6 ();	// { dg-error "use of allocated storage after deallocation in a constant expression" }
+				// { dg-message "in 'constexpr' expansion of" "" { target *-*-* } .-1  }
--- gcc/testsuite/g++.dg/cpp2a/constexpr-new4.C.jj	2019-09-27 18:25:41.319059745 +0200
+++ gcc/testsuite/g++.dg/cpp2a/constexpr-new4.C	2019-09-27 20:07:33.928641928 +0200
@@ -0,0 +1,29 @@
+// P0784R7
+// { dg-do compile { target c++2a } }
+
+struct S
+{
+  constexpr S () : s (0) { s++; }
+  constexpr S (int x) : s (x) { s += 2; }
+  constexpr ~S () { if (s != 35) asm (""); s = 5; }
+  int s;
+};
+
+constexpr bool
+foo ()
+{
+  S *p = new S (7);
+  if (p->s != 9) return false;
+  p->s = 35;
+  delete p;
+  p = new S[3] { 11, 13, 15 };
+  if (p[0].s != 13 || p[1].s != 15 || p[2].s != 17) return false;
+  p[0].s = 35;
+  p[2].s = 35;
+  p[1].s = 35;
+  delete[] p;
+  return true;
+}
+
+constexpr bool a = foo ();
+static_assert (a);
--- gcc/testsuite/g++.dg/cpp2a/feat-cxx2a.C.jj	2019-09-26 21:34:22.341906710 +0200
+++ gcc/testsuite/g++.dg/cpp2a/feat-cxx2a.C	2019-09-27 18:25:41.319059745 +0200
@@ -430,16 +430,34 @@
 
 // C++20 features
 
-#if __cpp_conditional_explicit != 201806
-# error "__cpp_conditional_explicit != 201806"
+#ifndef __cpp_conditional_explicit
+#  error "__cpp_conditional_explicit"
+#elif __cpp_conditional_explicit != 201806
+#  error "__cpp_conditional_explicit != 201806"
 #endif
 
-#if __cpp_nontype_template_parameter_class != 201806
-# error "__cpp_nontype_template_parameter_class != 201806"
+#ifndef __cpp_nontype_template_parameter_class
+#  error "__cpp_nontype_template_parameter_class"
+#elif __cpp_nontype_template_parameter_class != 201806
+#  error "__cpp_nontype_template_parameter_class != 201806"
 #endif
 
-#if __cpp_impl_destroying_delete != 201806
-# error "__cpp_impl_destroying_delete != 201806"
+#ifndef __cpp_impl_destroying_delete
+#  error "__cpp_impl_destroying_delete"
+#elif __cpp_impl_destroying_delete != 201806
+#  error "__cpp_impl_destroying_delete != 201806"
+#endif
+
+#ifndef __cpp_constinit
+#  error "__cpp_constinit"
+#elif __cpp_constinit != 201907
+#  error "__cpp_constinit != 201907"
+#endif
+
+#ifndef __cpp_constexpr_dynamic_alloc
+#  error "__cpp_constexpr_dynamic_alloc"
+#elif __cpp_constexpr_dynamic_alloc != 201907
+#  error "__cpp_constexpr_dynamic_alloc != 201907"
 #endif
 
 #ifdef __has_cpp_attribute
@@ -484,8 +502,6 @@
 #  error "__has_cpp_attribute"
 #endif
 
-// C++2A features:
-
 #ifndef __cpp_char8_t
 #  error "__cpp_char8_t"
 #elif __cpp_char8_t != 201811
--- gcc/testsuite/g++.dg/ext/is_literal_type3.C.jj	2019-09-27 18:25:40.904065942 +0200
+++ gcc/testsuite/g++.dg/ext/is_literal_type3.C	2019-09-27 18:25:40.904065942 +0200
@@ -0,0 +1,26 @@
+// { dg-do compile { target c++11 } }
+
+struct S {
+  constexpr S () : n{} { }
+  ~S () { n = 1; }
+  int n;
+};
+
+static_assert(!__is_literal_type(S), "");
+
+#ifdef __cpp_constexpr_dynamic_alloc
+struct T {
+  constexpr T () : n{} { }
+  constexpr ~T () { n = 1; }
+  int n;
+};
+
+static_assert(__is_literal_type(T), "");
+
+struct U : public T {
+  constexpr U () : u{} { }
+  int u;
+};
+
+static_assert(__is_literal_type(U), "");
+#endif
