]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/cp/constexpr.c
Update copyright years.
[thirdparty/gcc.git] / gcc / cp / constexpr.c
index a6a55b940dd691a18ba10ce61d152a414249557c..c8852bd93090e3f6e8cb725d46b9364ab392b04e 100644 (file)
@@ -2,7 +2,7 @@
    constexpr functions.  These routines are used both during actual parsing
    and during the instantiation of template functions.
 
-   Copyright (C) 1998-2019 Free Software Foundation, Inc.
+   Copyright (C) 1998-2020 Free Software Foundation, Inc.
 
    This file is part of GCC.
 
@@ -34,6 +34,7 @@ along with GCC; see the file COPYING3.  If not see
 #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)                                             \
@@ -766,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)
@@ -814,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)
@@ -880,16 +885,16 @@ register_constexpr_fundef (tree fun, tree body)
       return NULL;
     }
 
-  if (!potential_rvalue_constant_expression (massaged))
-    {
-      if (!DECL_GENERATED_P (fun))
-       require_potential_rvalue_constant_expression (massaged);
-      return NULL;
-    }
+  bool potential = potential_rvalue_constant_expression (massaged);
+  if (!potential && !DECL_GENERATED_P (fun))
+    require_potential_rvalue_constant_expression (massaged);
 
   if (DECL_CONSTRUCTOR_P (fun)
       && cx_check_missing_mem_inits (DECL_CONTEXT (fun),
                                     massaged, !DECL_GENERATED_P (fun)))
+    potential = false;
+
+  if (!potential && !DECL_GENERATED_P (fun))
     return NULL;
 
   /* Create the constexpr function table if necessary.  */
@@ -912,6 +917,12 @@ register_constexpr_fundef (tree fun, tree body)
   if (clear_ctx)
     DECL_CONTEXT (DECL_RESULT (fun)) = NULL_TREE;
 
+  if (!potential)
+    /* For a template instantiation, we want to remember the pre-generic body
+       for explain_invalid_constexpr_fn, but do tell cxx_eval_call_expression
+       that it doesn't need to bother trying to expand the function.  */
+    entry.result = error_mark_node;
+
   gcc_assert (*slot == NULL);
   *slot = ggc_alloc<constexpr_fundef> ();
   **slot = entry;
@@ -933,7 +944,10 @@ explain_invalid_constexpr_fn (tree fun)
   if (!DECL_DEFAULTED_FN (fun)
       && !LAMBDA_TYPE_P (CP_DECL_CONTEXT (fun))
       && !is_instantiation_of_constexpr (fun))
-    return;
+    {
+      inform (DECL_SOURCE_LOCATION (fun), "%qD declared here", fun);
+      return;
+    }
   if (diagnosed == NULL)
     diagnosed = new hash_set<tree>;
   if (diagnosed->add (fun))
