From 87c2080b056ea2b7f145cba927f36e4f40900205 Mon Sep 17 00:00:00 2001
From: Jason Merrill <jason@redhat.com>
Date: Wed, 13 Oct 2021 11:47:25 -0400
Subject: [PATCH] c++: Add -fimplicit-constexpr

With each successive C++ standard the restrictions on the use of the
constexpr keyword for functions get weaker and weaker; it recently occurred
to me that it is heading toward the same fate as the C register keyword,
which was once useful for optimization but became obsolete.  Similarly, it
seems to me that we should be able to just treat inlines as constexpr
functions and not make people add the extra keyword everywhere.

There were a lot of testcase changes needed; many disabling errors about
non-constexpr functions that are now constexpr, and many disabling implicit
constexpr so that the tests can check the same thing as before, whether
that's mangling or whatever.

gcc/c-family/ChangeLog:

	* c.opt: Add -fimplicit-constexpr.
	* c-cppbuiltin.c: Define __cpp_implicit_constexpr.
	* c-opts.c (c_common_post_options): Disable below C++14.

gcc/cp/ChangeLog:

	* cp-tree.h (struct lang_decl_fn): Add implicit_constexpr.
	(decl_implicit_constexpr_p): New.
	* class.c (type_maybe_constexpr_destructor): Use
	TYPE_HAS_TRIVIAL_DESTRUCTOR and maybe_constexpr_fn.
	(finalize_literal_type_property): Simplify.
	* constexpr.c (is_valid_constexpr_fn): Check for dtor.
	(maybe_save_constexpr_fundef): Try to set DECL_DECLARED_CONSTEXPR_P
	on inlines.
	(cxx_eval_call_expression): Use maybe_constexpr_fn.
	(maybe_constexpr_fn): Handle flag_implicit_constexpr.
	(var_in_maybe_constexpr_fn): Use maybe_constexpr_fn.
	(potential_constant_expression_1): Likewise.
	(decl_implicit_constexpr_p): New.
	* decl.c (validate_constexpr_redeclaration): Allow change with
	-fimplicit-constexpr.
	(grok_special_member_properties): Use maybe_constexpr_fn.
	* error.c (dump_function_decl): Don't print 'constexpr'
	if it's implicit.
	* Make-lang.in (check-c++-all): Update.

libstdc++-v3/ChangeLog:

	* testsuite/20_util/to_address/1_neg.cc: Adjust error.
	* testsuite/26_numerics/random/concept.cc: Adjust asserts.

gcc/testsuite/ChangeLog:

	* lib/g++-dg.exp: Handle "impcx".
	* lib/target-supports.exp
	(check_effective_target_implicit_constexpr): New.
	* g++.dg/abi/abi-tag16.C:
	* g++.dg/abi/abi-tag18a.C:
	* g++.dg/abi/guard4.C:
	* g++.dg/abi/lambda-defarg1.C:
	* g++.dg/abi/mangle26.C:
	* g++.dg/cpp0x/constexpr-diag3.C:
	* g++.dg/cpp0x/constexpr-ex1.C:
	* g++.dg/cpp0x/constexpr-ice5.C:
	* g++.dg/cpp0x/constexpr-incomplete2.C:
	* g++.dg/cpp0x/constexpr-memfn1.C:
	* g++.dg/cpp0x/constexpr-neg3.C:
	* g++.dg/cpp0x/constexpr-specialization.C:
	* g++.dg/cpp0x/inh-ctor19.C:
	* g++.dg/cpp0x/inh-ctor30.C:
	* g++.dg/cpp0x/lambda/lambda-mangle3.C:
	* g++.dg/cpp0x/lambda/lambda-mangle5.C:
	* g++.dg/cpp1y/auto-fn12.C:
	* g++.dg/cpp1y/constexpr-loop5.C:
	* g++.dg/cpp1z/constexpr-lambda7.C:
	* g++.dg/cpp2a/constexpr-dtor3.C:
	* g++.dg/cpp2a/constexpr-new13.C:
	* g++.dg/cpp2a/constinit11.C:
	* g++.dg/cpp2a/constinit12.C:
	* g++.dg/cpp2a/constinit14.C:
	* g++.dg/cpp2a/constinit15.C:
	* g++.dg/cpp2a/spaceship-constexpr1.C:
	* g++.dg/cpp2a/spaceship-eq3.C:
	* g++.dg/cpp2a/udlit-class-nttp-neg2.C:
	* g++.dg/debug/dwarf2/auto1.C:
	* g++.dg/debug/dwarf2/cdtor-1.C:
	* g++.dg/debug/dwarf2/lambda1.C:
	* g++.dg/debug/dwarf2/pr54508.C:
	* g++.dg/debug/dwarf2/pubnames-2.C:
	* g++.dg/debug/dwarf2/pubnames-3.C:
	* g++.dg/ext/is_literal_type3.C:
	* g++.dg/ext/visibility/template7.C:
	* g++.dg/gcov/gcov-12.C:
	* g++.dg/gcov/gcov-2.C:
	* g++.dg/ipa/devirt-35.C:
	* g++.dg/ipa/devirt-36.C:
	* g++.dg/ipa/devirt-37.C:
	* g++.dg/ipa/devirt-44.C:
	* g++.dg/ipa/imm-devirt-1.C:
	* g++.dg/lookup/builtin5.C:
	* g++.dg/lto/inline-crossmodule-1_0.C:
	* g++.dg/modules/enum-1_a.C:
	* g++.dg/modules/fn-inline-1_c.C:
	* g++.dg/modules/pmf-1_b.C:
	* g++.dg/modules/used-1_c.C:
	* g++.dg/tls/thread_local11.C:
	* g++.dg/tls/thread_local11a.C:
	* g++.dg/tm/pr46653.C:
	* g++.dg/ubsan/pr70035.C:
	* g++.old-deja/g++.other/delete6.C:
	* g++.dg/modules/pmf-1_a.H:
	Adjust for implicit constexpr.
---
 gcc/c-family/c-cppbuiltin.c                   |  2 +
 gcc/c-family/c-opts.c                         |  3 +
 gcc/c-family/c.opt                            |  4 +
 gcc/cp/Make-lang.in                           |  2 +-
 gcc/cp/class.c                                | 11 ++-
 gcc/cp/constexpr.c                            | 85 ++++++++++++++++---
 gcc/cp/cp-tree.h                              |  4 +-
 gcc/cp/decl.c                                 |  8 +-
 gcc/cp/error.c                                |  3 +-
 gcc/testsuite/g++.dg/abi/abi-tag16.C          |  2 +-
 gcc/testsuite/g++.dg/abi/abi-tag18a.C         |  2 +-
 gcc/testsuite/g++.dg/abi/guard4.C             |  3 +-
 gcc/testsuite/g++.dg/abi/lambda-defarg1.C     |  1 +
 gcc/testsuite/g++.dg/abi/mangle26.C           |  2 +-
 gcc/testsuite/g++.dg/cpp0x/constexpr-diag3.C  | 14 +--
 gcc/testsuite/g++.dg/cpp0x/constexpr-ex1.C    |  4 +-
 gcc/testsuite/g++.dg/cpp0x/constexpr-ice5.C   |  2 +-
 .../g++.dg/cpp0x/constexpr-incomplete2.C      |  2 +-
 gcc/testsuite/g++.dg/cpp0x/constexpr-memfn1.C |  4 +-
 gcc/testsuite/g++.dg/cpp0x/constexpr-neg3.C   |  4 +-
 .../g++.dg/cpp0x/constexpr-specialization.C   |  8 +-
 gcc/testsuite/g++.dg/cpp0x/inh-ctor19.C       |  2 +-
 gcc/testsuite/g++.dg/cpp0x/inh-ctor30.C       |  1 +
 .../g++.dg/cpp0x/lambda/lambda-mangle3.C      |  1 +
 .../g++.dg/cpp0x/lambda/lambda-mangle5.C      |  1 +
 gcc/testsuite/g++.dg/cpp1y/auto-fn12.C        |  1 +
 gcc/testsuite/g++.dg/cpp1y/constexpr-loop5.C  |  4 +-
 .../g++.dg/cpp1z/constexpr-lambda7.C          |  2 +-
 gcc/testsuite/g++.dg/cpp2a/constexpr-dtor3.C  | 18 ++--
 gcc/testsuite/g++.dg/cpp2a/constexpr-new13.C  |  4 +-
 gcc/testsuite/g++.dg/cpp2a/constinit11.C      | 10 +--
 gcc/testsuite/g++.dg/cpp2a/constinit12.C      |  4 +-
 gcc/testsuite/g++.dg/cpp2a/constinit14.C      |  2 +-
 gcc/testsuite/g++.dg/cpp2a/constinit15.C      |  2 +-
 .../g++.dg/cpp2a/spaceship-constexpr1.C       |  4 +-
 gcc/testsuite/g++.dg/cpp2a/spaceship-eq3.C    |  4 +-
 .../g++.dg/cpp2a/udlit-class-nttp-neg2.C      |  4 +-
 gcc/testsuite/g++.dg/debug/dwarf2/auto1.C     |  2 +-
 gcc/testsuite/g++.dg/debug/dwarf2/cdtor-1.C   |  2 +-
 gcc/testsuite/g++.dg/debug/dwarf2/lambda1.C   |  2 +-
 gcc/testsuite/g++.dg/debug/dwarf2/pr54508.C   |  2 +-
 .../g++.dg/debug/dwarf2/pubnames-2.C          |  2 +-
 .../g++.dg/debug/dwarf2/pubnames-3.C          |  2 +-
 gcc/testsuite/g++.dg/ext/is_literal_type3.C   |  4 +
 .../g++.dg/ext/visibility/template7.C         |  2 +-
 gcc/testsuite/g++.dg/gcov/gcov-12.C           |  2 +-
 gcc/testsuite/g++.dg/gcov/gcov-2.C            |  2 +-
 gcc/testsuite/g++.dg/ipa/devirt-35.C          |  5 +-
 gcc/testsuite/g++.dg/ipa/devirt-36.C          |  4 +-
 gcc/testsuite/g++.dg/ipa/devirt-37.C          |  2 +-
 gcc/testsuite/g++.dg/ipa/devirt-44.C          |  2 +-
 gcc/testsuite/g++.dg/ipa/imm-devirt-1.C       |  4 +-
 gcc/testsuite/g++.dg/lookup/builtin5.C        |  2 +-
 .../g++.dg/lto/inline-crossmodule-1_0.C       |  2 +-
 gcc/testsuite/g++.dg/modules/enum-1_a.C       |  2 +-
 gcc/testsuite/g++.dg/modules/fn-inline-1_c.C  |  2 +-
 gcc/testsuite/g++.dg/modules/pmf-1_a.H        |  2 +-
 gcc/testsuite/g++.dg/modules/pmf-1_b.C        |  2 +-
 gcc/testsuite/g++.dg/modules/used-1_c.C       |  2 +-
 gcc/testsuite/g++.dg/tls/thread_local11.C     |  2 +-
 gcc/testsuite/g++.dg/tls/thread_local11a.C    |  2 +-
 gcc/testsuite/g++.dg/tm/pr46653.C             |  2 +-
 gcc/testsuite/g++.dg/ubsan/pr70035.C          |  2 +-
 .../g++.old-deja/g++.other/delete6.C          |  2 +-
 gcc/testsuite/lib/g++-dg.exp                  |  3 +-
 gcc/testsuite/lib/target-supports.exp         |  4 +
 .../testsuite/20_util/to_address/1_neg.cc     |  2 +-
 .../testsuite/26_numerics/random/concept.cc   |  8 ++
 68 files changed, 211 insertions(+), 103 deletions(-)

