[clang] Disable constexpr function body checking in more situations (PR #94347)

Aaron Ballman via cfe-commits cfe-commits at lists.llvm.org
Tue Jun 4 05:48:33 PDT 2024


https://github.com/AaronBallman created https://github.com/llvm/llvm-project/pull/94347

Before C++23, we would check a constexpr function body to diagnose if the function can never be evaluated in a constant expression context. This was previously required standards behavior, but C++23 relaxed the restrictions with P2448R2. While this checking is useful, it is also quite expensive, especially in pathological cases (see #92924 for an example), because it means the mere presence of a constexpr function definition will require constant evaluation even if the function is not used within the TU.

Clang suppresses diagnostics in system headers by default and system headers (like STL implementations) can be full of constexpr function bodies. Now we suppress the check for a diagnostic if the function definition is in a system header or if the `-Winvalid-constexpr` diagnostic is disabled. This should have some mild compile time performance improvements.

Also, the previous implementation would disable the diagnostic in C++23 mode entirely. Due to the benefit of the check, this patch now makes it possible to enable the diagnostic explicitly in C++23 mode.

>From 3963099140ad6c75ba438f6e14a6bd2ce38e4493 Mon Sep 17 00:00:00 2001
From: Aaron Ballman <aaron at aaronballman.com>
Date: Fri, 31 May 2024 09:55:41 -0400
Subject: [PATCH 1/4] Stop checking whether a function can never be constexpr

While this is useful functionality, it means the mere *presence* of a
constexpr function will impact compile time overhead.

This is currently an experiment to see whether removing this causes a
noticable difference in compile time overhead.
---
 clang/lib/Sema/SemaDeclCXX.cpp                | 27 ------
 clang/test/AST/Interp/arrays.cpp              | 28 +++---
 clang/test/AST/Interp/cxx11.cpp               | 16 ++--
 clang/test/AST/Interp/cxx17.cpp               |  4 +-
 clang/test/AST/Interp/cxx23.cpp               | 53 ++++-------
 clang/test/AST/Interp/functions.cpp           | 14 ++-
 clang/test/AST/Interp/invalid.cpp             | 56 +++++-------
 clang/test/AST/Interp/lifetimes.cpp           |  6 +-
 clang/test/AST/Interp/literals.cpp            | 32 ++++---
 clang/test/AST/Interp/records.cpp             | 35 ++++---
 clang/test/AST/Interp/shifts.cpp              | 29 +++---
 .../CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp | 10 +-
 .../CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp | 25 ++---
 .../CXX/dcl.dcl/dcl.spec/dcl.constexpr/p5.cpp | 38 ++++----
 .../CXX/dcl.dcl/dcl.spec/dcl.constexpr/p6.cpp |  4 +-
 clang/test/CXX/drs/cwg6xx.cpp                 | 17 +---
 clang/test/CXX/expr/expr.const/p2-0x.cpp      | 11 ++-
 clang/test/Misc/constexpr-source-ranges.cpp   |  9 +-
 .../SemaCXX/builtin-object-size-cxx14.cpp     | 10 +-
 clang/test/SemaCXX/builtin-std-move.cpp       |  7 +-
 .../SemaCXX/constant-expression-cxx11.cpp     | 32 ++++---
 .../SemaCXX/constant-expression-cxx14.cpp     | 40 ++++----
 .../SemaCXX/constant-expression-cxx2a.cpp     | 91 ++++++++++++++-----
 .../test/SemaCXX/constexpr-frame-describe.cpp | 14 ++-
 .../constexpr-function-recovery-crash.cpp     |  9 +-
 clang/test/SemaCXX/constexpr-string.cpp       | 20 ++--
 clang/test/SemaCXX/cxx23-assume.cpp           |  5 +-
 clang/test/SemaCXX/cxx2a-consteval.cpp        |  3 +-
 .../test/SemaCXX/cxx2a-constexpr-dynalloc.cpp |  3 +-
 clang/test/SemaCXX/literal-type.cpp           |  8 +-
 clang/test/SemaCXX/ms-constexpr-invalid.cpp   | 18 ++--
 clang/test/SemaCXX/ms-constexpr.cpp           |  4 +-
 32 files changed, 328 insertions(+), 350 deletions(-)

diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 631fd4e354927..56f23e1be154a 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -2457,33 +2457,6 @@ static bool CheckConstexprFunctionBody(Sema &SemaRef, const FunctionDecl *Dcl,
     }
   }
 
-  // C++11 [dcl.constexpr]p5:
-  //   if no function argument values exist such that the function invocation
-  //   substitution would produce a constant expression, the program is
-  //   ill-formed; no diagnostic required.
-  // C++11 [dcl.constexpr]p3:
-  //   - every constructor call and implicit conversion used in initializing the
-  //     return value shall be one of those allowed in a constant expression.
-  // C++11 [dcl.constexpr]p4:
-  //   - every constructor involved in initializing non-static data members and
-  //     base class sub-objects shall be a constexpr constructor.
-  //
-  // Note that this rule is distinct from the "requirements for a constexpr
-  // function", so is not checked in CheckValid mode.
-  SmallVector<PartialDiagnosticAt, 8> Diags;
-  if (Kind == Sema::CheckConstexprKind::Diagnose &&
-      !Expr::isPotentialConstantExpr(Dcl, Diags) &&
-      !SemaRef.getLangOpts().CPlusPlus23) {
-    SemaRef.Diag(Dcl->getLocation(),
-                 diag::ext_constexpr_function_never_constant_expr)
-        << isa<CXXConstructorDecl>(Dcl) << Dcl->isConsteval()
-        << Dcl->getNameInfo().getSourceRange();
-    for (size_t I = 0, N = Diags.size(); I != N; ++I)
-      SemaRef.Diag(Diags[I].first, Diags[I].second);
-    // Don't return false here: we allow this for compatibility in
-    // system headers.
-  }
-
   return true;
 }
 