@@ -954,11 +968,15 @@ explain_invalid_constexpr_fn (tree fun)
     {
       /* Then if it's OK, the body.  */
       if (!DECL_DECLARED_CONSTEXPR_P (fun)
-         && !LAMBDA_TYPE_P (CP_DECL_CONTEXT (fun)))
+         && DECL_DEFAULTED_FN (fun))
        explain_implicit_non_constexpr (fun);
       else
        {
-         body = massage_constexpr_body (fun, DECL_SAVED_TREE (fun));
+         if (constexpr_fundef *fd = retrieve_constexpr_fundef (fun))
+           body = fd->body;
+         else
+           body = DECL_SAVED_TREE (fun);
+         body = massage_constexpr_body (fun, body);
          require_potential_rvalue_constant_expression (body);
          if (DECL_CONSTRUCTOR_P (fun))
            cx_check_missing_mem_inits (DECL_CONTEXT (fun), body, true);
@@ -1006,19 +1024,39 @@ enum constexpr_switch_state {
   css_default_processing
 };
 
+/* The constexpr expansion context part which needs one instance per
+   cxx_eval_outermost_constant_expr invocation.  VALUES is a map of values of
+   variables initialized within the expression.  */
+
+struct constexpr_global_ctx {
+  /* Values for any temporaries or local variables within the
+     constant-expression. */
+  hash_map<tree,tree> values;
+  /* Number of cxx_eval_constant_expression calls (except skipped ones,
+     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.  */
+  auto_vec<tree, 16> heap_vars;
+  /* Cleanups that need to be evaluated at the end of CLEANUP_POINT_EXPR.  */
+  vec<tree> *cleanups;
+  /* Constructor.  */
+  constexpr_global_ctx () : constexpr_ops_count (0), cleanups (NULL) {}
+};
+
 /* The constexpr expansion context.  CALL is the current function
    expansion, CTOR is the current aggregate initializer, OBJECT is the
-   object being initialized by CTOR, either a VAR_DECL or a _REF.  VALUES
-   is a map of values of variables initialized within the expression.  */
+   object being initialized by CTOR, either a VAR_DECL or a _REF.    */
 
 struct constexpr_ctx {
+  /* The part of the context that needs to be unique to the whole
+     cxx_eval_outermost_constant_expr invocation.  */
+  constexpr_global_ctx *global;
   /* The innermost call we're evaluating.  */
   constexpr_call *call;
-  /* Values for any temporaries or local variables within the
-     constant-expression. */
-  hash_map<tree,tree> *values;
-  /* SAVE_EXPRs that we've seen within the current LOOP_EXPR.  NULL if we
-     aren't inside a loop.  */
+  /* SAVE_EXPRs and TARGET_EXPR_SLOT vars of TARGET_EXPRs that we've seen
+     within the current LOOP_EXPR.  NULL if we aren't inside a loop.  */
   vec<tree> *save_exprs;
   /* The CONSTRUCTOR we're currently building up for an aggregate
      initializer.  */
@@ -1027,10 +1065,6 @@ struct constexpr_ctx {
   tree object;
   /* If inside SWITCH_EXPR.  */
   constexpr_switch_state *css_state;
-  /* Number of cxx_eval_constant_expression calls (except skipped ones,
-     on simple constants or location wrappers) encountered during current
-     cxx_eval_outermost_constant_expr call.  */
-  HOST_WIDE_INT *constexpr_ops_count;
 
   /* Whether we should error on a non-constant expression or fail quietly.  */
   bool quiet;
@@ -1220,6 +1254,9 @@ cxx_eval_builtin_function_call (const constexpr_ctx *ctx, tree t, tree fun,
       return boolean_true_node;
     }
 
+  if (fndecl_built_in_p (fun, CP_BUILT_IN_SOURCE_LOCATION, BUILT_IN_FRONTEND))
+    return fold_builtin_source_location (EXPR_LOCATION (t));
+
   /* Be permissive for arguments to built-ins; __builtin_constant_p should
      return constant false for a non-constant argument.  */
   constexpr_ctx new_ctx = *ctx;
@@ -1245,7 +1282,7 @@ cxx_eval_builtin_function_call (const constexpr_ctx *ctx, tree t, tree fun,
     }
 
   bool save_ffbcp = force_folding_builtin_constant_p;
-  force_folding_builtin_constant_p = true;
+  force_folding_builtin_constant_p |= ctx->manifestly_const_eval;
   tree save_cur_fn = current_function_decl;
   /* Return name of ctx->call->fundef->decl for __builtin_FUNCTION ().  */
   if (fndecl_built_in_p (fun, BUILT_IN_FUNCTION)
@@ -1414,15 +1451,32 @@ cxx_bind_parameters_in_call (const constexpr_ctx *ctx, tree t,
 
       if (!*non_constant_p)
        {
-         /* Unsharing here isn't necessary for correctness, but it
-            significantly improves memory performance for some reason.  */
-         arg = unshare_constructor (arg);
          /* Make sure the binding has the same type as the parm.  But
             only for constant args.  */
          if (!TYPE_REF_P (type))
            arg = adjust_temp_type (type, arg);
          if (!TREE_CONSTANT (arg))
            *non_constant_args = true;
+         /* For virtual calls, adjust the this argument, so that it is
+            the object on which the method is called, rather than
+            one of its bases.  */
+         if (i == 0 && DECL_VIRTUAL_P (fun))
+           {
+             tree addr = arg;
+             STRIP_NOPS (addr);
+             if (TREE_CODE (addr) == ADDR_EXPR)
+               {
+                 tree obj = TREE_OPERAND (addr, 0);
+                 while (TREE_CODE (obj) == COMPONENT_REF
+                        && DECL_FIELD_IS_BASE (TREE_OPERAND (obj, 1))
+                        && !same_type_ignoring_top_level_qualifiers_p
+                                       (TREE_TYPE (obj), DECL_CONTEXT (fun)))
+                   obj = TREE_OPERAND (obj, 0);
+                 if (obj != TREE_OPERAND (addr, 0))
+                   arg = build_fold_addr_expr_with_type (obj,
+                                                         TREE_TYPE (arg));
+               }
+           }
          TREE_VEC_ELT (binds, i) = arg;
        }
       parms = TREE_CHAIN (parms);
@@ -1578,6 +1632,305 @@ modifying_const_object_error (tree expr, tree obj)
   inform (location_of (obj), "originally declared %<const%> here");
 }
 
+/* Return true if FNDECL is a replaceable global allocation function that
+   should be useable during constant expression evaluation.  */
+
+static inline bool
+cxx_replaceable_global_alloc_fn (tree fndecl)
+{
+  return (cxx_dialect >= cxx2a
+         && IDENTIFIER_NEWDEL_OP_P (DECL_NAME (fndecl))
+         && CP_DECL_CONTEXT (fndecl) == global_namespace
+         && (DECL_IS_REPLACEABLE_OPERATOR_NEW_P (fndecl)
+             || DECL_IS_OPERATOR_DELETE_P (fndecl)));
+}
+
+/* Return true if FNDECL is a placement new function that should be
+   useable during constant expression evaluation of std::construct_at.  */
+
+static inline bool
+cxx_placement_new_fn (tree fndecl)
+{
+  if (cxx_dialect >= cxx2a
+      && IDENTIFIER_NEW_OP_P (DECL_NAME (fndecl))
+      && CP_DECL_CONTEXT (fndecl) == global_namespace
+      && !DECL_IS_REPLACEABLE_OPERATOR_NEW_P (fndecl)
+      && TREE_CODE (TREE_TYPE (fndecl)) == FUNCTION_TYPE)
+    {
+      tree first_arg = TREE_CHAIN (TYPE_ARG_TYPES (TREE_TYPE (fndecl)));
+      if (TREE_VALUE (first_arg) == ptr_type_node
+         && TREE_CHAIN (first_arg) == void_list_node)
+       return true;
+    }
+  return false;
+}
+
+/* Return true if FNDECL is std::construct_at.  */
+
+static inline bool
+is_std_construct_at (tree fndecl)
+{
+  if (!decl_in_std_namespace_p (fndecl))
+    return false;
+
+  tree name = DECL_NAME (fndecl);
+  return name && id_equal (name, "construct_at");
+}
+
+/* Return true if FNDECL is std::allocator<T>::{,de}allocate.  */
+
+static inline bool
+is_std_allocator_allocate (tree fndecl)
+{
+  tree name = DECL_NAME (fndecl);
+  if (name == NULL_TREE
+      || !(id_equal (name, "allocate") || id_equal (name, "deallocate")))
+    return false;
+
+  tree ctx = DECL_CONTEXT (fndecl);
+  if (ctx == NULL_TREE || !CLASS_TYPE_P (ctx) || !TYPE_MAIN_DECL (ctx))
+    return false;
+
+  tree decl = TYPE_MAIN_DECL (ctx);
+  name = DECL_NAME (decl);
+  if (name == NULL_TREE || !id_equal (name, "allocator"))
+    return false;
+
+  return decl_in_std_namespace_p (decl);
+}
+
+/* Return true if FNDECL is __dynamic_cast.  */
+
+static inline bool
+cxx_dynamic_cast_fn_p (tree fndecl)
+{
+  return (cxx_dialect >= cxx2a
+         && id_equal (DECL_NAME (fndecl), "__dynamic_cast")
+         && CP_DECL_CONTEXT (fndecl) == global_namespace);
+}
+
+/* Often, we have an expression in the form of address + offset, e.g.
+   "&_ZTV1A + 16".  Extract the object from it, i.e. "_ZTV1A".  */
+
+static tree
+extract_obj_from_addr_offset (tree expr)
+{
+  if (TREE_CODE (expr) == POINTER_PLUS_EXPR)
+    expr = TREE_OPERAND (expr, 0);
+  STRIP_NOPS (expr);
+  if (TREE_CODE (expr) == ADDR_EXPR)
+    expr = TREE_OPERAND (expr, 0);
+  return expr;
+}
+
+/* Given a PATH like
+
+     g.D.2181.D.2154.D.2102.D.2093
+
+   find a component with type TYPE.  Return NULL_TREE if not found, and
+   error_mark_node if the component is not accessible.  If STOP is non-null,
+   this function will return NULL_TREE if STOP is found before TYPE.  */
+
+static tree
+get_component_with_type (tree path, tree type, tree stop)
+{
+  while (true)
+    {
+      if (same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (path), type))
+       /* Found it.  */
+       return path;
+      else if (stop
+              && (same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (path),
+                                                             stop)))
+       return NULL_TREE;
+      else if (TREE_CODE (path) == COMPONENT_REF
+              && DECL_FIELD_IS_BASE (TREE_OPERAND (path, 1)))
+       {
+         /* We need to check that the component we're accessing is in fact
+            accessible.  */
+         if (TREE_PRIVATE (TREE_OPERAND (path, 1))
+             || TREE_PROTECTED (TREE_OPERAND (path, 1)))
+           return error_mark_node;
+         path = TREE_OPERAND (path, 0);
+       }
+      else
+       return NULL_TREE;
+    }
+}
+
+/* Evaluate a call to __dynamic_cast (permitted by P1327R1).
+
+   The declaration of __dynamic_cast is:
+
+   void* __dynamic_cast (const void* __src_ptr,
+                        const __class_type_info* __src_type,
+                        const __class_type_info* __dst_type,
+                        ptrdiff_t __src2dst);
+
+   where src2dst has the following possible values
+
+   >-1: src_type is a unique public non-virtual base of dst_type
+       dst_ptr + src2dst == src_ptr
+   -1: unspecified relationship
+   -2: src_type is not a public base of dst_type
+   -3: src_type is a multiple public non-virtual base of dst_type
+
+  Since literal types can't have virtual bases, we only expect hint >=0,
+  -2, or -3.  */
+
+static tree
+cxx_eval_dynamic_cast_fn (const constexpr_ctx *ctx, tree call,
+                         bool *non_constant_p, bool *overflow_p)
+{
+  /* T will be something like
+      __dynamic_cast ((B*) b, &_ZTI1B, &_ZTI1D, 8)
+     dismantle it.  */
+  gcc_assert (call_expr_nargs (call) == 4);
+  tsubst_flags_t complain = ctx->quiet ? tf_none : tf_warning_or_error;
+  tree obj = CALL_EXPR_ARG (call, 0);
+  tree type = CALL_EXPR_ARG (call, 2);
+  HOST_WIDE_INT hint = int_cst_value (CALL_EXPR_ARG (call, 3));
+  location_t loc = cp_expr_loc_or_input_loc (call);
+
+  /* Get the target type of the dynamic_cast.  */
+  gcc_assert (TREE_CODE (type) == ADDR_EXPR);
+  type = TREE_OPERAND (type, 0);
+  type = TREE_TYPE (DECL_NAME (type));
+
+  /* TYPE can only be either T* or T&.  We can't know which of these it
+     is by looking at TYPE, but OBJ will be "(T*) x" in the first case,
+     and something like "(T*)(T&)(T*) x" in the second case.  */
+  bool reference_p = false;
+  while (CONVERT_EXPR_P (obj) || TREE_CODE (obj) == SAVE_EXPR)
+    {
+      reference_p |= TYPE_REF_P (TREE_TYPE (obj));
+      obj = TREE_OPERAND (obj, 0);
+    }
+
+  /* Evaluate the object so that we know its dynamic type.  */
+  obj = cxx_eval_constant_expression (ctx, obj, /*lval*/false, non_constant_p,
+                                     overflow_p);
+  if (*non_constant_p)
+    return call;
+
+  /* We expect OBJ to be in form of &d.D.2102 when HINT == 0,
+     but when HINT is > 0, it can also be something like
+     &d.D.2102 + 18446744073709551608, which includes the BINFO_OFFSET.  */
+  obj = extract_obj_from_addr_offset (obj);
+  const tree objtype = TREE_TYPE (obj);
+  /* If OBJ doesn't refer to a base field, we're done.  */
+  if (tree t = (TREE_CODE (obj) == COMPONENT_REF
+               ? TREE_OPERAND (obj, 1) : obj))
+    if (TREE_CODE (t) != FIELD_DECL || !DECL_FIELD_IS_BASE (t))
+      return integer_zero_node;
+
+  /* [class.cdtor] When a dynamic_cast is used in a constructor ...
+     or in a destructor ... if the operand of the dynamic_cast refers
+     to the object under construction or destruction, this object is
+     considered to be a most derived object that has the type of the
+     constructor or destructor's class.  */
+  tree vtable = build_vfield_ref (obj, TREE_TYPE (obj));
+  vtable = cxx_eval_constant_expression (ctx, vtable, /*lval*/false,
+                                        non_constant_p, overflow_p);
+  if (*non_constant_p)
+    return call;
+  /* VTABLE will be &_ZTV1A + 16 or similar, get _ZTV1A.  */
+  vtable = extract_obj_from_addr_offset (vtable);
+  const tree mdtype = DECL_CONTEXT (vtable);
+
+  /* Given dynamic_cast<T>(v),
+
+     [expr.dynamic.cast] If C is the class type to which T points or refers,
+     the runtime check logically executes as follows:
+
+     If, in the most derived object pointed (referred) to by v, v points
+     (refers) to a public base class subobject of a C object, and if only
+     one object of type C is derived from the subobject pointed (referred)
+     to by v the result points (refers) to that C object.
+
+     In this case, HINT >= 0 or -3.  */
+  if (hint >= 0 || hint == -3)
+    {
+      /* Look for a component with type TYPE.  */
+      tree t = get_component_with_type (obj, type, mdtype);
+      /* If not accessible, give an error.  */
+      if (t == error_mark_node)
+       {
+         if (reference_p)
+           {
+             if (!ctx->quiet)
+               {
+                 error_at (loc, "reference %<dynamic_cast%> failed");
+                 inform (loc, "static type %qT of its operand is a "
+                         "non-public base class of dynamic type %qT",
+                         objtype, type);
+
+               }
+             *non_constant_p = true;
+           }
+         return integer_zero_node;
+       }
+      else if (t)
+       /* The result points to the TYPE object.  */
+       return cp_build_addr_expr (t, complain);
+      /* Else, TYPE was not found, because the HINT turned out to be wrong.
+        Fall through to the normal processing.  */
+    }
+
+  /* Otherwise, if v points (refers) to a public base class subobject of the
+     most derived object, and the type of the most derived object has a base
+     class, of type C, that is unambiguous and public, the result points
+     (refers) to the C subobject of the most derived object.
+
+     But it can also be an invalid case.  */
+      
+  /* Get the most derived object.  */
+  obj = get_component_with_type (obj, mdtype, NULL_TREE);
+  if (obj == error_mark_node)
+    {
+      if (reference_p)
+       {
+         if (!ctx->quiet)
+           {
+             error_at (loc, "reference %<dynamic_cast%> failed");
+             inform (loc, "static type %qT of its operand is a non-public"
+                     " base class of dynamic type %qT", objtype, mdtype);
+           }
+         *non_constant_p = true;
+       }
+      return integer_zero_node;
+    }
+  else
+    gcc_assert (obj);
+
+  /* Check that the type of the most derived object has a base class
+     of type TYPE that is unambiguous and public.  */
+  base_kind b_kind;
+  tree binfo = lookup_base (mdtype, type, ba_check, &b_kind, tf_none);
+  if (!binfo || binfo == error_mark_node)
+    {
+      if (reference_p)
+       {
+         if (!ctx->quiet)
+           {
+             error_at (loc, "reference %<dynamic_cast%> failed");
+             if (b_kind == bk_ambig)
+               inform (loc, "%qT is an ambiguous base class of dynamic "
+                       "type %qT of its operand", type, mdtype);
+             else
+               inform (loc, "dynamic type %qT of its operand does not "
+                       "have an unambiguous public base class %qT",
+                       mdtype, type);
+           }
+         *non_constant_p = true;
+       }
+      return integer_zero_node;
+    }
+  /* If so, return the TYPE subobject of the most derived object.  */
+  obj = convert_to_base_statically (obj, binfo);
+  return cp_build_addr_expr (obj, complain);
+}
+
 /* Subroutine of cxx_eval_constant_expression.
    Evaluate the call expression tree T in the context of OLD_CALL expression
    evaluation.  */
@@ -1587,6 +1940,10 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
                          bool lval,
                          bool *non_constant_p, bool *overflow_p)
 {
+  /* Handle concept checks separately.  */
+  if (concept_check_p (t))
+    return evaluate_concept_check (t, tf_warning_or_error);
+
   location_t loc = cp_expr_loc_or_input_loc (t);
   tree fun = get_function_named_in_call (t);
   constexpr_call new_call
@@ -1656,6 +2013,92 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
                                           lval, non_constant_p, overflow_p);
   if (!DECL_DECLARED_CONSTEXPR_P (fun))
     {
+      if (TREE_CODE (t) == CALL_EXPR
+         && cxx_replaceable_global_alloc_fn (fun)
+         && (CALL_FROM_NEW_OR_DELETE_P (t)
+             || (ctx->call
+                 && ctx->call->fundef
+                 && is_std_allocator_allocate (ctx->call->fundef->decl))))
+       {
+         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->global->heap_vars.safe_push (var);
+             ctx->global->values.put (var, NULL_TREE);
+             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->global->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)
+               error_at (loc, "deallocation of storage that was "
+                              "not previously allocated");
+             *non_constant_p = true;
+             return t;
+           }
+       }
+      /* Allow placement new in std::construct_at, just return the second
+        argument.  */
+      if (TREE_CODE (t) == CALL_EXPR
+         && cxx_placement_new_fn (fun)
+         && ctx->call
+         && ctx->call->fundef
+         && is_std_construct_at (ctx->call->fundef->decl))
+       {
+         const int nargs = call_expr_nargs (t);
+         tree arg1 = 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 == 1)
+               arg1 = arg;
+           }
+         gcc_assert (arg1);
+         return arg1;
+       }
+      else if (cxx_dynamic_cast_fn_p (fun))
+       return cxx_eval_dynamic_cast_fn (ctx, t, non_constant_p, overflow_p);
+
       if (!ctx->quiet)
        {
          if (!lambda_static_thunk_p (fun))
@@ -1675,7 +2118,7 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
       new_ctx.object = AGGR_INIT_EXPR_SLOT (t);
       tree ctor = new_ctx.ctor = build_constructor (DECL_CONTEXT (fun), NULL);
       CONSTRUCTOR_NO_CLEARING (ctor) = true;
-      ctx->values->put (new_ctx.object, ctor);
+      ctx->global->values.put (new_ctx.object, ctor);
       ctx = &new_ctx;
     }
 