diff --git a/gcc/c-family/c-cppbuiltin.c b/gcc/c-family/c-cppbuiltin.c
index 60e9e0520628..eb34d5af0045 100644
--- a/gcc/c-family/c-cppbuiltin.c
+++ b/gcc/c-family/c-cppbuiltin.c
@@ -1111,6 +1111,8 @@ c_cpp_builtins (cpp_reader *pfile)
       if (cxx_dialect >= cxx11 && strcmp (thread_model, "single") != 0)
 	cpp_define (pfile, "__STDCPP_THREADS__=1");
 #endif
+      if (flag_implicit_constexpr)
+	cpp_define (pfile, "__cpp_implicit_constexpr=20211111L");
     }
   /* Note that we define this for C as well, so that we know if
      __attribute__((cleanup)) will interface with EH.  */
diff --git a/gcc/c-family/c-opts.c b/gcc/c-family/c-opts.c
index 0225cba7a4bf..62f58295c119 100644
--- a/gcc/c-family/c-opts.c
+++ b/gcc/c-family/c-opts.c
@@ -1052,6 +1052,9 @@ c_common_post_options (const char **pfilename)
       && flag_strong_eval_order == -1)
     flag_strong_eval_order = (cxx_dialect >= cxx17 ? 2 : 1);
 
+  if (flag_implicit_constexpr && cxx_dialect < cxx14)
+    flag_implicit_constexpr = false;
+
   /* Global sized deallocation is new in C++14.  */
   if (flag_sized_deallocation == -1)
     flag_sized_deallocation = (cxx_dialect >= cxx14);
diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index 06457ac739e4..8a4cd634f77e 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -1712,6 +1712,10 @@ fimplement-inlines
 C++ ObjC++ Var(flag_implement_inlines) Init(1)
 Export functions even if they can be inlined.
 
+fimplicit-constexpr
+C++ ObjC++ Var(flag_implicit_constexpr)
+Make inline functions constexpr by default.
+
 fimplicit-inline-templates
 C++ ObjC++ Var(flag_implicit_inline_templates) Init(1)
 Emit implicit instantiations of inline templates.
diff --git a/gcc/cp/Make-lang.in b/gcc/cp/Make-lang.in
index 84694249b873..de1fc0249e67 100644
--- a/gcc/cp/Make-lang.in
+++ b/gcc/cp/Make-lang.in
@@ -221,7 +221,7 @@ check-c++17:
 
 # Run the testsuite in all standard conformance levels.
 check-c++-all:
-	$(MAKE) RUNTESTFLAGS="$(RUNTESTFLAGS) --stds=98,11,14,17,2a,concepts" check-g++
+	$(MAKE) RUNTESTFLAGS="$(RUNTESTFLAGS) --stds=98,11,14,17,20,23,impcx" check-g++
 
 # Run the testsuite with garbage collection at every opportunity.
 check-g++-strict-gc:
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index bf92300a1789..c30a44f039b2 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -5547,10 +5547,16 @@ type_has_constexpr_destructor (tree t)
 static bool
 type_maybe_constexpr_destructor (tree t)
 {
+  /* Until C++20, only trivial destruction is constexpr.  */
+  if (TYPE_HAS_TRIVIAL_DESTRUCTOR (t))
+    return true;
+  if (cxx_dialect < cxx20)
+    return false;
   if (CLASS_TYPE_P (t) && CLASSTYPE_LAZY_DESTRUCTOR (t))
     /* Assume it's constexpr.  */
     return true;
-  return type_has_constexpr_destructor (t);
+  tree fn = CLASSTYPE_DESTRUCTOR (t);
+  return (fn && maybe_constexpr_fn (fn));
 }
 
 /* Returns true iff class TYPE has a virtual destructor.  */
@@ -5823,8 +5829,7 @@ finalize_literal_type_property (tree t)
   if (cxx_dialect < cxx11)
     CLASSTYPE_LITERAL_P (t) = false;
   else if (CLASSTYPE_LITERAL_P (t)
-	   && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t)
-	   && (cxx_dialect < cxx20 || !type_maybe_constexpr_destructor (t)))
+	   && !type_maybe_constexpr_destructor (t))
     CLASSTYPE_LITERAL_P (t) = false;
   else if (CLASSTYPE_LITERAL_P (t) && LAMBDA_TYPE_P (t))
     CLASSTYPE_LITERAL_P (t) = (cxx_dialect >= cxx17);
diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index c92db5d413c2..69d9d3daeca7 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -37,6 +37,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "stor-layout.h"
 #include "cgraph.h"
 #include "opts.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 static bool verify_constant (tree, bool, bool *, bool *);
 #define VERIFY_CONSTANT(X)						\
@@ -220,6 +222,17 @@ is_valid_constexpr_fn (tree fun, bool complain)
 	inform (DECL_SOURCE_LOCATION (fun),
 		"lambdas are implicitly %<constexpr%> only in C++17 and later");
     }