diff --git a/clang/test/AST/Interp/arrays.cpp b/clang/test/AST/Interp/arrays.cpp
index dd5064d993e66..5d6cc2b9d26d9 100644
--- a/clang/test/AST/Interp/arrays.cpp
+++ b/clang/test/AST/Interp/arrays.cpp
@@ -208,8 +208,7 @@ class AU {
 public:
   int a;
   constexpr AU() : a(5 / 0) {} // both-warning {{division by zero is undefined}} \
-                               // both-note 2{{division by zero}} \
-                               // both-error {{never produces a constant expression}}
+                               // both-note {{division by zero}}
 };
 class B {
 public:
@@ -290,25 +289,25 @@ namespace IncDec {
   }
   static_assert(getSecondToLast2() == 3, "");
 
-  constexpr int bad1() { // both-error {{never produces a constant expression}}
+  constexpr int bad1() {
     const int *e =  E + 3;
     e++; // This is fine because it's a one-past-the-end pointer
-    return *e; // both-note 2{{read of dereferenced one-past-the-end pointer}}
+    return *e; // both-note {{read of dereferenced one-past-the-end pointer}}
   }
   static_assert(bad1() == 0, ""); // both-error {{not an integral constant expression}} \
                                   // both-note {{in call to}}
 
-  constexpr int bad2() { // both-error {{never produces a constant expression}}
+  constexpr int bad2() {
     const int *e = E + 4;
-    e++; // both-note 2{{cannot refer to element 5 of array of 4 elements}}
+    e++; // both-note {{cannot refer to element 5 of array of 4 elements}}
     return *e; // This is UB as well
   }
   static_assert(bad2() == 0, ""); // both-error {{not an integral constant expression}} \
                                   // both-note {{in call to}}
 
-  constexpr int bad3() { // both-error {{never produces a constant expression}}
+  constexpr int bad3() {
     const int *e = E;
-    e--; // both-note 2{{cannot refer to element -1 of array of 4 elements}}
+    e--; // both-note {{cannot refer to element -1 of array of 4 elements}}
     return *e; // This is UB as well
   }
    static_assert(bad3() == 0, ""); // both-error {{not an integral constant expression}} \
@@ -385,11 +384,11 @@ namespace NoInitMapLeak {
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wdivision-by-zero"
 #pragma clang diagnostic ignored "-Wc++20-extensions"
-  constexpr int testLeak() { // both-error {{never produces a constant expression}}
+  constexpr int testLeak() {
     int a[2];
     a[0] = 1;
     // interrupts interpretation.
-    (void)(1 / 0); // both-note 2{{division by zero}}
+    (void)(1 / 0); // both-note {{division by zero}}
 
     return 1;
   }
@@ -408,8 +407,8 @@ namespace NoInitMapLeak {
   static_assert(b == 1, ""); // ref-error {{not an integral constant expression}} \
                              // ref-note {{not a constant expression}}
 
-  constexpr int f() { // both-error {{never produces a constant expression}}
-    int a[] = {19,2,3/0,4}; // both-note 2{{division by zero}} \
+  constexpr int f() {
+    int a[] = {19,2,3/0,4}; // both-note {{division by zero}} \
                             // both-warning {{is undefined}}
     return 1;
   }
@@ -587,10 +586,9 @@ const int SZA[] = {};
 void testZeroSizedArrayAccess() { unsigned c = SZA[4]; }
 
 #if __cplusplus >= 202002L
-constexpr int test_multiarray2() { // both-error {{never produces a constant expression}}
+constexpr int test_multiarray2() {
   int multi2[2][1]; // both-note {{declared here}}
-  return multi2[2][0]; // both-note {{cannot access array element of pointer past the end of object}} \
-                       // both-warning {{array index 2 is past the end of the array (that has type 'int[2][1]')}}
+  return multi2[2][0]; // both-warning {{array index 2 is past the end of the array (that has type 'int[2][1]')}}
 }
 
 /// Same but with a dummy pointer.
diff --git a/clang/test/AST/Interp/cxx11.cpp b/clang/test/AST/Interp/cxx11.cpp
index f06a5dd173cba..4d1efbbdc5c8e 100644
--- a/clang/test/AST/Interp/cxx11.cpp
+++ b/clang/test/AST/Interp/cxx11.cpp
@@ -31,18 +31,18 @@ constexpr const int *p = &s.m + 1;
 
 constexpr const int *np2 = &(*(int(*)[4])nullptr)[0]; // ok
 
-constexpr int preDec(int x) { // both-error {{never produces a constant expression}}
-  return --x;                 // both-note {{subexpression}}
+constexpr int preDec(int x) {
+  return --x;
 }
 
-constexpr int postDec(int x) { // both-error {{never produces a constant expression}}
-  return x--;                  // both-note {{subexpression}}
+constexpr int postDec(int x) {
+  return x--;
 }
 
-constexpr int preInc(int x) { // both-error {{never produces a constant expression}}
-  return ++x;                  // both-note {{subexpression}}
+constexpr int preInc(int x) {
+  return ++x;
 }
 
-constexpr int postInc(int x) { // both-error {{never produces a constant expression}}
-  return x++;                  // both-note {{subexpression}}
+constexpr int postInc(int x) {
+  return x++;
 }
diff --git a/clang/test/AST/Interp/cxx17.cpp b/clang/test/AST/Interp/cxx17.cpp
index 5e38d1a588700..9576217b458d6 100644
--- a/clang/test/AST/Interp/cxx17.cpp
+++ b/clang/test/AST/Interp/cxx17.cpp
@@ -83,8 +83,8 @@ static_assert(b() == 11);
 
 /// The diagnostics between the two interpreters used to be different here.
 struct S { int a; };
-constexpr S getS() { // both-error {{constexpr function never produces a constant expression}}
-  (void)(1/0); // both-note 2{{division by zero}} \
+constexpr S getS() {
+  (void)(1/0); // both-note {{division by zero}} \
                // both-warning {{division by zero}}
   return S{12};
 }
diff --git a/clang/test/AST/Interp/cxx23.cpp b/clang/test/AST/Interp/cxx23.cpp
index c91d52c552b12..bbd70d0588e8e 100644
--- a/clang/test/AST/Interp/cxx23.cpp
+++ b/clang/test/AST/Interp/cxx23.cpp
@@ -4,51 +4,39 @@
 // RUN: %clang_cc1 -std=c++20 -fsyntax-only -fcxx-exceptions -verify=expected20,all,all20 %s -fexperimental-new-constant-interpreter
 // RUN: %clang_cc1 -std=c++23 -fsyntax-only -fcxx-exceptions -verify=expected23,all %s -fexperimental-new-constant-interpreter
 
-/// FIXME: The new interpreter is missing all the 'control flows through...' diagnostics.
-
-constexpr int f(int n) {  // ref20-error {{constexpr function never produces a constant expression}}
-  static const int m = n; // ref20-note {{control flows through the definition of a static variable}} \
-                          // ref20-warning {{is a C++23 extension}} \
+constexpr int f(int n) {
+  static const int m = n; // ref20-warning {{is a C++23 extension}} \
                           // expected20-warning {{is a C++23 extension}}
 
   return m;
 }
-constexpr int g(int n) {        // ref20-error {{constexpr function never produces a constant expression}}
-  thread_local const int m = n; // ref20-note {{control flows through the definition of a thread_local variable}} \
-                                // ref20-warning {{is a C++23 extension}} \
+constexpr int g(int n) {
+  thread_local const int m = n; // ref20-warning {{is a C++23 extension}} \
                                 // expected20-warning {{is a C++23 extension}}
   return m;
 }
 
-constexpr int c_thread_local(int n) { // ref20-error {{constexpr function never produces a constant expression}} \
-                                      // expected20-error {{constexpr function never produces a constant expression}}
-  static _Thread_local int m = 0;     // ref20-note {{control flows through the definition of a thread_local variable}} \
-                                      // ref20-warning {{is a C++23 extension}} \
-                                      // expected20-warning {{is a C++23 extension}} \
-                                      // expected20-note {{declared here}}
-  return m; // expected20-note {{read of non-const variable}}
+constexpr int c_thread_local(int n) {
+  static _Thread_local int m = 0;     // ref20-warning {{is a C++23 extension}} \
+                                      // expected20-warning {{is a C++23 extension}}
+  return m;
 }
 
 
-constexpr int gnu_thread_local(int n) { // ref20-error {{constexpr function never produces a constant expression}} \
-                                        // expected20-error {{constexpr function never produces a constant expression}}
-  static __thread int m = 0;            // ref20-note {{control flows through the definition of a thread_local variable}} \
-                                        // ref20-warning {{is a C++23 extension}} \
-                                        // expected20-warning {{is a C++23 extension}} \
-                                        // expected20-note {{declared here}}
-  return m; // expected20-note {{read of non-const variable}}
+constexpr int gnu_thread_local(int n) {
+  static __thread int m = 0;            // ref20-warning {{is a C++23 extension}} \
+                                        // expected20-warning {{is a C++23 extension}}
+  return m;
 }
 
-constexpr int h(int n) {  // ref20-error {{constexpr function never produces a constant expression}}
-  static const int m = n; // ref20-note {{control flows through the definition of a static variable}} \
-                          // ref20-warning {{is a C++23 extension}} \
+constexpr int h(int n) {
+  static const int m = n; // ref20-warning {{is a C++23 extension}} \
                           // expected20-warning {{is a C++23 extension}}
   return &m - &m;
 }
 
-constexpr int i(int n) {        // ref20-error {{constexpr function never produces a constant expression}}
-  thread_local const int m = n; // ref20-note {{control flows through the definition of a thread_local variable}} \
-                                // ref20-warning {{is a C++23 extension}} \
+constexpr int i(int n) {
+  thread_local const int m = n; // ref20-warning {{is a C++23 extension}} \
                                 // expected20-warning {{is a C++23 extension}}
   return &m - &m;
 }
@@ -104,9 +92,8 @@ namespace StaticOperators {
   static_assert(f2() == 3);
 
   struct S1 {
-    constexpr S1() { // all20-error {{never produces a constant expression}}
-      throw; // all-note {{not valid in a constant expression}} \
-             // all20-note {{not valid in a constant expression}}
+    constexpr S1() {
+      throw; // all-note {{not valid in a constant expression}}
     }
     static constexpr int operator()() { return 3; } // ref20-warning {{C++23 extension}} \
                                                     // expected20-warning {{C++23 extension}}
@@ -160,9 +147,9 @@ namespace VirtualBases {
 }
 
 namespace LabelGoto {
-  constexpr int foo() { // all20-error {{never produces a constant expression}}
+  constexpr int foo() {
     a: // all20-warning {{use of this statement in a constexpr function is a C++23 extension}}
-    goto a; // all20-note 2{{subexpression not valid in a constant expression}} \
+    goto a; // all20-note {{subexpression not valid in a constant expression}} \
             // ref23-note {{subexpression not valid in a constant expression}} \
             // expected23-note {{subexpression not valid in a constant expression}}
 
diff --git a/clang/test/AST/Interp/functions.cpp b/clang/test/AST/Interp/functions.cpp
index 10c62a43ef33b..2cbbf6a3e19b5 100644
--- a/clang/test/AST/Interp/functions.cpp
+++ b/clang/test/AST/Interp/functions.cpp
@@ -241,15 +241,19 @@ struct BodylessMemberFunction {
   }
 };
 
+// FIXME: The new constant expression interpreter diagnoses differently than
+// the reference implementation.
 constexpr int nyd(int m);
-constexpr int doit() { return nyd(10); }
-constexpr int nyd(int m) { return m; }
-static_assert(doit() == 10, "");
+constexpr int doit() { return nyd(10); } // expected-note {{in call to}}
+constexpr int nyd(int m) { return m; } // expected-note {{function parameter 'm' with unknown value cannot be used in a constant expression}} \
+                                          expected-note {{declared here}}
+static_assert(doit() == 10, ""); // expected-error {{static assertion expression is not an integral constant expression}} \
+                                    expected-note {{in call to}}
 
 namespace InvalidCall {
   struct S {
-    constexpr int a() const { // both-error {{never produces a constant expression}}
-      return 1 / 0; // both-note 2{{division by zero}} \
+    constexpr int a() const {
+      return 1 / 0; // both-note {{division by zero}} \
                     // both-warning {{is undefined}}
     }
   };
diff --git a/clang/test/AST/Interp/invalid.cpp b/clang/test/AST/Interp/invalid.cpp
index 522ad02f71ce0..dceaf4dd497a1 100644
--- a/clang/test/AST/Interp/invalid.cpp
+++ b/clang/test/AST/Interp/invalid.cpp
@@ -1,68 +1,56 @@
-// RUN: %clang_cc1 -fcxx-exceptions -std=c++20 -fexperimental-new-constant-interpreter -verify %s
-// RUN: %clang_cc1 -fcxx-exceptions -std=c++20 -verify=ref %s
+// RUN: %clang_cc1 -fcxx-exceptions -std=c++20 -fexperimental-new-constant-interpreter -verify=expected,both %s
+// RUN: %clang_cc1 -fcxx-exceptions -std=c++20 -verify=ref,both %s
 
 namespace Throw {
 
   constexpr int ConditionalThrow(bool t) {
     if (t)
-      throw 4; // expected-note {{subexpression not valid in a constant expression}} \
-               // ref-note {{subexpression not valid in a constant expression}}
+      throw 4; // both-note {{subexpression not valid in a constant expression}}
 
     return 0;
   }
 
   static_assert(ConditionalThrow(false) == 0, "");
-  static_assert(ConditionalThrow(true) == 0, ""); // expected-error {{not an integral constant expression}} \
-                                                  // expected-note {{in call to 'ConditionalThrow(true)'}} \
-                                                  // ref-error {{not an integral constant expression}} \
-                                                  // ref-note {{in call to 'ConditionalThrow(true)'}}
+  static_assert(ConditionalThrow(true) == 0, ""); // both-error {{not an integral constant expression}} \
+                                                     both-note {{in call to 'ConditionalThrow(true)'}}
 
-  constexpr int Throw() { // expected-error {{never produces a constant expression}} \
-                          // ref-error {{never produces a constant expression}}
-    throw 5; // expected-note {{subexpression not valid in a constant expression}} \
-             // ref-note {{subexpression not valid in a constant expression}}
+  constexpr int Throw() {
+    throw 5; // both-note {{subexpression not valid in a constant expression}}
     return 0;
   }
+  static_assert(Throw() == 0, ""); // both-error {{not an integral constant expression}} \
+                                      both-note {{in call to}}
 
-  constexpr int NoSubExpr() { // ref-error {{never produces a constant expression}} \
-                              // expected-error {{never produces a constant expression}}
-    throw; // ref-note 2{{subexpression not valid}} \
-           // expected-note 2{{subexpression not valid}}
+  constexpr int NoSubExpr() {
+    throw; // both-note {{subexpression not valid}}
     return 0;
   }
-  static_assert(NoSubExpr() == 0, ""); // ref-error {{not an integral constant expression}} \
-                                       // ref-note {{in call to}} \
-                                       // expected-error {{not an integral constant expression}} \
-                                       // expected-note {{in call to}}
+  static_assert(NoSubExpr() == 0, ""); // both-error {{not an integral constant expression}} \
+                                          both-note {{in call to}}
 }
 
 namespace Asm {
   constexpr int ConditionalAsm(bool t) {
     if (t)
-      asm(""); // expected-note {{subexpression not valid in a constant expression}} \
-               // ref-note {{subexpression not valid in a constant expression}}
+      asm(""); // both-note {{subexpression not valid in a constant expression}}
 
     return 0;
   }
   static_assert(ConditionalAsm(false) == 0, "");
-  static_assert(ConditionalAsm(true) == 0, ""); // expected-error {{not an integral constant expression}} \
-                                                // expected-note {{in call to 'ConditionalAsm(true)'}} \
-                                                // ref-error {{not an integral constant expression}} \
-                                                // ref-note {{in call to 'ConditionalAsm(true)'}}
+  static_assert(ConditionalAsm(true) == 0, ""); // both-error {{not an integral constant expression}} \
+                                                // both-note {{in call to 'ConditionalAsm(true)'}}
 
 
-  constexpr int Asm() { // expected-error {{never produces a constant expression}} \
-                        // ref-error {{never produces a constant expression}}
-    __asm volatile(""); // expected-note {{subexpression not valid in a constant expression}} \
-                        // ref-note {{subexpression not valid in a constant expression}}
+  constexpr int Asm() {
+    __asm volatile(""); // both-note {{subexpression not valid in a constant expression}}
     return 0;
   }
+  static_assert(Asm() == 0, ""); // both-error {{not an integral constant expression}} \
+                                    both-note {{in call to}}
 }
 
 namespace Casts {
-  constexpr int a = reinterpret_cast<int>(12); // expected-error {{must be initialized by a constant expression}} \
-                                               // expected-note {{reinterpret_cast is not allowed}} \
-                                               // ref-error {{must be initialized by a constant expression}} \
-                                               // ref-note {{reinterpret_cast is not allowed}}
+  constexpr int a = reinterpret_cast<int>(12); // both-error {{must be initialized by a constant expression}} \
+                                               // both-note {{reinterpret_cast is not allowed}}
 
 }
diff --git a/clang/test/AST/Interp/lifetimes.cpp b/clang/test/AST/Interp/lifetimes.cpp
index c1046e5689207..2bb5a662469e2 100644
--- a/clang/test/AST/Interp/lifetimes.cpp
+++ b/clang/test/AST/Interp/lifetimes.cpp
@@ -5,15 +5,15 @@ struct Foo {
   int a;
 };
 
-constexpr int dead1() { // expected-error {{never produces a constant expression}}
+constexpr int dead1() {
 
   Foo *F2 = nullptr;
   {
-    Foo F{12}; // expected-note 2{{declared here}}
+    Foo F{12}; // expected-note {{declared here}}
     F2 = &F;
   } // Ends lifetime of F.
 
-  return F2->a; // expected-note 2{{read of variable whose lifetime has ended}} \
+  return F2->a; // expected-note {{read of variable whose lifetime has ended}} \
                 // ref-note {{read of object outside its lifetime is not allowed in a constant expression}}
 }
 static_assert(dead1() == 1, ""); // expected-error {{not an integral constant expression}} \
diff --git a/clang/test/AST/Interp/literals.cpp b/clang/test/AST/Interp/literals.cpp
index c160be06dd241..b2cf7fe961f1c 100644
--- a/clang/test/AST/Interp/literals.cpp
+++ b/clang/test/AST/Interp/literals.cpp
@@ -257,10 +257,10 @@ namespace SizeOf {
   }
 
 #if __cplusplus >= 201402L
-  constexpr int IgnoredRejected() { // ref-error {{never produces a constant expression}}
+  constexpr int IgnoredRejected() {
     int n = 0;
     sizeof(int[n++]); // both-warning {{expression result unused}} \
-                      // ref-note 2{{subexpression not valid in a constant expression}}
+                      // ref-note {{subexpression not valid in a constant expression}}
     return n;
   }
   /// FIXME: This is rejected because the parameter so sizeof() is not constant.
@@ -272,8 +272,8 @@ namespace SizeOf {
 
 #if __cplusplus >= 202002L
   /// FIXME: The following code should be accepted.
-  consteval int foo(int n) { // ref-error {{consteval function never produces a constant expression}}
-    return sizeof(int[n]); // ref-note 3{{not valid in a constant expression}}
+  consteval int foo(int n) {
+    return sizeof(int[n]); // ref-note 2{{not valid in a constant expression}}
   }
   constinit int var = foo(5); // ref-error {{not a constant expression}} \
                               // ref-note 2{{in call to}} \
@@ -593,17 +593,17 @@ namespace IncDec {
                                                    // ref-note {{in call to 'uninit<int *, false, false>()'}} \
                                                    // expected-note {{in call to 'uninit()'}}
 
-  constexpr int OverFlow() { // both-error {{never produces a constant expression}}
+  constexpr int OverFlow() {
     int a = INT_MAX;
-    ++a; // both-note 2{{is outside the range}}
+    ++a; // both-note {{is outside the range}}
     return -1;
   }
   static_assert(OverFlow() == -1, "");  // both-error {{not an integral constant expression}} \
                                         // both-note {{in call to 'OverFlow()'}}
 
-  constexpr int UnderFlow() { // both-error {{never produces a constant expression}}
+  constexpr int UnderFlow() {
     int a = INT_MIN;
-    --a; // both-note 2{{is outside the range}}
+    --a; // both-note {{is outside the range}}
     return -1;
   }
   static_assert(UnderFlow() == -1, "");  // both-error {{not an integral constant expression}} \
@@ -792,11 +792,13 @@ namespace IncDec {
   }
   static_assert(ptrInc2() == 2, "");
 
-  constexpr int ptrInc3() { // both-error {{never produces a constant expression}}
+  constexpr int ptrInc3() {
     const int *p = arr;
     p += 12; // both-note {{cannot refer to element 12 of array of 3 elements}}
     return *p;
   }
+  static_assert(ptrInc3() == 0, ""); // both-error {{static assertion expression is not an integral constant expression}} \
+                                        both-note {{in call to}}
 
   constexpr int ptrIncDec1() {
     const int *p = arr;
@@ -806,11 +808,13 @@ namespace IncDec {
   }
   static_assert(ptrIncDec1() == 2, "");
 
-  constexpr int ptrDec1() { // both-error {{never produces a constant expression}}
+  constexpr int ptrDecl() {
     const int *p = arr;
     p -= 1;  // both-note {{cannot refer to element -1 of array of 3 elements}}
     return *p;
   }
+  static_assert(ptrDecl() == 0, ""); // both-error {{static assertion expression is not an integral constant expression}} \
+                                        both-note {{in call to}}
 
   /// This used to leave a 0 on the stack instead of the previous
   /// value of a.
@@ -1182,11 +1186,11 @@ namespace incdecbool {
 
 
 #if __cplusplus == 201103L
-  constexpr bool foo() { // both-error {{never produces a constant expression}}
+  constexpr bool foo() {
     bool b = true; // both-warning {{variable declaration in a constexpr function is a C++14 extension}}
     b++; // both-warning {{incrementing expression of type bool is deprecated and incompatible with C++17}} \
          // both-warning {{use of this statement in a constexpr function is a C++14 extension}} \
-         // both-note 2{{subexpression not valid in a constant expression}}
+         // both-note {{subexpression not valid in a constant expression}}
 
     return b;
   }
@@ -1201,11 +1205,13 @@ namespace incdecbool {
 #if __cplusplus >= 201402L
 /// NOTE: The diagnostics of the two interpreters are a little
 /// different here, but they both make sense.
-constexpr int externvar1() { // both-error {{never produces a constant expression}}
+constexpr int externvar1() {
   extern char arr[]; // ref-note {{declared here}}
    return arr[0]; // ref-note {{read of non-constexpr variable 'arr'}} \
                   // expected-note {{array-to-pointer decay of array member without known bound is not supported}}
 }
+static_assert(externvar1() == 0, ""); // both-error {{not an integral constant expression}} \
+                                         both-note {{in call to}}
 #endif
 
 namespace Extern {
diff --git a/clang/test/AST/Interp/records.cpp b/clang/test/AST/Interp/records.cpp
index 0a89c81bafd57..a811f8705eea9 100644
--- a/clang/test/AST/Interp/records.cpp
+++ b/clang/test/AST/Interp/records.cpp
@@ -192,9 +192,9 @@ namespace thisPointer {
     constexpr int get12() { return 12; }
   };
 
-  constexpr int foo() { // both-error {{never produces a constant expression}}
+  constexpr int foo() {
     S *s = nullptr;
-    return s->get12(); // both-note 2{{member call on dereferenced null pointer}}
+    return s->get12(); // both-note {{member call on dereferenced null pointer}}
 
   }
   static_assert(foo() == 12, ""); // both-error {{not an integral constant expression}} \
@@ -329,8 +329,7 @@ namespace InitializerTemporaries {
   struct S {
     constexpr S() {}
     constexpr ~S() noexcept(false) { throw 12; } // both-error {{cannot use 'throw'}} \
-                                                 // both-error {{never produces a constant expression}} \
-                                                 // both-note 2{{subexpression not valid}}
+                                                 // both-note {{subexpression not valid}}
   };
 
   constexpr int f() {
@@ -404,17 +403,14 @@ namespace MI {
 
 namespace DeriveFailures {
 #if __cplusplus < 202002L
-  struct Base { // both-note {{declared here}} \
-                // ref-note {{declared here}}
+  struct Base { // both-note {{declared here}}
     int Val;
   };
 
   struct Derived : Base {
     int OtherVal;
 
-    constexpr Derived(int i) : OtherVal(i) {} // ref-error {{never produces a constant expression}} \
-                                              // both-note {{non-constexpr constructor 'Base' cannot be used in a constant expression}} \
-                                              // ref-note {{non-constexpr constructor 'Base' cannot be used in a constant expression}} 
+    constexpr Derived(int i) : OtherVal(i) {} // both-note {{non-constexpr constructor 'Base' cannot be used in a constant expression}}
   };
 
   constexpr Derived D(12); // both-error {{must be initialized by a constant expression}} \
@@ -597,9 +593,9 @@ namespace Destructors {
 
   struct S {
     constexpr S() {}
-    constexpr ~S() { // both-error {{never produces a constant expression}}
+    constexpr ~S() {
       int i = 1 / 0; // both-warning {{division by zero}} \
-                     // both-note 2{{division by zero}}
+                     // both-note {{division by zero}}
     }
   };
   constexpr int testS() {
@@ -1066,20 +1062,20 @@ namespace AccessOnNullptr {
     int a;
   };
 
-  constexpr int a() { // both-error {{never produces a constant expression}}
+  constexpr int a() {
     F *f = nullptr;
 
-    f->a = 0; // both-note 2{{cannot access field of null pointer}}
+    f->a = 0; // both-note {{cannot access field of null pointer}}
     return f->a;
   }
   static_assert(a() == 0, ""); // both-error {{not an integral constant expression}} \
                                // both-note {{in call to 'a()'}}
 
-  constexpr int a2() { // both-error {{never produces a constant expression}}
+  constexpr int a2() {
     F *f = nullptr;
 
 
-    const int *a = &(f->a); // both-note 2{{cannot access field of null pointer}}
+    const int *a = &(f->a); // both-note {{cannot access field of null pointer}}
     return f->a;
   }
   static_assert(a2() == 0, ""); // both-error {{not an integral constant expression}} \
@@ -1246,8 +1242,11 @@ namespace InvalidCtorInitializer {
 extern int f(); // both-note {{here}}
 struct HasNonConstExprMemInit {
   int x = f(); // both-note {{non-constexpr function}}
-  constexpr HasNonConstExprMemInit() {} // both-error {{never produces a constant expression}}
+  constexpr HasNonConstExprMemInit() {}
 };
+HasNonConstExprMemInit NonConstexprUse;
+constexpr HasNonConstExprMemInit ConstexprUse; // both-error {{constexpr variable 'ConstexprUse' must be initialized by a constant expression}} \
+                                                  both-note {{in call to}}
 
 namespace {
   template <class Tp, Tp v>
@@ -1448,8 +1447,8 @@ namespace TemporaryWithInvalidDestructor {
 #if __cplusplus >= 202002L
   struct A {
     bool a = true;
-    constexpr ~A() noexcept(false) { // both-error {{never produces a constant expression}}
-      throw; // both-note 2{{not valid in a constant expression}} \
+    constexpr ~A() noexcept(false) {
+      throw; // both-note {{not valid in a constant expression}} \
              // both-error {{cannot use 'throw' with exceptions disabled}}
     }
   };
diff --git a/clang/test/AST/Interp/shifts.cpp b/clang/test/AST/Interp/shifts.cpp
index 76047d0f752d5..af212783093f3 100644
--- a/clang/test/AST/Interp/shifts.cpp
+++ b/clang/test/AST/Interp/shifts.cpp
@@ -1,17 +1,13 @@
-// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -std=c++20 -verify %s
-// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -std=c++17 -verify=cxx17 %s
-// RUN: %clang_cc1 -std=c++20 -verify=ref %s
-// RUN: %clang_cc1 -std=c++17 -verify=ref-cxx17 %s
+// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -std=c++20 -verify=expected,all %s
+// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -std=c++17 -verify=cxx17,all,all-cxx17 %s
+// RUN: %clang_cc1 -std=c++20 -verify=ref,all %s
+// RUN: %clang_cc1 -std=c++17 -verify=ref-cxx17,all,all-cxx17 %s
 
 #define INT_MIN (~__INT_MAX__)
 
 
 namespace shifts {
-  constexpr void test() { // ref-error {{constexpr function never produces a constant expression}} \
-                          // ref-cxx17-error {{constexpr function never produces a constant expression}} \
-                          // expected-error {{constexpr function never produces a constant expression}} \
-                          // cxx17-error {{constexpr function never produces a constant expression}} \
-
+  constexpr int test() {
     char c; // cxx17-warning {{uninitialized variable}} \
             // ref-cxx17-warning {{uninitialized variable}}
 
@@ -107,8 +103,13 @@ namespace shifts {
     lli = INT_MIN << 2; // cxx17-warning {{shifting a negative signed value is undefined}} \
                         // ref-cxx17-warning {{shifting a negative signed value is undefined}}
     lli = 1LL << (sizeof(long long) * __CHAR_BIT__ - 2);
+
+    return 0;
   }
 
+  static_assert(test() == 0, ""); // all-error {{static assertion expression is not an integral constant expression}} \
+                                     all-note {{in call to}}
+
   static_assert(1 << 4 == 16, "");
   constexpr unsigned m = 2 >> 1;
   static_assert(m == 1, "");
@@ -155,21 +156,23 @@ namespace shifts {
   constexpr decltype(L) M2 = (R > 32 && R < 64) ?  L >> R : 0;
 
 
-  constexpr int signedShift() { // cxx17-error {{never produces a constant expression}} \
-                                // ref-cxx17-error {{never produces a constant expression}}
+  constexpr int signedShift() {
     return 1024 << 31; // cxx17-warning {{signed shift result}} \
                        // ref-cxx17-warning {{signed shift result}} \
                        // cxx17-note {{signed left shift discards bits}} \
                        // ref-cxx17-note {{signed left shift discards bits}}
   }
+  static_assert(signedShift() == 0, ""); // all-cxx17-error {{static assertion expression is not an integral constant expression}} \
+                                            all-cxx17-note {{in call to}}
 
-  constexpr int negativeShift() { // cxx17-error {{never produces a constant expression}} \
-                                  // ref-cxx17-error {{never produces a constant expression}}
+  constexpr int negativeShift() {
     return -1 << 2; // cxx17-warning {{shifting a negative signed value is undefined}} \
                     // ref-cxx17-warning {{shifting a negative signed value is undefined}} \
                     // cxx17-note {{left shift of negative value -1}} \
                     // ref-cxx17-note {{left shift of negative value -1}}
   }
+  static_assert(negativeShift() == -4, ""); // all-cxx17-error {{static assertion expression is not an integral constant expression}} \
+                                               all-cxx17-note {{in call to}}
 
   constexpr int foo(int a) {
     return -a << 2; // cxx17-note {{left shift of negative value -10}} \
diff --git a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp
index 4416c82522649..08270ccb9dcb4 100644
--- a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp
+++ b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp
@@ -229,9 +229,9 @@ namespace DR1364 {
     return k; // ok, even though lvalue-to-rvalue conversion of a function
               // parameter is not allowed in a constant expression.
   }
-  int kGlobal; // beforecxx23-note {{here}}
-  constexpr int f() { // beforecxx23-error {{constexpr function never produces a constant expression}}
-    return kGlobal;   // beforecxx23-note {{read of non-const}}
+  int kGlobal;
+  constexpr int f() {
+    return kGlobal;
   }
 }
 
@@ -272,8 +272,8 @@ namespace std_example {
     int a; // beforecxx20-warning {{uninitialized}}
     return a;
   }
-  constexpr int prev(int x) { // beforecxx14-error {{never produces a constant expression}}
-    return --x;               // beforecxx14-note {{subexpression}}
+  constexpr int prev(int x) {
+    return --x;
   }
 
   constexpr int g(int x, int n) {
diff --git a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp
index 92698ec1c7387..ce97953600095 100644
--- a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp
+++ b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp
@@ -16,7 +16,7 @@ struct NonLiteral { // expected-note 2{{no constexpr constructors}}
 };
 struct Literal {
   constexpr Literal() {}
-  explicit Literal(int); // expected-note 2 {{here}}
+  explicit Literal(int);
   operator int() const { return 0; }
 };
 
@@ -240,18 +240,15 @@ template<typename T> struct enable_shared_from_this {
 };
 constexpr int f(enable_shared_from_this<int>);
 
-// - every constructor involved in initializing non-static data members and base
-//   class sub-objects shall be a constexpr constructor.
-// This will no longer be the case once we support P2448R2
 struct ConstexprBaseMemberCtors : Literal {
   Literal l;
 
   constexpr ConstexprBaseMemberCtors() : Literal(), l() {} // ok
-  constexpr ConstexprBaseMemberCtors(char) : // expected-error {{constexpr constructor never produces a constant expression}}
-    Literal(0), // expected-note {{non-constexpr constructor}}
+  constexpr ConstexprBaseMemberCtors(char) :
+    Literal(0),
     l() {}
-  constexpr ConstexprBaseMemberCtors(double) : Literal(), // expected-error {{constexpr constructor never produces a constant expression}}
-    l(0) // expected-note {{non-constexpr constructor}}
+  constexpr ConstexprBaseMemberCtors(double) : Literal(),
+    l(0)
   {}
 };
 
@@ -295,18 +292,10 @@ struct XU4 {
 static_assert(XU2().a == 1, "");
 static_assert(XU4().a == 1, "");
 
-//  - every implicit conversion used in converting a constructor argument to the
-//    corresponding parameter type and converting a full-expression to the
-//    corresponding member type shall be one of those allowed in a constant
-//    expression.
-//
-// We implement the proposed resolution of DR1364 and ignore this bullet.
-// However, we implement the intent of this wording as part of the p5 check that
-// the function must be able to produce a constant expression.
-int kGlobal; // expected-note {{here}}
+int kGlobal;
 struct Z {
   constexpr Z(int a) : n(a) {}
-  constexpr Z() : n(kGlobal) {} // expected-error {{constexpr constructor never produces a constant expression}} expected-note {{read of non-const}}
+  constexpr Z() : n(kGlobal) {}
   int n;
 };
 
diff --git a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p5.cpp b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p5.cpp
index 18b2c6b1d6d15..728af894958de 100644
--- a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p5.cpp
+++ b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p5.cpp
@@ -30,54 +30,54 @@ static_assert(g4() == 5, "");
 
 constexpr int f(bool b)
   { return b ? throw 0 : 0; } // ok
-constexpr int f() { return throw 0, 0; } // expected-error {{constexpr function never produces a constant expression}} expected-note {{subexpression}}
+constexpr int f() { return throw 0, 0; }
 
 struct B {
   constexpr B(int x) : i(0) { }
   int i;
 };
 
-int global; // expected-note {{declared here}}
+int global;
 
 struct D : B {
-  constexpr D() : B(global) { } // expected-error {{constexpr constructor never produces a constant expression}} expected-note {{read of non-const}}
+  constexpr D() : B(global) { }
 };
 
 }
 
 namespace PotentialConstant {
 
-constexpr int Comma(int n) { return // expected-error {{constexpr function never produces a constant expression}}
+constexpr int Comma(int n) { return
   (void)(n * 2),
-  throw 0, // expected-note {{subexpression}}
+  throw 0,
   0;
 }
 
-int ng; // expected-note 6{{here}}
-constexpr int BinaryOp1(int n) { return n + ng; } // expected-error {{never produces}} expected-note {{read}}
-constexpr int BinaryOp2(int n) { return ng + n; } // expected-error {{never produces}} expected-note {{read}}
+int ng;
+constexpr int BinaryOp1(int n) { return n + ng; }
+constexpr int BinaryOp2(int n) { return ng + n; }
 
-double dg; // expected-note 2{{here}}
-constexpr double BinaryOp1(double d) { return d + dg; } // expected-error {{never produces}} expected-note {{read}}
-constexpr double BinaryOp2(double d) { return dg + d; } // expected-error {{never produces}} expected-note {{read}}
+double dg;
+constexpr double BinaryOp1(double d) { return d + dg; }
+constexpr double BinaryOp2(double d) { return dg + d; }
 
 constexpr int Add(int a, int b, int c) { return a + b + c; }
-constexpr int FunctionArgs(int a) { return Add(a, ng, a); } // expected-error {{never produces}} expected-note {{read}}
+constexpr int FunctionArgs(int a) { return Add(a, ng, a); }
 
 struct S { int a; int b; int c[2]; };
-constexpr S InitList(int a) { return { a, ng }; }; // expected-error {{never produces}} expected-note {{read}}
-constexpr S InitList1a(int a) { return S{ a, ng }; }; // expected-error {{never produces}} expected-note {{read}}
-constexpr S InitList2(int a) { return { a, a, { ng } }; }; // expected-error {{never produces}} expected-note {{read}}
+constexpr S InitList(int a) { return { a, ng }; };
+constexpr S InitList1a(int a) { return S{ a, ng }; };
+constexpr S InitList2(int a) { return { a, a, { ng } }; };
 constexpr S InitList3(int a) { return a ? S{ a, a } : S{ a, ng }; }; // ok
 
 constexpr int LogicalAnd1(int n) { return n && (throw, 0); } // ok
-constexpr int LogicalAnd2(int n) { return 1 && (throw, 0); } // expected-error {{never produces}} expected-note {{subexpression}}
+constexpr int LogicalAnd2(int n) { return 1 && (throw, 0); }
 
 constexpr int LogicalOr1(int n) { return n || (throw, 0); } // ok
-constexpr int LogicalOr2(int n) { return 0 || (throw, 0); } // expected-error {{never produces}} expected-note {{subexpression}}
+constexpr int LogicalOr2(int n) { return 0 || (throw, 0); }
 
 constexpr int Conditional1(bool b, int n) { return b ? n : ng; } // ok
-constexpr int Conditional2(bool b, int n) { return b ? n * ng : n + ng; } // expected-error {{never produces}} expected-note {{both arms of conditional operator are unable to produce a constant expression}}
+constexpr int Conditional2(bool b, int n) { return b ? n * ng : n + ng; }
 
 // __builtin_constant_p ? : is magical, and is always a potential constant.
 constexpr bool BcpCall(int n) {
@@ -136,5 +136,5 @@ namespace PR14550 {
 #endif
 
 #if __cplusplus >= 201402L
-constexpr void f() { throw; } // expected-error {{never produces}} expected-note {{subexpression}}
+constexpr void f() { throw; }
 #endif
diff --git a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p6.cpp b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p6.cpp
index 00ef78426289f..a4a7eb131d246 100644
--- a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p6.cpp
+++ b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p6.cpp
@@ -42,8 +42,8 @@ template<typename ...P> struct ConstexprCtor {
 };
 constexpr ConstexprCtor<> f1() { return {}; } // ok
 constexpr ConstexprCtor<int> f2() { return 0; } // ok
-constexpr ConstexprCtor<NonLiteral> f3() { return { 0 }; } // expected-error {{never produces a constant expression}} expected-note {{non-literal type 'NonLiteral}}
-constexpr ConstexprCtor<int, NonLiteral> f4() { return { 0, 0 }; } // expected-error {{never produces a constant expression}} expected-note {{non-literal type 'NonLiteral}}
+constexpr ConstexprCtor<NonLiteral> f3() { return { 0 }; }
+constexpr ConstexprCtor<int, NonLiteral> f4() { return { 0, 0 }; }
 
 struct VirtBase : virtual S {}; // expected-note {{here}}
 
diff --git a/clang/test/CXX/drs/cwg6xx.cpp b/clang/test/CXX/drs/cwg6xx.cpp
index 069102d9c5975..8af58ccfecda9 100644
--- a/clang/test/CXX/drs/cwg6xx.cpp
+++ b/clang/test/CXX/drs/cwg6xx.cpp
@@ -402,7 +402,7 @@ namespace cwg638 { // cwg638: no
 
   class X {
     typedef int type;
-    template<class T> friend struct A<T>::B; 
+    template<class T> friend struct A<T>::B;
     // expected-warning at -1 {{dependent nested name specifier 'A<T>::' for friend class declaration is not supported; turning off access control for 'X'}}
     template<class T> friend void A<T>::f();
     // expected-warning at -1 {{dependent nested name specifier 'A<T>::' for friend class declaration is not supported; turning off access control for 'X'}}
@@ -599,25 +599,16 @@ namespace cwg647 { // cwg647: 3.1
     int n;
     D d;
 
-    // FIXME: We should diagnose this, as the conversion function is not
-    // constexpr. However, that part of this issue is supreseded by cwg1364 and
-    // others; no diagnostic is required for this any more.
     constexpr E()
         : n(D(0)),
           d(0) {}
 
     constexpr E(int)
-    // cxx11-20-error at -1 {{constexpr constructor never produces a constant expression}}
-    //   cxx11-20-note@#cwg647-int-d {{non-constexpr constructor 'D' cannot be used in a constant expression}}
-    //   cxx11-20-note@#cwg647-D-float-ctor {{declared here}}
         : n(0),
-          d(0.0f) {} // #cwg647-int-d
+          d(0.0f) {}
     constexpr E(float f)
-    // cxx11-20-error at -1 {{never produces a constant expression}}
-    //   cxx11-20-note@#cwg647-float-d {{non-constexpr constructor}}
-    //   cxx11-20-note@#cwg647-D-float-ctor {{declared here}}
         : n(get()),
-          d(D(0) + f) {} // #cwg647-float-d
+          d(D(0) + f) {}
   };
 }
 #endif
@@ -1073,7 +1064,7 @@ namespace cwg677 { // cwg677: no
   struct A {
     void *operator new(std::size_t);
     void operator delete(void*) = delete; // #cwg677-A-delete
-    // cxx98-error at -1 {{deleted function definitions are a C++11 extension}} 
+    // cxx98-error at -1 {{deleted function definitions are a C++11 extension}}
   };
   struct B {
     void *operator new(std::size_t);
diff --git a/clang/test/CXX/expr/expr.const/p2-0x.cpp b/clang/test/CXX/expr/expr.const/p2-0x.cpp
index e3cd057baba75..90fe189926953 100644
--- a/clang/test/CXX/expr/expr.const/p2-0x.cpp
+++ b/clang/test/CXX/expr/expr.const/p2-0x.cpp
@@ -302,10 +302,11 @@ constexpr float negpi = -pi; // expect no error on unary operator
 
 #if __cplusplus >= 201703L
 namespace CompoundAssignment {
-constexpr int rem() { // expected-error {{constexpr function never produces a constant expression}}
+constexpr int rem() {
     int x = ~__INT_MAX__;
     return x%=-1; // cxx20-note {{value 2147483648 is outside the range of representable values of type 'int'}}
 }
+static_assert(rem() == 0); // cxx20-error {{static assertion expression is not an integral constant expression}} cxx20-note {{in call to}}
 }
 #endif
 }
@@ -447,9 +448,9 @@ namespace PseudoDtor {
     int n : (k.~I(), 1); // expected-error {{constant expression}} expected-note {{visible outside that expression}}
   };
 
-  constexpr int f(int a = 1) { // cxx11-error {{constant expression}} expected-note {{destroying object 'a' whose lifetime has already ended}}
+  constexpr int f(int a = 1) { // expected-note {{destroying object 'a' whose lifetime has already ended}}
     return (
-        a.~I(), // cxx11-note {{pseudo-destructor}}
+        a.~I(),
         0);
   }
   static_assert(f() == 0, ""); // expected-error {{constant expression}}
@@ -457,9 +458,9 @@ namespace PseudoDtor {
   // This is OK in C++20: the union has no active member after the
   // pseudo-destructor call, so the union destructor has no effect.
   union U { int x; };
-  constexpr int g(U u = {1}) { // cxx11-error {{constant expression}}
+  constexpr int g(U u = {1}) {
     return (
-        u.x.~I(), // cxx11-note 2{{pseudo-destructor}}
+        u.x.~I(), // cxx11-note {{pseudo-destructor}}
         0);
   }
   static_assert(g() == 0, ""); // cxx11-error {{constant expression}} cxx11-note {{in call}}
diff --git a/clang/test/Misc/constexpr-source-ranges.cpp b/clang/test/Misc/constexpr-source-ranges.cpp
index fde05b5c75aa4..d9e23b9f3d5ae 100644
--- a/clang/test/Misc/constexpr-source-ranges.cpp
+++ b/clang/test/Misc/constexpr-source-ranges.cpp
@@ -6,7 +6,7 @@ constexpr int f() {
   return 0;
 }
 
-// CHECK: constexpr-source-ranges.cpp:5:3:{5:3-5:10}
+
 
 
 constexpr int I = 12;
@@ -24,7 +24,6 @@ static_assert(divByZero() == 0, "");
 /// We see this twice. Once from sema and once when
 /// evaluating the static_assert above.
 // CHECK: constexpr-source-ranges.cpp:23:15:{23:15-23:31}
-// CHECK: constexpr-source-ranges.cpp:21:12:{21:14-21:20}
 
 constexpr int div(bool a, bool b) {
   return 1 / (int)b;
@@ -33,7 +32,7 @@ constexpr int ints(int a, int b, int c, int d) {
   return 1;
 }
 static_assert(ints(1, div(true, false), 2, div(false, true)) == 1, "");
-// CHECK: constexpr-source-ranges.cpp:35:23:{35:23-35:39}
+// CHECK: constexpr-source-ranges.cpp:34:23:{34:23-34:39}
 
 namespace overflow {
 // CHECK:      :{[[@LINE+1]]:9-[[@LINE+1]]:29}:
@@ -49,7 +48,3 @@ constexpr int uninit() {
   return aaa;
 }
 static_assert(uninit() == 0, "");
-
-
-constexpr void neverValid() { throw; }
-// CHECK: :{[[@LINE-1]]:16-[[@LINE-1]]:26}:
diff --git a/clang/test/SemaCXX/builtin-object-size-cxx14.cpp b/clang/test/SemaCXX/builtin-object-size-cxx14.cpp
index b7c6f6be01f54..8ba57a3a3bcea 100644
--- a/clang/test/SemaCXX/builtin-object-size-cxx14.cpp
+++ b/clang/test/SemaCXX/builtin-object-size-cxx14.cpp
@@ -115,7 +115,11 @@ namespace InvalidBase {
 }
 
 // PR44268
-constexpr int bos_new() { // cxx14-error {{constant expression}}
-  void *p = new int; // cxx14-note {{until C++20}}
-  return __builtin_object_size(p, 0);
+constexpr int bos_new() {
+  auto *p = new int; // cxx14-note {{until C++20}}
+  int ret = __builtin_object_size(p, 0);
+  delete p;
+  return ret;
 }
+static_assert(bos_new() == sizeof(int), ""); // cxx14-error {{static assertion expression is not an integral constant expression}} cxx14-note {{in call to}}
+
diff --git a/clang/test/SemaCXX/builtin-std-move.cpp b/clang/test/SemaCXX/builtin-std-move.cpp
index a2ae21986308a..b320b16618d6c 100644
--- a/clang/test/SemaCXX/builtin-std-move.cpp
+++ b/clang/test/SemaCXX/builtin-std-move.cpp
@@ -100,8 +100,8 @@ namespace std {
 // Note: this doesn't have a 'moveable' member. Instantiation of the above
 // functions will fail if it's attempted.
 struct A {};
-constexpr bool f(A a) { // #f
-  A &&move = std::move(a); // #call
+constexpr bool f(A a) {
+  A &&move = std::move(a);
   A &&move_if_noexcept = std::move_if_noexcept(a);
   A &&forward1 = std::forward<A>(a);
   A &forward2 = std::forward<A&>(a);
@@ -116,9 +116,6 @@ constexpr bool f(A a) { // #f
 
 #ifndef NO_CONSTEXPR
 static_assert(f({}), "should be constexpr");
-#elif !defined(NEW_INTERP)
-// expected-error@#f {{never produces a constant expression}}
-// expected-note@#call {{}}
 #endif
 
 A &forward_rval_as_lval() {
diff --git a/clang/test/SemaCXX/constant-expression-cxx11.cpp b/clang/test/SemaCXX/constant-expression-cxx11.cpp
index efb391ba0922d..9e8c48d14cc87 100644
--- a/clang/test/SemaCXX/constant-expression-cxx11.cpp
+++ b/clang/test/SemaCXX/constant-expression-cxx11.cpp
@@ -1273,9 +1273,10 @@ namespace PR11595 {
   struct B { B(); A& x; };
   static_assert(B().x == 3, "");  // expected-error {{constant expression}} expected-note {{non-literal type 'B' cannot be used in a constant expression}}
 
-  constexpr bool f(int k) { // cxx11_20-error {{constexpr function never produces a constant expression}}
-    return B().x == k; // cxx11_20-note {{non-literal type 'B' cannot be used in a constant expression}}
+  constexpr bool f(int k) {
+    return B().x == k; // expected-note {{non-literal type 'B' cannot be used in a constant expression}}
   }
+  static_assert(f(3), ""); // expected-error {{static assertion expression is not an integral constant expression}} expected-note {{in call to}}
 }
 
 namespace ExprWithCleanups {
@@ -1326,8 +1327,9 @@ namespace ExternConstexpr {
   constexpr int g() { return q; } // expected-note {{outside its lifetime}}
   constexpr int q = g(); // expected-error {{constant expression}} expected-note {{in call}}
 
-  extern int r; // cxx11_20-note {{here}}
-  constexpr int h() { return r; } // cxx11_20-error {{never produces a constant}} cxx11_20-note {{read of non-const}}
+  extern int r; // expected-note {{here}}
+  constexpr int h() { return r; } // expected-note {{read of non-const}}
+  static_assert(h() == 0, ""); // expected-error {{static assertion expression is not an integral constant expression}} expected-note {{in call to}}
 
   struct S { int n; };
   extern const S s;
@@ -1906,12 +1908,13 @@ namespace StmtExpr {
     });
   }
   static_assert(g(123) == 15129, "");
-  constexpr int h() { // cxx11_20-error {{never produces a constant}}
+  constexpr int h() {
     return ({ // expected-warning {{extension}}
-      return 0; // cxx11_20-note {{not supported}}
+      return 0; // expected-note {{not supported}}
       1;
     });
   }
+  static_assert(h() == 0, ""); // expected-error {{static assertion expression is not an integral constant expression}} expected-note {{in call to}}
 }
 
 namespace VirtualFromBase {
@@ -2093,9 +2096,10 @@ namespace ZeroSizeTypes {
   // expected-note at -2 {{subtraction of pointers to type 'int[0]' of zero size}}
 
   int arr[5][0];
-  constexpr int f() { // cxx11_20-error {{never produces a constant expression}}
-    return &arr[3] - &arr[0]; // cxx11_20-note {{subtraction of pointers to type 'int[0]' of zero size}}
+  constexpr int f() {
+    return &arr[3] - &arr[0]; // expected-note {{subtraction of pointers to type 'int[0]' of zero size}}
   }
+  static_assert(f() == 0, ""); // expected-error {{static assertion expression is not an integral constant expression}} expected-note {{in call to}}
 }
 
 namespace BadDefaultInit {
@@ -2118,11 +2122,12 @@ namespace NeverConstantTwoWays {
   // If we see something non-constant but foldable followed by something
   // non-constant and not foldable, we want the first diagnostic, not the
   // second.
-  constexpr int f(int n) { // cxx11_20-error {{never produces a constant expression}}
-    return (int *)(long)&n == &n ? // cxx11_20-note {{reinterpret_cast}}
-        1 / 0 : // expected-warning {{division by zero}}
+  constexpr int f(int n) {
+    return (int *)(long)&n == &n ?
+        1 / 0 : // expected-note {{division by zero}} expected-warning {{division by zero is undefined}}
         0;
   }
+  static_assert(f(0) == 0, ""); // expected-error {{static assertion expression is not an integral constant expression}} expected-note {{in call to}}
 
   constexpr int n = // expected-error {{must be initialized by a constant expression}}
       (int *)(long)&n == &n ? // expected-note {{reinterpret_cast}}
@@ -2318,10 +2323,9 @@ namespace PR28366 {
 namespace ns1 {
 
 void f(char c) { //expected-note{{declared here}}
-  //cxx11_20-note at -1{{declared here}}
   struct X {
-    static constexpr char f() { // cxx11_20-error {{never produces a constant expression}}
-      return c; //expected-error{{reference to local}} cxx11_20-note{{function parameter}}
+    static constexpr char f() {
+      return c; //expected-error{{reference to local}}
     }
   };
   int I = X::f();
diff --git a/clang/test/SemaCXX/constant-expression-cxx14.cpp b/clang/test/SemaCXX/constant-expression-cxx14.cpp
index 80a7a2dd31531..8279afcc8ce69 100644
--- a/clang/test/SemaCXX/constant-expression-cxx14.cpp
+++ b/clang/test/SemaCXX/constant-expression-cxx14.cpp
@@ -44,16 +44,18 @@ constexpr int g(int k) {
   return 3 * k3 + 5 * k2 + n * k - 20;
 }
 static_assert(g(2) == 42, "");
-constexpr int h(int n) {  // cxx14_20-error {{constexpr function never produces a constant expression}}
-  static const int m = n; // cxx14_20-note {{control flows through the definition of a static variable}} \
+constexpr int h(int n) {
+  static const int m = n; // expected-note {{control flows through the definition of a static variable}} \
                           // cxx14_20-warning {{definition of a static variable in a constexpr function is a C++23 extension}}
   return m;
 }
-constexpr int i(int n) {        // cxx14_20-error {{constexpr function never produces a constant expression}}
-  thread_local const int m = n; // cxx14_20-note {{control flows through the definition of a thread_local variable}} \
+static_assert(h(0) == 0, ""); // expected-error {{static assertion expression is not an integral constant expression}} expected-note {{in call to}}
+constexpr int i(int n) {
+  thread_local const int m = n; // expected-note {{control flows through the definition of a thread_local variable}} \
                                 // cxx14_20-warning {{definition of a thread_local variable in a constexpr function is a C++23 extension}}
   return m;
 }
+static_assert(i(0) == 0, ""); // expected-error {{static assertion expression is not an integral constant expression}} expected-note {{in call to}}
 
 // if-statements can be used in constexpr functions.
 constexpr int j(int k) {
@@ -68,7 +70,6 @@ constexpr int j(int k) {
     }
   }
 } // expected-note 2{{control reached end of constexpr function}}
-  // cxx23-warning at -1 {{does not return a value in all control paths}}
 static_assert(j(0) == -3, "");
 static_assert(j(1) == 5, "");
 static_assert(j(2), ""); // expected-error {{constant expression}} expected-note {{in call to 'j(2)'}}
@@ -105,11 +106,12 @@ static_assert(l(false) == 5, "");
 static_assert(l(true), ""); // expected-error {{constant expression}} expected-note {{in call to 'l(true)'}}
 
 // Potential constant expression checking is still applied where possible.
-constexpr int htonl(int x) { // cxx14_20-error {{never produces a constant expression}}
+constexpr int htonl(int x) {
   typedef unsigned char uchar;
   uchar arr[4] = { uchar(x >> 24), uchar(x >> 16), uchar(x >> 8), uchar(x) };
-  return *reinterpret_cast<int*>(arr); // cxx14_20-note {{reinterpret_cast is not allowed in a constant expression}}
+  return *reinterpret_cast<int*>(arr); // expected-note {{reinterpret_cast is not allowed in a constant expression}}
 }
+static_assert(htonl(0) == 0, ""); // expected-error {{static assertion expression is not an integral constant expression}} expected-note {{in call to}}
 
 constexpr int maybe_htonl(bool isBigEndian, int x) {
   if (isBigEndian)
@@ -184,7 +186,7 @@ namespace string_assign {
   static_assert(!test1(100), "");
   static_assert(!test1(101), ""); // expected-error {{constant expression}} expected-note {{in call to 'test1(101)'}}
 
-  constexpr void f() { // cxx14_20-error{{constexpr function never produces a constant expression}} cxx14_20-note at +2{{assignment to dereferenced one-past-the-end pointer is not allowed in a constant expression}}
+  constexpr void f() {
     char foo[10] = { "z" }; // expected-note {{here}}
     foo[10] = 'x'; // expected-warning {{past the end}}
   }
@@ -208,15 +210,17 @@ namespace array_resize {
 namespace potential_const_expr {
   constexpr void set(int &n) { n = 1; }
   constexpr int div_zero_1() { int z = 0; set(z); return 100 / z; } // no error
-  constexpr int div_zero_2() { // cxx14_20-error {{never produces a constant expression}}
+  constexpr int div_zero_2() {
     int z = 0;
-    return 100 / (set(z), 0); // cxx14_20-note {{division by zero}}
+    return 100 / (set(z), 0); // expected-note {{division by zero}}
   }
-  int n; // cxx14_20-note {{declared here}}
-  constexpr int ref() { // cxx14_20-error {{never produces a constant expression}}
+  static_assert(div_zero_2() == 0, ""); // expected-error {{static assertion expression is not an integral constant expression}} expected-note {{in call to}}
+  int n; // expected-note {{declared here}}
+  constexpr int ref() {
     int &r = n;
-    return r; // cxx14_20-note {{read of non-const variable 'n'}}
+    return r; // expected-note {{read of non-const variable 'n'}}
   }
+  static_assert(ref() == 0, ""); // expected-error {{static assertion expression is not an integral constant expression}} expected-note {{in call to}}
 }
 
 namespace subobject {
@@ -847,10 +851,11 @@ namespace StmtExpr {
   static_assert(g() == 0, ""); // expected-error {{constant expression}} expected-note {{in call}}
 
   // FIXME: We should handle the void statement expression case.
-  constexpr int h() { // cxx14_20-error {{never produces a constant}}
-    ({ if (true) {} }); // cxx14_20-note {{not supported}}
+  constexpr int h() {
+    ({ if (true) {} }); // expected-note {{not supported}}
     return 0;
   }
+  static_assert(h() == 0, ""); // expected-error {{static assertion expression is not an integral constant expression}} expected-note {{in call to}}
 }
 
 namespace VirtualFromBase {
@@ -1044,10 +1049,9 @@ static_assert(sum(Cs) == 'a' + 'b', ""); // expected-error{{not an integral cons
 constexpr int S = sum(Cs); // expected-error{{must be initialized by a constant expression}} expected-note{{in call}}
 }
 
-constexpr void PR28739(int n) { // cxx14_20-error {{never produces a constant}}
+constexpr void PR28739(int n) {
   int *p = &n;                  // expected-note {{array 'p' declared here}}
-  p += (__int128)(unsigned long)-1; // cxx14_20-note {{cannot refer to element 18446744073709551615 of non-array object in a constant expression}}
-  // expected-warning at -1 {{the pointer incremented by 18446744073709551615 refers past the last possible element for an array in 64-bit address space containing 32-bit (4-byte) elements (max possible 4611686018427387904 elements)}}
+  p += (__int128)(unsigned long)-1; // expected-warning {{the pointer incremented by 18446744073709551615 refers past the last possible element for an array in 64-bit address space containing 32-bit (4-byte) elements (max possible 4611686018427387904 elements)}}
 }
 
 constexpr void Void(int n) {
diff --git a/clang/test/SemaCXX/constant-expression-cxx2a.cpp b/clang/test/SemaCXX/constant-expression-cxx2a.cpp
index e4d97dcb73562..cc9b4c3ce699c 100644
--- a/clang/test/SemaCXX/constant-expression-cxx2a.cpp
+++ b/clang/test/SemaCXX/constant-expression-cxx2a.cpp
@@ -352,26 +352,29 @@ namespace Union {
     A a;
     int b;
   };
-  constexpr int read_wrong_member() { // expected-error {{never produces a constant}}
+  constexpr int read_wrong_member() {
     B b = {.b = 1};
     return b.a.x; // expected-note {{read of member 'a' of union with active member 'b'}}
   }
+  static_assert(read_wrong_member()); // expected-error {{static assertion expression is not an integral constant expression}} expected-note {{in call to}}
   constexpr int change_member() {
     B b = {.b = 1};
     b.a.x = 1;
     return b.a.x;
   }
   static_assert(change_member() == 1);
-  constexpr int change_member_then_read_wrong_member() { // expected-error {{never produces a constant}}
+  constexpr int change_member_then_read_wrong_member() {
     B b = {.b = 1};
     b.a.x = 1;
     return b.b; // expected-note {{read of member 'b' of union with active member 'a'}}
   }
-  constexpr int read_wrong_member_indirect() { // expected-error {{never produces a constant}}
+  static_assert(change_member_then_read_wrong_member()); // expected-error {{static assertion expression is not an integral constant expression}} expected-note {{in call to}}
+  constexpr int read_wrong_member_indirect() {
     B b = {.b = 1};
     int *p = &b.a.y;
     return *p; // expected-note {{read of member 'a' of union with active member 'b'}}
   }
+  static_assert(read_wrong_member_indirect()); // expected-error {{static assertion expression is not an integral constant expression}} expected-note {{in call to}}
   constexpr int read_uninitialized() {
     B b = {.b = 1};
     int *p = &b.a.y;
@@ -379,11 +382,13 @@ namespace Union {
     return *p; // expected-note {{read of uninitialized object}}
   }
   static_assert(read_uninitialized() == 0); // expected-error {{constant}} expected-note {{in call}}
-  constexpr void write_wrong_member_indirect() { // expected-error {{never produces a constant}}
+  constexpr int write_wrong_member_indirect() {
     B b = {.b = 1};
     int *p = &b.a.y;
     *p = 1; // expected-note {{assignment to member 'a' of union with active member 'b'}}
+    return 0;
   }
+  static_assert(write_wrong_member_indirect()); // expected-error {{static assertion expression is not an integral constant expression}} expected-note {{in call to}}
   constexpr int write_uninitialized() {
     B b = {.b = 1};
     int *p = &b.a.y;
@@ -475,12 +480,13 @@ namespace Union {
     return r.a.r.b;
   }
   static_assert(ref_member_test_1() == 2);
-  constexpr int ref_member_test_2() { // expected-error {{never produces a constant}}
+  constexpr int ref_member_test_2() {
     ref_member_3 r = {.a = {.r = {.a = 1}}};
     // FIXME: This note isn't great. The 'read' here is reading the referent of the reference.
     r.b.r.b = 2; // expected-note {{read of member 'b' of union with active member 'a'}}
     return r.b.r.b;
   }
+  static_assert(ref_member_test_2()); // expected-error {{static assertion expression is not an integral constant expression}} expected-note {{in call to}}
 
   namespace PR43762 {
     struct A { int x = 1; constexpr int f() { return 1; } };
@@ -766,7 +772,7 @@ namespace dynamic_alloc {
   }
   static_assert(f(123) == 123 * 122 / 2);
 
-  constexpr bool nvdtor() { // expected-error {{never produces a constant expression}}
+  constexpr bool nvdtor() {
     struct S {
       constexpr ~S() {}
     };
@@ -774,6 +780,7 @@ namespace dynamic_alloc {
     delete (S*)new T; // expected-note {{delete of object with dynamic type 'T' through pointer to base class type 'S' with non-virtual destructor}}
     return true;
   }
+  static_assert(nvdtor()); // expected-error {{static assertion expression is not an integral constant expression}} expected-note {{in call to}}
 
   constexpr int vdtor_1() {
     int a;
@@ -837,10 +844,12 @@ namespace dynamic_alloc {
   static_assert(vdtor_3(2) == 3); // expected-error {{}} expected-note {{in call}}
   static_assert(vdtor_3(3) == 3);
 
-  constexpr void delete_mismatch() { // expected-error {{never produces a constant expression}}
+  constexpr int delete_mismatch() {
     delete[] // expected-note {{array delete used to delete pointer to non-array object of type 'int'}}
       new int; // expected-note {{allocation}}
+    return 0;
   }
+  static_assert(delete_mismatch()); // expected-error {{static assertion expression is not an integral constant expression}} expected-note {{in call to}}
 
   template<typename T>
   constexpr T dynarray(int elems, int i) {
@@ -911,11 +920,13 @@ namespace dynamic_alloc {
   }
   static_assert(evaluate_nothrow_arg());
 
-  constexpr void double_delete() { // expected-error {{never produces a constant expression}}
+  constexpr int double_delete() {
     int *p = new int;
     delete p;
     delete p; // expected-note {{delete of pointer that has already been deleted}}
+    return 0;
   }
+  static_assert(double_delete()); // expected-error {{static assertion expression is not an integral constant expression}} expected-note {{in call to}}
   constexpr bool super_secret_double_delete() {
     struct A {
       constexpr ~A() { delete this; } // expected-note {{destruction of object that is already being destroyed}} expected-note {{in call}}
@@ -925,17 +936,21 @@ namespace dynamic_alloc {
   }
   static_assert(super_secret_double_delete()); // expected-error {{constant expression}} expected-note {{in call}}
 
-  constexpr void use_after_free() { // expected-error {{never produces a constant expression}}
+  constexpr int use_after_free() {
     int *p = new int;
     delete p;
     *p = 1; // expected-note {{assignment to heap allocated object that has been deleted}}
+    return 0;
   }
-  constexpr void use_after_free_2() { // expected-error {{never produces a constant expression}}
+  static_assert(use_after_free()); // expected-error {{static assertion expression is not an integral constant expression}} expected-note {{in call to}}
+  constexpr int use_after_free_2() {
     struct X { constexpr void f() {} };
     X *p = new X;
     delete p;
     p->f(); // expected-note {{member call on heap allocated object that has been deleted}}
+    return 0;
   }
+  static_assert(use_after_free_2()); // expected-error {{static assertion expression is not an integral constant expression}} expected-note {{in call to}}
 
   template<typename T> struct X {
     std::size_t n;
@@ -1069,10 +1084,12 @@ namespace std {
 
 namespace dtor_call {
   struct A { int n; };
-  constexpr void f() { // expected-error {{never produces a constant expression}}
+  constexpr int f() {
     A a; // expected-note {{destroying object 'a' whose lifetime has already ended}}
     a.~A();
+    return 0;
   }
+  static_assert(f()); // expected-error {{static assertion expression is not an integral constant expression}} expected-note {{in call to}}
   union U { A a; };
   constexpr void g() {
     U u;
@@ -1206,21 +1223,27 @@ namespace dtor_call {
   }
   static_assert((destroy_after_lifetime3(), true)); // expected-error {{}} expected-note {{in call}}
 
-  constexpr void destroy_after_lifetime4() { // expected-error {{never produces a constant expression}}
+  constexpr int destroy_after_lifetime4() {
     A *p = new A;
     delete p;
     p->~A(); // expected-note {{destruction of heap allocated object that has been deleted}}
+    return 0;
   }
+  static_assert(destroy_after_lifetime4()); // expected-error {{static assertion expression is not an integral constant expression}} expected-note {{in call to}}
 
   struct Extern { constexpr ~Extern() {} } extern e;
-  constexpr void destroy_extern() { // expected-error {{never produces a constant expression}}
+  constexpr int destroy_extern() {
     e.~Extern(); // expected-note {{cannot modify an object that is visible outside}}
+    return 0;
   }
+  static_assert(destroy_extern()); // expected-error {{static assertion expression is not an integral constant expression}} expected-note {{in call to}}
 
   constexpr A &&a_ref = A(); // expected-note {{temporary created here}}
-  constexpr void destroy_extern_2() { // expected-error {{never produces a constant expression}}
+  constexpr int destroy_extern_2() {
     a_ref.~A(); // expected-note {{destruction of temporary is not allowed in a constant expression outside the expression that created the temporary}}
+    return 0;
   }
+  static_assert(destroy_extern_2()); // expected-error {{static assertion expression is not an integral constant expression}} expected-note {{in call to}}
 
   struct S {
     constexpr S() { n = 1; }
@@ -1232,42 +1255,54 @@ namespace dtor_call {
   }
   static_assert((destroy_volatile(), true)); // ok, not volatile during construction and destruction
 
-  constexpr void destroy_null() { // expected-error {{never produces a constant expression}}
+  constexpr int destroy_null() {
     ((A*)nullptr)->~A(); // expected-note {{destruction of dereferenced null pointer}}
+    return 0;
   }
+  static_assert(destroy_null()); // expected-error {{static assertion expression is not an integral constant expression}} expected-note {{in call to}}
 
-  constexpr void destroy_past_end() { // expected-error {{never produces a constant expression}}
+  constexpr int destroy_past_end() {
     A a;
     (&a+1)->~A(); // expected-note {{destruction of dereferenced one-past-the-end pointer}}
+    return 0;
   }
+  static_assert(destroy_past_end()); // expected-error {{static assertion expression is not an integral constant expression}} expected-note {{in call to}}
 
-  constexpr void destroy_past_end_array() { // expected-error {{never produces a constant expression}}
+  constexpr int destroy_past_end_array() {
     A a[2];
     a[2].~A(); // expected-note {{destruction of dereferenced one-past-the-end pointer}}
+    return 0;
   }
+  static_assert(destroy_past_end_array()); // expected-error {{static assertion expression is not an integral constant expression}} expected-note {{in call to}}
 
   union As {
     A a, b;
   };
 
-  constexpr void destroy_no_active() { // expected-error {{never produces a constant expression}}
+  constexpr int destroy_no_active() {
     As as;
     as.b.~A(); // expected-note {{destruction of member 'b' of union with no active member}}
+    return 0;
   }
+  static_assert(destroy_no_active()); // expected-error {{static assertion expression is not an integral constant expression}} expected-note {{in call to}}
 
-  constexpr void destroy_inactive() { // expected-error {{never produces a constant expression}}
+  constexpr int destroy_inactive() {
     As as;
     as.a.n = 1;
     as.b.~A(); // expected-note {{destruction of member 'b' of union with active member 'a'}}
+    return 0;
   }
+  static_assert(destroy_inactive()); // expected-error {{static assertion expression is not an integral constant expression}} expected-note {{in call to}}
 
-  constexpr void destroy_no_active_2() { // expected-error {{never produces a constant expression}}
+  constexpr int destroy_no_active_2() {
     As as;
     as.a.n = 1;
     as.a.~A();
     // FIXME: This diagnostic is wrong; the union has no active member now.
     as.b.~A(); // expected-note {{destruction of member 'b' of union with active member 'a'}}
+    return 0;
   }
+  static_assert(destroy_no_active_2()); // expected-error {{static assertion expression is not an integral constant expression}} expected-note {{in call to}}
 
   constexpr void destroy_pointer() {
     using T = int*;
@@ -1327,16 +1362,22 @@ namespace mutable_subobjects {
   auto &ti2 = typeid(a.m);
   auto &ti3 = typeid(a.n);
 
-  constexpr void destroy1() { // expected-error {{constexpr}}
+  constexpr int destroy1() {
     a.~A(); // expected-note {{cannot modify an object that is visible outside}}
+    return 0;
   }
+  static_assert(destroy1()); // expected-error {{static assertion expression is not an integral constant expression}} expected-note {{in call to}}
   using T = int;
-  constexpr void destroy2() { // expected-error {{constexpr}}
+  constexpr int destroy2() {
     a.m.~T(); // expected-note {{cannot modify an object that is visible outside}}
+    return 0;
   }
-  constexpr void destroy3() { // expected-error {{constexpr}}
+  static_assert(destroy2()); // expected-error {{static assertion expression is not an integral constant expression}} expected-note {{in call to}}
+  constexpr int destroy3() {
     a.n.~T(); // expected-note {{cannot modify an object that is visible outside}}
+    return 0;
   }
+  static_assert(destroy3()); // expected-error {{static assertion expression is not an integral constant expression}} expected-note {{in call to}}
 
   struct X {
     mutable int n = 0;
@@ -1466,9 +1507,9 @@ namespace PR45879 {
   static_assert(f());
 
   // Only syntactic assignments change the active union member.
-  constexpr bool g() { // expected-error {{never produces a constant expression}}
+  constexpr bool g() {
     C c = {.n = 1};
-    c.a.operator=(B{2}.a); // expected-note 2{{member call on member 'a' of union with active member 'n' is not allowed in a constant expression}}
+    c.a.operator=(B{2}.a); // expected-note {{member call on member 'a' of union with active member 'n' is not allowed in a constant expression}}
     return c.a.n == 2;
   }
   static_assert(g()); // expected-error {{constant expression}} expected-note {{in call}}
diff --git a/clang/test/SemaCXX/constexpr-frame-describe.cpp b/clang/test/SemaCXX/constexpr-frame-describe.cpp
index 7b832d9a4b4a1..94ab786a62a4f 100644
--- a/clang/test/SemaCXX/constexpr-frame-describe.cpp
+++ b/clang/test/SemaCXX/constexpr-frame-describe.cpp
@@ -2,16 +2,15 @@
 
 
 struct Foo {
-    constexpr void zomg() const { (void)(1 / 0); } // expected-error {{constant expression}} \
-                                                      expected-warning {{division by zero}} \
-                                                      expected-note 2{{division by zero}}
+    constexpr void zomg() const { (void)(1 / 0); } // expected-warning {{division by zero}} \
+                                                      expected-note {{division by zero}}
 };
 
 struct S {
     constexpr S() {}
-    constexpr bool operator==(const S&) const { // expected-error {{never produces a constant expression}}
+    constexpr bool operator==(const S&) const {
       return 1 / 0; // expected-warning {{division by zero}} \
-                       expected-note 3{{division by zero}}
+                       expected-note 2{{division by zero}}
     }
 
     constexpr bool heh() const {
@@ -36,9 +35,8 @@ static_assert(*sptr == *sptr2); // expected-error {{constant expression}} \
                                    expected-note {{in call to '*sptr.operator==(s2)'}}
 
 struct A {
-  constexpr int foo() { (void)(1/0); return 1;} // expected-error {{never produces a constant expression}} \
-                                                   expected-warning {{division by zero}} \
-                                                   expected-note 2{{division by zero}}
+  constexpr int foo() { (void)(1/0); return 1;} // expected-warning {{division by zero}} \
+                                                   expected-note {{division by zero}}
 };
 
 struct B {
diff --git a/clang/test/SemaCXX/constexpr-function-recovery-crash.cpp b/clang/test/SemaCXX/constexpr-function-recovery-crash.cpp
index 90ee7892b2fc2..736abfcfeb7ab 100644
--- a/clang/test/SemaCXX/constexpr-function-recovery-crash.cpp
+++ b/clang/test/SemaCXX/constexpr-function-recovery-crash.cpp
@@ -34,17 +34,16 @@ constexpr int test4() {
     return 0;
 }
 
-constexpr int test5() { // expected-error {{constexpr function never produce}}
-  for (;; a++); // expected-error {{use of undeclared identifier}}  \
-                   expected-note {{constexpr evaluation hit maximum step limit; possible infinite loop?}}
+constexpr int test5() {
+  for (;; a++); // expected-error {{use of undeclared identifier}}
   return 1;
 }
 
-constexpr int test6() { // expected-error {{constexpr function never produce}}
+constexpr int test6() {
   int n = 0;
   switch (n) {
     for (;; a++) { // expected-error {{use of undeclared identifier}}
-    case 0:; // expected-note {{constexpr evaluation hit maximum step limit; possible infinite loop?}}
+    case 0:;
     }
   }
   return 0;
diff --git a/clang/test/SemaCXX/constexpr-string.cpp b/clang/test/SemaCXX/constexpr-string.cpp
index c456740ef7551..2516b483ec2b6 100644
--- a/clang/test/SemaCXX/constexpr-string.cpp
+++ b/clang/test/SemaCXX/constexpr-string.cpp
@@ -601,15 +601,15 @@ namespace MemcpyEtc {
     constexpr NonTrivial(const NonTrivial &) : n(1) {}
     int n;
   };
-  constexpr bool test_nontrivial_memcpy() { // expected-error {{never produces a constant}}
+  constexpr bool test_nontrivial_memcpy() {
     NonTrivial arr[3] = {};
-    __builtin_memcpy(arr, arr + 1, sizeof(NonTrivial)); // expected-note 2{{non-trivially-copyable}}
+    __builtin_memcpy(arr, arr + 1, sizeof(NonTrivial)); // expected-note {{non-trivially-copyable}}
     return true;
   }
   static_assert(test_nontrivial_memcpy()); // expected-error {{constant}} expected-note {{in call}}
-  constexpr bool test_nontrivial_memmove() { // expected-error {{never produces a constant}}
+  constexpr bool test_nontrivial_memmove() {
     NonTrivial arr[3] = {};
-    __builtin_memcpy(arr, arr + 1, sizeof(NonTrivial)); // expected-note 2{{non-trivially-copyable}}
+    __builtin_memcpy(arr, arr + 1, sizeof(NonTrivial)); // expected-note {{non-trivially-copyable}}
     return true;
   }
   static_assert(test_nontrivial_memmove()); // expected-error {{constant}} expected-note {{in call}}
@@ -649,29 +649,29 @@ namespace MemcpyEtc {
   static_assert(test_address_of_const_array_type() == 1234);
 
   // Check that an incomplete array is rejected.
-  constexpr int test_incomplete_array_type() { // expected-error {{never produces a constant}}
+  constexpr int test_incomplete_array_type() {
     extern int arr[];
     __builtin_memmove(arr, arr, 4 * sizeof(arr[0]));
-    // expected-note at -1 2{{'memmove' not supported: source is not a contiguous array of at least 4 elements of type 'int'}}
+    // expected-note at -1 {{'memmove' not supported: source is not a contiguous array of at least 4 elements of type 'int'}}
     return arr[0] * 1000 + arr[1] * 100 + arr[2] * 10 + arr[3];
   }
   static_assert(test_incomplete_array_type() == 1234); // expected-error {{constant}} expected-note {{in call}}
 
   // Check that a pointer to an incomplete array is rejected.
-  constexpr int test_address_of_incomplete_array_type() { // expected-error {{never produces a constant}}
+  constexpr int test_address_of_incomplete_array_type() {
     extern int arr[];
     __builtin_memmove(&arr, &arr, 4 * sizeof(arr[0]));
-    // expected-note at -1 2{{cannot constant evaluate 'memmove' between objects of incomplete type 'int[]'}}
+    // expected-note at -1 {{cannot constant evaluate 'memmove' between objects of incomplete type 'int[]'}}
     return arr[0] * 1000 + arr[1] * 100 + arr[2] * 10 + arr[3];
   }
   static_assert(test_address_of_incomplete_array_type() == 1234); // expected-error {{constant}} expected-note {{in call}}
 
   // Check that a pointer to an incomplete struct is rejected.
-  constexpr bool test_address_of_incomplete_struct_type() { // expected-error {{never produces a constant}}
+  constexpr bool test_address_of_incomplete_struct_type() {
     struct Incomplete;
     extern Incomplete x, y;
     __builtin_memcpy(&x, &x, 4);
-    // expected-note at -1 2{{cannot constant evaluate 'memcpy' between objects of incomplete type 'Incomplete'}}
+    // expected-note at -1 {{cannot constant evaluate 'memcpy' between objects of incomplete type 'Incomplete'}}
     return true;
   }
   static_assert(test_address_of_incomplete_struct_type()); // expected-error {{constant}} expected-note {{in call}}
diff --git a/clang/test/SemaCXX/cxx23-assume.cpp b/clang/test/SemaCXX/cxx23-assume.cpp
index 9138501d726dd..f3f9390fe42fb 100644
--- a/clang/test/SemaCXX/cxx23-assume.cpp
+++ b/clang/test/SemaCXX/cxx23-assume.cpp
@@ -72,10 +72,11 @@ static_assert(h(4) == sizeof(int));
 static_assert(__has_cpp_attribute(assume) == 202207L);
 static_assert(__has_attribute(assume));
 
-constexpr bool i() { // ext-error {{never produces a constant expression}}
-  [[assume(false)]]; // ext-note {{assumption evaluated to false}} expected-note {{assumption evaluated to false}} ext-warning {{C++23 extension}}
+constexpr bool i() {
+  [[assume(false)]]; // expected-note 2 {{assumption evaluated to false}} ext-warning {{C++23 extension}}
   return true;
 }
+static_assert(i()); // expected-error {{static assertion expression is not an integral constant expression}} expected-note {{in call to}}
 
 constexpr bool j(bool b) {
   [[assume(b)]]; // expected-note {{assumption evaluated to false}} ext-warning {{C++23 extension}}
diff --git a/clang/test/SemaCXX/cxx2a-consteval.cpp b/clang/test/SemaCXX/cxx2a-consteval.cpp
index 622ec31c459dd..351fb73b6631a 100644
--- a/clang/test/SemaCXX/cxx2a-consteval.cpp
+++ b/clang/test/SemaCXX/cxx2a-consteval.cpp
@@ -904,7 +904,7 @@ void func() {
   S<Baz, 3> s7;
 }
 
-consteval int aConstevalFunction() { // expected-error {{consteval function never produces a constant expression}}
+consteval int aConstevalFunction() {
   // Defaulted default constructors are implicitly consteval.
   S<Bar, 1> s1;
 
@@ -914,6 +914,7 @@ consteval int aConstevalFunction() { // expected-error {{consteval function neve
   S<Baz, 3> s3;
   return 0;
 }
+static_assert(aConstevalFunction() == 0); // expected-error {{static assertion expression is not an integral constant expression}} expected-note {{in call to}}
 
 } // namespace multiple_default_constructors
 
diff --git a/clang/test/SemaCXX/cxx2a-constexpr-dynalloc.cpp b/clang/test/SemaCXX/cxx2a-constexpr-dynalloc.cpp
index 357dc67bd5ad2..7870bc2d77f97 100644
--- a/clang/test/SemaCXX/cxx2a-constexpr-dynalloc.cpp
+++ b/clang/test/SemaCXX/cxx2a-constexpr-dynalloc.cpp
@@ -90,11 +90,12 @@ constexpr int no_deallocate_nonalloc = (std::allocator<int>().deallocate((int*)&
 // expected-note at -2 {{declared here}}
 
 void *operator new(std::size_t, void *p) { return p; }
-constexpr bool no_placement_new_in_user_code() { // expected-error {{never produces a constant expression}}
+constexpr bool no_placement_new_in_user_code() {
   int a;
   new (&a) int(42); // expected-note {{call to placement 'operator new'}}
   return a == 42;
 }
+static_assert(no_placement_new_in_user_code()); // expected-error {{static assertion expression is not an integral constant expression}} expected-note {{in call to}}
 
 namespace std {
   constexpr bool placement_new_in_stdlib() {
diff --git a/clang/test/SemaCXX/literal-type.cpp b/clang/test/SemaCXX/literal-type.cpp
index 88535c169fe01..046fa2c8a6efd 100644
--- a/clang/test/SemaCXX/literal-type.cpp
+++ b/clang/test/SemaCXX/literal-type.cpp
@@ -1,6 +1,6 @@
 // RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
 // RUN: %clang_cc1 -fsyntax-only -verify -std=c++20 %s
-
+// expected-no-diagnostics
 
 static_assert(__is_literal(int), "fail");
 static_assert(__is_literal_type(int), "fail"); // alternate spelling for GCC
@@ -53,10 +53,10 @@ static_assert(!__is_literal(HasNonLiteralBase), "fail");
 static_assert(!__is_literal(HasNonLiteralMember), "fail");
 
 // DR1361 removes the brace-or-equal-initializer bullet so that we can allow:
-extern int f(); // expected-note {{here}}
+extern int f();
 struct HasNonConstExprMemInit {
-  int x = f(); // expected-note {{non-constexpr function}}
-  constexpr HasNonConstExprMemInit() {} // expected-error {{never produces a constant expression}}
+  int x = f();
+  constexpr HasNonConstExprMemInit() {}
   constexpr HasNonConstExprMemInit(int y) : x(y) {} // ok
 };
 static_assert(__is_literal(HasNonConstExprMemInit), "fail");
diff --git a/clang/test/SemaCXX/ms-constexpr-invalid.cpp b/clang/test/SemaCXX/ms-constexpr-invalid.cpp
index e5bec0c7119b0..247ef53ba072d 100644
--- a/clang/test/SemaCXX/ms-constexpr-invalid.cpp
+++ b/clang/test/SemaCXX/ms-constexpr-invalid.cpp
@@ -3,10 +3,11 @@
 
 // Check explicitly invalid code
 
-void runtime() {} // expected-note {{declared here}}
+void runtime() {}
 
-[[msvc::constexpr]] void f0() { runtime(); } // expected-error {{constexpr function never produces a constant expression}} \
-                                             // expected-note {{non-constexpr function 'runtime' cannot be used in a constant expression}}
+[[msvc::constexpr]] int f0() { runtime(); return 0; } // expected-note {{declared here}}
+static_assert(f0() == 0); // expected-error {{static assertion expression is not an integral constant expression}} \
+                             expected-note{{non-constexpr function 'f0' cannot be used in a constant expression}}
 [[msvc::constexpr]] constexpr void f1() {} // expected-error {{attribute 'msvc::constexpr' cannot be applied to the constexpr function 'f1'}}
 #if __cplusplus >= 202202L
 [[msvc::constexpr]] consteval void f2() {} // expected-error {{attribute 'msvc::constexpr' cannot be applied to the consteval function 'f1'}}
@@ -22,24 +23,19 @@ struct [[msvc::constexpr]] S2{}; // expected-error {{'constexpr' attribute only
 // Check invalid code mixed with valid code
 
 [[msvc::constexpr]] int f4(int x) { return x > 1 ? 1 + f4(x / 2) : 0; } // expected-note {{non-constexpr function 'f4' cannot be used in a constant expression}} \
-                                                                        // expected-note {{declared here}} \
                                                                         // expected-note {{declared here}} \
                                                                         // expected-note {{declared here}}
 constexpr bool f5() { [[msvc::constexpr]] return f4(32) == 5; } // expected-note {{in call to 'f4(32)'}}
 static_assert(f5()); // expected-error {{static assertion expression is not an integral constant expression}} \
                      // expected-note {{in call to 'f5()'}}
 
-int f6(int x) { [[msvc::constexpr]] return x > 1 ? 1 + f6(x / 2) : 0; } // expected-note {{declared here}} \
-                                                                        // expected-note {{declared here}}
-constexpr bool f7() { [[msvc::constexpr]] return f6(32) == 5; } // expected-error {{constexpr function never produces a constant expression}} \
-                                                                // expected-note {{non-constexpr function 'f6' cannot be used in a constant expression}} \
-                                                                // expected-note {{non-constexpr function 'f6' cannot be used in a constant expression}}
+int f6(int x) { [[msvc::constexpr]] return x > 1 ? 1 + f6(x / 2) : 0; } // expected-note {{declared here}}
+constexpr bool f7() { [[msvc::constexpr]] return f6(32) == 5; } // expected-note {{non-constexpr function 'f6' cannot be used in a constant expression}}
 static_assert(f7()); // expected-error {{static assertion expression is not an integral constant expression}} \
                      // expected-note {{in call to 'f7()'}}
 
-constexpr bool f8() { // expected-error {{constexpr function never produces a constant expression}}
+constexpr bool f8() {
     [[msvc::constexpr]] f4(32); // expected-error {{'constexpr' attribute only applies to functions and return statements}} \
-                                // expected-note {{non-constexpr function 'f4' cannot be used in a constant expression}} \
                                 // expected-note {{non-constexpr function 'f4' cannot be used in a constant expression}}
     [[msvc::constexpr]] int i5 = f4(32); // expected-error {{'constexpr' attribute only applies to functions and return statements}}
     return i5 == 5;
diff --git a/clang/test/SemaCXX/ms-constexpr.cpp b/clang/test/SemaCXX/ms-constexpr.cpp
index 79f71a34cb7d8..7a94962202f80 100644
--- a/clang/test/SemaCXX/ms-constexpr.cpp
+++ b/clang/test/SemaCXX/ms-constexpr.cpp
@@ -29,9 +29,7 @@ static_assert(test_get_msconstexpr_true());
 struct S2 {
     [[msvc::constexpr]] S2() {}
     [[msvc::constexpr]] bool value() { return true; }
-    static constexpr bool check() { [[msvc::constexpr]] return S2{}.value(); } // expected-error {{constexpr function never produces a constant expression}} \
-                                                                               // expected-note {{non-literal type 'S2' cannot be used in a constant expression}} \
-                                                                               // expected-note {{non-literal type 'S2' cannot be used in a constant expression}}
+    static constexpr bool check() { [[msvc::constexpr]] return S2{}.value(); }  // expected-note {{non-literal type 'S2' cannot be used in a constant expression}}
 };
 static_assert(S2::check()); // expected-error {{static assertion expression is not an integral constant expression}} \
                             // expected-note {{in call to 'check()'}}

>From ddf35baedd9a75aec79467ed77152feb42d194e9 Mon Sep 17 00:00:00 2001
From: Aaron Ballman <aaron at aaronballman.com>
Date: Mon, 3 Jun 2024 09:51:50 -0400
Subject: [PATCH 2/4] Revert back to original, almost

This leaves the code in place but disables it for system headers and
when the diagnostic itself is disabled. It also corrects the logic for
C++23 so that we don't check for potential evaluation in C++23 mode or
later.
---
 clang/lib/Sema/SemaDeclCXX.cpp                | 34 +++++++
 clang/test/AST/Interp/arrays.cpp              | 28 +++---
 clang/test/AST/Interp/cxx11.cpp               | 16 ++--
 clang/test/AST/Interp/cxx17.cpp               |  4 +-
 clang/test/AST/Interp/cxx23.cpp               | 53 +++++++----
 clang/test/AST/Interp/functions.cpp           | 14 +--
 clang/test/AST/Interp/invalid.cpp             | 56 +++++++-----
 clang/test/AST/Interp/lifetimes.cpp           |  6 +-
 clang/test/AST/Interp/literals.cpp            | 32 +++----
 clang/test/AST/Interp/records.cpp             | 35 +++----
 clang/test/AST/Interp/shifts.cpp              | 29 +++---
 .../CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp | 10 +-
 .../CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp | 25 +++--
 .../CXX/dcl.dcl/dcl.spec/dcl.constexpr/p5.cpp | 38 ++++----
 .../CXX/dcl.dcl/dcl.spec/dcl.constexpr/p6.cpp |  4 +-
 clang/test/CXX/drs/cwg6xx.cpp                 | 17 +++-
 clang/test/CXX/expr/expr.const/p2-0x.cpp      | 11 +--
 clang/test/Misc/constexpr-source-ranges.cpp   |  9 +-
 .../SemaCXX/builtin-object-size-cxx14.cpp     | 10 +-
 clang/test/SemaCXX/builtin-std-move.cpp       |  7 +-
 .../SemaCXX/constant-expression-cxx11.cpp     | 32 +++----
 .../SemaCXX/constant-expression-cxx14.cpp     | 40 ++++----
 .../SemaCXX/constant-expression-cxx2a.cpp     | 91 +++++--------------
 .../test/SemaCXX/constexpr-frame-describe.cpp | 14 +--
 .../constexpr-function-recovery-crash.cpp     |  9 +-
 clang/test/SemaCXX/constexpr-string.cpp       | 20 ++--
 clang/test/SemaCXX/cxx23-assume.cpp           |  5 +-
 clang/test/SemaCXX/cxx2a-consteval.cpp        |  3 +-
 .../test/SemaCXX/cxx2a-constexpr-dynalloc.cpp |  3 +-
 clang/test/SemaCXX/literal-type.cpp           |  8 +-
 clang/test/SemaCXX/ms-constexpr-invalid.cpp   | 18 ++--
 clang/test/SemaCXX/ms-constexpr.cpp           |  4 +-
 32 files changed, 357 insertions(+), 328 deletions(-)

diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 56f23e1be154a..af3b5c8c39eb7 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -2457,6 +2457,40 @@ static bool CheckConstexprFunctionBody(Sema &SemaRef, const FunctionDecl *Dcl,
     }
   }
 
+  // C++11 [dcl.constexpr]p5:
+  //   if no function argument values exist such that the function invocation
+  //   substitution would produce a constant expression, the program is
+  //   ill-formed; no diagnostic required.
+  // C++11 [dcl.constexpr]p3:
+  //   - every constructor call and implicit conversion used in initializing the
+  //     return value shall be one of those allowed in a constant expression.
+  // C++11 [dcl.constexpr]p4:
+  //   - every constructor involved in initializing non-static data members and
+  //     base class sub-objects shall be a constexpr constructor.
+  //
+  // Note that this rule is distinct from the "requirements for a constexpr
+  // function", so is not checked in CheckValid mode. Because the check for
+  // constexpr potential is expensive, skip the check if the diagnostic is
+  // disabled, the function is declared in a system header, or we're in C++23
+  // or later mode (see https://wg21.link/P2448).
+  bool SkipCheck =
+      SemaRef.getLangOpts().CPlusPlus23 ||
+      SemaRef.getSourceManager().isInSystemHeader(Dcl->getLocation()) ||
+      SemaRef.getDiagnostics().isIgnored(
+          diag::ext_constexpr_function_never_constant_expr, Dcl->getLocation());
+  SmallVector<PartialDiagnosticAt, 8> Diags;
+  if (!SkipCheck && Kind == Sema::CheckConstexprKind::Diagnose &&
+      !Expr::isPotentialConstantExpr(Dcl, Diags)) {
+    SemaRef.Diag(Dcl->getLocation(),
+                 diag::ext_constexpr_function_never_constant_expr)
+        << isa<CXXConstructorDecl>(Dcl) << Dcl->isConsteval()
+        << Dcl->getNameInfo().getSourceRange();
+    for (size_t I = 0, N = Diags.size(); I != N; ++I)
+      SemaRef.Diag(Diags[I].first, Diags[I].second);
+    // Don't return false here: we allow this for compatibility in
+    // system headers.
+  }
+
   return true;
 }
 
diff --git a/clang/test/AST/Interp/arrays.cpp b/clang/test/AST/Interp/arrays.cpp
index 5d6cc2b9d26d9..dd5064d993e66 100644
--- a/clang/test/AST/Interp/arrays.cpp
+++ b/clang/test/AST/Interp/arrays.cpp
@@ -208,7 +208,8 @@ class AU {
 public:
   int a;
   constexpr AU() : a(5 / 0) {} // both-warning {{division by zero is undefined}} \
-                               // both-note {{division by zero}}
+                               // both-note 2{{division by zero}} \
+                               // both-error {{never produces a constant expression}}
 };
 class B {
 public:
@@ -289,25 +290,25 @@ namespace IncDec {
   }
   static_assert(getSecondToLast2() == 3, "");
 
-  constexpr int bad1() {
+  constexpr int bad1() { // both-error {{never produces a constant expression}}
     const int *e =  E + 3;
     e++; // This is fine because it's a one-past-the-end pointer
-    return *e; // both-note {{read of dereferenced one-past-the-end pointer}}
+    return *e; // both-note 2{{read of dereferenced one-past-the-end pointer}}
   }
   static_assert(bad1() == 0, ""); // both-error {{not an integral constant expression}} \
                                   // both-note {{in call to}}
 
-  constexpr int bad2() {
+  constexpr int bad2() { // both-error {{never produces a constant expression}}
     const int *e = E + 4;
-    e++; // both-note {{cannot refer to element 5 of array of 4 elements}}
+    e++; // both-note 2{{cannot refer to element 5 of array of 4 elements}}
     return *e; // This is UB as well
   }
   static_assert(bad2() == 0, ""); // both-error {{not an integral constant expression}} \
                                   // both-note {{in call to}}
 
-  constexpr int bad3() {
+  constexpr int bad3() { // both-error {{never produces a constant expression}}
     const int *e = E;
-    e--; // both-note {{cannot refer to element -1 of array of 4 elements}}
+    e--; // both-note 2{{cannot refer to element -1 of array of 4 elements}}
     return *e; // This is UB as well
   }
    static_assert(bad3() == 0, ""); // both-error {{not an integral constant expression}} \
@@ -384,11 +385,11 @@ namespace NoInitMapLeak {
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wdivision-by-zero"
 #pragma clang diagnostic ignored "-Wc++20-extensions"
-  constexpr int testLeak() {
+  constexpr int testLeak() { // both-error {{never produces a constant expression}}
     int a[2];
     a[0] = 1;
     // interrupts interpretation.
-    (void)(1 / 0); // both-note {{division by zero}}
+    (void)(1 / 0); // both-note 2{{division by zero}}
 
     return 1;
   }
@@ -407,8 +408,8 @@ namespace NoInitMapLeak {
   static_assert(b == 1, ""); // ref-error {{not an integral constant expression}} \
                              // ref-note {{not a constant expression}}
 
-  constexpr int f() {
-    int a[] = {19,2,3/0,4}; // both-note {{division by zero}} \
+  constexpr int f() { // both-error {{never produces a constant expression}}
+    int a[] = {19,2,3/0,4}; // both-note 2{{division by zero}} \
                             // both-warning {{is undefined}}
     return 1;
   }
@@ -586,9 +587,10 @@ const int SZA[] = {};
 void testZeroSizedArrayAccess() { unsigned c = SZA[4]; }
 
 #if __cplusplus >= 202002L
-constexpr int test_multiarray2() {
+constexpr int test_multiarray2() { // both-error {{never produces a constant expression}}
   int multi2[2][1]; // both-note {{declared here}}
-  return multi2[2][0]; // both-warning {{array index 2 is past the end of the array (that has type 'int[2][1]')}}
+  return multi2[2][0]; // both-note {{cannot access array element of pointer past the end of object}} \
+                       // both-warning {{array index 2 is past the end of the array (that has type 'int[2][1]')}}
 }
 
 /// Same but with a dummy pointer.
diff --git a/clang/test/AST/Interp/cxx11.cpp b/clang/test/AST/Interp/cxx11.cpp
index 4d1efbbdc5c8e..f06a5dd173cba 100644
--- a/clang/test/AST/Interp/cxx11.cpp
+++ b/clang/test/AST/Interp/cxx11.cpp
@@ -31,18 +31,18 @@ constexpr const int *p = &s.m + 1;
 
 constexpr const int *np2 = &(*(int(*)[4])nullptr)[0]; // ok
 
-constexpr int preDec(int x) {
-  return --x;
+constexpr int preDec(int x) { // both-error {{never produces a constant expression}}
+  return --x;                 // both-note {{subexpression}}
 }
 
-constexpr int postDec(int x) {
-  return x--;
+constexpr int postDec(int x) { // both-error {{never produces a constant expression}}
+  return x--;                  // both-note {{subexpression}}
 }
 
-constexpr int preInc(int x) {
-  return ++x;
+constexpr int preInc(int x) { // both-error {{never produces a constant expression}}
+  return ++x;                  // both-note {{subexpression}}
 }
 
-constexpr int postInc(int x) {
-  return x++;
+constexpr int postInc(int x) { // both-error {{never produces a constant expression}}
+  return x++;                  // both-note {{subexpression}}
 }
diff --git a/clang/test/AST/Interp/cxx17.cpp b/clang/test/AST/Interp/cxx17.cpp
index 9576217b458d6..5e38d1a588700 100644
--- a/clang/test/AST/Interp/cxx17.cpp
+++ b/clang/test/AST/Interp/cxx17.cpp
@@ -83,8 +83,8 @@ static_assert(b() == 11);
 
 /// The diagnostics between the two interpreters used to be different here.
 struct S { int a; };
-constexpr S getS() {
-  (void)(1/0); // both-note {{division by zero}} \
+constexpr S getS() { // both-error {{constexpr function never produces a constant expression}}
+  (void)(1/0); // both-note 2{{division by zero}} \
                // both-warning {{division by zero}}
   return S{12};
 }
diff --git a/clang/test/AST/Interp/cxx23.cpp b/clang/test/AST/Interp/cxx23.cpp
index bbd70d0588e8e..c91d52c552b12 100644
--- a/clang/test/AST/Interp/cxx23.cpp
+++ b/clang/test/AST/Interp/cxx23.cpp
@@ -4,39 +4,51 @@
 // RUN: %clang_cc1 -std=c++20 -fsyntax-only -fcxx-exceptions -verify=expected20,all,all20 %s -fexperimental-new-constant-interpreter
 // RUN: %clang_cc1 -std=c++23 -fsyntax-only -fcxx-exceptions -verify=expected23,all %s -fexperimental-new-constant-interpreter
 
-constexpr int f(int n) {
-  static const int m = n; // ref20-warning {{is a C++23 extension}} \
+/// FIXME: The new interpreter is missing all the 'control flows through...' diagnostics.
+
+constexpr int f(int n) {  // ref20-error {{constexpr function never produces a constant expression}}
+  static const int m = n; // ref20-note {{control flows through the definition of a static variable}} \
+                          // ref20-warning {{is a C++23 extension}} \
                           // expected20-warning {{is a C++23 extension}}
 
   return m;
 }
-constexpr int g(int n) {
-  thread_local const int m = n; // ref20-warning {{is a C++23 extension}} \
+constexpr int g(int n) {        // ref20-error {{constexpr function never produces a constant expression}}
+  thread_local const int m = n; // ref20-note {{control flows through the definition of a thread_local variable}} \
+                                // ref20-warning {{is a C++23 extension}} \
                                 // expected20-warning {{is a C++23 extension}}
   return m;
 }
 
-constexpr int c_thread_local(int n) {
-  static _Thread_local int m = 0;     // ref20-warning {{is a C++23 extension}} \
-                                      // expected20-warning {{is a C++23 extension}}
-  return m;
+constexpr int c_thread_local(int n) { // ref20-error {{constexpr function never produces a constant expression}} \
+                                      // expected20-error {{constexpr function never produces a constant expression}}
+  static _Thread_local int m = 0;     // ref20-note {{control flows through the definition of a thread_local variable}} \
+                                      // ref20-warning {{is a C++23 extension}} \
+                                      // expected20-warning {{is a C++23 extension}} \
+                                      // expected20-note {{declared here}}
+  return m; // expected20-note {{read of non-const variable}}
 }
 
 
-constexpr int gnu_thread_local(int n) {
-  static __thread int m = 0;            // ref20-warning {{is a C++23 extension}} \
-                                        // expected20-warning {{is a C++23 extension}}
-  return m;
+constexpr int gnu_thread_local(int n) { // ref20-error {{constexpr function never produces a constant expression}} \
+                                        // expected20-error {{constexpr function never produces a constant expression}}
+  static __thread int m = 0;            // ref20-note {{control flows through the definition of a thread_local variable}} \
+                                        // ref20-warning {{is a C++23 extension}} \
+                                        // expected20-warning {{is a C++23 extension}} \
+                                        // expected20-note {{declared here}}
+  return m; // expected20-note {{read of non-const variable}}
 }
 
-constexpr int h(int n) {
-  static const int m = n; // ref20-warning {{is a C++23 extension}} \
+constexpr int h(int n) {  // ref20-error {{constexpr function never produces a constant expression}}
+  static const int m = n; // ref20-note {{control flows through the definition of a static variable}} \
+                          // ref20-warning {{is a C++23 extension}} \
                           // expected20-warning {{is a C++23 extension}}
   return &m - &m;
 }
 
-constexpr int i(int n) {
-  thread_local const int m = n; // ref20-warning {{is a C++23 extension}} \
+constexpr int i(int n) {        // ref20-error {{constexpr function never produces a constant expression}}
+  thread_local const int m = n; // ref20-note {{control flows through the definition of a thread_local variable}} \
+                                // ref20-warning {{is a C++23 extension}} \
                                 // expected20-warning {{is a C++23 extension}}
   return &m - &m;
 }
@@ -92,8 +104,9 @@ namespace StaticOperators {
   static_assert(f2() == 3);
 
   struct S1 {
-    constexpr S1() {
-      throw; // all-note {{not valid in a constant expression}}
+    constexpr S1() { // all20-error {{never produces a constant expression}}
+      throw; // all-note {{not valid in a constant expression}} \
+             // all20-note {{not valid in a constant expression}}
     }
     static constexpr int operator()() { return 3; } // ref20-warning {{C++23 extension}} \
                                                     // expected20-warning {{C++23 extension}}
@@ -147,9 +160,9 @@ namespace VirtualBases {
 }
 
 namespace LabelGoto {
-  constexpr int foo() {
+  constexpr int foo() { // all20-error {{never produces a constant expression}}
     a: // all20-warning {{use of this statement in a constexpr function is a C++23 extension}}
-    goto a; // all20-note {{subexpression not valid in a constant expression}} \
+    goto a; // all20-note 2{{subexpression not valid in a constant expression}} \
             // ref23-note {{subexpression not valid in a constant expression}} \
             // expected23-note {{subexpression not valid in a constant expression}}
 
diff --git a/clang/test/AST/Interp/functions.cpp b/clang/test/AST/Interp/functions.cpp
index 2cbbf6a3e19b5..10c62a43ef33b 100644
--- a/clang/test/AST/Interp/functions.cpp
+++ b/clang/test/AST/Interp/functions.cpp
@@ -241,19 +241,15 @@ struct BodylessMemberFunction {
   }
 };
 
-// FIXME: The new constant expression interpreter diagnoses differently than
-// the reference implementation.
 constexpr int nyd(int m);
-constexpr int doit() { return nyd(10); } // expected-note {{in call to}}
-constexpr int nyd(int m) { return m; } // expected-note {{function parameter 'm' with unknown value cannot be used in a constant expression}} \
-                                          expected-note {{declared here}}
-static_assert(doit() == 10, ""); // expected-error {{static assertion expression is not an integral constant expression}} \
-                                    expected-note {{in call to}}
+constexpr int doit() { return nyd(10); }
+constexpr int nyd(int m) { return m; }
+static_assert(doit() == 10, "");
 
 namespace InvalidCall {
   struct S {
-    constexpr int a() const {
-      return 1 / 0; // both-note {{division by zero}} \
+    constexpr int a() const { // both-error {{never produces a constant expression}}
+      return 1 / 0; // both-note 2{{division by zero}} \
                     // both-warning {{is undefined}}
     }
   };
diff --git a/clang/test/AST/Interp/invalid.cpp b/clang/test/AST/Interp/invalid.cpp
index dceaf4dd497a1..522ad02f71ce0 100644
--- a/clang/test/AST/Interp/invalid.cpp
+++ b/clang/test/AST/Interp/invalid.cpp
@@ -1,56 +1,68 @@
-// RUN: %clang_cc1 -fcxx-exceptions -std=c++20 -fexperimental-new-constant-interpreter -verify=expected,both %s
-// RUN: %clang_cc1 -fcxx-exceptions -std=c++20 -verify=ref,both %s
+// RUN: %clang_cc1 -fcxx-exceptions -std=c++20 -fexperimental-new-constant-interpreter -verify %s
+// RUN: %clang_cc1 -fcxx-exceptions -std=c++20 -verify=ref %s
 
 namespace Throw {
 
   constexpr int ConditionalThrow(bool t) {
     if (t)
-      throw 4; // both-note {{subexpression not valid in a constant expression}}
+      throw 4; // expected-note {{subexpression not valid in a constant expression}} \
+               // ref-note {{subexpression not valid in a constant expression}}
 
     return 0;
   }
 
   static_assert(ConditionalThrow(false) == 0, "");
-  static_assert(ConditionalThrow(true) == 0, ""); // both-error {{not an integral constant expression}} \
-                                                     both-note {{in call to 'ConditionalThrow(true)'}}
+  static_assert(ConditionalThrow(true) == 0, ""); // expected-error {{not an integral constant expression}} \
+                                                  // expected-note {{in call to 'ConditionalThrow(true)'}} \
+                                                  // ref-error {{not an integral constant expression}} \
+                                                  // ref-note {{in call to 'ConditionalThrow(true)'}}
 
-  constexpr int Throw() {
-    throw 5; // both-note {{subexpression not valid in a constant expression}}
+  constexpr int Throw() { // expected-error {{never produces a constant expression}} \
+                          // ref-error {{never produces a constant expression}}
+    throw 5; // expected-note {{subexpression not valid in a constant expression}} \
+             // ref-note {{subexpression not valid in a constant expression}}
     return 0;
   }
-  static_assert(Throw() == 0, ""); // both-error {{not an integral constant expression}} \
-                                      both-note {{in call to}}
 
-  constexpr int NoSubExpr() {
-    throw; // both-note {{subexpression not valid}}
+  constexpr int NoSubExpr() { // ref-error {{never produces a constant expression}} \
+                              // expected-error {{never produces a constant expression}}
+    throw; // ref-note 2{{subexpression not valid}} \
+           // expected-note 2{{subexpression not valid}}
     return 0;
   }
-  static_assert(NoSubExpr() == 0, ""); // both-error {{not an integral constant expression}} \
-                                          both-note {{in call to}}
+  static_assert(NoSubExpr() == 0, ""); // ref-error {{not an integral constant expression}} \
+                                       // ref-note {{in call to}} \
+                                       // expected-error {{not an integral constant expression}} \
+                                       // expected-note {{in call to}}
 }
 
 namespace Asm {
   constexpr int ConditionalAsm(bool t) {
     if (t)
-      asm(""); // both-note {{subexpression not valid in a constant expression}}
+      asm(""); // expected-note {{subexpression not valid in a constant expression}} \
+               // ref-note {{subexpression not valid in a constant expression}}
 
     return 0;
   }
   static_assert(ConditionalAsm(false) == 0, "");
-  static_assert(ConditionalAsm(true) == 0, ""); // both-error {{not an integral constant expression}} \
-                                                // both-note {{in call to 'ConditionalAsm(true)'}}
+  static_assert(ConditionalAsm(true) == 0, ""); // expected-error {{not an integral constant expression}} \
+                                                // expected-note {{in call to 'ConditionalAsm(true)'}} \
+                                                // ref-error {{not an integral constant expression}} \
+                                                // ref-note {{in call to 'ConditionalAsm(true)'}}
 
 
-  constexpr int Asm() {
-    __asm volatile(""); // both-note {{subexpression not valid in a constant expression}}
+  constexpr int Asm() { // expected-error {{never produces a constant expression}} \
+                        // ref-error {{never produces a constant expression}}
+    __asm volatile(""); // expected-note {{subexpression not valid in a constant expression}} \
+                        // ref-note {{subexpression not valid in a constant expression}}
     return 0;
   }
-  static_assert(Asm() == 0, ""); // both-error {{not an integral constant expression}} \
-                                    both-note {{in call to}}
 }
 
 namespace Casts {
-  constexpr int a = reinterpret_cast<int>(12); // both-error {{must be initialized by a constant expression}} \
-                                               // both-note {{reinterpret_cast is not allowed}}
+  constexpr int a = reinterpret_cast<int>(12); // expected-error {{must be initialized by a constant expression}} \
+                                               // expected-note {{reinterpret_cast is not allowed}} \
+                                               // ref-error {{must be initialized by a constant expression}} \
+                                               // ref-note {{reinterpret_cast is not allowed}}
 
 }
diff --git a/clang/test/AST/Interp/lifetimes.cpp b/clang/test/AST/Interp/lifetimes.cpp
index 2bb5a662469e2..c1046e5689207 100644
--- a/clang/test/AST/Interp/lifetimes.cpp
+++ b/clang/test/AST/Interp/lifetimes.cpp
@@ -5,15 +5,15 @@ struct Foo {
   int a;
 };
 
-constexpr int dead1() {
+constexpr int dead1() { // expected-error {{never produces a constant expression}}
 
   Foo *F2 = nullptr;
   {
-    Foo F{12}; // expected-note {{declared here}}
+    Foo F{12}; // expected-note 2{{declared here}}
     F2 = &F;
   } // Ends lifetime of F.
 
-  return F2->a; // expected-note {{read of variable whose lifetime has ended}} \
+  return F2->a; // expected-note 2{{read of variable whose lifetime has ended}} \
                 // ref-note {{read of object outside its lifetime is not allowed in a constant expression}}
 }
 static_assert(dead1() == 1, ""); // expected-error {{not an integral constant expression}} \
diff --git a/clang/test/AST/Interp/literals.cpp b/clang/test/AST/Interp/literals.cpp
index b2cf7fe961f1c..c160be06dd241 100644
--- a/clang/test/AST/Interp/literals.cpp
+++ b/clang/test/AST/Interp/literals.cpp
@@ -257,10 +257,10 @@ namespace SizeOf {
   }
 
 #if __cplusplus >= 201402L
-  constexpr int IgnoredRejected() {
+  constexpr int IgnoredRejected() { // ref-error {{never produces a constant expression}}
     int n = 0;
     sizeof(int[n++]); // both-warning {{expression result unused}} \
-                      // ref-note {{subexpression not valid in a constant expression}}
+                      // ref-note 2{{subexpression not valid in a constant expression}}
     return n;
   }
   /// FIXME: This is rejected because the parameter so sizeof() is not constant.
@@ -272,8 +272,8 @@ namespace SizeOf {
 
 #if __cplusplus >= 202002L
   /// FIXME: The following code should be accepted.
-  consteval int foo(int n) {
-    return sizeof(int[n]); // ref-note 2{{not valid in a constant expression}}
+  consteval int foo(int n) { // ref-error {{consteval function never produces a constant expression}}
+    return sizeof(int[n]); // ref-note 3{{not valid in a constant expression}}
   }
   constinit int var = foo(5); // ref-error {{not a constant expression}} \
                               // ref-note 2{{in call to}} \
@@ -593,17 +593,17 @@ namespace IncDec {
                                                    // ref-note {{in call to 'uninit<int *, false, false>()'}} \
                                                    // expected-note {{in call to 'uninit()'}}
 
-  constexpr int OverFlow() {
+  constexpr int OverFlow() { // both-error {{never produces a constant expression}}
     int a = INT_MAX;
-    ++a; // both-note {{is outside the range}}
+    ++a; // both-note 2{{is outside the range}}
     return -1;
   }
   static_assert(OverFlow() == -1, "");  // both-error {{not an integral constant expression}} \
                                         // both-note {{in call to 'OverFlow()'}}
 
-  constexpr int UnderFlow() {
+  constexpr int UnderFlow() { // both-error {{never produces a constant expression}}
     int a = INT_MIN;
-    --a; // both-note {{is outside the range}}
+    --a; // both-note 2{{is outside the range}}
     return -1;
   }
   static_assert(UnderFlow() == -1, "");  // both-error {{not an integral constant expression}} \
@@ -792,13 +792,11 @@ namespace IncDec {
   }
   static_assert(ptrInc2() == 2, "");
 
-  constexpr int ptrInc3() {
+  constexpr int ptrInc3() { // both-error {{never produces a constant expression}}
     const int *p = arr;
     p += 12; // both-note {{cannot refer to element 12 of array of 3 elements}}
     return *p;
   }
-  static_assert(ptrInc3() == 0, ""); // both-error {{static assertion expression is not an integral constant expression}} \
-                                        both-note {{in call to}}
 
   constexpr int ptrIncDec1() {
     const int *p = arr;
@@ -808,13 +806,11 @@ namespace IncDec {
   }
   static_assert(ptrIncDec1() == 2, "");
 
-  constexpr int ptrDecl() {
+  constexpr int ptrDec1() { // both-error {{never produces a constant expression}}
     const int *p = arr;
     p -= 1;  // both-note {{cannot refer to element -1 of array of 3 elements}}
     return *p;
   }
-  static_assert(ptrDecl() == 0, ""); // both-error {{static assertion expression is not an integral constant expression}} \
-                                        both-note {{in call to}}
 
   /// This used to leave a 0 on the stack instead of the previous
   /// value of a.
@@ -1186,11 +1182,11 @@ namespace incdecbool {
 
 
 #if __cplusplus == 201103L
-  constexpr bool foo() {
+  constexpr bool foo() { // both-error {{never produces a constant expression}}
     bool b = true; // both-warning {{variable declaration in a constexpr function is a C++14 extension}}
     b++; // both-warning {{incrementing expression of type bool is deprecated and incompatible with C++17}} \
          // both-warning {{use of this statement in a constexpr function is a C++14 extension}} \
-         // both-note {{subexpression not valid in a constant expression}}
+         // both-note 2{{subexpression not valid in a constant expression}}
 
     return b;
   }
@@ -1205,13 +1201,11 @@ namespace incdecbool {
 #if __cplusplus >= 201402L
 /// NOTE: The diagnostics of the two interpreters are a little
 /// different here, but they both make sense.
-constexpr int externvar1() {
+constexpr int externvar1() { // both-error {{never produces a constant expression}}
   extern char arr[]; // ref-note {{declared here}}
    return arr[0]; // ref-note {{read of non-constexpr variable 'arr'}} \
                   // expected-note {{array-to-pointer decay of array member without known bound is not supported}}
 }
-static_assert(externvar1() == 0, ""); // both-error {{not an integral constant expression}} \
-                                         both-note {{in call to}}
 #endif
 
 namespace Extern {
diff --git a/clang/test/AST/Interp/records.cpp b/clang/test/AST/Interp/records.cpp
index a811f8705eea9..0a89c81bafd57 100644
--- a/clang/test/AST/Interp/records.cpp
+++ b/clang/test/AST/Interp/records.cpp
@@ -192,9 +192,9 @@ namespace thisPointer {
     constexpr int get12() { return 12; }
   };
 
-  constexpr int foo() {
+  constexpr int foo() { // both-error {{never produces a constant expression}}
     S *s = nullptr;
-    return s->get12(); // both-note {{member call on dereferenced null pointer}}
+    return s->get12(); // both-note 2{{member call on dereferenced null pointer}}
 
   }
   static_assert(foo() == 12, ""); // both-error {{not an integral constant expression}} \
@@ -329,7 +329,8 @@ namespace InitializerTemporaries {
   struct S {
     constexpr S() {}
     constexpr ~S() noexcept(false) { throw 12; } // both-error {{cannot use 'throw'}} \
-                                                 // both-note {{subexpression not valid}}
+                                                 // both-error {{never produces a constant expression}} \
+                                                 // both-note 2{{subexpression not valid}}
   };
 
   constexpr int f() {
@@ -403,14 +404,17 @@ namespace MI {
 
 namespace DeriveFailures {
 #if __cplusplus < 202002L
-  struct Base { // both-note {{declared here}}
+  struct Base { // both-note {{declared here}} \
+                // ref-note {{declared here}}
     int Val;
   };
 
   struct Derived : Base {
     int OtherVal;
 
-    constexpr Derived(int i) : OtherVal(i) {} // both-note {{non-constexpr constructor 'Base' cannot be used in a constant expression}}
+    constexpr Derived(int i) : OtherVal(i) {} // ref-error {{never produces a constant expression}} \
+                                              // both-note {{non-constexpr constructor 'Base' cannot be used in a constant expression}} \
+                                              // ref-note {{non-constexpr constructor 'Base' cannot be used in a constant expression}} 
   };
 
   constexpr Derived D(12); // both-error {{must be initialized by a constant expression}} \
@@ -593,9 +597,9 @@ namespace Destructors {
 
   struct S {
     constexpr S() {}
-    constexpr ~S() {
+    constexpr ~S() { // both-error {{never produces a constant expression}}
       int i = 1 / 0; // both-warning {{division by zero}} \
-                     // both-note {{division by zero}}
+                     // both-note 2{{division by zero}}
     }
   };
   constexpr int testS() {
@@ -1062,20 +1066,20 @@ namespace AccessOnNullptr {
     int a;
   };
 
-  constexpr int a() {
+  constexpr int a() { // both-error {{never produces a constant expression}}
     F *f = nullptr;
 
-    f->a = 0; // both-note {{cannot access field of null pointer}}
+    f->a = 0; // both-note 2{{cannot access field of null pointer}}
     return f->a;
   }
   static_assert(a() == 0, ""); // both-error {{not an integral constant expression}} \
                                // both-note {{in call to 'a()'}}
 
-  constexpr int a2() {
+  constexpr int a2() { // both-error {{never produces a constant expression}}
     F *f = nullptr;
 
 
-    const int *a = &(f->a); // both-note {{cannot access field of null pointer}}
+    const int *a = &(f->a); // both-note 2{{cannot access field of null pointer}}
     return f->a;
   }
   static_assert(a2() == 0, ""); // both-error {{not an integral constant expression}} \
@@ -1242,11 +1246,8 @@ namespace InvalidCtorInitializer {
 extern int f(); // both-note {{here}}
 struct HasNonConstExprMemInit {
   int x = f(); // both-note {{non-constexpr function}}
-  constexpr HasNonConstExprMemInit() {}
+  constexpr HasNonConstExprMemInit() {} // both-error {{never produces a constant expression}}
 };
-HasNonConstExprMemInit NonConstexprUse;
-constexpr HasNonConstExprMemInit ConstexprUse; // both-error {{constexpr variable 'ConstexprUse' must be initialized by a constant expression}} \
-                                                  both-note {{in call to}}
 
 namespace {
   template <class Tp, Tp v>
@@ -1447,8 +1448,8 @@ namespace TemporaryWithInvalidDestructor {
 #if __cplusplus >= 202002L
   struct A {
     bool a = true;
-    constexpr ~A() noexcept(false) {
-      throw; // both-note {{not valid in a constant expression}} \
+    constexpr ~A() noexcept(false) { // both-error {{never produces a constant expression}}
+      throw; // both-note 2{{not valid in a constant expression}} \
              // both-error {{cannot use 'throw' with exceptions disabled}}
     }
   };
diff --git a/clang/test/AST/Interp/shifts.cpp b/clang/test/AST/Interp/shifts.cpp
index af212783093f3..76047d0f752d5 100644
--- a/clang/test/AST/Interp/shifts.cpp
+++ b/clang/test/AST/Interp/shifts.cpp
@@ -1,13 +1,17 @@
-// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -std=c++20 -verify=expected,all %s
-// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -std=c++17 -verify=cxx17,all,all-cxx17 %s
-// RUN: %clang_cc1 -std=c++20 -verify=ref,all %s
-// RUN: %clang_cc1 -std=c++17 -verify=ref-cxx17,all,all-cxx17 %s
+// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -std=c++20 -verify %s
+// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -std=c++17 -verify=cxx17 %s
+// RUN: %clang_cc1 -std=c++20 -verify=ref %s
+// RUN: %clang_cc1 -std=c++17 -verify=ref-cxx17 %s
 
 #define INT_MIN (~__INT_MAX__)
 
 
 namespace shifts {
-  constexpr int test() {
+  constexpr void test() { // ref-error {{constexpr function never produces a constant expression}} \
+                          // ref-cxx17-error {{constexpr function never produces a constant expression}} \
+                          // expected-error {{constexpr function never produces a constant expression}} \
+                          // cxx17-error {{constexpr function never produces a constant expression}} \
+
     char c; // cxx17-warning {{uninitialized variable}} \
             // ref-cxx17-warning {{uninitialized variable}}
 
@@ -103,13 +107,8 @@ namespace shifts {
     lli = INT_MIN << 2; // cxx17-warning {{shifting a negative signed value is undefined}} \
                         // ref-cxx17-warning {{shifting a negative signed value is undefined}}
     lli = 1LL << (sizeof(long long) * __CHAR_BIT__ - 2);
-
-    return 0;
   }
 
-  static_assert(test() == 0, ""); // all-error {{static assertion expression is not an integral constant expression}} \
-                                     all-note {{in call to}}
-
   static_assert(1 << 4 == 16, "");
   constexpr unsigned m = 2 >> 1;
   static_assert(m == 1, "");
@@ -156,23 +155,21 @@ namespace shifts {
   constexpr decltype(L) M2 = (R > 32 && R < 64) ?  L >> R : 0;
 
 
-  constexpr int signedShift() {
+  constexpr int signedShift() { // cxx17-error {{never produces a constant expression}} \
+                                // ref-cxx17-error {{never produces a constant expression}}
     return 1024 << 31; // cxx17-warning {{signed shift result}} \
                        // ref-cxx17-warning {{signed shift result}} \
                        // cxx17-note {{signed left shift discards bits}} \
                        // ref-cxx17-note {{signed left shift discards bits}}
   }
-  static_assert(signedShift() == 0, ""); // all-cxx17-error {{static assertion expression is not an integral constant expression}} \
-                                            all-cxx17-note {{in call to}}
 
-  constexpr int negativeShift() {
+  constexpr int negativeShift() { // cxx17-error {{never produces a constant expression}} \
+                                  // ref-cxx17-error {{never produces a constant expression}}
     return -1 << 2; // cxx17-warning {{shifting a negative signed value is undefined}} \
                     // ref-cxx17-warning {{shifting a negative signed value is undefined}} \
                     // cxx17-note {{left shift of negative value -1}} \
                     // ref-cxx17-note {{left shift of negative value -1}}
   }
-  static_assert(negativeShift() == -4, ""); // all-cxx17-error {{static assertion expression is not an integral constant expression}} \
-                                               all-cxx17-note {{in call to}}
 
   constexpr int foo(int a) {
     return -a << 2; // cxx17-note {{left shift of negative value -10}} \
diff --git a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp
index 08270ccb9dcb4..4416c82522649 100644
--- a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp
+++ b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp
@@ -229,9 +229,9 @@ namespace DR1364 {
     return k; // ok, even though lvalue-to-rvalue conversion of a function
               // parameter is not allowed in a constant expression.
   }
-  int kGlobal;
-  constexpr int f() {
-    return kGlobal;
+  int kGlobal; // beforecxx23-note {{here}}
+  constexpr int f() { // beforecxx23-error {{constexpr function never produces a constant expression}}
+    return kGlobal;   // beforecxx23-note {{read of non-const}}
   }
 }
 
@@ -272,8 +272,8 @@ namespace std_example {
     int a; // beforecxx20-warning {{uninitialized}}
     return a;
   }
-  constexpr int prev(int x) {
-    return --x;
+  constexpr int prev(int x) { // beforecxx14-error {{never produces a constant expression}}
+    return --x;               // beforecxx14-note {{subexpression}}
   }
 
   constexpr int g(int x, int n) {
diff --git a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp
index ce97953600095..92698ec1c7387 100644
--- a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp
+++ b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp
@@ -16,7 +16,7 @@ struct NonLiteral { // expected-note 2{{no constexpr constructors}}
 };
 struct Literal {
   constexpr Literal() {}
-  explicit Literal(int);
+  explicit Literal(int); // expected-note 2 {{here}}
   operator int() const { return 0; }
 };
 
@@ -240,15 +240,18 @@ template<typename T> struct enable_shared_from_this {
 };
 constexpr int f(enable_shared_from_this<int>);
 
+// - every constructor involved in initializing non-static data members and base
+//   class sub-objects shall be a constexpr constructor.
+// This will no longer be the case once we support P2448R2
 struct ConstexprBaseMemberCtors : Literal {
   Literal l;
 
   constexpr ConstexprBaseMemberCtors() : Literal(), l() {} // ok
-  constexpr ConstexprBaseMemberCtors(char) :
-    Literal(0),
+  constexpr ConstexprBaseMemberCtors(char) : // expected-error {{constexpr constructor never produces a constant expression}}
+    Literal(0), // expected-note {{non-constexpr constructor}}
     l() {}
-  constexpr ConstexprBaseMemberCtors(double) : Literal(),
-    l(0)
+  constexpr ConstexprBaseMemberCtors(double) : Literal(), // expected-error {{constexpr constructor never produces a constant expression}}
+    l(0) // expected-note {{non-constexpr constructor}}
   {}
 };
 
@@ -292,10 +295,18 @@ struct XU4 {
 static_assert(XU2().a == 1, "");
 static_assert(XU4().a == 1, "");
 
-int kGlobal;
+//  - every implicit conversion used in converting a constructor argument to the
+//    corresponding parameter type and converting a full-expression to the
+//    corresponding member type shall be one of those allowed in a constant
+//    expression.
+//
+// We implement the proposed resolution of DR1364 and ignore this bullet.
+// However, we implement the intent of this wording as part of the p5 check that
+// the function must be able to produce a constant expression.
+int kGlobal; // expected-note {{here}}
 struct Z {
   constexpr Z(int a) : n(a) {}
-  constexpr Z() : n(kGlobal) {}
+  constexpr Z() : n(kGlobal) {} // expected-error {{constexpr constructor never produces a constant expression}} expected-note {{read of non-const}}
   int n;
 };
 
diff --git a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p5.cpp b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p5.cpp
index 728af894958de..18b2c6b1d6d15 100644
--- a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p5.cpp
+++ b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p5.cpp
@@ -30,54 +30,54 @@ static_assert(g4() == 5, "");
 
 constexpr int f(bool b)
   { return b ? throw 0 : 0; } // ok
-constexpr int f() { return throw 0, 0; }
+constexpr int f() { return throw 0, 0; } // expected-error {{constexpr function never produces a constant expression}} expected-note {{subexpression}}
 
 struct B {
   constexpr B(int x) : i(0) { }
   int i;
 };
 
-int global;
+int global; // expected-note {{declared here}}
 
 struct D : B {
-  constexpr D() : B(global) { }
+  constexpr D() : B(global) { } // expected-error {{constexpr constructor never produces a constant expression}} expected-note {{read of non-const}}
 };
 
 }
 
 namespace PotentialConstant {
 
-constexpr int Comma(int n) { return
+constexpr int Comma(int n) { return // expected-error {{constexpr function never produces a constant expression}}
   (void)(n * 2),
-  throw 0,
+  throw 0, // expected-note {{subexpression}}
   0;
 }
 
-int ng;
-constexpr int BinaryOp1(int n) { return n + ng; }
-constexpr int BinaryOp2(int n) { return ng + n; }
+int ng; // expected-note 6{{here}}
+constexpr int BinaryOp1(int n) { return n + ng; } // expected-error {{never produces}} expected-note {{read}}
+constexpr int BinaryOp2(int n) { return ng + n; } // expected-error {{never produces}} expected-note {{read}}
 
-double dg;
-constexpr double BinaryOp1(double d) { return d + dg; }
-constexpr double BinaryOp2(double d) { return dg + d; }
+double dg; // expected-note 2{{here}}
+constexpr double BinaryOp1(double d) { return d + dg; } // expected-error {{never produces}} expected-note {{read}}
+constexpr double BinaryOp2(double d) { return dg + d; } // expected-error {{never produces}} expected-note {{read}}
 
 constexpr int Add(int a, int b, int c) { return a + b + c; }
-constexpr int FunctionArgs(int a) { return Add(a, ng, a); }
+constexpr int FunctionArgs(int a) { return Add(a, ng, a); } // expected-error {{never produces}} expected-note {{read}}
 
 struct S { int a; int b; int c[2]; };
-constexpr S InitList(int a) { return { a, ng }; };
-constexpr S InitList1a(int a) { return S{ a, ng }; };
-constexpr S InitList2(int a) { return { a, a, { ng } }; };
+constexpr S InitList(int a) { return { a, ng }; }; // expected-error {{never produces}} expected-note {{read}}
+constexpr S InitList1a(int a) { return S{ a, ng }; }; // expected-error {{never produces}} expected-note {{read}}
+constexpr S InitList2(int a) { return { a, a, { ng } }; }; // expected-error {{never produces}} expected-note {{read}}
 constexpr S InitList3(int a) { return a ? S{ a, a } : S{ a, ng }; }; // ok
 
 constexpr int LogicalAnd1(int n) { return n && (throw, 0); } // ok
-constexpr int LogicalAnd2(int n) { return 1 && (throw, 0); }
+constexpr int LogicalAnd2(int n) { return 1 && (throw, 0); } // expected-error {{never produces}} expected-note {{subexpression}}
 
 constexpr int LogicalOr1(int n) { return n || (throw, 0); } // ok
-constexpr int LogicalOr2(int n) { return 0 || (throw, 0); }
+constexpr int LogicalOr2(int n) { return 0 || (throw, 0); } // expected-error {{never produces}} expected-note {{subexpression}}
 
 constexpr int Conditional1(bool b, int n) { return b ? n : ng; } // ok
-constexpr int Conditional2(bool b, int n) { return b ? n * ng : n + ng; }
+constexpr int Conditional2(bool b, int n) { return b ? n * ng : n + ng; } // expected-error {{never produces}} expected-note {{both arms of conditional operator are unable to produce a constant expression}}
 
 // __builtin_constant_p ? : is magical, and is always a potential constant.
 constexpr bool BcpCall(int n) {
@@ -136,5 +136,5 @@ namespace PR14550 {
 #endif
 
 #if __cplusplus >= 201402L
-constexpr void f() { throw; }
+constexpr void f() { throw; } // expected-error {{never produces}} expected-note {{subexpression}}
 #endif
diff --git a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p6.cpp b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p6.cpp
index a4a7eb131d246..00ef78426289f 100644
--- a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p6.cpp
+++ b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p6.cpp
@@ -42,8 +42,8 @@ template<typename ...P> struct ConstexprCtor {
 };
 constexpr ConstexprCtor<> f1() { return {}; } // ok
 constexpr ConstexprCtor<int> f2() { return 0; } // ok
-constexpr ConstexprCtor<NonLiteral> f3() { return { 0 }; }
-constexpr ConstexprCtor<int, NonLiteral> f4() { return { 0, 0 }; }
+constexpr ConstexprCtor<NonLiteral> f3() { return { 0 }; } // expected-error {{never produces a constant expression}} expected-note {{non-literal type 'NonLiteral}}
+constexpr ConstexprCtor<int, NonLiteral> f4() { return { 0, 0 }; } // expected-error {{never produces a constant expression}} expected-note {{non-literal type 'NonLiteral}}
 
 struct VirtBase : virtual S {}; // expected-note {{here}}
 
diff --git a/clang/test/CXX/drs/cwg6xx.cpp b/clang/test/CXX/drs/cwg6xx.cpp
index 8af58ccfecda9..069102d9c5975 100644
--- a/clang/test/CXX/drs/cwg6xx.cpp
+++ b/clang/test/CXX/drs/cwg6xx.cpp
@@ -402,7 +402,7 @@ namespace cwg638 { // cwg638: no
 
   class X {
     typedef int type;
-    template<class T> friend struct A<T>::B;
+    template<class T> friend struct A<T>::B; 
     // expected-warning at -1 {{dependent nested name specifier 'A<T>::' for friend class declaration is not supported; turning off access control for 'X'}}
     template<class T> friend void A<T>::f();
     // expected-warning at -1 {{dependent nested name specifier 'A<T>::' for friend class declaration is not supported; turning off access control for 'X'}}
@@ -599,16 +599,25 @@ namespace cwg647 { // cwg647: 3.1
     int n;
     D d;
 
+    // FIXME: We should diagnose this, as the conversion function is not
+    // constexpr. However, that part of this issue is supreseded by cwg1364 and
+    // others; no diagnostic is required for this any more.
     constexpr E()
         : n(D(0)),
           d(0) {}
 
     constexpr E(int)
+    // cxx11-20-error at -1 {{constexpr constructor never produces a constant expression}}
+    //   cxx11-20-note@#cwg647-int-d {{non-constexpr constructor 'D' cannot be used in a constant expression}}
+    //   cxx11-20-note@#cwg647-D-float-ctor {{declared here}}
         : n(0),
-          d(0.0f) {}
+          d(0.0f) {} // #cwg647-int-d
     constexpr E(float f)
+    // cxx11-20-error at -1 {{never produces a constant expression}}
+    //   cxx11-20-note@#cwg647-float-d {{non-constexpr constructor}}
+    //   cxx11-20-note@#cwg647-D-float-ctor {{declared here}}
         : n(get()),
-          d(D(0) + f) {}
+          d(D(0) + f) {} // #cwg647-float-d
   };
 }
 #endif
@@ -1064,7 +1073,7 @@ namespace cwg677 { // cwg677: no
   struct A {
     void *operator new(std::size_t);
     void operator delete(void*) = delete; // #cwg677-A-delete
-    // cxx98-error at -1 {{deleted function definitions are a C++11 extension}}
+    // cxx98-error at -1 {{deleted function definitions are a C++11 extension}} 
   };
   struct B {
     void *operator new(std::size_t);
diff --git a/clang/test/CXX/expr/expr.const/p2-0x.cpp b/clang/test/CXX/expr/expr.const/p2-0x.cpp
index 90fe189926953..e3cd057baba75 100644
--- a/clang/test/CXX/expr/expr.const/p2-0x.cpp
+++ b/clang/test/CXX/expr/expr.const/p2-0x.cpp
@@ -302,11 +302,10 @@ constexpr float negpi = -pi; // expect no error on unary operator
 
 #if __cplusplus >= 201703L
 namespace CompoundAssignment {
-constexpr int rem() {
+constexpr int rem() { // expected-error {{constexpr function never produces a constant expression}}
     int x = ~__INT_MAX__;
     return x%=-1; // cxx20-note {{value 2147483648 is outside the range of representable values of type 'int'}}
 }
-static_assert(rem() == 0); // cxx20-error {{static assertion expression is not an integral constant expression}} cxx20-note {{in call to}}
 }
 #endif
 }
@@ -448,9 +447,9 @@ namespace PseudoDtor {
     int n : (k.~I(), 1); // expected-error {{constant expression}} expected-note {{visible outside that expression}}
   };
 
-  constexpr int f(int a = 1) { // expected-note {{destroying object 'a' whose lifetime has already ended}}
+  constexpr int f(int a = 1) { // cxx11-error {{constant expression}} expected-note {{destroying object 'a' whose lifetime has already ended}}
     return (
-        a.~I(),
+        a.~I(), // cxx11-note {{pseudo-destructor}}
         0);
   }
   static_assert(f() == 0, ""); // expected-error {{constant expression}}
@@ -458,9 +457,9 @@ namespace PseudoDtor {
   // This is OK in C++20: the union has no active member after the
   // pseudo-destructor call, so the union destructor has no effect.
   union U { int x; };
-  constexpr int g(U u = {1}) {
+  constexpr int g(U u = {1}) { // cxx11-error {{constant expression}}
     return (
-        u.x.~I(), // cxx11-note {{pseudo-destructor}}
+        u.x.~I(), // cxx11-note 2{{pseudo-destructor}}
         0);
   }
   static_assert(g() == 0, ""); // cxx11-error {{constant expression}} cxx11-note {{in call}}
diff --git a/clang/test/Misc/constexpr-source-ranges.cpp b/clang/test/Misc/constexpr-source-ranges.cpp
index d9e23b9f3d5ae..fde05b5c75aa4 100644
--- a/clang/test/Misc/constexpr-source-ranges.cpp
+++ b/clang/test/Misc/constexpr-source-ranges.cpp
@@ -6,7 +6,7 @@ constexpr int f() {
   return 0;
 }
 
-
+// CHECK: constexpr-source-ranges.cpp:5:3:{5:3-5:10}
 
 
 constexpr int I = 12;
@@ -24,6 +24,7 @@ static_assert(divByZero() == 0, "");
 /// We see this twice. Once from sema and once when
 /// evaluating the static_assert above.
 // CHECK: constexpr-source-ranges.cpp:23:15:{23:15-23:31}
+// CHECK: constexpr-source-ranges.cpp:21:12:{21:14-21:20}
 
 constexpr int div(bool a, bool b) {
   return 1 / (int)b;
@@ -32,7 +33,7 @@ constexpr int ints(int a, int b, int c, int d) {
   return 1;
 }
 static_assert(ints(1, div(true, false), 2, div(false, true)) == 1, "");
-// CHECK: constexpr-source-ranges.cpp:34:23:{34:23-34:39}
+// CHECK: constexpr-source-ranges.cpp:35:23:{35:23-35:39}
 
 namespace overflow {
 // CHECK:      :{[[@LINE+1]]:9-[[@LINE+1]]:29}:
@@ -48,3 +49,7 @@ constexpr int uninit() {
   return aaa;
 }
 static_assert(uninit() == 0, "");
+
+
+constexpr void neverValid() { throw; }
+// CHECK: :{[[@LINE-1]]:16-[[@LINE-1]]:26}:
diff --git a/clang/test/SemaCXX/builtin-object-size-cxx14.cpp b/clang/test/SemaCXX/builtin-object-size-cxx14.cpp
index 8ba57a3a3bcea..b7c6f6be01f54 100644
--- a/clang/test/SemaCXX/builtin-object-size-cxx14.cpp
+++ b/clang/test/SemaCXX/builtin-object-size-cxx14.cpp
@@ -115,11 +115,7 @@ namespace InvalidBase {
 }
 
 // PR44268
-constexpr int bos_new() {
-  auto *p = new int; // cxx14-note {{until C++20}}
-  int ret = __builtin_object_size(p, 0);
-  delete p;
-  return ret;
+constexpr int bos_new() { // cxx14-error {{constant expression}}
+  void *p = new int; // cxx14-note {{until C++20}}
+  return __builtin_object_size(p, 0);
 }
-static_assert(bos_new() == sizeof(int), ""); // cxx14-error {{static assertion expression is not an integral constant expression}} cxx14-note {{in call to}}
-
diff --git a/clang/test/SemaCXX/builtin-std-move.cpp b/clang/test/SemaCXX/builtin-std-move.cpp
index b320b16618d6c..a2ae21986308a 100644
--- a/clang/test/SemaCXX/builtin-std-move.cpp
+++ b/clang/test/SemaCXX/builtin-std-move.cpp
@@ -100,8 +100,8 @@ namespace std {
 // Note: this doesn't have a 'moveable' member. Instantiation of the above
 // functions will fail if it's attempted.
 struct A {};
-constexpr bool f(A a) {
-  A &&move = std::move(a);
+constexpr bool f(A a) { // #f
+  A &&move = std::move(a); // #call
   A &&move_if_noexcept = std::move_if_noexcept(a);
   A &&forward1 = std::forward<A>(a);
   A &forward2 = std::forward<A&>(a);
@@ -116,6 +116,9 @@ constexpr bool f(A a) {
 
 #ifndef NO_CONSTEXPR
 static_assert(f({}), "should be constexpr");
+#elif !defined(NEW_INTERP)
+// expected-error@#f {{never produces a constant expression}}
+// expected-note@#call {{}}
 #endif
 
 A &forward_rval_as_lval() {
diff --git a/clang/test/SemaCXX/constant-expression-cxx11.cpp b/clang/test/SemaCXX/constant-expression-cxx11.cpp
index 9e8c48d14cc87..efb391ba0922d 100644
--- a/clang/test/SemaCXX/constant-expression-cxx11.cpp
+++ b/clang/test/SemaCXX/constant-expression-cxx11.cpp
@@ -1273,10 +1273,9 @@ namespace PR11595 {
   struct B { B(); A& x; };
   static_assert(B().x == 3, "");  // expected-error {{constant expression}} expected-note {{non-literal type 'B' cannot be used in a constant expression}}
 
-  constexpr bool f(int k) {
-    return B().x == k; // expected-note {{non-literal type 'B' cannot be used in a constant expression}}
+  constexpr bool f(int k) { // cxx11_20-error {{constexpr function never produces a constant expression}}
+    return B().x == k; // cxx11_20-note {{non-literal type 'B' cannot be used in a constant expression}}
   }
-  static_assert(f(3), ""); // expected-error {{static assertion expression is not an integral constant expression}} expected-note {{in call to}}
 }
 
 namespace ExprWithCleanups {
@@ -1327,9 +1326,8 @@ namespace ExternConstexpr {
   constexpr int g() { return q; } // expected-note {{outside its lifetime}}
   constexpr int q = g(); // expected-error {{constant expression}} expected-note {{in call}}
 
-  extern int r; // expected-note {{here}}
-  constexpr int h() { return r; } // expected-note {{read of non-const}}
-  static_assert(h() == 0, ""); // expected-error {{static assertion expression is not an integral constant expression}} expected-note {{in call to}}
+  extern int r; // cxx11_20-note {{here}}
+  constexpr int h() { return r; } // cxx11_20-error {{never produces a constant}} cxx11_20-note {{read of non-const}}
 
   struct S { int n; };
   extern const S s;
@@ -1908,13 +1906,12 @@ namespace StmtExpr {
     });
   }
   static_assert(g(123) == 15129, "");
-  constexpr int h() {
+  constexpr int h() { // cxx11_20-error {{never produces a constant}}
     return ({ // expected-warning {{extension}}
-      return 0; // expected-note {{not supported}}
+      return 0; // cxx11_20-note {{not supported}}
       1;
     });
   }
-  static_assert(h() == 0, ""); // expected-error {{static assertion expression is not an integral constant expression}} expected-note {{in call to}}
 }
 
 namespace VirtualFromBase {
@@ -2096,10 +2093,9 @@ namespace ZeroSizeTypes {
   // expected-note at -2 {{subtraction of pointers to type 'int[0]' of zero size}}
 
   int arr[5][0];
-  constexpr int f() {
-    return &arr[3] - &arr[0]; // expected-note {{subtraction of pointers to type 'int[0]' of zero size}}
+  constexpr int f() { // cxx11_20-error {{never produces a constant expression}}
+    return &arr[3] - &arr[0]; // cxx11_20-note {{subtraction of pointers to type 'int[0]' of zero size}}
   }
-  static_assert(f() == 0, ""); // expected-error {{static assertion expression is not an integral constant expression}} expected-note {{in call to}}
 }
 
 namespace BadDefaultInit {
@@ -2122,12 +2118,11 @@ namespace NeverConstantTwoWays {
   // If we see something non-constant but foldable followed by something
   // non-constant and not foldable, we want the first diagnostic, not the
   // second.
-  constexpr int f(int n) {
-    return (int *)(long)&n == &n ?
-        1 / 0 : // expected-note {{division by zero}} expected-warning {{division by zero is undefined}}
+  constexpr int f(int n) { // cxx11_20-error {{never produces a constant expression}}
+    return (int *)(long)&n == &n ? // cxx11_20-note {{reinterpret_cast}}
+        1 / 0 : // expected-warning {{division by zero}}
         0;
   }
-  static_assert(f(0) == 0, ""); // expected-error {{static assertion expression is not an integral constant expression}} expected-note {{in call to}}
 
   constexpr int n = // expected-error {{must be initialized by a constant expression}}
       (int *)(long)&n == &n ? // expected-note {{reinterpret_cast}}
@@ -2323,9 +2318,10 @@ namespace PR28366 {
 namespace ns1 {
 
 void f(char c) { //expected-note{{declared here}}
+  //cxx11_20-note at -1{{declared here}}
   struct X {
-    static constexpr char f() {
-      return c; //expected-error{{reference to local}}
+    static constexpr char f() { // cxx11_20-error {{never produces a constant expression}}
+      return c; //expected-error{{reference to local}} cxx11_20-note{{function parameter}}
     }
   };
   int I = X::f();
diff --git a/clang/test/SemaCXX/constant-expression-cxx14.cpp b/clang/test/SemaCXX/constant-expression-cxx14.cpp
index 8279afcc8ce69..80a7a2dd31531 100644
--- a/clang/test/SemaCXX/constant-expression-cxx14.cpp
+++ b/clang/test/SemaCXX/constant-expression-cxx14.cpp
@@ -44,18 +44,16 @@ constexpr int g(int k) {
   return 3 * k3 + 5 * k2 + n * k - 20;
 }
 static_assert(g(2) == 42, "");
-constexpr int h(int n) {
-  static const int m = n; // expected-note {{control flows through the definition of a static variable}} \
+constexpr int h(int n) {  // cxx14_20-error {{constexpr function never produces a constant expression}}
+  static const int m = n; // cxx14_20-note {{control flows through the definition of a static variable}} \
                           // cxx14_20-warning {{definition of a static variable in a constexpr function is a C++23 extension}}
   return m;
 }
-static_assert(h(0) == 0, ""); // expected-error {{static assertion expression is not an integral constant expression}} expected-note {{in call to}}
-constexpr int i(int n) {
-  thread_local const int m = n; // expected-note {{control flows through the definition of a thread_local variable}} \
+constexpr int i(int n) {        // cxx14_20-error {{constexpr function never produces a constant expression}}
+  thread_local const int m = n; // cxx14_20-note {{control flows through the definition of a thread_local variable}} \
                                 // cxx14_20-warning {{definition of a thread_local variable in a constexpr function is a C++23 extension}}
   return m;
 }
-static_assert(i(0) == 0, ""); // expected-error {{static assertion expression is not an integral constant expression}} expected-note {{in call to}}
 
 // if-statements can be used in constexpr functions.
 constexpr int j(int k) {
@@ -70,6 +68,7 @@ constexpr int j(int k) {
     }
   }
 } // expected-note 2{{control reached end of constexpr function}}
+  // cxx23-warning at -1 {{does not return a value in all control paths}}
 static_assert(j(0) == -3, "");
 static_assert(j(1) == 5, "");
 static_assert(j(2), ""); // expected-error {{constant expression}} expected-note {{in call to 'j(2)'}}
@@ -106,12 +105,11 @@ static_assert(l(false) == 5, "");
 static_assert(l(true), ""); // expected-error {{constant expression}} expected-note {{in call to 'l(true)'}}
 
 // Potential constant expression checking is still applied where possible.
-constexpr int htonl(int x) {
+constexpr int htonl(int x) { // cxx14_20-error {{never produces a constant expression}}
   typedef unsigned char uchar;
   uchar arr[4] = { uchar(x >> 24), uchar(x >> 16), uchar(x >> 8), uchar(x) };
-  return *reinterpret_cast<int*>(arr); // expected-note {{reinterpret_cast is not allowed in a constant expression}}
+  return *reinterpret_cast<int*>(arr); // cxx14_20-note {{reinterpret_cast is not allowed in a constant expression}}
 }
-static_assert(htonl(0) == 0, ""); // expected-error {{static assertion expression is not an integral constant expression}} expected-note {{in call to}}
 
 constexpr int maybe_htonl(bool isBigEndian, int x) {
   if (isBigEndian)
@@ -186,7 +184,7 @@ namespace string_assign {
   static_assert(!test1(100), "");
   static_assert(!test1(101), ""); // expected-error {{constant expression}} expected-note {{in call to 'test1(101)'}}
 
-  constexpr void f() {
+  constexpr void f() { // cxx14_20-error{{constexpr function never produces a constant expression}} cxx14_20-note at +2{{assignment to dereferenced one-past-the-end pointer is not allowed in a constant expression}}
     char foo[10] = { "z" }; // expected-note {{here}}
     foo[10] = 'x'; // expected-warning {{past the end}}
   }
@@ -210,17 +208,15 @@ namespace array_resize {
 namespace potential_const_expr {
   constexpr void set(int &n) { n = 1; }
   constexpr int div_zero_1() { int z = 0; set(z); return 100 / z; } // no error
-  constexpr int div_zero_2() {
+  constexpr int div_zero_2() { // cxx14_20-error {{never produces a constant expression}}
     int z = 0;
-    return 100 / (set(z), 0); // expected-note {{division by zero}}
+    return 100 / (set(z), 0); // cxx14_20-note {{division by zero}}
   }
-  static_assert(div_zero_2() == 0, ""); // expected-error {{static assertion expression is not an integral constant expression}} expected-note {{in call to}}
-  int n; // expected-note {{declared here}}
-  constexpr int ref() {
+  int n; // cxx14_20-note {{declared here}}
+  constexpr int ref() { // cxx14_20-error {{never produces a constant expression}}
     int &r = n;
-    return r; // expected-note {{read of non-const variable 'n'}}
+    return r; // cxx14_20-note {{read of non-const variable 'n'}}
   }
-  static_assert(ref() == 0, ""); // expected-error {{static assertion expression is not an integral constant expression}} expected-note {{in call to}}
 }
 
 namespace subobject {
@@ -851,11 +847,10 @@ namespace StmtExpr {
   static_assert(g() == 0, ""); // expected-error {{constant expression}} expected-note {{in call}}
 
   // FIXME: We should handle the void statement expression case.
-  constexpr int h() {
-    ({ if (true) {} }); // expected-note {{not supported}}
+  constexpr int h() { // cxx14_20-error {{never produces a constant}}
+    ({ if (true) {} }); // cxx14_20-note {{not supported}}
     return 0;
   }
-  static_assert(h() == 0, ""); // expected-error {{static assertion expression is not an integral constant expression}} expected-note {{in call to}}
 }
 
 namespace VirtualFromBase {
@@ -1049,9 +1044,10 @@ static_assert(sum(Cs) == 'a' + 'b', ""); // expected-error{{not an integral cons
 constexpr int S = sum(Cs); // expected-error{{must be initialized by a constant expression}} expected-note{{in call}}
 }
 
-constexpr void PR28739(int n) {
+constexpr void PR28739(int n) { // cxx14_20-error {{never produces a constant}}
   int *p = &n;                  // expected-note {{array 'p' declared here}}
-  p += (__int128)(unsigned long)-1; // expected-warning {{the pointer incremented by 18446744073709551615 refers past the last possible element for an array in 64-bit address space containing 32-bit (4-byte) elements (max possible 4611686018427387904 elements)}}
+  p += (__int128)(unsigned long)-1; // cxx14_20-note {{cannot refer to element 18446744073709551615 of non-array object in a constant expression}}
+  // expected-warning at -1 {{the pointer incremented by 18446744073709551615 refers past the last possible element for an array in 64-bit address space containing 32-bit (4-byte) elements (max possible 4611686018427387904 elements)}}
 }
 
 constexpr void Void(int n) {
diff --git a/clang/test/SemaCXX/constant-expression-cxx2a.cpp b/clang/test/SemaCXX/constant-expression-cxx2a.cpp
index cc9b4c3ce699c..e4d97dcb73562 100644
--- a/clang/test/SemaCXX/constant-expression-cxx2a.cpp
+++ b/clang/test/SemaCXX/constant-expression-cxx2a.cpp
@@ -352,29 +352,26 @@ namespace Union {
     A a;
     int b;
   };
-  constexpr int read_wrong_member() {
+  constexpr int read_wrong_member() { // expected-error {{never produces a constant}}
     B b = {.b = 1};
     return b.a.x; // expected-note {{read of member 'a' of union with active member 'b'}}
   }
-  static_assert(read_wrong_member()); // expected-error {{static assertion expression is not an integral constant expression}} expected-note {{in call to}}
   constexpr int change_member() {
     B b = {.b = 1};
     b.a.x = 1;
     return b.a.x;
   }
   static_assert(change_member() == 1);
-  constexpr int change_member_then_read_wrong_member() {
+  constexpr int change_member_then_read_wrong_member() { // expected-error {{never produces a constant}}
     B b = {.b = 1};
     b.a.x = 1;
     return b.b; // expected-note {{read of member 'b' of union with active member 'a'}}
   }
-  static_assert(change_member_then_read_wrong_member()); // expected-error {{static assertion expression is not an integral constant expression}} expected-note {{in call to}}
-  constexpr int read_wrong_member_indirect() {
+  constexpr int read_wrong_member_indirect() { // expected-error {{never produces a constant}}
     B b = {.b = 1};
     int *p = &b.a.y;
     return *p; // expected-note {{read of member 'a' of union with active member 'b'}}
   }
-  static_assert(read_wrong_member_indirect()); // expected-error {{static assertion expression is not an integral constant expression}} expected-note {{in call to}}
   constexpr int read_uninitialized() {
     B b = {.b = 1};
     int *p = &b.a.y;
@@ -382,13 +379,11 @@ namespace Union {
     return *p; // expected-note {{read of uninitialized object}}
   }
   static_assert(read_uninitialized() == 0); // expected-error {{constant}} expected-note {{in call}}
-  constexpr int write_wrong_member_indirect() {
+  constexpr void write_wrong_member_indirect() { // expected-error {{never produces a constant}}
     B b = {.b = 1};
     int *p = &b.a.y;
     *p = 1; // expected-note {{assignment to member 'a' of union with active member 'b'}}
-    return 0;
   }
-  static_assert(write_wrong_member_indirect()); // expected-error {{static assertion expression is not an integral constant expression}} expected-note {{in call to}}
   constexpr int write_uninitialized() {
     B b = {.b = 1};
     int *p = &b.a.y;
@@ -480,13 +475,12 @@ namespace Union {
     return r.a.r.b;
   }
   static_assert(ref_member_test_1() == 2);
-  constexpr int ref_member_test_2() {
+  constexpr int ref_member_test_2() { // expected-error {{never produces a constant}}
     ref_member_3 r = {.a = {.r = {.a = 1}}};
     // FIXME: This note isn't great. The 'read' here is reading the referent of the reference.
     r.b.r.b = 2; // expected-note {{read of member 'b' of union with active member 'a'}}
     return r.b.r.b;
   }
-  static_assert(ref_member_test_2()); // expected-error {{static assertion expression is not an integral constant expression}} expected-note {{in call to}}
 
   namespace PR43762 {
     struct A { int x = 1; constexpr int f() { return 1; } };
@@ -772,7 +766,7 @@ namespace dynamic_alloc {
   }
   static_assert(f(123) == 123 * 122 / 2);
 
-  constexpr bool nvdtor() {
+  constexpr bool nvdtor() { // expected-error {{never produces a constant expression}}
     struct S {
       constexpr ~S() {}
     };
@@ -780,7 +774,6 @@ namespace dynamic_alloc {
     delete (S*)new T; // expected-note {{delete of object with dynamic type 'T' through pointer to base class type 'S' with non-virtual destructor}}
     return true;
   }
-  static_assert(nvdtor()); // expected-error {{static assertion expression is not an integral constant expression}} expected-note {{in call to}}
 
   constexpr int vdtor_1() {
     int a;
@@ -844,12 +837,10 @@ namespace dynamic_alloc {
   static_assert(vdtor_3(2) == 3); // expected-error {{}} expected-note {{in call}}
   static_assert(vdtor_3(3) == 3);
 
-  constexpr int delete_mismatch() {
+  constexpr void delete_mismatch() { // expected-error {{never produces a constant expression}}
     delete[] // expected-note {{array delete used to delete pointer to non-array object of type 'int'}}
       new int; // expected-note {{allocation}}
-    return 0;
   }
-  static_assert(delete_mismatch()); // expected-error {{static assertion expression is not an integral constant expression}} expected-note {{in call to}}
 
   template<typename T>
   constexpr T dynarray(int elems, int i) {
@@ -920,13 +911,11 @@ namespace dynamic_alloc {
   }
   static_assert(evaluate_nothrow_arg());
 
-  constexpr int double_delete() {
+  constexpr void double_delete() { // expected-error {{never produces a constant expression}}
     int *p = new int;
     delete p;
     delete p; // expected-note {{delete of pointer that has already been deleted}}
-    return 0;
   }
-  static_assert(double_delete()); // expected-error {{static assertion expression is not an integral constant expression}} expected-note {{in call to}}
   constexpr bool super_secret_double_delete() {
     struct A {
       constexpr ~A() { delete this; } // expected-note {{destruction of object that is already being destroyed}} expected-note {{in call}}
@@ -936,21 +925,17 @@ namespace dynamic_alloc {
   }
   static_assert(super_secret_double_delete()); // expected-error {{constant expression}} expected-note {{in call}}
 
-  constexpr int use_after_free() {
+  constexpr void use_after_free() { // expected-error {{never produces a constant expression}}
     int *p = new int;
     delete p;
     *p = 1; // expected-note {{assignment to heap allocated object that has been deleted}}
-    return 0;
   }
-  static_assert(use_after_free()); // expected-error {{static assertion expression is not an integral constant expression}} expected-note {{in call to}}
-  constexpr int use_after_free_2() {
+  constexpr void use_after_free_2() { // expected-error {{never produces a constant expression}}
     struct X { constexpr void f() {} };
     X *p = new X;
     delete p;
     p->f(); // expected-note {{member call on heap allocated object that has been deleted}}
-    return 0;
   }
-  static_assert(use_after_free_2()); // expected-error {{static assertion expression is not an integral constant expression}} expected-note {{in call to}}
 
   template<typename T> struct X {
     std::size_t n;
@@ -1084,12 +1069,10 @@ namespace std {
 
 namespace dtor_call {
   struct A { int n; };
-  constexpr int f() {
+  constexpr void f() { // expected-error {{never produces a constant expression}}
     A a; // expected-note {{destroying object 'a' whose lifetime has already ended}}
     a.~A();
-    return 0;
   }
-  static_assert(f()); // expected-error {{static assertion expression is not an integral constant expression}} expected-note {{in call to}}
   union U { A a; };
   constexpr void g() {
     U u;
@@ -1223,27 +1206,21 @@ namespace dtor_call {
   }
   static_assert((destroy_after_lifetime3(), true)); // expected-error {{}} expected-note {{in call}}
 
-  constexpr int destroy_after_lifetime4() {
+  constexpr void destroy_after_lifetime4() { // expected-error {{never produces a constant expression}}
     A *p = new A;
     delete p;
     p->~A(); // expected-note {{destruction of heap allocated object that has been deleted}}
-    return 0;
   }
-  static_assert(destroy_after_lifetime4()); // expected-error {{static assertion expression is not an integral constant expression}} expected-note {{in call to}}
 
   struct Extern { constexpr ~Extern() {} } extern e;
-  constexpr int destroy_extern() {
+  constexpr void destroy_extern() { // expected-error {{never produces a constant expression}}
     e.~Extern(); // expected-note {{cannot modify an object that is visible outside}}
-    return 0;
   }
-  static_assert(destroy_extern()); // expected-error {{static assertion expression is not an integral constant expression}} expected-note {{in call to}}
 
   constexpr A &&a_ref = A(); // expected-note {{temporary created here}}
-  constexpr int destroy_extern_2() {
+  constexpr void destroy_extern_2() { // expected-error {{never produces a constant expression}}
     a_ref.~A(); // expected-note {{destruction of temporary is not allowed in a constant expression outside the expression that created the temporary}}
-    return 0;
   }
-  static_assert(destroy_extern_2()); // expected-error {{static assertion expression is not an integral constant expression}} expected-note {{in call to}}
 
   struct S {
     constexpr S() { n = 1; }
@@ -1255,54 +1232,42 @@ namespace dtor_call {
   }
   static_assert((destroy_volatile(), true)); // ok, not volatile during construction and destruction
 
-  constexpr int destroy_null() {
+  constexpr void destroy_null() { // expected-error {{never produces a constant expression}}
     ((A*)nullptr)->~A(); // expected-note {{destruction of dereferenced null pointer}}
-    return 0;
   }
-  static_assert(destroy_null()); // expected-error {{static assertion expression is not an integral constant expression}} expected-note {{in call to}}
 
-  constexpr int destroy_past_end() {
+  constexpr void destroy_past_end() { // expected-error {{never produces a constant expression}}
     A a;
     (&a+1)->~A(); // expected-note {{destruction of dereferenced one-past-the-end pointer}}
-    return 0;
   }
-  static_assert(destroy_past_end()); // expected-error {{static assertion expression is not an integral constant expression}} expected-note {{in call to}}
 
-  constexpr int destroy_past_end_array() {
+  constexpr void destroy_past_end_array() { // expected-error {{never produces a constant expression}}
     A a[2];
     a[2].~A(); // expected-note {{destruction of dereferenced one-past-the-end pointer}}
-    return 0;
   }
-  static_assert(destroy_past_end_array()); // expected-error {{static assertion expression is not an integral constant expression}} expected-note {{in call to}}
 
   union As {
     A a, b;
   };
 
-  constexpr int destroy_no_active() {
+  constexpr void destroy_no_active() { // expected-error {{never produces a constant expression}}
     As as;
     as.b.~A(); // expected-note {{destruction of member 'b' of union with no active member}}
-    return 0;
   }
-  static_assert(destroy_no_active()); // expected-error {{static assertion expression is not an integral constant expression}} expected-note {{in call to}}
 
-  constexpr int destroy_inactive() {
+  constexpr void destroy_inactive() { // expected-error {{never produces a constant expression}}
     As as;
     as.a.n = 1;
     as.b.~A(); // expected-note {{destruction of member 'b' of union with active member 'a'}}
-    return 0;
   }
-  static_assert(destroy_inactive()); // expected-error {{static assertion expression is not an integral constant expression}} expected-note {{in call to}}
 
-  constexpr int destroy_no_active_2() {
+  constexpr void destroy_no_active_2() { // expected-error {{never produces a constant expression}}
     As as;
     as.a.n = 1;
     as.a.~A();
     // FIXME: This diagnostic is wrong; the union has no active member now.
     as.b.~A(); // expected-note {{destruction of member 'b' of union with active member 'a'}}
-    return 0;
   }
-  static_assert(destroy_no_active_2()); // expected-error {{static assertion expression is not an integral constant expression}} expected-note {{in call to}}
 
   constexpr void destroy_pointer() {
     using T = int*;
@@ -1362,22 +1327,16 @@ namespace mutable_subobjects {
   auto &ti2 = typeid(a.m);
   auto &ti3 = typeid(a.n);
 
-  constexpr int destroy1() {
+  constexpr void destroy1() { // expected-error {{constexpr}}
     a.~A(); // expected-note {{cannot modify an object that is visible outside}}
-    return 0;
   }
-  static_assert(destroy1()); // expected-error {{static assertion expression is not an integral constant expression}} expected-note {{in call to}}
   using T = int;
-  constexpr int destroy2() {
+  constexpr void destroy2() { // expected-error {{constexpr}}
     a.m.~T(); // expected-note {{cannot modify an object that is visible outside}}
-    return 0;
   }
-  static_assert(destroy2()); // expected-error {{static assertion expression is not an integral constant expression}} expected-note {{in call to}}
-  constexpr int destroy3() {
+  constexpr void destroy3() { // expected-error {{constexpr}}
     a.n.~T(); // expected-note {{cannot modify an object that is visible outside}}
-    return 0;
   }
-  static_assert(destroy3()); // expected-error {{static assertion expression is not an integral constant expression}} expected-note {{in call to}}
 
   struct X {
     mutable int n = 0;
@@ -1507,9 +1466,9 @@ namespace PR45879 {
   static_assert(f());
 
   // Only syntactic assignments change the active union member.
-  constexpr bool g() {
+  constexpr bool g() { // expected-error {{never produces a constant expression}}
     C c = {.n = 1};
-    c.a.operator=(B{2}.a); // expected-note {{member call on member 'a' of union with active member 'n' is not allowed in a constant expression}}
+    c.a.operator=(B{2}.a); // expected-note 2{{member call on member 'a' of union with active member 'n' is not allowed in a constant expression}}
     return c.a.n == 2;
   }
   static_assert(g()); // expected-error {{constant expression}} expected-note {{in call}}
diff --git a/clang/test/SemaCXX/constexpr-frame-describe.cpp b/clang/test/SemaCXX/constexpr-frame-describe.cpp
index 94ab786a62a4f..7b832d9a4b4a1 100644
--- a/clang/test/SemaCXX/constexpr-frame-describe.cpp
+++ b/clang/test/SemaCXX/constexpr-frame-describe.cpp
@@ -2,15 +2,16 @@
 
 
 struct Foo {
-    constexpr void zomg() const { (void)(1 / 0); } // expected-warning {{division by zero}} \
-                                                      expected-note {{division by zero}}
+    constexpr void zomg() const { (void)(1 / 0); } // expected-error {{constant expression}} \
+                                                      expected-warning {{division by zero}} \
+                                                      expected-note 2{{division by zero}}
 };
 
 struct S {
     constexpr S() {}
-    constexpr bool operator==(const S&) const {
+    constexpr bool operator==(const S&) const { // expected-error {{never produces a constant expression}}
       return 1 / 0; // expected-warning {{division by zero}} \
-                       expected-note 2{{division by zero}}
+                       expected-note 3{{division by zero}}
     }
 
     constexpr bool heh() const {
@@ -35,8 +36,9 @@ static_assert(*sptr == *sptr2); // expected-error {{constant expression}} \
                                    expected-note {{in call to '*sptr.operator==(s2)'}}
 
 struct A {
-  constexpr int foo() { (void)(1/0); return 1;} // expected-warning {{division by zero}} \
-                                                   expected-note {{division by zero}}
+  constexpr int foo() { (void)(1/0); return 1;} // expected-error {{never produces a constant expression}} \
+                                                   expected-warning {{division by zero}} \
+                                                   expected-note 2{{division by zero}}
 };
 
 struct B {
diff --git a/clang/test/SemaCXX/constexpr-function-recovery-crash.cpp b/clang/test/SemaCXX/constexpr-function-recovery-crash.cpp
index 736abfcfeb7ab..90ee7892b2fc2 100644
--- a/clang/test/SemaCXX/constexpr-function-recovery-crash.cpp
+++ b/clang/test/SemaCXX/constexpr-function-recovery-crash.cpp
@@ -34,16 +34,17 @@ constexpr int test4() {
     return 0;
 }
 
-constexpr int test5() {
-  for (;; a++); // expected-error {{use of undeclared identifier}}
+constexpr int test5() { // expected-error {{constexpr function never produce}}
+  for (;; a++); // expected-error {{use of undeclared identifier}}  \
+                   expected-note {{constexpr evaluation hit maximum step limit; possible infinite loop?}}
   return 1;
 }
 
-constexpr int test6() {
+constexpr int test6() { // expected-error {{constexpr function never produce}}
   int n = 0;
   switch (n) {
     for (;; a++) { // expected-error {{use of undeclared identifier}}
-    case 0:;
+    case 0:; // expected-note {{constexpr evaluation hit maximum step limit; possible infinite loop?}}
     }
   }
   return 0;
diff --git a/clang/test/SemaCXX/constexpr-string.cpp b/clang/test/SemaCXX/constexpr-string.cpp
index 2516b483ec2b6..c456740ef7551 100644
--- a/clang/test/SemaCXX/constexpr-string.cpp
+++ b/clang/test/SemaCXX/constexpr-string.cpp
@@ -601,15 +601,15 @@ namespace MemcpyEtc {
     constexpr NonTrivial(const NonTrivial &) : n(1) {}
     int n;
   };
-  constexpr bool test_nontrivial_memcpy() {
+  constexpr bool test_nontrivial_memcpy() { // expected-error {{never produces a constant}}
     NonTrivial arr[3] = {};
-    __builtin_memcpy(arr, arr + 1, sizeof(NonTrivial)); // expected-note {{non-trivially-copyable}}
+    __builtin_memcpy(arr, arr + 1, sizeof(NonTrivial)); // expected-note 2{{non-trivially-copyable}}
     return true;
   }
   static_assert(test_nontrivial_memcpy()); // expected-error {{constant}} expected-note {{in call}}
-  constexpr bool test_nontrivial_memmove() {
+  constexpr bool test_nontrivial_memmove() { // expected-error {{never produces a constant}}
     NonTrivial arr[3] = {};
-    __builtin_memcpy(arr, arr + 1, sizeof(NonTrivial)); // expected-note {{non-trivially-copyable}}
+    __builtin_memcpy(arr, arr + 1, sizeof(NonTrivial)); // expected-note 2{{non-trivially-copyable}}
     return true;
   }
   static_assert(test_nontrivial_memmove()); // expected-error {{constant}} expected-note {{in call}}
@@ -649,29 +649,29 @@ namespace MemcpyEtc {
   static_assert(test_address_of_const_array_type() == 1234);
 
   // Check that an incomplete array is rejected.
-  constexpr int test_incomplete_array_type() {
+  constexpr int test_incomplete_array_type() { // expected-error {{never produces a constant}}
     extern int arr[];
     __builtin_memmove(arr, arr, 4 * sizeof(arr[0]));
-    // expected-note at -1 {{'memmove' not supported: source is not a contiguous array of at least 4 elements of type 'int'}}
+    // expected-note at -1 2{{'memmove' not supported: source is not a contiguous array of at least 4 elements of type 'int'}}
     return arr[0] * 1000 + arr[1] * 100 + arr[2] * 10 + arr[3];
   }
   static_assert(test_incomplete_array_type() == 1234); // expected-error {{constant}} expected-note {{in call}}
 
   // Check that a pointer to an incomplete array is rejected.
-  constexpr int test_address_of_incomplete_array_type() {
+  constexpr int test_address_of_incomplete_array_type() { // expected-error {{never produces a constant}}
     extern int arr[];
     __builtin_memmove(&arr, &arr, 4 * sizeof(arr[0]));
-    // expected-note at -1 {{cannot constant evaluate 'memmove' between objects of incomplete type 'int[]'}}
+    // expected-note at -1 2{{cannot constant evaluate 'memmove' between objects of incomplete type 'int[]'}}
     return arr[0] * 1000 + arr[1] * 100 + arr[2] * 10 + arr[3];
   }
   static_assert(test_address_of_incomplete_array_type() == 1234); // expected-error {{constant}} expected-note {{in call}}
 
   // Check that a pointer to an incomplete struct is rejected.
-  constexpr bool test_address_of_incomplete_struct_type() {
+  constexpr bool test_address_of_incomplete_struct_type() { // expected-error {{never produces a constant}}
     struct Incomplete;
     extern Incomplete x, y;
     __builtin_memcpy(&x, &x, 4);
-    // expected-note at -1 {{cannot constant evaluate 'memcpy' between objects of incomplete type 'Incomplete'}}
+    // expected-note at -1 2{{cannot constant evaluate 'memcpy' between objects of incomplete type 'Incomplete'}}
     return true;
   }
   static_assert(test_address_of_incomplete_struct_type()); // expected-error {{constant}} expected-note {{in call}}
diff --git a/clang/test/SemaCXX/cxx23-assume.cpp b/clang/test/SemaCXX/cxx23-assume.cpp
index f3f9390fe42fb..9138501d726dd 100644
--- a/clang/test/SemaCXX/cxx23-assume.cpp
+++ b/clang/test/SemaCXX/cxx23-assume.cpp
@@ -72,11 +72,10 @@ static_assert(h(4) == sizeof(int));
 static_assert(__has_cpp_attribute(assume) == 202207L);
 static_assert(__has_attribute(assume));
 
-constexpr bool i() {
-  [[assume(false)]]; // expected-note 2 {{assumption evaluated to false}} ext-warning {{C++23 extension}}
+constexpr bool i() { // ext-error {{never produces a constant expression}}
+  [[assume(false)]]; // ext-note {{assumption evaluated to false}} expected-note {{assumption evaluated to false}} ext-warning {{C++23 extension}}
   return true;
 }
-static_assert(i()); // expected-error {{static assertion expression is not an integral constant expression}} expected-note {{in call to}}
 
 constexpr bool j(bool b) {
   [[assume(b)]]; // expected-note {{assumption evaluated to false}} ext-warning {{C++23 extension}}
diff --git a/clang/test/SemaCXX/cxx2a-consteval.cpp b/clang/test/SemaCXX/cxx2a-consteval.cpp
index 351fb73b6631a..622ec31c459dd 100644
--- a/clang/test/SemaCXX/cxx2a-consteval.cpp
+++ b/clang/test/SemaCXX/cxx2a-consteval.cpp
@@ -904,7 +904,7 @@ void func() {
   S<Baz, 3> s7;
 }
 
-consteval int aConstevalFunction() {
+consteval int aConstevalFunction() { // expected-error {{consteval function never produces a constant expression}}
   // Defaulted default constructors are implicitly consteval.
   S<Bar, 1> s1;
 
@@ -914,7 +914,6 @@ consteval int aConstevalFunction() {
   S<Baz, 3> s3;
   return 0;
 }
-static_assert(aConstevalFunction() == 0); // expected-error {{static assertion expression is not an integral constant expression}} expected-note {{in call to}}
 
 } // namespace multiple_default_constructors
 
diff --git a/clang/test/SemaCXX/cxx2a-constexpr-dynalloc.cpp b/clang/test/SemaCXX/cxx2a-constexpr-dynalloc.cpp
index 7870bc2d77f97..357dc67bd5ad2 100644
--- a/clang/test/SemaCXX/cxx2a-constexpr-dynalloc.cpp
+++ b/clang/test/SemaCXX/cxx2a-constexpr-dynalloc.cpp
@@ -90,12 +90,11 @@ constexpr int no_deallocate_nonalloc = (std::allocator<int>().deallocate((int*)&
 // expected-note at -2 {{declared here}}
 
 void *operator new(std::size_t, void *p) { return p; }
-constexpr bool no_placement_new_in_user_code() {
+constexpr bool no_placement_new_in_user_code() { // expected-error {{never produces a constant expression}}
   int a;
   new (&a) int(42); // expected-note {{call to placement 'operator new'}}
   return a == 42;
 }
-static_assert(no_placement_new_in_user_code()); // expected-error {{static assertion expression is not an integral constant expression}} expected-note {{in call to}}
 
 namespace std {
   constexpr bool placement_new_in_stdlib() {
diff --git a/clang/test/SemaCXX/literal-type.cpp b/clang/test/SemaCXX/literal-type.cpp
index 046fa2c8a6efd..88535c169fe01 100644
--- a/clang/test/SemaCXX/literal-type.cpp
+++ b/clang/test/SemaCXX/literal-type.cpp
@@ -1,6 +1,6 @@
 // RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
 // RUN: %clang_cc1 -fsyntax-only -verify -std=c++20 %s
-// expected-no-diagnostics
+
 
 static_assert(__is_literal(int), "fail");
 static_assert(__is_literal_type(int), "fail"); // alternate spelling for GCC
@@ -53,10 +53,10 @@ static_assert(!__is_literal(HasNonLiteralBase), "fail");
 static_assert(!__is_literal(HasNonLiteralMember), "fail");
 
 // DR1361 removes the brace-or-equal-initializer bullet so that we can allow:
-extern int f();
+extern int f(); // expected-note {{here}}
 struct HasNonConstExprMemInit {
-  int x = f();
-  constexpr HasNonConstExprMemInit() {}
+  int x = f(); // expected-note {{non-constexpr function}}
+  constexpr HasNonConstExprMemInit() {} // expected-error {{never produces a constant expression}}
   constexpr HasNonConstExprMemInit(int y) : x(y) {} // ok
 };
 static_assert(__is_literal(HasNonConstExprMemInit), "fail");
diff --git a/clang/test/SemaCXX/ms-constexpr-invalid.cpp b/clang/test/SemaCXX/ms-constexpr-invalid.cpp
index 247ef53ba072d..e5bec0c7119b0 100644
--- a/clang/test/SemaCXX/ms-constexpr-invalid.cpp
+++ b/clang/test/SemaCXX/ms-constexpr-invalid.cpp
@@ -3,11 +3,10 @@
 
 // Check explicitly invalid code
 
-void runtime() {}
+void runtime() {} // expected-note {{declared here}}
 
-[[msvc::constexpr]] int f0() { runtime(); return 0; } // expected-note {{declared here}}
-static_assert(f0() == 0); // expected-error {{static assertion expression is not an integral constant expression}} \
-                             expected-note{{non-constexpr function 'f0' cannot be used in a constant expression}}
+[[msvc::constexpr]] void f0() { runtime(); } // expected-error {{constexpr function never produces a constant expression}} \
+                                             // expected-note {{non-constexpr function 'runtime' cannot be used in a constant expression}}
 [[msvc::constexpr]] constexpr void f1() {} // expected-error {{attribute 'msvc::constexpr' cannot be applied to the constexpr function 'f1'}}
 #if __cplusplus >= 202202L
 [[msvc::constexpr]] consteval void f2() {} // expected-error {{attribute 'msvc::constexpr' cannot be applied to the consteval function 'f1'}}
@@ -23,19 +22,24 @@ struct [[msvc::constexpr]] S2{}; // expected-error {{'constexpr' attribute only
 // Check invalid code mixed with valid code
 
 [[msvc::constexpr]] int f4(int x) { return x > 1 ? 1 + f4(x / 2) : 0; } // expected-note {{non-constexpr function 'f4' cannot be used in a constant expression}} \
+                                                                        // expected-note {{declared here}} \
                                                                         // expected-note {{declared here}} \
                                                                         // expected-note {{declared here}}
 constexpr bool f5() { [[msvc::constexpr]] return f4(32) == 5; } // expected-note {{in call to 'f4(32)'}}
 static_assert(f5()); // expected-error {{static assertion expression is not an integral constant expression}} \
                      // expected-note {{in call to 'f5()'}}
 
-int f6(int x) { [[msvc::constexpr]] return x > 1 ? 1 + f6(x / 2) : 0; } // expected-note {{declared here}}
-constexpr bool f7() { [[msvc::constexpr]] return f6(32) == 5; } // expected-note {{non-constexpr function 'f6' cannot be used in a constant expression}}
+int f6(int x) { [[msvc::constexpr]] return x > 1 ? 1 + f6(x / 2) : 0; } // expected-note {{declared here}} \
+                                                                        // expected-note {{declared here}}
+constexpr bool f7() { [[msvc::constexpr]] return f6(32) == 5; } // expected-error {{constexpr function never produces a constant expression}} \
+                                                                // expected-note {{non-constexpr function 'f6' cannot be used in a constant expression}} \
+                                                                // expected-note {{non-constexpr function 'f6' cannot be used in a constant expression}}
 static_assert(f7()); // expected-error {{static assertion expression is not an integral constant expression}} \
                      // expected-note {{in call to 'f7()'}}
 
-constexpr bool f8() {
+constexpr bool f8() { // expected-error {{constexpr function never produces a constant expression}}
     [[msvc::constexpr]] f4(32); // expected-error {{'constexpr' attribute only applies to functions and return statements}} \
+                                // expected-note {{non-constexpr function 'f4' cannot be used in a constant expression}} \
                                 // expected-note {{non-constexpr function 'f4' cannot be used in a constant expression}}
     [[msvc::constexpr]] int i5 = f4(32); // expected-error {{'constexpr' attribute only applies to functions and return statements}}
     return i5 == 5;
diff --git a/clang/test/SemaCXX/ms-constexpr.cpp b/clang/test/SemaCXX/ms-constexpr.cpp
index 7a94962202f80..79f71a34cb7d8 100644
--- a/clang/test/SemaCXX/ms-constexpr.cpp
+++ b/clang/test/SemaCXX/ms-constexpr.cpp
@@ -29,7 +29,9 @@ static_assert(test_get_msconstexpr_true());
 struct S2 {
     [[msvc::constexpr]] S2() {}
     [[msvc::constexpr]] bool value() { return true; }
-    static constexpr bool check() { [[msvc::constexpr]] return S2{}.value(); }  // expected-note {{non-literal type 'S2' cannot be used in a constant expression}}
+    static constexpr bool check() { [[msvc::constexpr]] return S2{}.value(); } // expected-error {{constexpr function never produces a constant expression}} \
+                                                                               // expected-note {{non-literal type 'S2' cannot be used in a constant expression}} \
+                                                                               // expected-note {{non-literal type 'S2' cannot be used in a constant expression}}
 };
 static_assert(S2::check()); // expected-error {{static assertion expression is not an integral constant expression}} \
                             // expected-note {{in call to 'check()'}}

>From 920a738e2b633ace302c9fa47ac1a04f8278281c Mon Sep 17 00:00:00 2001
From: Aaron Ballman <aaron at aaronballman.com>
Date: Mon, 3 Jun 2024 13:55:18 -0400
Subject: [PATCH 3/4] Update code, add test coverage, add release note

---
 clang/docs/ReleaseNotes.rst                     | 11 +++++++++++
 clang/lib/Sema/SemaDeclCXX.cpp                  | 14 ++++++++------
 clang/test/SemaCXX/constexpr-never-constant.cpp | 16 ++++++++++++++++
 3 files changed, 35 insertions(+), 6 deletions(-)
 create mode 100644 clang/test/SemaCXX/constexpr-never-constant.cpp

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 32515fbac64f6..b40b03671792c 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -323,6 +323,17 @@ Non-comprehensive list of changes in this release
 - Builtins ``__builtin_shufflevector()`` and ``__builtin_convertvector()`` may
   now be used within constant expressions.
 
+- When compiling a constexpr function, Clang will check to see whether the
+  function can *never* be used in a constant expression context and issues a
+  diagnostic under the ``-Winvalid-constexpr`` diagostic flag (which defaults
+  to an error). This check can be expensive because the mere presence of a
+  function marked ``constexpr`` will cause us to undergo constant expression
+  evaluation, even if the function is not called within the translation unit
+  being compiled. Due to the expense, Clang no longer checks constexpr function
+  bodies when the function is defined in a system header file or when
+  ``-Winvalid-constexpr`` is not enabled for the function definition, which
+  should result in mild compile-time performance improvements.
+
 New Compiler Flags
 ------------------
 - ``-fsanitize=implicit-bitfield-conversion`` checks implicit truncation and
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index af3b5c8c39eb7..3584590f24723 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -2473,13 +2473,15 @@ static bool CheckConstexprFunctionBody(Sema &SemaRef, const FunctionDecl *Dcl,
   // constexpr potential is expensive, skip the check if the diagnostic is
   // disabled, the function is declared in a system header, or we're in C++23
   // or later mode (see https://wg21.link/P2448).
-  bool SkipCheck =
-      SemaRef.getLangOpts().CPlusPlus23 ||
-      SemaRef.getSourceManager().isInSystemHeader(Dcl->getLocation()) ||
-      SemaRef.getDiagnostics().isIgnored(
-          diag::ext_constexpr_function_never_constant_expr, Dcl->getLocation());
+  auto SkipCheck = [&SemaRef, Dcl] {
+    return SemaRef.getLangOpts().CPlusPlus23 ||
+           SemaRef.getSourceManager().isInSystemHeader(Dcl->getLocation()) ||
+           SemaRef.getDiagnostics().isIgnored(
+               diag::ext_constexpr_function_never_constant_expr,
+               Dcl->getLocation());
+  };
   SmallVector<PartialDiagnosticAt, 8> Diags;
-  if (!SkipCheck && Kind == Sema::CheckConstexprKind::Diagnose &&
+  if (Kind == Sema::CheckConstexprKind::Diagnose && !SkipCheck() &&
       !Expr::isPotentialConstantExpr(Dcl, Diags)) {
     SemaRef.Diag(Dcl->getLocation(),
                  diag::ext_constexpr_function_never_constant_expr)
diff --git a/clang/test/SemaCXX/constexpr-never-constant.cpp b/clang/test/SemaCXX/constexpr-never-constant.cpp
new file mode 100644
index 0000000000000..5b3cc0e6eb5c3
--- /dev/null
+++ b/clang/test/SemaCXX/constexpr-never-constant.cpp
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++20 -verify -fcxx-exceptions %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++23 -verify=good -fcxx-exceptions %s
+// RUN: %clang_cc1 -fsyntax-only -Wno-invalid-constexpr -verify=good -fcxx-exceptions %s
+// good-no-diagnostics
+
+constexpr void func() { // expected-error {{constexpr function never produces a constant expression}}
+  throw 12;             // expected-note {{subexpression not valid in a constant expression}}
+}
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Winvalid-constexpr"
+constexpr void other_func() {
+#pragma clang diagnostic pop
+
+  throw 12;
+}

>From d339e643cbb6124d07683649e865f7efe4114ccf Mon Sep 17 00:00:00 2001
From: Aaron Ballman <aaron at aaronballman.com>
Date: Tue, 4 Jun 2024 08:34:23 -0400
Subject: [PATCH 4/4] Allow the diagnostic to be enabled in C++23 mode, add
 tests

---
 clang/docs/ReleaseNotes.rst                     |  3 +++
 clang/include/clang/Basic/LangOptions.def       |  3 +++
 clang/include/clang/Driver/Options.td           |  4 ++++
 clang/lib/Frontend/CompilerInvocation.cpp       |  6 ++++++
 clang/lib/Sema/SemaDeclCXX.cpp                  |  2 +-
 clang/test/SemaCXX/constexpr-never-constant.cpp | 10 ++++++++++
 6 files changed, 27 insertions(+), 1 deletion(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index b40b03671792c..6f599bbe11a2f 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -207,6 +207,9 @@ C++23 Feature Support
 - Implemented `P1774R8: Portable assumptions <https://wg21.link/P1774R8>`_.
 
 - Implemented `P2448R2: Relaxing some constexpr restrictions <https://wg21.link/P2448R2>`_.
+  Note, the ``-Winvalid-constexpr`` diagnostic is now disabled in C++23 mode,
+  but can be explicitly specified to retain the old diagnostic checking
+  behavior.
 
 - Added a ``__reference_converts_from_temporary`` builtin, completing the necessary compiler support for
   `P2255R2: Type trait to determine if a reference binds to a temporary <https://wg21.link/P2255R2>`_.
diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def
index 4061451b2150a..cd0c430850159 100644
--- a/clang/include/clang/Basic/LangOptions.def
+++ b/clang/include/clang/Basic/LangOptions.def
@@ -505,6 +505,9 @@ COMPATIBLE_LANGOPT(IncrementalExtensions, 1, 0, " True if we want to process sta
 
 BENIGN_LANGOPT(CheckNew, 1, 0, "Do not assume C++ operator new may not return NULL")
 
+BENIGN_LANGOPT(CheckConstexprFunctionBodies, 1, 1,
+               "True if we want to emit a diagnostics for a constexpr function "
+               "body if it can never be used in a constant expression.")
 #undef LANGOPT
 #undef COMPATIBLE_LANGOPT
 #undef BENIGN_LANGOPT
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index 57f37c5023110..904547a0a13de 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -961,6 +961,10 @@ def Wdeprecated : Flag<["-"], "Wdeprecated">, Group<W_Group>,
   HelpText<"Enable warnings for deprecated constructs and define __DEPRECATED">;
 def Wno_deprecated : Flag<["-"], "Wno-deprecated">, Group<W_Group>,
   Visibility<[ClangOption, CC1Option]>;
+def Winvalid_constexpr : Flag<["-"], "Winvalid-constexpr">, Group<W_Group>,
+  Visibility<[ClangOption, CC1Option]>;
+def Wno_invalid_constexpr : Flag<["-"], "Wno-invalid-constexpr">,
+  Group<W_Group>, Visibility<[ClangOption, CC1Option]>;
 def Wl_COMMA : CommaJoined<["-"], "Wl,">, Visibility<[ClangOption, FlangOption]>,
   Flags<[LinkerInput, RenderAsInput]>,
   HelpText<"Pass the comma separated arguments in <arg> to the linker">,
diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp
index 14ee02c4cd582..a5ced4791a8c7 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -593,6 +593,12 @@ static bool FixupInvocation(CompilerInvocation &Invocation,
   CodeGenOpts.CodeModel = TargetOpts.CodeModel;
   CodeGenOpts.LargeDataThreshold = TargetOpts.LargeDataThreshold;
 
+  // -Winvalid-constexpr is enabled by default. We want to disable it in C++23
+  // mode, but only if `-Winvalid-constexpr` is not specified on the command
+  // line.
+  LangOpts.CheckConstexprFunctionBodies = Args.hasFlagNoClaim(
+      OPT_Winvalid_constexpr, OPT_Wno_invalid_constexpr, !LangOpts.CPlusPlus23);
+
   if (LangOpts.getExceptionHandling() !=
           LangOptions::ExceptionHandlingKind::None &&
       T.isWindowsMSVCEnvironment())
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 3584590f24723..ef34359347a95 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -2474,7 +2474,7 @@ static bool CheckConstexprFunctionBody(Sema &SemaRef, const FunctionDecl *Dcl,
   // disabled, the function is declared in a system header, or we're in C++23
   // or later mode (see https://wg21.link/P2448).
   auto SkipCheck = [&SemaRef, Dcl] {
-    return SemaRef.getLangOpts().CPlusPlus23 ||
+    return !SemaRef.getLangOpts().CheckConstexprFunctionBodies ||
            SemaRef.getSourceManager().isInSystemHeader(Dcl->getLocation()) ||
            SemaRef.getDiagnostics().isIgnored(
                diag::ext_constexpr_function_never_constant_expr,
diff --git a/clang/test/SemaCXX/constexpr-never-constant.cpp b/clang/test/SemaCXX/constexpr-never-constant.cpp
index 5b3cc0e6eb5c3..307810ee263dd 100644
--- a/clang/test/SemaCXX/constexpr-never-constant.cpp
+++ b/clang/test/SemaCXX/constexpr-never-constant.cpp
@@ -1,5 +1,15 @@
 // RUN: %clang_cc1 -fsyntax-only -std=c++20 -verify -fcxx-exceptions %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++23 -Winvalid-constexpr -verify -fcxx-exceptions %s
+// Note: for a diagnostic that defaults to an error, -Wno-foo -Wfoo will
+// disable the diagnostic and then re-enable it *as a warning* rather than as
+// an error. So we manually enable it as an error again with -Werror to keep
+// the diagnostic checks consistent.
+// RUN: %clang_cc1 -fsyntax-only -std=c++23 -Wno-invalid-constexpr -Winvalid-constexpr -Werror=invalid-constexpr -verify -fcxx-exceptions %s
+
+// RUN: %clang_cc1 -fsyntax-only -Wno-invalid-constexpr -verify=good -fcxx-exceptions %s
 // RUN: %clang_cc1 -fsyntax-only -std=c++23 -verify=good -fcxx-exceptions %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++23 -Wno-invalid-constexpr -verify=good -fcxx-exceptions %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++23 -Winvalid-constexpr -Wno-invalid-constexpr -verify=good -fcxx-exceptions %s
 // RUN: %clang_cc1 -fsyntax-only -Wno-invalid-constexpr -verify=good -fcxx-exceptions %s
 // good-no-diagnostics
 



More information about the cfe-commits mailing list