@@ -1721,6 +2164,7 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
     {
       new_call.fundef = retrieve_constexpr_fundef (fun);
       if (new_call.fundef == NULL || new_call.fundef->body == NULL
+         || new_call.fundef->result == error_mark_node
          || fun == current_function_decl)
         {
          if (!ctx->quiet)
@@ -1758,19 +2202,11 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
      this function exits.  */
   class free_bindings
   {
+    tree *bindings;
   public:
-    tree &bindings;
-    bool do_free;
-    free_bindings (tree &b): bindings (b), do_free(true) { }
-    void preserve () { do_free = false; }
-    ~free_bindings () {
-      if (do_free)
-       {
-         for (int i = 0; i < TREE_VEC_LENGTH (bindings); ++i)
-           free_constructor (TREE_VEC_ELT (bindings, i));
-         ggc_free (bindings);
-       }
-    }
+    free_bindings (tree &b): bindings (&b) { }
+    ~free_bindings () { if (bindings) ggc_free (*bindings); }
+    void preserve () { bindings = NULL; }
   } fb (new_call.bindings);
 
   if (*non_constant_p)
@@ -1873,11 +2309,22 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
          for (int i = 0; i < TREE_VEC_LENGTH (bound); ++i)
            {
              tree arg = TREE_VEC_ELT (bound, i);
-             /* Don't share a CONSTRUCTOR that might be changed.  */
+             if (entry)
+               {
+                 /* Unshare args going into the hash table to separate them
+                    from the caller's context, for better GC and to avoid
+                    problems with verify_gimple.  */
+                 arg = unshare_expr_without_location (arg);
+                 TREE_VEC_ELT (bound, i) = arg;
+               }
+             /* Don't share a CONSTRUCTOR that might be changed.  This is not
+                redundant with the unshare just above; we also don't want to
+                change the argument values in the hash table.  XXX Could we
+                unshare lazily in cxx_eval_store_expression?  */
              arg = unshare_constructor (arg);
              if (TREE_CODE (arg) == CONSTRUCTOR)
                vec_safe_push (ctors, arg);
-             ctx->values->put (remapped, arg);
+             ctx->global->values.put (remapped, arg);
              remapped = DECL_CHAIN (remapped);
            }
          /* Add the RESULT_DECL to the values map, too.  */
@@ -1887,14 +2334,14 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
              slot = AGGR_INIT_EXPR_SLOT (t);
              tree addr = build_address (slot);
              addr = build_nop (TREE_TYPE (res), addr);
-             ctx->values->put (res, addr);
-             ctx->values->put (slot, NULL_TREE);
+             ctx->global->values.put (res, addr);
+             ctx->global->values.put (slot, NULL_TREE);
            }
          else
-           ctx->values->put (res, NULL_TREE);
+           ctx->global->values.put (res, NULL_TREE);
 
-         /* Track the callee's evaluated SAVE_EXPRs so that we can forget
-            their values after the call.  */
+         /* Track the callee's evaluated SAVE_EXPRs and TARGET_EXPRs so that
+            we can forget their values after the call.  */
          constexpr_ctx ctx_with_save_exprs = *ctx;
          auto_vec<tree, 10> save_exprs;
          ctx_with_save_exprs.save_exprs = &save_exprs;
@@ -1916,7 +2363,7 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
            result = void_node;
          else
            {
-             result = *ctx->values->get (slot ? slot : res);
+             result = *ctx->global->values.get (slot ? slot : res);
              if (result == NULL_TREE && !*non_constant_p)
                {
                  if (!ctx->quiet)
@@ -1934,8 +2381,8 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
              && CLASS_TYPE_P (TREE_TYPE (new_obj))
              && CP_TYPE_CONST_P (TREE_TYPE (new_obj)))
            {
-             /* Subobjects might not be stored in ctx->values but we can
-                get its CONSTRUCTOR by evaluating *this.  */
+             /* Subobjects might not be stored in ctx->global->values but we
+                can get its CONSTRUCTOR by evaluating *this.  */
              tree e = cxx_eval_constant_expression (ctx, new_obj,
                                                     /*lval*/false,
                                                     non_constant_p,
@@ -1943,21 +2390,22 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
              TREE_READONLY (e) = true;
            }
 
-         /* Forget the saved values of the callee's SAVE_EXPRs.  */
+         /* Forget the saved values of the callee's SAVE_EXPRs and
+            TARGET_EXPRs.  */
          unsigned int i;
          tree save_expr;
          FOR_EACH_VEC_ELT (save_exprs, i, save_expr)
-           ctx_with_save_exprs.values->remove (save_expr);
+           ctx->global->values.remove (save_expr);
 
          /* Remove the parms/result from the values map.  Is it worth
             bothering to do this when the map itself is only live for
             one constexpr evaluation?  If so, maybe also clear out
             other vars from call, maybe in BIND_EXPR handling?  */
-         ctx->values->remove (res);
+         ctx->global->values.remove (res);
          if (slot)
-           ctx->values->remove (slot);
+           ctx->global->values.remove (slot);
          for (tree parm = parms; parm; parm = TREE_CHAIN (parm))
-           ctx->values->remove (parm);
+           ctx->global->values.remove (parm);
 
          /* Free any parameter CONSTRUCTORs we aren't returning directly.  */
          while (!ctors->is_empty ())
@@ -1981,15 +2429,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)
@@ -2011,6 +2470,12 @@ 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)));
        }