+  else if (DECL_DESTRUCTOR_P (fun))
+    {
+      if (cxx_dialect < cxx20)
+	{
+	  ret = false;
+	  if (complain)
+	    error_at (DECL_SOURCE_LOCATION (fun),
+		      "%<constexpr%> destructors only available"
+		      " with %<-std=c++20%> or %<-std=gnu++20%>");
+	}
+    }
   else if (!DECL_CONSTRUCTOR_P (fun))
     {
       tree rettype = TREE_TYPE (TREE_TYPE (fun));
@@ -865,12 +878,31 @@ void
 maybe_save_constexpr_fundef (tree fun)
 {
   if (processing_template_decl
-      || !DECL_DECLARED_CONSTEXPR_P (fun)
       || cp_function_chain->invalid_constexpr
       || (DECL_CLONED_FUNCTION_P (fun) && !DECL_DELETING_DESTRUCTOR_P (fun)))
     return;
 
-  bool complain = !DECL_GENERATED_P (fun);
+  /* With -fimplicit-constexpr, try to make inlines constexpr.  We'll
+     actually set DECL_DECLARED_CONSTEXPR_P below if the checks pass.  */
+  bool implicit = false;
+  if (flag_implicit_constexpr)
+    {
+      if (DECL_DELETING_DESTRUCTOR_P (fun)
+	  && decl_implicit_constexpr_p (DECL_CLONED_FUNCTION (fun)))
+	/* Don't inherit implicit constexpr from the non-deleting
+	   destructor.  */
+	DECL_DECLARED_CONSTEXPR_P (fun) = false;
+
+      if (!DECL_DECLARED_CONSTEXPR_P (fun)
+	  && DECL_DECLARED_INLINE_P (fun)
+	  && !lookup_attribute ("noinline", DECL_ATTRIBUTES (fun)))
+	implicit = true;
+    }
+
+  if (!DECL_DECLARED_CONSTEXPR_P (fun) && !implicit)
+    return;
+
+  bool complain = !DECL_GENERATED_P (fun) && !implicit;
 
   if (!is_valid_constexpr_fn (fun, complain))
     return;
@@ -878,7 +910,7 @@ maybe_save_constexpr_fundef (tree fun)
   tree massaged = massage_constexpr_body (fun, DECL_SAVED_TREE (fun));
   if (massaged == NULL_TREE || massaged == error_mark_node)
     {
-      if (!DECL_CONSTRUCTOR_P (fun))
+      if (!DECL_CONSTRUCTOR_P (fun) && complain)
 	error ("body of %<constexpr%> function %qD not a return-statement",
 	       fun);
       return;
@@ -907,6 +939,21 @@ maybe_save_constexpr_fundef (tree fun)
   if (!potential && complain)
     return;
 
+  if (implicit)
+    {
+      if (potential)
+	{
+	  DECL_DECLARED_CONSTEXPR_P (fun) = true;
+	  DECL_LANG_SPECIFIC (fun)->u.fn.implicit_constexpr = true;
+	  if (DECL_CONSTRUCTOR_P (fun))
+	    TYPE_HAS_CONSTEXPR_CTOR (DECL_CONTEXT (fun)) = true;
+	}
+      else
+	/* Don't bother keeping the pre-generic body of unsuitable functions
+	   not explicitly declared constexpr.  */
+	return;
+    }
+
   constexpr_fundef entry = {fun, NULL_TREE, NULL_TREE, NULL_TREE};
   bool clear_ctx = false;
   if (DECL_RESULT (fun) && DECL_CONTEXT (DECL_RESULT (fun)) == NULL_TREE)
@@ -2404,7 +2451,7 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
 					   lval, non_constant_p, overflow_p);
   if (DECL_THUNK_P (fun))
     return cxx_eval_thunk_call (ctx, t, fun, lval, non_constant_p, overflow_p);
-  if (!DECL_DECLARED_CONSTEXPR_P (fun))
+  if (!maybe_constexpr_fn (fun))
     {
       if (TREE_CODE (t) == CALL_EXPR
 	  && cxx_replaceable_global_alloc_fn (fun)
@@ -5229,7 +5276,9 @@ bool
 maybe_constexpr_fn (tree t)
 {
   return (DECL_DECLARED_CONSTEXPR_P (t)
-	  || (cxx_dialect >= cxx17 && LAMBDA_FUNCTION_P (t)));
+	  || (cxx_dialect >= cxx17 && LAMBDA_FUNCTION_P (t))
+	  || (flag_implicit_constexpr
+	      && DECL_DECLARED_INLINE_P (STRIP_TEMPLATE (t))));
 }
 
 /* True if T was declared in a function that might be constexpr: either a
@@ -5238,11 +5287,8 @@ maybe_constexpr_fn (tree t)
 bool
 var_in_maybe_constexpr_fn (tree t)
 {
-  if (cxx_dialect >= cxx17
-      && DECL_FUNCTION_SCOPE_P (t)
-      && LAMBDA_FUNCTION_P (DECL_CONTEXT (t)))
-    return true;
-  return var_in_constexpr_fn (t);
+  return (DECL_FUNCTION_SCOPE_P (t)
+	  && maybe_constexpr_fn (DECL_CONTEXT (t)));
 }
 
 /* We're assigning INIT to TARGET.  In do_build_copy_constructor and
@@ -8219,7 +8265,7 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
 	      {
 		if (builtin_valid_in_constant_expr_p (fun))
 		  return true;
-		if (!DECL_DECLARED_CONSTEXPR_P (fun)
+		if (!maybe_constexpr_fn (fun)
 		    /* Allow any built-in function; if the expansion
 		       isn't constant, we'll deal with that then.  */
 		    && !fndecl_built_in_p (fun)
@@ -9257,6 +9303,23 @@ is_nondependent_static_init_expression (tree t)
 	  && !instantiation_dependent_expression_p (t));
 }
 
+/* True iff FN is an implicitly constexpr function.  */
+
+bool
+decl_implicit_constexpr_p (tree fn)
+{
+  if (!(flag_implicit_constexpr
+	&& TREE_CODE (fn) == FUNCTION_DECL
+	&& DECL_DECLARED_CONSTEXPR_P (fn)))
+    return false;
+
+  if (DECL_CLONED_FUNCTION_P (fn))
+    fn = DECL_CLONED_FUNCTION (fn);
+
+  return (DECL_LANG_SPECIFIC (fn)
+	  && DECL_LANG_SPECIFIC (fn)->u.fn.implicit_constexpr);
+}
+
 /* Finalize constexpr processing after parsing.  */
 
 void
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index f387b5036d27..acc98c9c452a 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -2868,8 +2868,9 @@ struct GTY(()) lang_decl_fn {
   unsigned immediate_fn_p : 1;
   unsigned maybe_deleted : 1;
   unsigned coroutine_p : 1;
+  unsigned implicit_constexpr : 1;
 
-  unsigned spare : 10;
+  unsigned spare : 9;
 
   /* 32-bits padding on 64-bit host.  */
 
@@ -8315,6 +8316,7 @@ extern vec<tree> cx_error_context               (void);
 extern tree fold_sizeof_expr			(tree);
 extern void clear_cv_and_fold_caches		(void);
 extern tree unshare_constructor			(tree CXX_MEM_STAT_INFO);
+extern bool decl_implicit_constexpr_p		(tree);
 
 /* An RAII sentinel used to restrict constexpr evaluation so that it
    doesn't do anything that causes extra DECL_UID generation.  */
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index eed478199ea5..2ddf0e4a5247 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -1290,6 +1290,12 @@ validate_constexpr_redeclaration (tree old_decl, tree new_decl)
     }
   if (TREE_CODE (old_decl) == FUNCTION_DECL)
     {
+      /* With -fimplicit-constexpr, ignore changes in the constexpr
+	 keyword.  */
+      if (flag_implicit_constexpr
+	  && (DECL_IMMEDIATE_FUNCTION_P (new_decl)
+	      == DECL_IMMEDIATE_FUNCTION_P (old_decl)))
+	return true;
       if (fndecl_built_in_p (old_decl))
 	{
 	  /* Hide a built-in declaration.  */
@@ -14863,7 +14869,7 @@ grok_special_member_properties (tree decl)
       if (is_list_ctor (decl))
 	TYPE_HAS_LIST_CTOR (class_type) = 1;
 
-      if (DECL_DECLARED_CONSTEXPR_P (decl)
+      if (maybe_constexpr_fn (decl)
 	  && !ctor && !move_fn_p (decl))
 	TYPE_HAS_CONSTEXPR_CTOR (class_type) = 1;
     }
diff --git a/gcc/cp/error.c b/gcc/cp/error.c
index 012a4ecddf44..872479369ab2 100644
--- a/gcc/cp/error.c
+++ b/gcc/cp/error.c
@@ -1686,7 +1686,8 @@ dump_function_decl (cxx_pretty_printer *pp, tree t, int flags)
   exceptions = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (t));
 
   /* Likewise for the constexpr specifier, in case t is a specialization.  */
-  constexpr_p = DECL_DECLARED_CONSTEXPR_P (t);
+  constexpr_p = (DECL_DECLARED_CONSTEXPR_P (t)
+		 && !decl_implicit_constexpr_p (t));
 
   /* Pretty print template instantiations only.  */
   if (DECL_USE_TEMPLATE (t) && DECL_TEMPLATE_INFO (t)
diff --git a/gcc/testsuite/g++.dg/abi/abi-tag16.C b/gcc/testsuite/g++.dg/abi/abi-tag16.C
index d4fa142762a8..3027d7906f51 100644
--- a/gcc/testsuite/g++.dg/abi/abi-tag16.C
+++ b/gcc/testsuite/g++.dg/abi/abi-tag16.C
@@ -1,4 +1,4 @@
-// { dg-options -Wabi=9 }
+// { dg-options "-Wabi=9 -fno-implicit-constexpr" }
 // { dg-final { scan-assembler "_ZGVZN1N1FEvE4NameB5cxx11" } }
 namespace std {
   __extension__ inline namespace __cxx11 __attribute__((abi_tag("cxx11"))) {
diff --git a/gcc/testsuite/g++.dg/abi/abi-tag18a.C b/gcc/testsuite/g++.dg/abi/abi-tag18a.C
index 95e192ae6f4a..c6fb1607a418 100644
--- a/gcc/testsuite/g++.dg/abi/abi-tag18a.C
+++ b/gcc/testsuite/g++.dg/abi/abi-tag18a.C
@@ -1,5 +1,5 @@
 // { dg-skip-if "PR 70349" { hppa*-*-hpux* && { ! lp64 } } }
-// { dg-options -fabi-version=9 }
+// { dg-options "-fabi-version=9 -fno-implicit-constexpr" }
 // { dg-final { scan-assembler "_Z1fB7__test1v" } }
 // { dg-final { scan-assembler "_ZZ1fB7__test1vEN1T1gB7__test2Ev" } }
 // { dg-final { scan-assembler "_ZZZ1fB7__test1vEN1T1gEvE1x" } }
diff --git a/gcc/testsuite/g++.dg/abi/guard4.C b/gcc/testsuite/g++.dg/abi/guard4.C
index 537c90524f3c..71e6744e3810 100644
--- a/gcc/testsuite/g++.dg/abi/guard4.C
+++ b/gcc/testsuite/g++.dg/abi/guard4.C
@@ -3,9 +3,10 @@
 
 namespace x {
   struct s {
-    s() {}
+    s();
     static int a;
   };
+  s::s() {}
   // { dg-final { scan-assembler {.weak[^\n]*_ZGVN1x1bE} } }
   struct s __attribute__((weak)) b = s();
 }
diff --git a/gcc/testsuite/g++.dg/abi/lambda-defarg1.C b/gcc/testsuite/g++.dg/abi/lambda-defarg1.C
index 8c5385812406..79e4fa64ac57 100644
--- a/gcc/testsuite/g++.dg/abi/lambda-defarg1.C
+++ b/gcc/testsuite/g++.dg/abi/lambda-defarg1.C
@@ -1,5 +1,6 @@
 // PR c++/91241
 // { dg-do compile { target c++11 } }
+// { dg-additional-options -fkeep-inline-functions }
 
 struct A {
   int *b(const int & = []() -> int { return 0; }(),
diff --git a/gcc/testsuite/g++.dg/abi/mangle26.C b/gcc/testsuite/g++.dg/abi/mangle26.C
index 5d1609596b90..2041d778b9a6 100644
--- a/gcc/testsuite/g++.dg/abi/mangle26.C
+++ b/gcc/testsuite/g++.dg/abi/mangle26.C
@@ -1,7 +1,7 @@
 // Test of std mangling
 
 // { dg-do compile }
-// { dg-options "-fno-inline" }
+// { dg-options "-fno-inline -fno-implicit-constexpr" }
 
 namespace std {
   struct A {
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-diag3.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-diag3.C
index 1c43569615c5..c167bb1d8bc1 100644
--- a/gcc/testsuite/g++.dg/cpp0x/constexpr-diag3.C
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-diag3.C
@@ -13,7 +13,7 @@ int main()
 
 // --------------------
 
-struct complex 			// { dg-message "no .constexpr. constructor" }
+struct complex 			// { dg-message "no .constexpr. constructor" "" { target { ! implicit_constexpr } } }
 {
   complex(double r, double i) : re(r), im(i) { }
   constexpr double real() const { return re; } // { dg-error "not a literal type" "" { target c++11_only } }
@@ -24,23 +24,23 @@ private:
   double im;
 };
 
-constexpr complex co1(0, 1);	   // { dg-error "19:the type .const complex. of .constexpr. variable .co1. is not literal" }
-constexpr double dd2 = co1.real(); // { dg-error "|in .constexpr. expansion of " }
+constexpr complex co1(0, 1);	   // { dg-error "19:the type .const complex. of .constexpr. variable .co1. is not literal" "" { target { ! implicit_constexpr } } }
+constexpr double dd2 = co1.real(); // { dg-error "|in .constexpr. expansion of " "" { target { ! implicit_constexpr } } }
 
 // --------------------
 
-struct base		       // { dg-message "no .constexpr. constructor" }
+struct base		       // { dg-message "no .constexpr. constructor" "" { target { ! implicit_constexpr } } }
 {
   int _M_i;
   base() : _M_i(5) { }
 };
 
-struct derived : public base	// { dg-message "base class" }
+struct derived : public base	// { dg-message "base class" "" { target { ! implicit_constexpr } } }
 {
-  constexpr derived(): base() { } // { dg-error "non-.constexpr. function" }
+  constexpr derived(): base() { } // { dg-error "non-.constexpr. function" "" { target { ! implicit_constexpr } } }
 };
 
-constexpr derived obj;		// { dg-error "not literal" }
+constexpr derived obj;		// { dg-error "not literal" "" { target { ! implicit_constexpr } } }
 
 // --------------------
 
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-ex1.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-ex1.C
index e5e58bddab0b..1d5c58b4090b 100644
--- a/gcc/testsuite/g++.dg/cpp0x/constexpr-ex1.C
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-ex1.C
@@ -87,7 +87,7 @@ struct resource {
   }
 };
 constexpr resource f(resource d)
-{ return d; }                  // { dg-error "non-.constexpr." }
-constexpr resource d = f(9);   // { dg-message ".constexpr." }
+{ return d; }                  // { dg-error "non-.constexpr." "" { target { ! implicit_constexpr } } }
+constexpr resource d = f(9);   // { dg-message ".constexpr." "" { target { ! implicit_constexpr } } }
 
 // 4.4 floating-point constant expressions
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-ice5.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-ice5.C
index 51b328e25980..e934421c2f48 100644
--- a/gcc/testsuite/g++.dg/cpp0x/constexpr-ice5.C
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-ice5.C
@@ -9,5 +9,5 @@ struct A
 struct B
 {
   A a[1];
-  constexpr B() : a() {} // { dg-error "non-constant|non-.constexpr." }
+  constexpr B() : a() {} // { dg-error "non-constant|non-.constexpr." "" { target { ! implicit_constexpr } } }
 };
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-incomplete2.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-incomplete2.C
index a04f1d51d22c..c018eded1de1 100644
--- a/gcc/testsuite/g++.dg/cpp0x/constexpr-incomplete2.C
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-incomplete2.C
@@ -28,4 +28,4 @@ struct D
   C<D> c;
 };
 
-constexpr D d {};		// { dg-error "non-.constexpr. function" }
+constexpr D d {};		// { dg-error "non-.constexpr. function" "" { target { ! implicit_constexpr } } }
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-memfn1.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-memfn1.C
index d58e2ec6b15f..37255282ded7 100644
--- a/gcc/testsuite/g++.dg/cpp0x/constexpr-memfn1.C
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-memfn1.C
@@ -13,6 +13,6 @@ constexpr X X::g(X x) { return x; }
 struct Y
 {
   Y() { }
-  constexpr Y f(Y y) { return y; }  // { dg-error "constexpr" }
-  static constexpr Y g(Y y) { return y; } // { dg-error "constexpr" }
+  constexpr Y f(Y y) { return y; }  // { dg-error "constexpr" "" { target { ! implicit_constexpr } } }
+  static constexpr Y g(Y y) { return y; } // { dg-error "constexpr" "" { target { ! implicit_constexpr } } }
 };
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-neg3.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-neg3.C
index 55bb838a2bfb..89559d760588 100644
--- a/gcc/testsuite/g++.dg/cpp0x/constexpr-neg3.C
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-neg3.C
@@ -9,7 +9,7 @@ struct A
 template<typename> struct B
 {
   A a;
-  constexpr int bar() { return a.foo(); } // { dg-error "foo" }
+  constexpr int bar() { return a.foo(); } // { dg-error "foo" "" { target { ! implicit_constexpr } } }
 };
 
-constexpr int i = B<void>().bar(); // { dg-error "bar" }
+constexpr int i = B<void>().bar(); // { dg-error "bar" "" { target { ! implicit_constexpr } } }
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-specialization.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-specialization.C
index 64d8f4ec2666..acda6e0bcbfd 100644
--- a/gcc/testsuite/g++.dg/cpp0x/constexpr-specialization.C
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-specialization.C
@@ -3,10 +3,10 @@
 
 template<typename T> constexpr int foo(T);
 template<> int foo(int);
-template<> int foo(int);            // { dg-message "previous declaration 'int foo" }
-template<> constexpr int foo(int);  // { dg-error "redeclaration 'constexpr int foo" }
+template<> int foo(int);            // { dg-message "previous declaration 'int foo" "" { target { ! implicit_constexpr } } }
+template<> constexpr int foo(int);  // { dg-error "redeclaration 'constexpr int foo" "" { target { ! implicit_constexpr } } }
 
 template<typename T> int bar(T);
 template<> constexpr int bar(int);
-template<> constexpr int bar(int);  // { dg-message "previous declaration 'constexpr int bar" }
-template<> int bar(int);            // { dg-error "redeclaration 'int bar" }
+template<> constexpr int bar(int);  // { dg-message "previous declaration 'constexpr int bar" "" { target { ! implicit_constexpr } } }
+template<> int bar(int);            // { dg-error "redeclaration 'int bar" "" { target { ! implicit_constexpr } } }
diff --git a/gcc/testsuite/g++.dg/cpp0x/inh-ctor19.C b/gcc/testsuite/g++.dg/cpp0x/inh-ctor19.C
index 7e2d58b422ef..3476f9607ac0 100644
--- a/gcc/testsuite/g++.dg/cpp0x/inh-ctor19.C
+++ b/gcc/testsuite/g++.dg/cpp0x/inh-ctor19.C
@@ -11,4 +11,4 @@ struct B : A
   using A::A;
 };
 
-constexpr B b;  // { dg-error "literal" }
+constexpr B b;  // { dg-error "literal" "" { target { ! implicit_constexpr } } }
diff --git a/gcc/testsuite/g++.dg/cpp0x/inh-ctor30.C b/gcc/testsuite/g++.dg/cpp0x/inh-ctor30.C
index 04c58636d8d5..c978f0c37616 100644
--- a/gcc/testsuite/g++.dg/cpp0x/inh-ctor30.C
+++ b/gcc/testsuite/g++.dg/cpp0x/inh-ctor30.C
@@ -1,6 +1,7 @@
 // PR c++/81860
 // { dg-do compile { target c++11 } }
 // { dg-final { scan-assembler "_ZN1AIjEC\[12\]Ev" } }
+// { dg-additional-options -fno-implicit-constexpr }
 
 template <typename T>
 struct A
diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-mangle3.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-mangle3.C
index 5f17a21cac48..2120d8c72fe9 100644
--- a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-mangle3.C
+++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-mangle3.C
@@ -1,6 +1,7 @@
 // PR c++/51818
 // { dg-do compile { target c++11 } }
 // { dg-final { scan-assembler "_ZN1AC1IN3foo3barMUlvE_EEET_" } }
+// { dg-additional-options -fno-implicit-constexpr }
 
 struct A
 {
diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-mangle5.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-mangle5.C
index dd95894755c9..23df3a2b4167 100644
--- a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-mangle5.C
+++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-mangle5.C
@@ -1,4 +1,5 @@
 // { dg-do compile { target c++11 } }
+// { dg-additional-options -fkeep-inline-functions }
 // { dg-final { scan-assembler "_ZZN1AIiEC4IiEET_S2_Ed_NKUlvE_clEv" } }
 
 template <class T> struct A
diff --git a/gcc/testsuite/g++.dg/cpp1y/auto-fn12.C b/gcc/testsuite/g++.dg/cpp1y/auto-fn12.C
index 224f2789bcd8..98885799de98 100644
--- a/gcc/testsuite/g++.dg/cpp1y/auto-fn12.C
+++ b/gcc/testsuite/g++.dg/cpp1y/auto-fn12.C
@@ -1,5 +1,6 @@
 // { dg-do compile { target c++14 } }
 // { dg-final { scan-assembler "_ZN1AIiEcvDaEv" } }
+// { dg-additional-options -fno-implicit-constexpr }
 
 template <class T>
 struct A {
diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-loop5.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-loop5.C
index 02f372d98887..150aadfe6094 100644
--- a/gcc/testsuite/g++.dg/cpp1y/constexpr-loop5.C
+++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-loop5.C
@@ -9,11 +9,11 @@ template<typename>
 constexpr int count()
 {
     auto item = thing {};
-    for(; (item.foo(), false);); // { dg-error "foo" }
+    for(; (item.foo(), false);); // { dg-error "foo" "" { target { ! implicit_constexpr } } }
     return 0;
 }
 
 int main()
 {
-    static_assert( count<int>() == 0, "" ); // { dg-error "" }
+    static_assert( count<int>() == 0, "" ); // { dg-error "" "" { target { ! implicit_constexpr } } }
 }
diff --git a/gcc/testsuite/g++.dg/cpp1z/constexpr-lambda7.C b/gcc/testsuite/g++.dg/cpp1z/constexpr-lambda7.C
index 474ce88f81f3..faac00ca9974 100644
--- a/gcc/testsuite/g++.dg/cpp1z/constexpr-lambda7.C
+++ b/gcc/testsuite/g++.dg/cpp1z/constexpr-lambda7.C
@@ -8,5 +8,5 @@ struct NonLiteral {
   int n;
 };
 
-static_assert( ID (NonLiteral{3}).n == 3); // { dg-error "non-literal" }
+static_assert( ID (NonLiteral{3}).n == 3); // { dg-error "non-literal" "" { target { ! implicit_constexpr } } }
 // { dg-prune-output "static assertion" }
diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-dtor3.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-dtor3.C
index 69fe9e26654f..a68a6b4af8bc 100644
--- a/gcc/testsuite/g++.dg/cpp2a/constexpr-dtor3.C
+++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-dtor3.C
@@ -7,16 +7,16 @@ struct S
   constexpr ~S () {}
   int s;
 };
-struct T	// { dg-message "'T' is not literal because" }
-{		// { dg-message "'T' does not have 'constexpr' destructor" "" { target *-*-* } .-1 }
+struct T	// { dg-message "'T' is not literal because" "" { target { ! implicit_constexpr } } }
+{		// { dg-message "'T' does not have 'constexpr' destructor" "" { target { ! implicit_constexpr } } .-1 }
   constexpr T () : t (0) {}
-  ~T () {}	// { dg-message "defaulted destructor calls non-'constexpr' 'T::~T\\(\\)'" }
+  ~T () {}	// { dg-message "defaulted destructor calls non-'constexpr' 'T::~T\\(\\)'" "" { target { ! implicit_constexpr } } }
   int t;
 };
 struct U : public S
 {
   constexpr U () : u (0) {}
-  constexpr ~U () = default;	// { dg-error "explicitly defaulted function 'constexpr U::~U\\(\\)' cannot be declared 'constexpr' because the implicit declaration is not 'constexpr'" }
+  constexpr ~U () = default;	// { dg-error "explicitly defaulted function 'constexpr U::~U\\(\\)' cannot be declared 'constexpr' because the implicit declaration is not 'constexpr'" "" { target { ! implicit_constexpr } } }
   int u;
   T t;
 };
@@ -100,11 +100,11 @@ struct W8
 struct X : public T
 {
   constexpr X () : x (0) {}
-  constexpr ~X () = default;	// { dg-error "explicitly defaulted function 'constexpr X::~X\\(\\)' cannot be declared 'constexpr' because the implicit declaration is not 'constexpr'" }
+  constexpr ~X () = default;	// { dg-error "explicitly defaulted function 'constexpr X::~X\\(\\)' cannot be declared 'constexpr' because the implicit declaration is not 'constexpr'" "" { target { ! implicit_constexpr } } }
   int x;
 };
 constexpr S s;
-constexpr T t;	// { dg-error "the type 'const T' of 'constexpr' variable 't' is not literal" }
+constexpr T t;	// { dg-error "the type 'const T' of 'constexpr' variable 't' is not literal" "" { target { ! implicit_constexpr } } }
 constexpr W0 w1;
 constexpr W0 w2 = 12;
 constexpr W1 w3 = 5;	// { dg-message "in 'constexpr' expansion of" }
@@ -167,19 +167,19 @@ constexpr int x5 = f5 ();	// { dg-message "in 'constexpr' expansion of" }
 void
 f6 ()
 {
-  constexpr T t2;	// { dg-error "the type 'const T' of 'constexpr' variable 't2' is not literal" }
+  constexpr T t2;	// { dg-error "the type 'const T' of 'constexpr' variable 't2' is not literal" "" { target { ! implicit_constexpr } } }
 }
 
 constexpr int
 f7 ()
 {
-  constexpr T t3;	// { dg-error "the type 'const T' of 'constexpr' variable 't3' is not literal" }
+  constexpr T t3;	// { dg-error "the type 'const T' of 'constexpr' variable 't3' is not literal" "" { target { ! implicit_constexpr } } }
   return 0;
 }
 
 constexpr int
 f8 ()
 {
-  T t4;			// { dg-error "variable 't4' of non-literal type 'T' in 'constexpr' function only available with" "" { target c++20_down } }
+  T t4;			// { dg-error "variable 't4' of non-literal type 'T' in 'constexpr' function only available with" "" { target { c++20_down && { ! implicit_constexpr } } } }
   return 0;
 }
diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-new13.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-new13.C
index 6762c24a3427..7eed50c7f4cf 100644
--- a/gcc/testsuite/g++.dg/cpp2a/constexpr-new13.C
+++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-new13.C
@@ -9,7 +9,7 @@ struct A {
 
 struct B : A {
   constexpr B () : b (0) {}
-  virtual int foo () { return 0 + b * 4; }	// { dg-message "declared here" }
+  virtual int foo () { return 0 + b * 4; }	// { dg-message "declared here" "" { target { ! implicit_constexpr } } }
   int b;
 };
 
@@ -18,7 +18,7 @@ foo ()
 {
   A *a = new B ();
   a->a = 4;
-  int r = a->foo ();	// { dg-error "call to non-.constexpr. function" }
+  int r = a->foo ();	// { dg-error "call to non-.constexpr. function" "" { target { ! implicit_constexpr } } }
   delete a;
   return r;
 }
diff --git a/gcc/testsuite/g++.dg/cpp2a/constinit11.C b/gcc/testsuite/g++.dg/cpp2a/constinit11.C
index e8b3bcb570b7..b09027718141 100644
--- a/gcc/testsuite/g++.dg/cpp2a/constinit11.C
+++ b/gcc/testsuite/g++.dg/cpp2a/constinit11.C
@@ -39,9 +39,9 @@ constinit thread_local const int &r2 = gl;
 constinit const int &r3 // { dg-error "variable .r3. does not have a constant initializer" }
   = foo (); // { dg-error "call to non-.constexpr. function" }
 constinit const literal &r4 = 42;
-constinit const nonliteral &r5 // { dg-error "variable .r5. does not have a constant initializer" }
-  = 42; // { dg-error "call to non-.constexpr. function" }
-constinit const int &r6 = nonliteral(2).m; // { dg-error "variable .r6. does not have a constant initializer|call to non-.constexpr. function" }
+constinit const nonliteral &r5 // { dg-error "variable .r5. does not have a constant initializer" "" { target { ! implicit_constexpr } } }
+  = 42; // { dg-error "call to non-.constexpr. function" "" { target { ! implicit_constexpr } } }
+constinit const int &r6 = nonliteral(2).m; // { dg-error "variable .r6. does not have a constant initializer|call to non-.constexpr. function" "" { target { ! implicit_constexpr } } }
 
 constinit pod p1;
 constinit pod p2 = { 42 };
@@ -64,8 +64,8 @@ constinit thread_local literal l11{};
 pod S::p;
 constinit pod S::pc(S::p); // { dg-error "variable .S::pc. does not have a constant initializer|not usable" }
 
-constinit const nonliteral S::n(42); // { dg-error "variable .S::n. does not have a constant initializer|call to non-.constexpr. function" }
-constinit int n1 = nonliteral{42}.m; // { dg-error "variable .n1. does not have a constant initializer|temporary of non-literal type" }
+constinit const nonliteral S::n(42); // { dg-error "variable .S::n. does not have a constant initializer|call to non-.constexpr. function" "" { target { ! implicit_constexpr } } }
+constinit int n1 = nonliteral{42}.m; // { dg-error "variable .n1. does not have a constant initializer|temporary of non-literal type" "" { target { ! implicit_constexpr } } }
 constinit int n2 = literal{42}.m;
 
 void
diff --git a/gcc/testsuite/g++.dg/cpp2a/constinit12.C b/gcc/testsuite/g++.dg/cpp2a/constinit12.C
index cc6569b2277b..faa1b430cee9 100644
--- a/gcc/testsuite/g++.dg/cpp2a/constinit12.C
+++ b/gcc/testsuite/g++.dg/cpp2a/constinit12.C
@@ -8,7 +8,7 @@ struct S {
 template <class T>
 struct U {
   T m;
-  constexpr U(int i) : m(i) { } // { dg-error "call to non-.constexpr. function" }
+  constexpr U(int i) : m(i) { } // { dg-error "call to non-.constexpr. function" "" { target { ! implicit_constexpr } } }
 };
 
-constinit U<S> u(42); // { dg-error "does not have a constant initializer|called in a constant expression" }
+constinit U<S> u(42); // { dg-error "does not have a constant initializer|called in a constant expression" "" { target { ! implicit_constexpr } } }
diff --git a/gcc/testsuite/g++.dg/cpp2a/constinit14.C b/gcc/testsuite/g++.dg/cpp2a/constinit14.C
index 86a058b632cc..06c4cb46722f 100644
--- a/gcc/testsuite/g++.dg/cpp2a/constinit14.C
+++ b/gcc/testsuite/g++.dg/cpp2a/constinit14.C
@@ -2,7 +2,7 @@
 // { dg-do compile { target c++20 } }
 
 struct Value {
-  Value() : v{new int{42}} {}
+  Value() : v{new int{42}} {}	// { dg-error "result of 'operator new'" "" { target implicit_constexpr } }
   int* v;
 };
 
diff --git a/gcc/testsuite/g++.dg/cpp2a/constinit15.C b/gcc/testsuite/g++.dg/cpp2a/constinit15.C
index 29e8b51326d4..b6215587badb 100644
--- a/gcc/testsuite/g++.dg/cpp2a/constinit15.C
+++ b/gcc/testsuite/g++.dg/cpp2a/constinit15.C
@@ -6,7 +6,7 @@ struct B {
 };
 
 struct A {
-    constinit static inline B b1{}; // { dg-error "does not have a constant initializer|call to non-.constexpr. function" }
+    constinit static inline B b1{}; // { dg-error "does not have a constant initializer|call to non-.constexpr. function" "" { target { ! implicit_constexpr } } }
 };
 
 int main() {
diff --git a/gcc/testsuite/g++.dg/cpp2a/spaceship-constexpr1.C b/gcc/testsuite/g++.dg/cpp2a/spaceship-constexpr1.C
index 6ccc7e8507bd..dff59271a1e6 100644
--- a/gcc/testsuite/g++.dg/cpp2a/spaceship-constexpr1.C
+++ b/gcc/testsuite/g++.dg/cpp2a/spaceship-constexpr1.C
@@ -9,7 +9,7 @@ struct A
 struct B
 {
   A a;
-  bool operator==(const B&) const = default; // { dg-error "A::operator==" }
+  bool operator==(const B&) const = default; // { dg-error "A::operator==" "" { target { ! implicit_constexpr } } }
 };
 
-constexpr bool x = B() == B();	// { dg-error "non-.constexpr" }
+constexpr bool x = B() == B();	// { dg-error "non-.constexpr" "" { target { ! implicit_constexpr } } }
diff --git a/gcc/testsuite/g++.dg/cpp2a/spaceship-eq3.C b/gcc/testsuite/g++.dg/cpp2a/spaceship-eq3.C
index d31faef095d0..7a517a8016c4 100644
--- a/gcc/testsuite/g++.dg/cpp2a/spaceship-eq3.C
+++ b/gcc/testsuite/g++.dg/cpp2a/spaceship-eq3.C
@@ -12,5 +12,5 @@ struct D
 };
 
 constexpr D d{A()};
-static_assert (d == d);		// { dg-error "non-constant|constexpr" }
-static_assert (!(d != d));	// { dg-error "non-constant|constexpr" }
+static_assert (d == d);		// { dg-error "constant|constexpr" }
+static_assert (!(d != d));	// { dg-error "constant|constexpr" }
diff --git a/gcc/testsuite/g++.dg/cpp2a/udlit-class-nttp-neg2.C b/gcc/testsuite/g++.dg/cpp2a/udlit-class-nttp-neg2.C
index 62cb86ae6954..ab7c012f5f47 100644
--- a/gcc/testsuite/g++.dg/cpp2a/udlit-class-nttp-neg2.C
+++ b/gcc/testsuite/g++.dg/cpp2a/udlit-class-nttp-neg2.C
@@ -9,5 +9,5 @@ struct non_literal_class {
   // auto operator<=> (const non_literal_fixed_string&) = default;
 };
 
-template <non_literal_class> // { dg-error "11:is not a valid type for a template non-type parameter because it is not structural" }
-int operator"" _udl();       // { dg-error "5:literal operator template .int operator\"\"_udl\\(\\). has invalid parameter list" }
+template <non_literal_class> // { dg-error "11:is not a valid type for a template non-type parameter because it is not structural" "" { target { ! implicit_constexpr } } }
+int operator"" _udl();       // { dg-error "5:literal operator template .int operator\"\"_udl\\(\\). has invalid parameter list" "" { target { ! implicit_constexpr } } }
diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/auto1.C b/gcc/testsuite/g++.dg/debug/dwarf2/auto1.C
index 5daf3cd5c879..3e5867d258c8 100644
--- a/gcc/testsuite/g++.dg/debug/dwarf2/auto1.C
+++ b/gcc/testsuite/g++.dg/debug/dwarf2/auto1.C
@@ -1,6 +1,6 @@
 // PR c++/53756
 // { dg-do compile { target c++14 } }
-// { dg-options "-gdwarf-2 -dA -fno-debug-types-section" }
+// { dg-options "-gdwarf-2 -dA -fno-debug-types-section -fno-inline" }
 // We're looking for something like
 
 // .uleb128 0x3    # (DIE (0x33) DW_TAG_subprogram)
diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/cdtor-1.C b/gcc/testsuite/g++.dg/debug/dwarf2/cdtor-1.C
index c0d3d2251870..b211c02c8940 100644
--- a/gcc/testsuite/g++.dg/debug/dwarf2/cdtor-1.C
+++ b/gcc/testsuite/g++.dg/debug/dwarf2/cdtor-1.C
@@ -1,5 +1,5 @@
 // origin PR debug/49047
-// { dg-options "-gdwarf-2 -dA -fno-merge-debug-strings" }
+// { dg-options "-gdwarf-2 -dA -fno-merge-debug-strings -fno-implicit-constexpr" }
 // { dg-do compile }
 
 struct K
diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/lambda1.C b/gcc/testsuite/g++.dg/debug/dwarf2/lambda1.C
index bd3ce5dc807b..b2566c7aa7a0 100644
--- a/gcc/testsuite/g++.dg/debug/dwarf2/lambda1.C
+++ b/gcc/testsuite/g++.dg/debug/dwarf2/lambda1.C
@@ -1,6 +1,6 @@
 // PR c++/43912
 // { dg-do compile { target c++11 } }
-// { dg-options "-gdwarf-2 -dA -fno-merge-debug-strings -gno-strict-dwarf" }
+// { dg-options "-gdwarf-2 -dA -fno-merge-debug-strings -gno-strict-dwarf -fno-inline" }
 
 // Check for the local alias variables that point to the members of the closure.
 // { dg-final { scan-assembler-times "DW_TAG_variable\[^.\]*\.ascii \"j.0\"" 4 { xfail { powerpc-ibm-aix* } } } }
diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/pr54508.C b/gcc/testsuite/g++.dg/debug/dwarf2/pr54508.C
index e7a6aa41c0d2..0a3721ee6b1b 100644
--- a/gcc/testsuite/g++.dg/debug/dwarf2/pr54508.C
+++ b/gcc/testsuite/g++.dg/debug/dwarf2/pr54508.C
@@ -1,6 +1,6 @@
 // PR debug/54508
 // { dg-do compile }
-// { dg-options "-gdwarf-2 -g2 -dA -fno-merge-debug-strings" }
+// { dg-options "-gdwarf-2 -g2 -dA -fno-merge-debug-strings -fno-inline" }
 
 // { dg-final { scan-assembler "\"cbase\\\\0\"\[ \t\]+\[#;/!|@\]+ +DW_AT_name" } }
 // { dg-final { scan-assembler "\"OPCODE\\\\0\"\[ \t\]+\[#;/!|@\]+ +DW_AT_name" } }
diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/pubnames-2.C b/gcc/testsuite/g++.dg/debug/dwarf2/pubnames-2.C
index af0f6f1b95cf..1fb5004df401 100644
--- a/gcc/testsuite/g++.dg/debug/dwarf2/pubnames-2.C
+++ b/gcc/testsuite/g++.dg/debug/dwarf2/pubnames-2.C
@@ -1,6 +1,6 @@
 // { dg-do compile { target c++11 } }
 // { dg-skip-if "" { powerpc-ibm-aix* } }
-// { dg-options "-gpubnames -gdwarf-4 -fno-debug-types-section -dA" }
+// { dg-options "-gpubnames -gdwarf-4 -fno-debug-types-section -dA -fno-inline" }
 // { dg-final { scan-assembler-times "\.section\[\t \]\[^\n\]*debug_pubnames" 1 } }
 // { dg-final { scan-assembler "\"\\(anonymous namespace\\)\\\\0\"+\[ \t\]+\[#;/|@!]+\[ \t\]+external name" } }
 // { dg-final { scan-assembler "\"one\\\\0\"+\[ \t\]+\[#;/|@!]+\[ \t\]+external name" } }
diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/pubnames-3.C b/gcc/testsuite/g++.dg/debug/dwarf2/pubnames-3.C
index 63b870bc8e7b..37e04fb6c972 100644
--- a/gcc/testsuite/g++.dg/debug/dwarf2/pubnames-3.C
+++ b/gcc/testsuite/g++.dg/debug/dwarf2/pubnames-3.C
@@ -1,6 +1,6 @@
 // { dg-do compile { target c++11 } }
 // { dg-skip-if "" { powerpc-ibm-aix* } }
-// { dg-options "-gpubnames -gdwarf-4 -fdebug-types-section -dA" }
+// { dg-options "-gpubnames -gdwarf-4 -fdebug-types-section -dA -fno-inline" }
 // { dg-final { scan-assembler-times "\.section\[\t \]\[^\n\]*debug_pubnames" 1 } }
 // { dg-final { scan-assembler "\"\\(anonymous namespace\\)\\\\0\"+\[ \t\]+\[#;/|@!]+\[ \t\]+external name" } }
 // { dg-final { scan-assembler "\"one\\\\0\"+\[ \t\]+\[#;/|@!]+\[ \t\]+external name" } }
diff --git a/gcc/testsuite/g++.dg/ext/is_literal_type3.C b/gcc/testsuite/g++.dg/ext/is_literal_type3.C
index 22d8494a2b47..4fede879a42a 100644
--- a/gcc/testsuite/g++.dg/ext/is_literal_type3.C
+++ b/gcc/testsuite/g++.dg/ext/is_literal_type3.C
@@ -6,7 +6,11 @@ struct S {
   int n;
 };
 
+#if __cpp_implicit_constexpr
+static_assert(__is_literal_type(S), "");
+#else
 static_assert(!__is_literal_type(S), "");
+#endif
 
 #ifdef __cpp_constexpr_dynamic_alloc
 struct T {
diff --git a/gcc/testsuite/g++.dg/ext/visibility/template7.C b/gcc/testsuite/g++.dg/ext/visibility/template7.C
index 5197fb1c9603..f1490fa3d32d 100644
--- a/gcc/testsuite/g++.dg/ext/visibility/template7.C
+++ b/gcc/testsuite/g++.dg/ext/visibility/template7.C
@@ -1,6 +1,6 @@
 // PR c++/35688
 // { dg-require-visibility "" }
-// { dg-options "-fvisibility=hidden" }
+// { dg-options "-fvisibility=hidden -fno-inline" }
 
 // { dg-final { scan-hidden "_ZN1s6vectorI1AEC1Ev" } }
 // { dg-final { scan-hidden "_ZN1s3fooI1AEEvT_" } }
diff --git a/gcc/testsuite/g++.dg/gcov/gcov-12.C b/gcc/testsuite/g++.dg/gcov/gcov-12.C
index c4708e40726b..9f2b29b4da50 100644
--- a/gcc/testsuite/g++.dg/gcov/gcov-12.C
+++ b/gcc/testsuite/g++.dg/gcov/gcov-12.C
@@ -1,5 +1,5 @@
 /* PR 51113 */
-/* { dg-options "-fprofile-arcs -ftest-coverage -fpic" } */
+/* { dg-options "-fprofile-arcs -ftest-coverage -fpic -fno-implicit-constexpr" } */
 /* { dg-do run { target native } } */
 /* { dg-additional-sources "gcovpart-12b.C" } */
 
diff --git a/gcc/testsuite/g++.dg/gcov/gcov-2.C b/gcc/testsuite/g++.dg/gcov/gcov-2.C
index 2b4cdd844e95..05db15de7cc5 100644
--- a/gcc/testsuite/g++.dg/gcov/gcov-2.C
+++ b/gcc/testsuite/g++.dg/gcov/gcov-2.C
@@ -1,6 +1,6 @@
 /* Verify line coverage counts for simple member functions. */
 
-/* { dg-options "-fprofile-arcs -ftest-coverage" } */
+/* { dg-options "-fprofile-arcs -ftest-coverage -fno-implicit-constexpr" } */
 /* { dg-do run { target native } } */
 
 class C {
diff --git a/gcc/testsuite/g++.dg/ipa/devirt-35.C b/gcc/testsuite/g++.dg/ipa/devirt-35.C
index 87f72b89984e..ca9ccb7a1334 100644
--- a/gcc/testsuite/g++.dg/ipa/devirt-35.C
+++ b/gcc/testsuite/g++.dg/ipa/devirt-35.C
@@ -15,7 +15,6 @@ m(struct B *b)
                   //  test2 may change the type of A by placement new.
                   // C++ standard is bit imprecise about this.
 }
-/* { dg-final { scan-tree-dump "converting indirect call to function virtual int B::t"  "fre1"  } } */
-/* { dg-final { scan-ipa-dump "to virtual int B::t"  "devirt"  } } */
+/* { dg-final { scan-tree-dump "converting indirect call to function virtual int B::t"  "fre1" { target { ! implicit_constexpr } } } } */
+/* { dg-final { scan-ipa-dump "to virtual int B::t"  "devirt" { target { ! implicit_constexpr } } } } */
 /* { dg-final { scan-ipa-dump "1 speculatively devirtualized"  "devirt"  } } */
-
diff --git a/gcc/testsuite/g++.dg/ipa/devirt-36.C b/gcc/testsuite/g++.dg/ipa/devirt-36.C
index 067a2bb8ca19..60b830186bb7 100644
--- a/gcc/testsuite/g++.dg/ipa/devirt-36.C
+++ b/gcc/testsuite/g++.dg/ipa/devirt-36.C
@@ -18,7 +18,7 @@ m(struct B *b)
                   //  test2 may change the type of A by placement new.
                   // C++ standard is bit imprecise about this.
 }
-/* { dg-final { scan-tree-dump "converting indirect call to function virtual int B::t"  "fre1"  } } */
-/* { dg-final { scan-ipa-dump "to virtual int B::t"  "devirt"  } } */
+/* { dg-final { scan-tree-dump "converting indirect call to function virtual int B::t"  "fre1" { target { ! implicit_constexpr } } } } */
+/* { dg-final { scan-ipa-dump "to virtual int B::t"  "devirt" { target { ! implicit_constexpr } } } } */
 /* { dg-final { scan-ipa-dump "1 speculatively devirtualized"  "devirt"  } } */
 
diff --git a/gcc/testsuite/g++.dg/ipa/devirt-37.C b/gcc/testsuite/g++.dg/ipa/devirt-37.C
index b7f52a0a5e9d..df5ab901f82a 100644
--- a/gcc/testsuite/g++.dg/ipa/devirt-37.C
+++ b/gcc/testsuite/g++.dg/ipa/devirt-37.C
@@ -33,4 +33,4 @@ t()
 /* { dg-final { scan-tree-dump "No dynamic type change found."  "fre3"  } } */
 /* { dg-final { scan-tree-dump "Checking vtbl store:"  "fre3"  } } */
 /* { dg-final { scan-tree-dump "Function call may change dynamic type:extcall"  "fre3"  } } */
-/* { dg-final { scan-tree-dump "converting indirect call to function virtual void"  "fre3"  } } */
+/* { dg-final { scan-tree-dump "converting indirect call to function virtual void"  "fre3" { target { ! implicit_constexpr } } } } */
diff --git a/gcc/testsuite/g++.dg/ipa/devirt-44.C b/gcc/testsuite/g++.dg/ipa/devirt-44.C
index 5de761412d05..ed211e117399 100644
--- a/gcc/testsuite/g++.dg/ipa/devirt-44.C
+++ b/gcc/testsuite/g++.dg/ipa/devirt-44.C
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O3 -fno-ipa-cp -fdump-ipa-inline-details -fno-early-inlining" } */
+/* { dg-options "-O3 -fno-ipa-cp -fdump-ipa-inline-details -fno-early-inlining -fno-implicit-constexpr" } */
 struct A {
   virtual int foo () {return 1;}
   void wrapfoo () {foo();}
diff --git a/gcc/testsuite/g++.dg/ipa/imm-devirt-1.C b/gcc/testsuite/g++.dg/ipa/imm-devirt-1.C
index 00ac61e7f384..fa31cfbae545 100644
--- a/gcc/testsuite/g++.dg/ipa/imm-devirt-1.C
+++ b/gcc/testsuite/g++.dg/ipa/imm-devirt-1.C
@@ -60,7 +60,7 @@ int main (int argc, char *argv[])
 
 /* middleman_2 gets early inlined and the virtual call should get turned to
    a direct call.  */
-/* { dg-final { scan-tree-dump "Inlining int middleman_1" "einline"  } } */
-/* { dg-final { scan-tree-dump "Inlining int middleman_2" "einline"  } } */
+/* { dg-final { scan-tree-dump "Inlining int middleman_1" "einline" { target { ! implicit_constexpr } } } } */
+/* { dg-final { scan-tree-dump "Inlining int middleman_2" "einline" { target { ! implicit_constexpr } } } } */
 /* { dg-final { scan-tree-dump "B::foo \\(" "einline"  } } */
 /* { dg-final { scan-tree-dump-times "OBJ_TYPE_REF" 2 "einline"  } } */
diff --git a/gcc/testsuite/g++.dg/lookup/builtin5.C b/gcc/testsuite/g++.dg/lookup/builtin5.C
index 1bd67dce5ac6..652e3f58b678 100644
--- a/gcc/testsuite/g++.dg/lookup/builtin5.C
+++ b/gcc/testsuite/g++.dg/lookup/builtin5.C
@@ -1,5 +1,5 @@
 // PR c++/37276
-
+// { dg-additional-options -fno-inline }
 // { dg-final { scan-assembler "_ZSt5atanhd" } }
 
 namespace std
diff --git a/gcc/testsuite/g++.dg/lto/inline-crossmodule-1_0.C b/gcc/testsuite/g++.dg/lto/inline-crossmodule-1_0.C
index adbc43ea2534..0294dcc4bfb7 100644
--- a/gcc/testsuite/g++.dg/lto/inline-crossmodule-1_0.C
+++ b/gcc/testsuite/g++.dg/lto/inline-crossmodule-1_0.C
@@ -1,5 +1,5 @@
 // { dg-lto-do link }
-/* { dg-lto-options { "-O2 -fno-early-inlining -flto -fdump-ipa-inline-details" } } */
+/* { dg-lto-options { "-O2 -fno-early-inlining -fno-implicit-constexpr -flto -fdump-ipa-inline-details" } } */
 #include "inline-crossmodule-1.h"
 int a::key ()
 {
diff --git a/gcc/testsuite/g++.dg/modules/enum-1_a.C b/gcc/testsuite/g++.dg/modules/enum-1_a.C
index 53e2ac88f208..24cad2864648 100644
--- a/gcc/testsuite/g++.dg/modules/enum-1_a.C
+++ b/gcc/testsuite/g++.dg/modules/enum-1_a.C
@@ -1,5 +1,5 @@
 // { dg-module-do run }
-// { dg-additional-options "-fmodules-ts -fdump-lang-module-uid" }
+// { dg-additional-options "-fmodules-ts -fdump-lang-module-uid -fno-implicit-constexpr" }
 export module enUm;
 // { dg-module-cmi "enUm" }
 
diff --git a/gcc/testsuite/g++.dg/modules/fn-inline-1_c.C b/gcc/testsuite/g++.dg/modules/fn-inline-1_c.C
index 55a7aaa26b46..2b8bbdcd1af9 100644
--- a/gcc/testsuite/g++.dg/modules/fn-inline-1_c.C
+++ b/gcc/testsuite/g++.dg/modules/fn-inline-1_c.C
@@ -1,4 +1,4 @@
-// { dg-additional-options "-fmodules-ts" }
+// { dg-additional-options "-fmodules-ts -fno-inline" }
 import bob;
 
 int main ()
diff --git a/gcc/testsuite/g++.dg/modules/pmf-1_a.H b/gcc/testsuite/g++.dg/modules/pmf-1_a.H
index c597db1fe8ab..a7b3fc370ecd 100644
--- a/gcc/testsuite/g++.dg/modules/pmf-1_a.H
+++ b/gcc/testsuite/g++.dg/modules/pmf-1_a.H
@@ -1,4 +1,4 @@
-// { dg-additional-options -fmodule-header }
+// { dg-additional-options "-fmodule-header -fno-implicit-constexpr" }
 // { dg-module-cmi {} }
 
 #include "pmf-1.h"
diff --git a/gcc/testsuite/g++.dg/modules/pmf-1_b.C b/gcc/testsuite/g++.dg/modules/pmf-1_b.C
index 0b0861070453..cb2a35bbc3b1 100644
--- a/gcc/testsuite/g++.dg/modules/pmf-1_b.C
+++ b/gcc/testsuite/g++.dg/modules/pmf-1_b.C
@@ -1,4 +1,4 @@
-// { dg-additional-options "-fmodules-ts -fno-module-lazy -fdump-lang-module-alias" }
+// { dg-additional-options "-fmodules-ts -fno-module-lazy -fdump-lang-module-alias -fno-implicit-constexpr" }
 
 #include "pmf-1.h"
 import "pmf-1_a.H";
diff --git a/gcc/testsuite/g++.dg/modules/used-1_c.C b/gcc/testsuite/g++.dg/modules/used-1_c.C
index 0d1514e031ca..b51a19fb8d75 100644
--- a/gcc/testsuite/g++.dg/modules/used-1_c.C
+++ b/gcc/testsuite/g++.dg/modules/used-1_c.C
@@ -1,4 +1,4 @@
-// { dg-additional-options -fmodules-ts }
+// { dg-additional-options "-fmodules-ts -fno-inline" }
 
 import "used-1_b.H";
 
diff --git a/gcc/testsuite/g++.dg/tls/thread_local11.C b/gcc/testsuite/g++.dg/tls/thread_local11.C
index 273ee03d7025..7e83a4537543 100644
--- a/gcc/testsuite/g++.dg/tls/thread_local11.C
+++ b/gcc/testsuite/g++.dg/tls/thread_local11.C
@@ -2,7 +2,7 @@
 // { dg-do compile { target c++11 } }
 // { dg-add-options tls }
 // { dg-require-effective-target tls_runtime }
-// { dg-additional-options "-fdump-tree-gimple" }
+// { dg-additional-options "-fdump-tree-gimple -fno-implicit-constexpr" }
 // { dg-final { scan-tree-dump-times "_ZTW2s1" 2 "gimple" } }
 // { dg-final { scan-tree-dump-times "_ZTW2s2" 2 "gimple" } }
 // { dg-final { scan-tree-dump-times "_ZTW2s3" 2 "gimple" } }
diff --git a/gcc/testsuite/g++.dg/tls/thread_local11a.C b/gcc/testsuite/g++.dg/tls/thread_local11a.C
index d8c4a6dc0ab8..a6283984eb79 100644
--- a/gcc/testsuite/g++.dg/tls/thread_local11a.C
+++ b/gcc/testsuite/g++.dg/tls/thread_local11a.C
@@ -3,7 +3,7 @@
 // { dg-add-options tls }
 // { dg-require-alias "" }
 // { dg-require-effective-target tls_runtime }
-// { dg-additional-options "-fdump-tree-gimple" }
+// { dg-additional-options "-fdump-tree-gimple -fno-implicit-constexpr" }
 // { dg-final { scan-tree-dump-times "_ZTH2s1" 1 "gimple" } }
 // { dg-final { scan-tree-dump-times "_ZTH2s2" 1 "gimple" } }
 // { dg-final { scan-tree-dump-times "_ZTH2s3" 1 "gimple" } }
diff --git a/gcc/testsuite/g++.dg/tm/pr46653.C b/gcc/testsuite/g++.dg/tm/pr46653.C
index f8f3a1d3117f..a4649eb5ffc9 100644
--- a/gcc/testsuite/g++.dg/tm/pr46653.C
+++ b/gcc/testsuite/g++.dg/tm/pr46653.C
@@ -1,5 +1,5 @@
 // { dg-do compile }
-// { dg-options "-fgnu-tm -O" }
+// { dg-options "-fgnu-tm -O -fno-implicit-constexpr" }
 
 class shared_count
 {
diff --git a/gcc/testsuite/g++.dg/ubsan/pr70035.C b/gcc/testsuite/g++.dg/ubsan/pr70035.C
index a1d3dc2ec169..521dcb8d8c02 100644
--- a/gcc/testsuite/g++.dg/ubsan/pr70035.C
+++ b/gcc/testsuite/g++.dg/ubsan/pr70035.C
@@ -1,7 +1,7 @@
 // PR c++/70035
 // { dg-do run }
 // { dg-shouldfail "ubsan" }
-// { dg-options "-fsanitize=vptr -fno-sanitize-recover=undefined" }
+// { dg-options "-fsanitize=vptr -fno-sanitize-recover=undefined -fno-implicit-constexpr" }
 
 struct A {
   A (int) {}
diff --git a/gcc/testsuite/g++.old-deja/g++.other/delete6.C b/gcc/testsuite/g++.old-deja/g++.other/delete6.C
index 733a6e22cb9b..56cfa000e8d5 100644
--- a/gcc/testsuite/g++.old-deja/g++.other/delete6.C
+++ b/gcc/testsuite/g++.old-deja/g++.other/delete6.C
@@ -25,4 +25,4 @@ inline void A::operator delete(void*p)
 
 int main()
 {A *ap=new A;
-delete ap;}
+delete ap;}			// { dg-prune-output "unallocated object 'i'" }
diff --git a/gcc/testsuite/lib/g++-dg.exp b/gcc/testsuite/lib/g++-dg.exp
index c360770a7a20..fd06d278faaf 100644
--- a/gcc/testsuite/lib/g++-dg.exp
+++ b/gcc/testsuite/lib/g++-dg.exp
@@ -57,7 +57,8 @@ proc g++-dg-runtest { testcases flags default-extra-flags } {
 	    set option_list { }
 	    foreach x $std_list {
 		# Handle "concepts" as C++17 plus Concepts TS.
-		if { $x eq "concepts" } then { set x "17 -fconcepts" }
+		if { $x eq "concepts" } then { set x "17 -fconcepts"
+		} elseif { $x eq "impcx" } then { set x "23 -fimplicit-constexpr" }
 		lappend option_list "${std_prefix}$x"
 	    }
 	} else {
diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp
index 8cbda192fe0f..c928d99a14be 100644
--- a/gcc/testsuite/lib/target-supports.exp
+++ b/gcc/testsuite/lib/target-supports.exp
@@ -10232,6 +10232,10 @@ proc check_effective_target_concepts { } {
     return [check-flags { "" { } { -fconcepts } }]
 }
 
+proc check_effective_target_implicit_constexpr { } {
+    return [check-flags { "" { } { -fimplicit-constexpr } }]
+}
+
 # Return 1 if expensive testcases should be run.
 
 proc check_effective_target_run_expensive_tests { } {
diff --git a/libstdc++-v3/testsuite/20_util/to_address/1_neg.cc b/libstdc++-v3/testsuite/20_util/to_address/1_neg.cc
index ff3a1fbcb5dd..5030f89b3452 100644
--- a/libstdc++-v3/testsuite/20_util/to_address/1_neg.cc
+++ b/libstdc++-v3/testsuite/20_util/to_address/1_neg.cc
@@ -32,5 +32,5 @@ struct P
 void test01()
 {
   P p;
-  std::to_address(p); // { dg-error "required from here" }
+  std::to_address(p); // { dg-error "" }
 }
diff --git a/libstdc++-v3/testsuite/26_numerics/random/concept.cc b/libstdc++-v3/testsuite/26_numerics/random/concept.cc
index 1adc0c11baaa..0a0cbbf7c4e1 100644
--- a/libstdc++-v3/testsuite/26_numerics/random/concept.cc
+++ b/libstdc++-v3/testsuite/26_numerics/random/concept.cc
@@ -227,7 +227,11 @@ struct N12
   static constexpr unsigned max() { return 1; }
 };
 
+#if __cpp_implicit_constexpr
+static_assert( std::uniform_random_bit_generator<N12> ); // LWG 3150
+#else
 static_assert( ! std::uniform_random_bit_generator<N12> ); // LWG 3150
+#endif
 
 struct N13
 {
@@ -236,7 +240,11 @@ struct N13
   static unsigned max() { return 1; } // not constexpr
 };
 
+#if __cpp_implicit_constexpr
+static_assert( std::uniform_random_bit_generator<N13> ); // LWG 3150
+#else
 static_assert( ! std::uniform_random_bit_generator<N13> ); // LWG 3150
+#endif
 
 struct N14
 {
-- 
GitLab