diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
index 40d9fdc0516..abdbc8fff8c 100644
--- a/gcc/cp/call.cc
+++ b/gcc/cp/call.cc
@@ -9763,7 +9763,7 @@ in_immediate_context ()
 /* Return true if a call to FN with number of arguments NARGS
    is an immediate invocation.  */
 
-static bool
+bool
 immediate_invocation_p (tree fn)
 {
   return (TREE_CODE (fn) == FUNCTION_DECL
@@ -10471,6 +10471,10 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
       fn = build_addr_func (fn, complain);
       if (fn == error_mark_node)
 	return error_mark_node;
+
+      /* We're actually invoking the function.  (Immediate functions get an
+	 & when invoking it even though the user didn't use &.)  */
+      ADDR_EXPR_DENOTES_CALL_P (fn) = true;
     }
 
   tree call = build_cxx_call (fn, nargs, argarray, complain|decltype_flag);
@@ -10488,41 +10492,7 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
       if (TREE_CODE (c) == CALL_EXPR)
 	suppress_warning (c /* Suppress all warnings.  */);
     }
-  if (TREE_CODE (fn) == ADDR_EXPR)
-    {
-      tree fndecl = STRIP_TEMPLATE (TREE_OPERAND (fn, 0));
-      if (immediate_invocation_p (fndecl))
-	{
-	  tree obj_arg = NULL_TREE;
-	  /* Undo convert_from_reference called by build_cxx_call.  */
-	  if (REFERENCE_REF_P (call))
-	    call = TREE_OPERAND (call, 0);
-	  if (DECL_CONSTRUCTOR_P (fndecl))
-	    obj_arg = cand->first_arg ? cand->first_arg : (*args)[0];
-	  if (obj_arg && is_dummy_object (obj_arg))
-	    {
-	      call = build_cplus_new (DECL_CONTEXT (fndecl), call, complain);
-	      obj_arg = NULL_TREE;
-	    }
-	  /* Look through *(const T *)&obj.  */
-	  else if (obj_arg && INDIRECT_REF_P (obj_arg))
-	    {
-	      tree addr = TREE_OPERAND (obj_arg, 0);
-	      STRIP_NOPS (addr);
-	      if (TREE_CODE (addr) == ADDR_EXPR)
-		{
-		  tree typeo = TREE_TYPE (obj_arg);
-		  tree typei = TREE_TYPE (TREE_OPERAND (addr, 0));
-		  if (same_type_ignoring_top_level_qualifiers_p (typeo, typei))
-		    obj_arg = TREE_OPERAND (addr, 0);
-		}
-	    }
-	  call = cxx_constant_value (call, obj_arg, complain);
-	  if (obj_arg && !error_operand_p (call))
-	    call = cp_build_init_expr (obj_arg, call);
-	  call = convert_from_reference (call);
-	}
-    }
+
   return call;
 }
 
diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index 8bd5c4a47f8..af4f98b1fe1 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -3135,6 +3135,11 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
 	  unsigned save_heap_alloc_count = ctx->global->heap_vars.length ();
 	  unsigned save_heap_dealloc_count = ctx->global->heap_dealloc_count;
 
+	  /* Make sure we fold std::is_constant_evaluated to true in an
+	     immediate function.  */
+	  if (immediate_invocation_p (fun))
+	    call_ctx.manifestly_const_eval = mce_true;
+
 	  /* If this is a constexpr destructor, the object's const and volatile
 	     semantics are no longer in effect; see [class.dtor]p5.  */
 	  if (new_obj && DECL_DESTRUCTOR_P (fun))
diff --git a/gcc/cp/cp-gimplify.cc b/gcc/cp/cp-gimplify.cc
index 206e791fcfd..29132aad158 100644
--- a/gcc/cp/cp-gimplify.cc
+++ b/gcc/cp/cp-gimplify.cc
@@ -1058,9 +1058,21 @@ cp_fold_r (tree *stmt_p, int *walk_subtrees, void *data_)
 	}
       break;
 