@@ -2024,14 +2489,20 @@ reduced_constant_expression_p (tree t)
            return false;
          if (field)
            {
-             if (idx != field)
-               return false;
+             /* Empty class field may or may not have an initializer.  */
+             for (; idx != field;
+                  field = next_initializable_field (DECL_CHAIN (field)))
+               if (!is_really_empty_class (TREE_TYPE (field),
+                                           /*ignore_vptr*/false))
+                 return false;
              field = next_initializable_field (DECL_CHAIN (field));
            }
        }
-      if (field)
-       return false;
-      else if (CONSTRUCTOR_NO_CLEARING (t))
+      /* There could be a non-empty field at the end.  */
+      for (; field; field = next_initializable_field (DECL_CHAIN (field)))
+       if (!is_really_empty_class (TREE_TYPE (field), /*ignore_vptr*/false))
+         return false;
+      if (CONSTRUCTOR_NO_CLEARING (t))
        /* All the fields are initialized.  */
        CONSTRUCTOR_NO_CLEARING (t) = false;
       return true;
@@ -2312,6 +2783,12 @@ cxx_eval_binary_expression (const constexpr_ctx *ctx, tree t,
   else if (code == POINTER_PLUS_EXPR)
     r = cxx_fold_pointer_plus_expression (ctx, t, lhs, rhs, non_constant_p,
                                          overflow_p);
+  else if (code == SPACESHIP_EXPR)
+    {
+      r = genericize_spaceship (type, lhs, rhs);
+      r = cxx_eval_constant_expression (ctx, r, false, non_constant_p,
+                                       overflow_p);
+    }
 
   if (r == NULL_TREE)
     r = fold_binary_loc (loc, code, type, lhs, rhs);
@@ -2805,7 +3282,10 @@ cxx_eval_component_reference (const constexpr_ctx *ctx, tree t,
          : field == part)
        {
          if (value)
-           return value;
+           {
+             STRIP_ANY_LOCATION_WRAPPER (value);
+             return value;
+           }
          else
            /* We're in the middle of initializing it.  */
            break;
@@ -2895,6 +3375,7 @@ cxx_eval_bit_field_ref (const constexpr_ctx *ctx, tree t,
   FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (whole), i, field, value)
     {
       tree bitpos = bit_position (field);
+      STRIP_ANY_LOCATION_WRAPPER (value);
       if (bitpos == start && DECL_SIZE (field) == TREE_OPERAND (t, 1))
        return value;
       if (TREE_CODE (TREE_TYPE (field)) == INTEGER_TYPE
@@ -3077,7 +3558,7 @@ verify_ctor_sanity (const constexpr_ctx *ctx, tree type)
                          (TREE_TYPE (type), TREE_TYPE (otype)))));
     }
   gcc_assert (!ctx->object || !DECL_P (ctx->object)
-             || *(ctx->values->get (ctx->object)) == ctx->ctor);
+             || *(ctx->global->values.get (ctx->object)) == ctx->ctor);
 }
 
 /* Subroutine of cxx_eval_constant_expression.
@@ -3346,6 +3827,103 @@ same_type_ignoring_tlq_and_bounds_p (tree type1, tree type2)
   return same_type_ignoring_top_level_qualifiers_p (type1, type2);
 }
 
+/* Helper function for cxx_fold_indirect_ref_1, called recursively.  */
+
+static tree
+cxx_fold_indirect_ref_1 (location_t loc, tree type, tree op,
+                        unsigned HOST_WIDE_INT off, bool *empty_base)
+{
+  tree optype = TREE_TYPE (op);
+  unsigned HOST_WIDE_INT const_nunits;
+  if (off == 0)
+    {
+      if (similar_type_p (optype, type))
+       return op;
+      /* Also handle conversion to an empty base class, which
+        is represented with a NOP_EXPR.  */
+      /* *(foo *)&complexfoo => __real__ complexfoo */
+      else if (TREE_CODE (optype) == COMPLEX_TYPE
+              && similar_type_p (type, TREE_TYPE (optype)))
+       return build1_loc (loc, REALPART_EXPR, type, op);
+    }
+  /* ((foo*)&complexfoo)[1] => __imag__ complexfoo */
+  else if (TREE_CODE (optype) == COMPLEX_TYPE
+          && similar_type_p (type, TREE_TYPE (optype))
+          && tree_to_uhwi (TYPE_SIZE_UNIT (type)) == off)
+    return build1_loc (loc, IMAGPART_EXPR, type, op);
+  if (is_empty_class (type)
+      && CLASS_TYPE_P (optype)
+      && DERIVED_FROM_P (type, optype))
+    {
+      *empty_base = true;
+      return op;
+    }
+  /* ((foo*)&vectorfoo)[x] => BIT_FIELD_REF<vectorfoo,...> */
+  else if (VECTOR_TYPE_P (optype)
+          && similar_type_p (type, TREE_TYPE (optype))
+          && TYPE_VECTOR_SUBPARTS (optype).is_constant (&const_nunits))
+    {
+      unsigned HOST_WIDE_INT part_width = tree_to_uhwi (TYPE_SIZE_UNIT (type));
+      unsigned HOST_WIDE_INT max_offset = part_width * const_nunits;
+      if (off < max_offset && off % part_width == 0)
+       {
+         tree index = bitsize_int (off * BITS_PER_UNIT);
+         return build3_loc (loc, BIT_FIELD_REF, type, op,
+                            TYPE_SIZE (type), index);
+       }
+    }
+  /* ((foo *)&fooarray)[x] => fooarray[x] */
+  else if (TREE_CODE (optype) == ARRAY_TYPE
+          && tree_fits_uhwi_p (TYPE_SIZE_UNIT (TREE_TYPE (optype)))
+          && !integer_zerop (TYPE_SIZE_UNIT (TREE_TYPE (optype))))
+    {
+      tree type_domain = TYPE_DOMAIN (optype);
+      tree min_val = size_zero_node;
+      if (type_domain && TYPE_MIN_VALUE (type_domain))
+       min_val = TYPE_MIN_VALUE (type_domain);
+      unsigned HOST_WIDE_INT el_sz
+       = tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (optype)));
+      unsigned HOST_WIDE_INT idx = off / el_sz;
+      unsigned HOST_WIDE_INT rem = off % el_sz;
+      if (tree_fits_uhwi_p (min_val))
+       {
+         tree index = size_int (idx + tree_to_uhwi (min_val));
+         op = build4_loc (loc, ARRAY_REF, TREE_TYPE (optype), op, index,
+                          NULL_TREE, NULL_TREE);
+         return cxx_fold_indirect_ref_1 (loc, type, op, rem,
+                                         empty_base);
+       }
+    }
+  /* ((foo *)&struct_with_foo_field)[x] => COMPONENT_REF */
+  else if (TREE_CODE (optype) == RECORD_TYPE)
+    {
+      for (tree field = TYPE_FIELDS (optype);
+          field; field = DECL_CHAIN (field))
+       if (TREE_CODE (field) == FIELD_DECL
+           && TREE_TYPE (field) != error_mark_node
+           && tree_fits_uhwi_p (TYPE_SIZE_UNIT (TREE_TYPE (field))))
+         {
+           tree pos = byte_position (field);
+           if (!tree_fits_uhwi_p (pos))
+             continue;
+           unsigned HOST_WIDE_INT upos = tree_to_uhwi (pos);
+           unsigned el_sz
+             = tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (field)));
+           if (upos <= off && off < upos + el_sz)
+             {
+               tree cop = build3 (COMPONENT_REF, TREE_TYPE (field),
+                                  op, field, NULL_TREE);
+               if (tree ret = cxx_fold_indirect_ref_1 (loc, type, cop,
+                                                       off - upos,
+                                                       empty_base))
+                 return ret;
+             }
+         }
+    }
+
+  return NULL_TREE;
+}
+
 /* A less strict version of fold_indirect_ref_1, which requires cv-quals to
    match.  We want to be less strict for simple *& folding; if we have a
    non-const temporary that we access through a const pointer, that should
@@ -3353,9 +3931,7 @@ same_type_ignoring_tlq_and_bounds_p (tree type1, tree type2)
    because we're dealing with things like ADDR_EXPR of INTEGER_CST which
    don't really make sense outside of constant expression evaluation.  Also
    we want to allow folding to COMPONENT_REF, which could cause trouble
-   with TBAA in fold_indirect_ref_1.
-
-   Try to keep this function synced with fold_indirect_ref_1.  */
+   with TBAA in fold_indirect_ref_1.  */
 
 static tree
 cxx_fold_indirect_ref (location_t loc, tree type, tree op0, bool *empty_base)
@@ -3386,139 +3962,19 @@ cxx_fold_indirect_ref (location_t loc, tree type, tree op0, bool *empty_base)
          else
            return op;
        }
-      /* *(foo *)&fooarray => fooarray[0] */
-      else if (TREE_CODE (optype) == ARRAY_TYPE
-              && similar_type_p (type, TREE_TYPE (optype)))
-       {
-         tree type_domain = TYPE_DOMAIN (optype);
-         tree min_val = size_zero_node;
-         if (type_domain && TYPE_MIN_VALUE (type_domain))
-           min_val = TYPE_MIN_VALUE (type_domain);
-         return build4_loc (loc, ARRAY_REF, type, op, min_val,
-                            NULL_TREE, NULL_TREE);
-       }
-      /* *(foo *)&complexfoo => __real__ complexfoo */
-      else if (TREE_CODE (optype) == COMPLEX_TYPE
-              && similar_type_p (type, TREE_TYPE (optype)))
-       return fold_build1_loc (loc, REALPART_EXPR, type, op);
-      /* *(foo *)&vectorfoo => BIT_FIELD_REF<vectorfoo,...> */
-      else if (VECTOR_TYPE_P (optype)
-              && similar_type_p (type, TREE_TYPE (optype)))
-       {
-         tree part_width = TYPE_SIZE (type);
-         tree index = bitsize_int (0);
-         return fold_build3_loc (loc, BIT_FIELD_REF, type, op, part_width,
-                                 index);
-       }
-      /* Also handle conversion to an empty base class, which
-        is represented with a NOP_EXPR.  */
-      else if (is_empty_class (type)
-              && CLASS_TYPE_P (optype)
-              && DERIVED_FROM_P (type, optype))
-       {
-         *empty_base = true;
-         return op;
-       }
-      /* *(foo *)&struct_with_foo_field => COMPONENT_REF */
-      else if (RECORD_OR_UNION_TYPE_P (optype))
-       {
-         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))
-             return fold_build3 (COMPONENT_REF, type, op, field, NULL_TREE);
-       }
+      else
+       return cxx_fold_indirect_ref_1 (loc, type, op, 0, empty_base);
     }
   else if (TREE_CODE (sub) == POINTER_PLUS_EXPR
-          && poly_int_tree_p (TREE_OPERAND (sub, 1), &const_op01))
+          && tree_fits_uhwi_p (TREE_OPERAND (sub, 1)))
     {
       tree op00 = TREE_OPERAND (sub, 0);
       tree op01 = TREE_OPERAND (sub, 1);
 
       STRIP_NOPS (op00);
       if (TREE_CODE (op00) == ADDR_EXPR)
-       {
-         tree op00type;
-         op00 = TREE_OPERAND (op00, 0);
-         op00type = TREE_TYPE (op00);
-
-         /* ((foo*)&vectorfoo)[1] => BIT_FIELD_REF<vectorfoo,...> */
-         if (VECTOR_TYPE_P (op00type)
-             && similar_type_p (type, TREE_TYPE (op00type))
-             /* POINTER_PLUS_EXPR second operand is sizetype, unsigned,
-                but we want to treat offsets with MSB set as negative.
-                For the code below negative offsets are invalid and
-                TYPE_SIZE of the element is something unsigned, so
-                check whether op01 fits into poly_int64, which implies
-                it is from 0 to INTTYPE_MAXIMUM (HOST_WIDE_INT), and
-                then just use poly_uint64 because we want to treat the
-                value as unsigned.  */
-             && tree_fits_poly_int64_p (op01))
-           {
-             tree part_width = TYPE_SIZE (type);
-             poly_uint64 max_offset
-               = (tree_to_uhwi (part_width) / BITS_PER_UNIT
-                  * TYPE_VECTOR_SUBPARTS (op00type));
-             if (known_lt (const_op01, max_offset))
-               {
-                 tree index = bitsize_int (const_op01 * BITS_PER_UNIT);
-                 return fold_build3_loc (loc,
-                                         BIT_FIELD_REF, type, op00,
-                                         part_width, index);
-               }
-           }
-         /* ((foo*)&complexfoo)[1] => __imag__ complexfoo */
-         else if (TREE_CODE (op00type) == COMPLEX_TYPE
-                  && similar_type_p (type, TREE_TYPE (op00type)))
-           {
-             if (known_eq (wi::to_poly_offset (TYPE_SIZE_UNIT (type)),
-                           const_op01))
-               return fold_build1_loc (loc, IMAGPART_EXPR, type, op00);
-           }
-         /* ((foo *)&fooarray)[1] => fooarray[1] */
-         else if (TREE_CODE (op00type) == ARRAY_TYPE
-                  && similar_type_p (type, TREE_TYPE (op00type)))
-           {
-             tree type_domain = TYPE_DOMAIN (op00type);
-             tree min_val = size_zero_node;
-             if (type_domain && TYPE_MIN_VALUE (type_domain))
-               min_val = TYPE_MIN_VALUE (type_domain);
-             offset_int off = wi::to_offset (op01);
-             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)
-               {
-                 off = off + wi::to_offset (min_val);
-                 op01 = wide_int_to_tree (sizetype, off);
-                 return build4_loc (loc, ARRAY_REF, type, op00, op01,
-                                    NULL_TREE, NULL_TREE);
-               }
-           }
-         /* Also handle conversion to an empty base class, which
-            is represented with a NOP_EXPR.  */
-         else if (is_empty_class (type)
-                  && CLASS_TYPE_P (op00type)
-                  && DERIVED_FROM_P (type, op00type))
-           {
-             *empty_base = true;
-             return op00;
-           }
-         /* ((foo *)&struct_with_foo_field)[1] => COMPONENT_REF */
-         else if (RECORD_OR_UNION_TYPE_P (op00type))
-           {
-             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))
-                 return fold_build3 (COMPONENT_REF, type, op00,
-                                     field, NULL_TREE);
-           }
-       }
+       return cxx_fold_indirect_ref_1 (loc, type, TREE_OPERAND (op00, 0),
+                                       tree_to_uhwi (op01), empty_base);
     }
   /* *(foo *)fooarrptr => (*fooarrptr)[0] */
   else if (TREE_CODE (TREE_TYPE (subtype)) == ARRAY_TYPE
@@ -3633,11 +4089,27 @@ cxx_eval_indirect_ref (const constexpr_ctx *ctx, tree t,
    cxx_eval_constant_expression.  */
 
 static void
-non_const_var_error (tree r)
+non_const_var_error (location_t loc, tree r)
 {
+  auto_diagnostic_group d;
   tree type = TREE_TYPE (r);
-  error ("the value of %qD is not usable in a constant "
-        "expression", r);
+  if (DECL_NAME (r) == heap_uninit_identifier
+      || DECL_NAME (r) == heap_identifier)
+    {
+      error_at (loc, "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_at (loc, "use of allocated storage after deallocation in a "
+               "constant expression");
+      inform (DECL_SOURCE_LOCATION (r), "allocated here");
+      return;
+    }
+  error_at (loc, "the value of %qD is not usable in a constant "
+           "expression", r);
   /* Avoid error cascade.  */
   if (DECL_INITIAL (r) == error_mark_node)
     return;
@@ -3833,10 +4305,6 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
            tree elt = TREE_OPERAND (probe, 1);
            if (TREE_CODE (elt) == FIELD_DECL && DECL_MUTABLE_P (elt))
              mutable_p = true;
-           if (evaluated
-               && modifying_const_object_p (TREE_CODE (t), probe, mutable_p)
-               && const_object_being_modified == NULL_TREE)
-             const_object_being_modified = probe;
            if (TREE_CODE (probe) == ARRAY_REF)
              {
                elt = eval_and_check_array_index (ctx, probe, false,
@@ -3844,6 +4312,15 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
                if (*non_constant_p)
                  return t;
              }
+           /* We don't check modifying_const_object_p for ARRAY_REFs.  Given
+              "int a[10]", an ARRAY_REF "a[2]" can be "const int", even though
+              the array isn't const.  Instead, check "a" in the next iteration;
+              that will detect modifying "const int a[10]".  */
+           else if (evaluated
+                    && modifying_const_object_p (TREE_CODE (t), probe,
+                                                 mutable_p)
+                    && const_object_being_modified == NULL_TREE)
+             const_object_being_modified = probe;
            vec_safe_push (refs, elt);
            vec_safe_push (refs, TREE_TYPE (probe));
            probe = ob;
@@ -3879,7 +4356,7 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
        DECL_NAME to handle TARGET_EXPR temporaries, which are fair game.  */
     valp = NULL;
   else if (DECL_P (object))
-    valp = ctx->values->get (object);
+    valp = ctx->global->values.get (object);
   else
     valp = NULL;
   if (!valp)
@@ -4081,7 +4558,7 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
                                           non_constant_p, overflow_p);
       if (ctors->is_empty())
        /* The hash table might have moved since the get earlier.  */
-       valp = ctx->values->get (object);
+       valp = ctx->global->values.get (object);
     }
 
   /* Don't share a CONSTRUCTOR that might be changed later.  */
@@ -4357,6 +4834,12 @@ cxx_eval_loop_expr (const constexpr_ctx *ctx, tree t,
                    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;
@@ -4431,11 +4914,11 @@ cxx_eval_loop_expr (const constexpr_ctx *ctx, tree t,
            gcc_assert (*jump_target);
        }
 
-      /* Forget saved values of SAVE_EXPRs.  */
+      /* Forget saved values of SAVE_EXPRs and TARGET_EXPRs.  */
       unsigned int i;
       tree save_expr;
       FOR_EACH_VEC_ELT (save_exprs, i, save_expr)
-       new_ctx.values->remove (save_expr);
+       ctx->global->values.remove (save_expr);
       save_exprs.truncate (0);
 
       if (++count >= constexpr_loop_limit)
@@ -4455,11 +4938,11 @@ cxx_eval_loop_expr (const constexpr_ctx *ctx, tree t,
         && (!switches (jump_target) || count == 0)
         && !*non_constant_p);
 
-  /* Forget saved values of SAVE_EXPRs.  */
+  /* Forget saved values of SAVE_EXPRs and TARGET_EXPRs.  */
   unsigned int i;
   tree save_expr;
   FOR_EACH_VEC_ELT (save_exprs, i, save_expr)
-    new_ctx.values->remove (save_expr);
+    ctx->global->values.remove (save_expr);
 
   return NULL_TREE;
 }
@@ -4585,6 +5068,8 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
       return t;
     }
 
+  location_t loc = cp_expr_loc_or_input_loc (t);
+
   STRIP_ANY_LOCATION_WRAPPER (t);
 
   if (CONSTANT_CLASS_P (t))
@@ -4611,14 +5096,14 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
     }
 
   /* Avoid excessively long constexpr evaluations.  */