+    /* Expand immediate invocations.  */
+    case CALL_EXPR:
+    case AGGR_INIT_EXPR:
+      if (!in_immediate_context ())
+	if (tree fn = cp_get_callee (stmt))
+	  if (TREE_CODE (fn) != ADDR_EXPR || ADDR_EXPR_DENOTES_CALL_P (fn))
+	    if (tree fndecl = cp_get_fndecl_from_callee (fn, /*fold*/false))
+	      if (DECL_IMMEDIATE_FUNCTION_P (fndecl))
+		*stmt_p = stmt = cxx_constant_value (stmt);
+      break;
+
     case ADDR_EXPR:
       if (TREE_CODE (TREE_OPERAND (stmt, 0)) == FUNCTION_DECL
-	  && DECL_IMMEDIATE_FUNCTION_P (TREE_OPERAND (stmt, 0)))
+	  && DECL_IMMEDIATE_FUNCTION_P (TREE_OPERAND (stmt, 0))
+	  && !in_immediate_context ())
 	{
 	  error_at (EXPR_LOCATION (stmt),
 		    "taking address of an immediate function %qD",
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 3ca011c61c8..8bd794c91fb 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -4784,6 +4784,11 @@ get_vec_init_expr (tree t)
 #define PTRMEM_OK_P(NODE) \
   TREE_LANG_FLAG_0 (TREE_CHECK3 ((NODE), ADDR_EXPR, OFFSET_REF, SCOPE_REF))
 
+/* True if this ADDR_EXPR denotes a function call; that is, it's
+   fn() rather than &fn.  */
+#define ADDR_EXPR_DENOTES_CALL_P(NODE) \
+  (ADDR_EXPR_CHECK(NODE)->base.protected_flag)
+
 /* Get the POINTER_TYPE to the METHOD_TYPE associated with this
    pointer to member function.  TYPE_PTRMEMFUNC_P _must_ be true,
    before using this macro.  */
@@ -6713,6 +6718,7 @@ extern tree perform_direct_initialization_if_possible (tree, tree, bool,
 extern vec<tree,va_gc> *resolve_args (vec<tree,va_gc>*, tsubst_flags_t);
 extern tree in_charge_arg_for_name		(tree);
 extern bool in_immediate_context		();
+extern bool immediate_invocation_p		(tree);
 extern tree build_cxx_call			(tree, int, tree *,
 						 tsubst_flags_t,
 						 tree = NULL_TREE);
diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
index 799183dc646..7dfb6de2da3 100644
--- a/gcc/cp/tree.cc
+++ b/gcc/cp/tree.cc
@@ -3254,7 +3254,7 @@ bot_manip (tree* tp, int* walk_subtrees, void* data_)
    variables.  */
 
 static tree
-bot_replace (tree* t, int* walk_subtrees, void* data_)
+bot_replace (tree* t, int*, void* data_)
 {
   bot_data &data = *(bot_data*)data_;
   splay_tree target_remap = data.target_remap;
@@ -3284,27 +3284,6 @@ bot_replace (tree* t, int* walk_subtrees, void* data_)
 			    /*check_access=*/false, /*nonnull=*/true,
 			    tf_warning_or_error);
     }
-  else if (cxx_dialect >= cxx20
-	   && (TREE_CODE (*t) == CALL_EXPR
-	       || TREE_CODE (*t) == AGGR_INIT_EXPR)
-	   && !in_immediate_context ())
-    {
-      /* Expand immediate invocations.  */
-      if (tree fndecl = cp_get_callee_fndecl_nofold (*t))
-	if (DECL_IMMEDIATE_FUNCTION_P (fndecl))
-	  {
-	    /* Make in_immediate_context true within the args.  */
-	    in_consteval_if_p_temp_override ito;
-	    in_consteval_if_p = true;
-	    int nargs = call_expr_nargs (*t);
-	    for (int i = 0; i < nargs; ++i)
-	      cp_walk_tree (&get_nth_callarg (*t, i), bot_replace, data_, NULL);
-	    *t = cxx_constant_value (*t);
-	    if (*t == error_mark_node)
-	      return error_mark_node;
-	    *walk_subtrees = 0;
-	  }
-    }
 
   return NULL_TREE;
 }
diff --git a/gcc/testsuite/g++.dg/cpp23/consteval-if2.C b/gcc/testsuite/g++.dg/cpp23/consteval-if2.C
index d1845da9e58..9fa95295c43 100644
--- a/gcc/testsuite/g++.dg/cpp23/consteval-if2.C
+++ b/gcc/testsuite/g++.dg/cpp23/consteval-if2.C
@@ -65,7 +65,7 @@ qux (int x)
   int r = 0;
   if not consteval	// { dg-warning "'if consteval' only available with" "" { target c++20_only } }
     {
-      r += foo (x);	// { dg-error "'x' is not a constant expression" }
+      r += foo (x);	// { dg-error "'x' is not a constant expression" "" { xfail *-*-* } }
     }
   else
     {
diff --git a/gcc/testsuite/g++.dg/cpp2a/consteval-memfn1.C b/gcc/testsuite/g++.dg/cpp2a/consteval-memfn1.C
index 910e7a1ac1e..63f4f1d526a 100644
--- a/gcc/testsuite/g++.dg/cpp2a/consteval-memfn1.C
+++ b/gcc/testsuite/g++.dg/cpp2a/consteval-memfn1.C
@@ -25,3 +25,10 @@ void VerifyHash(fixed_string s) {
   fixed_string::size_static(-1); // { dg-message "expansion of" }
   s(); // { dg-bogus "" }
 }
+
+void
+do_test ()
+{
+  fixed_string f;
+  VerifyHash<int>(f);
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/consteval11.C b/gcc/testsuite/g++.dg/cpp2a/consteval11.C
index 2f68ec0f892..9fd32dcab7b 100644
--- a/gcc/testsuite/g++.dg/cpp2a/consteval11.C
+++ b/gcc/testsuite/g++.dg/cpp2a/consteval11.C
@@ -5,25 +5,25 @@ consteval int bar (int i) { if (i != 1) throw 1; return 0; }	// { dg-error "is n
 
 constexpr int a = bar (1);
 constexpr int b = bar (2);		// { dg-message "in 'constexpr' expansion of" }
-constexpr int c = 0 ? bar (3) : 1;	// { dg-message "in 'constexpr' expansion of" }
+constexpr int c = 0 ? bar (3) : 1;
 const int d = bar (4);			// { dg-message "in 'constexpr' expansion of" }
-const int e = 0 ? bar (5) : 1;		// { dg-message "in 'constexpr' expansion of" }
+const int e = 0 ? bar (5) : 1;
 int f = bar (1);
 int g = bar (6);			// { dg-message "in 'constexpr' expansion of" }
-int h = 0 ? bar (7) : 1;		// { dg-message "in 'constexpr' expansion of" }
+int h = 0 ? bar (7) : 1;
 
 void
 foo ()
 {
   constexpr int a = bar (1);
   constexpr int b = bar (2);		// { dg-message "in 'constexpr' expansion of" }
-  constexpr int c = 0 ? bar (3) : 1;	// { dg-message "in 'constexpr' expansion of" }
+  constexpr int c = 0 ? bar (3) : 1;
   const int d = bar (4);		// { dg-message "in 'constexpr' expansion of" }
-  const int e = 0 ? bar (5) : 1;	// { dg-message "in 'constexpr' expansion of" }
+  const int e = 0 ? bar (5) : 1;
   int f = bar (1);
   int g = bar (6);			// { dg-message "in 'constexpr' expansion of" }
-  int h = 0 ? bar (7) : 1;		// { dg-message "in 'constexpr' expansion of" }
-  h += 0 ? bar (8) : 1;			// { dg-message "in 'constexpr' expansion of" }
+  int h = 0 ? bar (7) : 1;
+  h += 0 ? bar (8) : 1;
   if (0)
     bar (9);				// { dg-message "in 'constexpr' expansion of" }
   else
@@ -33,13 +33,13 @@ foo ()
   else
     bar (12);				// { dg-message "in 'constexpr' expansion of" }
   if constexpr (0)
-    bar (13);				// { dg-message "in 'constexpr' expansion of" }
+    bar (13);
   else
     bar (14);				// { dg-message "in 'constexpr' expansion of" }
   if constexpr (1)
     bar (15);				// { dg-message "in 'constexpr' expansion of" }
   else
-    bar (16);				// { dg-message "in 'constexpr' expansion of" }
+    bar (16);
 }
 
 consteval int
@@ -77,22 +77,25 @@ template <typename T>
 void
 qux ()
 {
+  // Used to give errors errors here, but not since we moved consteval
+  // function folding to cp_fold_r which isn't called on uninstantiated
+  // templates.
   if (0)
-    bar (2);				// { dg-message "in 'constexpr' expansion of" }
+    bar (2);
   else
-    bar (3);				// { dg-message "in 'constexpr' expansion of" }
+    bar (3);
   if (1)
-    bar (4);				// { dg-message "in 'constexpr' expansion of" }
+    bar (4);
   else
-    bar (5);				// { dg-message "in 'constexpr' expansion of" }
+    bar (5);
   if constexpr (0)
-    bar (6);				// { dg-message "in 'constexpr' expansion of" }
+    bar (6);
   else
-    bar (7);				// { dg-message "in 'constexpr' expansion of" }
+    bar (7);
   if constexpr (1)
-    bar (8);				// { dg-message "in 'constexpr' expansion of" }
+    bar (8);
   else
-    bar (9);				// { dg-message "in 'constexpr' expansion of" }
+    bar (9);
   if (0)
     bar ((T) 2);
   else
diff --git a/gcc/testsuite/g++.dg/cpp2a/consteval3.C b/gcc/testsuite/g++.dg/cpp2a/consteval3.C
index 627ab142d5a..9efac8c8eae 100644
--- a/gcc/testsuite/g++.dg/cpp2a/consteval3.C
+++ b/gcc/testsuite/g++.dg/cpp2a/consteval3.C
@@ -18,8 +18,7 @@ consteval int f6 (int x) { return x; }
 int d = 6;		// { dg-message "'int d' is not const" }
 int e = f6 (d);		// { dg-error "the value of 'd' is not usable in a constant expression" }
 constexpr int f7 (int x) { return f6 (x); }	// { dg-error "'x' is not a constant expression" }
-constexpr int f = f7 (5);	// { dg-error "" }
-				// { dg-message "in 'constexpr' expansion of" "" { target *-*-* } .-1 }
+constexpr int f = f7 (5);
 using fnptr = int (int);
 fnptr *g = f6;		// { dg-error "taking address of an immediate function 'consteval int f6\\(int\\)'" }
 int f8 (fnptr *);
diff --git a/gcc/testsuite/g++.dg/cpp2a/consteval32.C b/gcc/testsuite/g++.dg/cpp2a/consteval32.C
new file mode 100644
index 00000000000..f1de63e41b9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/consteval32.C
@@ -0,0 +1,4 @@
+// { dg-do compile { target c++20 } }
+
+consteval int foo ()  { return 42; }
+int bar () { return (*(&foo)) (); } // { dg-error "taking address" }
diff --git a/gcc/testsuite/g++.dg/cpp2a/consteval33.C b/gcc/testsuite/g++.dg/cpp2a/consteval33.C
new file mode 100644
index 00000000000..3d50b00c7a3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/consteval33.C
@@ -0,0 +1,34 @@
+// { dg-do compile { target c++20 } }
+
+consteval int id (int i) { return i; }
+consteval int add (int i, int j) { return i + j; }
+
+constexpr int
+foo (int i = id (42))
+{
+  return i + id (id (id (0)));
+}
+
+constexpr int
+bar (int i = id (id (id (42))))
+{
+  return i;
+}
+
+constexpr int
+baz (int i = add (add (id (1), id (2)), id (3)))
+{
+  return i;
+}
+
+void
+g ()
+{
+  foo ();
+  bar ();
+  baz ();
+}
+
+static_assert (foo () == 42);
+static_assert (bar () == 42);
+static_assert (baz () == 6);
diff --git a/gcc/testsuite/g++.dg/cpp2a/consteval9.C b/gcc/testsuite/g++.dg/cpp2a/consteval9.C
index 489286a12d2..230a6e9951c 100644
--- a/gcc/testsuite/g++.dg/cpp2a/consteval9.C
+++ b/gcc/testsuite/g++.dg/cpp2a/consteval9.C
@@ -18,7 +18,7 @@ void qux ()
 template <int N>
 void quux ()
 {
-  int a = bar (5);	// { dg-message "in 'constexpr' expansion of 'bar\\(5\\)'" }
+  int a = bar (5);
 }
 
 void
diff --git a/libstdc++-v3/testsuite/20_util/allocator/105975.cc b/libstdc++-v3/testsuite/20_util/allocator/105975.cc
index 09f27ba86e3..06f1d96d9b7 100644
--- a/libstdc++-v3/testsuite/20_util/allocator/105975.cc
+++ b/libstdc++-v3/testsuite/20_util/allocator/105975.cc
@@ -14,6 +14,6 @@ consteval bool test_pr105957()
   a.deallocate(p, n);
   return true;
 }
-static_assert( test_pr105957() );
+static_assert( test_pr105957() ); // { dg-error "non-constant" }
 
 // { dg-error "throw_bad_array_new_length" "" { target *-*-* } 0 }