-  if (++*ctx->constexpr_ops_count >= constexpr_ops_limit)
+  if (++ctx->global->constexpr_ops_count >= constexpr_ops_limit)
     {
       if (!ctx->quiet)
-       error_at (cp_expr_loc_or_input_loc (t),
+       error_at (loc,
                  "%<constexpr%> evaluation operation count exceeds limit of "
                  "%wd (use %<-fconstexpr-ops-limit=%> to increase the limit)",
                  constexpr_ops_limit);
-      *ctx->constexpr_ops_count = INTTYPE_MINIMUM (HOST_WIDE_INT);
+      ctx->global->constexpr_ops_count = INTTYPE_MINIMUM (HOST_WIDE_INT);
       *non_constant_p = true;
       return t;
     }
@@ -4635,7 +5120,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
       /* We ask for an rvalue for the RESULT_DECL when indirecting
         through an invisible reference, or in named return value
         optimization.  */
-      if (tree *p = ctx->values->get (t))
+      if (tree *p = ctx->global->values.get (t))
        return *p;
       else
        {
@@ -4691,13 +5176,13 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
          && TREE_CODE (TARGET_EXPR_INITIAL (r)) == CONSTRUCTOR)
        r = TARGET_EXPR_INITIAL (r);
       if (VAR_P (r))
-       if (tree *p = ctx->values->get (r))
+       if (tree *p = ctx->global->values.get (r))
          if (*p != NULL_TREE)
            r = *p;
       if (DECL_P (r))
        {
          if (!ctx->quiet)
-           non_const_var_error (r);
+           non_const_var_error (loc, r);
          *non_constant_p = true;
        }
       break;
@@ -4718,7 +5203,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
     case PARM_DECL:
       if (lval && !TYPE_REF_P (TREE_TYPE (t)))
        /* glvalue use.  */;
-      else if (tree *p = ctx->values->get (r))
+      else if (tree *p = ctx->global->values.get (r))
        r = *p;
       else if (lval)
        /* Defer in case this is only used for its type.  */;
@@ -4760,7 +5245,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
            new_ctx.object = r;
            new_ctx.ctor = build_constructor (TREE_TYPE (r), NULL);
            CONSTRUCTOR_NO_CLEARING (new_ctx.ctor) = true;
-           new_ctx.values->put (r, new_ctx.ctor);
+           ctx->global->values.put (r, new_ctx.ctor);
            ctx = &new_ctx;
          }
 
@@ -4776,12 +5261,12 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
            if (CLASS_TYPE_P (TREE_TYPE (r))
                && CP_TYPE_CONST_P (TREE_TYPE (r)))
              TREE_READONLY (init) = true;
-           ctx->values->put (r, init);
+           ctx->global->values.put (r, init);
          }
        else if (ctx == &new_ctx)
          /* We gave it a CONSTRUCTOR above.  */;
        else
-         ctx->values->put (r, NULL_TREE);
+         ctx->global->values.put (r, NULL_TREE);
       }
       break;
 
@@ -4798,6 +5283,14 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
          *non_constant_p = true;
          break;
        }
+      /* Avoid evaluating a TARGET_EXPR more than once.  */
+      if (tree *p = ctx->global->values.get (TARGET_EXPR_SLOT (t)))
+       {
+         if (lval)
+           return TARGET_EXPR_SLOT (t);
+         r = *p;
+         break;
+       }
       if ((AGGREGATE_TYPE_P (TREE_TYPE (t)) || VECTOR_TYPE_P (TREE_TYPE (t))))
        {
          /* We're being expanded without an explicit target, so start
@@ -4807,7 +5300,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
          new_ctx.ctor = build_constructor (TREE_TYPE (t), NULL);
          CONSTRUCTOR_NO_CLEARING (new_ctx.ctor) = true;
          new_ctx.object = TARGET_EXPR_SLOT (t);
-         ctx->values->put (new_ctx.object, new_ctx.ctor);
+         ctx->global->values.put (new_ctx.object, new_ctx.ctor);
          ctx = &new_ctx;
        }
       /* Pass false for 'lval' because this indicates
@@ -4818,13 +5311,14 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
       if (!*non_constant_p)
        /* Adjust the type of the result to the type of the temporary.  */
        r = adjust_temp_type (TREE_TYPE (t), r);
+      if (TARGET_EXPR_CLEANUP (t) && !CLEANUP_EH_ONLY (t))
+       ctx->global->cleanups->safe_push (TARGET_EXPR_CLEANUP (t));
+      r = unshare_constructor (r);
+      ctx->global->values.put (TARGET_EXPR_SLOT (t), r);
+      if (ctx->save_exprs)
+       ctx->save_exprs->safe_push (TARGET_EXPR_SLOT (t));
       if (lval)
-       {
-         tree slot = TARGET_EXPR_SLOT (t);
-         r = unshare_constructor (r);
-         ctx->values->put (slot, r);
-         return slot;
-       }
+       return TARGET_EXPR_SLOT (t);
       break;
 
     case INIT_EXPR:
@@ -4862,22 +5356,27 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
 
     case SAVE_EXPR:
       /* Avoid evaluating a SAVE_EXPR more than once.  */
-      if (tree *p = ctx->values->get (t))
+      if (tree *p = ctx->global->values.get (t))
        r = *p;
       else
        {
          r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0), false,
                                            non_constant_p, overflow_p);
-         ctx->values->put (t, r);
+         ctx->global->values.put (t, r);
          if (ctx->save_exprs)
            ctx->save_exprs->safe_push (t);
        }
       break;
 
-    case NON_LVALUE_EXPR:
     case TRY_CATCH_EXPR:
+      if (TREE_OPERAND (t, 0) == NULL_TREE)
+       {
+         r = void_node;
+         break;
+       }
+      /* FALLTHRU */
+    case NON_LVALUE_EXPR:
     case TRY_BLOCK:
-    case CLEANUP_POINT_EXPR:
     case MUST_NOT_THROW_EXPR:
     case EXPR_STMT:
     case EH_SPEC_BLOCK:
@@ -4887,6 +5386,26 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
                                        jump_target);
       break;
 
+    case CLEANUP_POINT_EXPR:
+      {
+       auto_vec<tree, 2> cleanups;
+       vec<tree> *prev_cleanups = ctx->global->cleanups;
+       ctx->global->cleanups = &cleanups;
+       r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0),
+                                         lval,
+                                         non_constant_p, overflow_p,
+                                         jump_target);
+       ctx->global->cleanups = prev_cleanups;
+       unsigned int i;
+       tree cleanup;
+       /* Evaluate the cleanups.  */
+       FOR_EACH_VEC_ELT_REVERSE (cleanups, i, cleanup)
+         cxx_eval_constant_expression (ctx, cleanup, false,
+                                       non_constant_p, overflow_p,
+                                       jump_target);
+      }
+      break;
+
     case TRY_FINALLY_EXPR:
       r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0), lval,
                                        non_constant_p, overflow_p,
@@ -4899,14 +5418,24 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
       break;
 
     case CLEANUP_STMT:
-      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.  */
-       cxx_eval_constant_expression (ctx, CLEANUP_EXPR (t), true,
-                                     non_constant_p, overflow_p,
-                                     jump_target);
+      {
+       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)
+         {
+           iloc_sentinel ils (loc);
+           /* 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 ? &initial_jump_target
+                                         : NULL);
+         }
+      }
       break;
 
       /* These differ from cxx_eval_unary_expression in that this doesn't
@@ -5029,8 +5558,6 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
     case MAX_EXPR:
     case LSHIFT_EXPR:
     case RSHIFT_EXPR:
-    case LROTATE_EXPR:
-    case RROTATE_EXPR:
     case BIT_IOR_EXPR:
     case BIT_XOR_EXPR:
     case BIT_AND_EXPR:
@@ -5041,6 +5568,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
     case GE_EXPR:
     case EQ_EXPR:
     case NE_EXPR:
+    case SPACESHIP_EXPR:
     case UNORDERED_EXPR:
     case ORDERED_EXPR:
     case UNLT_EXPR:
@@ -5173,7 +5701,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
       if (REINTERPRET_CAST_P (t))
        {
          if (!ctx->quiet)
-           error_at (cp_expr_loc_or_input_loc (t),
+           error_at (loc,
                      "%<reinterpret_cast%> is not a constant expression");
          *non_constant_p = true;
          return t;
@@ -5195,8 +5723,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
        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)
@@ -5214,7 +5741,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
                if (TYPE_REF_P (type))
                  {
                    if (!ctx->quiet)
-                     error_at (cp_expr_loc_or_input_loc (t),
+                     error_at (loc,
                                "dereferencing a null pointer");
                    *non_constant_p = true;
                    return t;
@@ -5226,7 +5753,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
                    if (!can_convert (type, from, tf_none))
                      {
                        if (!ctx->quiet)
-                         error_at (cp_expr_loc_or_input_loc (t),
+                         error_at (loc,
                                    "conversion of %qT null pointer to %qT "
                                    "is not a constant expression",
                                    from, type);
@@ -5241,8 +5768,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
                     reinterpret_cast<void*>(sizeof 0)
                */
                if (!ctx->quiet)
-                 error_at (cp_expr_loc_or_input_loc (t),
-                           "%<reinterpret_cast<%T>(%E)%> is not "
+                 error_at (loc, "%<reinterpret_cast<%T>(%E)%> is not "
                            "a constant expression",
                            type, op);
                *non_constant_p = true;
@@ -5250,6 +5776,34 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
              }
          }
 
+       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_size = TYPE_SIZE_UNIT (TREE_TYPE (var));
+           tree elt_type = TREE_TYPE (type);
+           tree cookie_size = NULL_TREE;
+           if (TREE_CODE (elt_type) == RECORD_TYPE
+               && TYPE_NAME (elt_type) == heap_identifier)
+             {
+               tree fld1 = TYPE_FIELDS (elt_type);
+               tree fld2 = DECL_CHAIN (fld1);
+               elt_type = TREE_TYPE (TREE_TYPE (fld2));
+               cookie_size = TYPE_SIZE_UNIT (TREE_TYPE (fld1));
+             }
+           DECL_NAME (var) = heap_identifier;
+           TREE_TYPE (var)
+             = build_new_constexpr_heap_type (elt_type, cookie_size,
+                                              var_size);
+           TREE_TYPE (TREE_OPERAND (op, 0))
+             = build_pointer_type (TREE_TYPE (var));
+         }
+
        if (op == oldop && tcode != UNARY_PLUS_EXPR)
          /* We didn't fold at the top so we could check for ptr-int
             conversion.  */
@@ -5315,8 +5869,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
     case BASELINK:
     case OFFSET_REF:
       if (!ctx->quiet)
-        error_at (cp_expr_loc_or_input_loc (t),
-                 "expression %qE is not a constant expression", t);
+       error_at (loc, "expression %qE is not a constant expression", t);
       *non_constant_p = true;
       break;
 
@@ -5328,13 +5881,13 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
        tree obj = OBJ_TYPE_REF_OBJECT (t);
        obj = cxx_eval_constant_expression (ctx, obj, lval, non_constant_p,
                                            overflow_p);
+       STRIP_NOPS (obj);
        /* We expect something in the form of &x.D.2103.D.2094; get x. */
        if (TREE_CODE (obj) != ADDR_EXPR
            || !DECL_P (get_base_address (TREE_OPERAND (obj, 0))))
          {
            if (!ctx->quiet)
-             error_at (cp_expr_loc_or_input_loc (t),
-                       "expression %qE is not a constant expression", t);
+             error_at (loc, "expression %qE is not a constant expression", t);
            *non_constant_p = true;
            return t;
          }
@@ -5410,7 +5963,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
          '!requires (T t) { ... }' which is not transformed into
          a constraint.  */
       if (!processing_template_decl)
-        return evaluate_constraint_expression (t, NULL_TREE);
+        return satisfy_constraint_expression (t);
       else
         *non_constant_p = true;
       return t;
@@ -5426,9 +5979,35 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
       r = void_node;
       break;
 
+    case TEMPLATE_ID_EXPR:
+      {
+        /* We can evaluate template-id that refers to a concept only if
+          the template arguments are non-dependent.  */
+       tree id = unpack_concept_check (t);
+       tree tmpl = TREE_OPERAND (id, 0);
+       if (!concept_definition_p (tmpl))
+         internal_error ("unexpected template-id %qE", t);
+
+       if (function_concept_p (tmpl))
+         {
+           if (!ctx->quiet)
+             error_at (cp_expr_loc_or_input_loc (t),
+                       "function concept must be called");
+           r = error_mark_node;
+           break;
+         }
+
+       if (!processing_template_decl)
+         r = evaluate_concept_check (t, tf_warning_or_error);
+       else
+         *non_constant_p = true;
+
+       break;
+      }
+
     case ASM_EXPR:
       if (!ctx->quiet)
-       inline_asm_in_constexpr_error (cp_expr_loc_or_input_loc (t));
+       inline_asm_in_constexpr_error (loc);
       *non_constant_p = true;
       return t;
 
@@ -5491,6 +6070,7 @@ instantiate_cx_fn_r (tree *tp, int *walk_subtrees, void */*data*/)
 
   return NULL_TREE;
 }
+
 static void
 instantiate_constexpr_fns (tree t)
 {
@@ -5499,34 +6079,97 @@ 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;
+}
+
+/* Find immediate function decls in *TP if any.  */
+
+static tree
+find_immediate_fndecl (tree *tp, int */*walk_subtrees*/, void */*data*/)
+{
+  if (TREE_CODE (*tp) == FUNCTION_DECL && DECL_IMMEDIATE_FUNCTION_P (*tp))
+    return *tp;
+  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);
 
   bool non_constant_p = false;
   bool overflow_p = false;
-  hash_map<tree,tree> map;
-  HOST_WIDE_INT constexpr_ctx_count = 0;
 
-  constexpr_ctx ctx = { NULL, &map, NULL, NULL, NULL, NULL,
-                       &constexpr_ctx_count, allow_non_constant, strict,
+  constexpr_global_ctx global_ctx;
+  constexpr_ctx ctx = { &global_ctx, NULL, NULL, NULL, NULL, NULL,
+                       allow_non_constant, strict,
                        manifestly_const_eval || !allow_non_constant };
 
   tree type = initialized_type (t);
   tree r = t;
+  bool is_consteval = false;
   if (VOID_TYPE_P (type))
-    return t;
+    {
+      if (constexpr_dtor)
+       /* Used for destructors of array elements.  */
+       type = TREE_TYPE (object);
+      else
+       {
+         if (cxx_dialect < cxx2a)
+           return t;
+         if (TREE_CODE (t) != CALL_EXPR && TREE_CODE (t) != AGGR_INIT_EXPR)
+           return t;
+         /* Calls to immediate functions returning void need to be
+            evaluated.  */
+         tree fndecl = cp_get_callee_fndecl_nofold (t);
+         if (fndecl == NULL_TREE || !DECL_IMMEDIATE_FUNCTION_P (fndecl))
+           return t;
+         else
+           is_consteval = true;
+       }
+    }
+  else if (cxx_dialect >= cxx2a
+          && (TREE_CODE (t) == CALL_EXPR
+              || TREE_CODE (t) == AGGR_INIT_EXPR
+              || TREE_CODE (t) == TARGET_EXPR))
+    {
+      /* For non-concept checks, determine if it is consteval.  */
+      if (!concept_check_p (t))
+       {
+         tree x = t;
+         if (TREE_CODE (x) == TARGET_EXPR)
+           x = TARGET_EXPR_INITIAL (x);
+         tree fndecl = cp_get_callee_fndecl_nofold (x);
+         if (fndecl && DECL_IMMEDIATE_FUNCTION_P (fndecl))
+           is_consteval = true;
+       }
+    }
   if (AGGREGATE_TYPE_P (type) || VECTOR_TYPE_P (type))
     {
       /* In C++14 an NSDMI can participate in aggregate initialization,
@@ -5536,8 +6179,24 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant,
         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));
+         if (error_operand_p (DECL_INITIAL (object)))
+           return t;
+         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)
@@ -5550,24 +6209,36 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant,
        gcc_assert (same_type_ignoring_top_level_qualifiers_p
                    (type, TREE_TYPE (object)));
       if (object && DECL_P (object))
-       map.put (object, ctx.ctor);
+       global_ctx.values.put (object, ctx.ctor);
       if (TREE_CODE (r) == TARGET_EXPR)
        /* Avoid creating another CONSTRUCTOR when we expand the
           TARGET_EXPR.  */
        r = TARGET_EXPR_INITIAL (r);
     }
 
+  auto_vec<tree, 16> cleanups;
+  global_ctx.cleanups = &cleanups;
+
   instantiate_constexpr_fns (r);
   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;
+
+  unsigned int i;
+  tree cleanup;
+  /* Evaluate the cleanups.  */
+  FOR_EACH_VEC_ELT_REVERSE (cleanups, i, cleanup)
+    cxx_eval_constant_expression (&ctx, cleanup, false,
+                                 &non_constant_p, &overflow_p);
 
   /* 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 "
@@ -5575,8 +6246,7 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant,
       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 "
@@ -5585,6 +6255,51 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant,
       non_constant_p = true;
     }
 
+  if (!global_ctx.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 (global_ctx.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;
+         }
+    }
+
+  /* Check that immediate invocation does not return an expression referencing
+     any immediate function decls.  They need to be allowed while parsing
+     immediate functions, but can't leak outside of them.  */
+  if (is_consteval
+      && t != r
+      && (current_function_decl == NULL_TREE
+         || !DECL_IMMEDIATE_FUNCTION_P (current_function_decl)))
+    if (tree immediate_fndecl
+       = cp_walk_tree_without_duplicates (&r, find_immediate_fndecl,
+                                          NULL))
+    {
+      if (!allow_non_constant && !non_constant_p)
+       error_at (cp_expr_loc_or_input_loc (t),
+                 "immediate evaluation returns address of immediate "
+                 "function %qD", immediate_fndecl);
+      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.  */
@@ -5610,6 +6325,8 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant,
 
   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
@@ -5617,7 +6334,7 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant,
         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
@@ -5645,7 +6362,7 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant,
        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;
        }
     }
@@ -5660,7 +6377,16 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant,
 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
@@ -5764,14 +6490,14 @@ maybe_constant_value (tree t, tree decl, bool manifestly_const_eval)
     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
@@ -5790,13 +6516,15 @@ clear_cv_cache (void)
     cv_cache->empty ();
 }
 
-/* Dispose of the whole CV_CACHE and FOLD_CACHE.  */
+/* Dispose of the whole CV_CACHE, FOLD_CACHE, and satisfaction caches.  */
 
 void
-clear_cv_and_fold_caches (void)
+clear_cv_and_fold_caches (bool sat /*= true*/)
 {
   clear_cv_cache ();
   clear_fold_cache ();
+  if (sat)
+    clear_satisfaction_cache ();
 }
 
 /* Internal function handling expressions in templates for
@@ -5812,7 +6540,8 @@ clear_cv_and_fold_caches (void)
 
 static tree
 fold_non_dependent_expr_template (tree t, tsubst_flags_t complain,
-                                 bool manifestly_const_eval)
+                                 bool manifestly_const_eval,
+                                 tree object)
 {
   gcc_assert (processing_template_decl);
 
@@ -5833,7 +6562,7 @@ fold_non_dependent_expr_template (tree t, tsubst_flags_t complain,
 
       tree r = cxx_eval_outermost_constant_expr (t, true, true,
                                                 manifestly_const_eval,
-                                                NULL_TREE);
+                                                false, object);
       /* cp_tree_equal looks through NOPs, so allow them.  */
       gcc_checking_assert (r == t
                           || CONVERT_EXPR_P (t)
@@ -5869,16 +6598,17 @@ fold_non_dependent_expr_template (tree t, tsubst_flags_t complain,
 tree
 fold_non_dependent_expr (tree t,
                         tsubst_flags_t complain /* = tf_warning_or_error */,
-                        bool manifestly_const_eval /* = false */)
+                        bool manifestly_const_eval /* = false */,
+                        tree object /* = NULL_TREE */)
 {
   if (t == NULL_TREE)
     return NULL_TREE;
 
   if (processing_template_decl)
     return fold_non_dependent_expr_template (t, complain,
-                                            manifestly_const_eval);
+                                            manifestly_const_eval, object);
 
-  return maybe_constant_value (t, NULL_TREE, manifestly_const_eval);
+  return maybe_constant_value (t, object, manifestly_const_eval);
 }
 
 
@@ -5895,7 +6625,7 @@ fold_non_dependent_init (tree t,
   if (processing_template_decl)
     {
       t = fold_non_dependent_expr_template (t, complain,
-                                           manifestly_const_eval);
+                                           manifestly_const_eval, NULL_TREE);
       /* maybe_constant_init does this stripping, so do it here too.  */
       if (TREE_CODE (t) == TARGET_EXPR)
        {
@@ -5937,7 +6667,7 @@ maybe_constant_init_1 (tree t, tree decl, bool allow_non_constant,
   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);
@@ -6135,6 +6865,7 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
     case LABEL_DECL:
     case LABEL_EXPR:
     case CASE_LABEL_EXPR:
+    case PREDICT_EXPR:
     case CONST_DECL:
     case SIZEOF_EXPR:
     case ALIGNOF_EXPR:
@@ -6231,7 +6962,21 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
                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_replaceable_global_alloc_fn (fun)
+                       || TREE_CODE (t) != CALL_EXPR
+                       || (!CALL_FROM_NEW_OR_DELETE_P (t)
+                           && (current_function_decl == NULL_TREE
+                               || !is_std_allocator_allocate
+                                               (current_function_decl))))
+                   /* Allow placement new in std::construct_at.  */
+                   && (!cxx_placement_new_fn (fun)
+                       || TREE_CODE (t) != CALL_EXPR
+                       || current_function_decl == NULL_TREE
+                       || !is_std_construct_at (current_function_decl))
+                   && !cxx_dynamic_cast_fn_p (fun))
                  {
                    if (flags & tf_error)
                      {
@@ -6340,7 +7085,7 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
          && !is_really_empty_class (TREE_TYPE (t), /*ignore_vptr*/false))
         {
           if (flags & tf_error)
-            non_const_var_error (t);
+           non_const_var_error (loc, t);
           return false;
         }
       return true;
@@ -6460,6 +7205,9 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
        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;
@@ -6601,6 +7349,7 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
     case OMP_DEPOBJ:
     case OACC_PARALLEL:
     case OACC_KERNELS:
+    case OACC_SERIAL:
     case OACC_DATA:
     case OACC_HOST_DATA:
     case OACC_LOOP:
@@ -6633,11 +7382,14 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
       return false;
 
     case TYPEID_EXPR:
-      /* -- a typeid expression whose operand is of polymorphic
-            class type;  */
+      /* In C++20, a typeid expression whose operand is of polymorphic
+        class type can be constexpr.  */
       {
         tree e = TREE_OPERAND (t, 0);
-        if (!TYPE_P (e) && !type_dependent_expression_p (e)
+       if (cxx_dialect < cxx2a
+           && strict
+           && !TYPE_P (e)
+           && !type_dependent_expression_p (e)
            && TYPE_POLYMORPHIC_P (TREE_TYPE (e)))
           {
             if (flags & tf_error)
@@ -6659,6 +7411,7 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
     case GE_EXPR:
     case EQ_EXPR:
     case NE_EXPR:
+    case SPACESHIP_EXPR:
       want_rval = true;
       goto binary;
 
@@ -6891,8 +7644,6 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
     case MAX_EXPR:
     case LSHIFT_EXPR:
     case RSHIFT_EXPR:
-    case LROTATE_EXPR:
-    case RROTATE_EXPR:
     case BIT_IOR_EXPR:
     case BIT_XOR_EXPR:
     case BIT_AND_EXPR:
@@ -6929,7 +7680,7 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
      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");
@@ -6975,8 +7726,13 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
       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;
 
     case GOTO_EXPR: