[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 07:47:44 PDT 2024


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

>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/5] 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/5] 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/5] 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/5] 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
 

>From d68e8c587073b50bd189c1f9e6117bd7a137e5b3 Mon Sep 17 00:00:00 2001
From: Aaron Ballman <aaron at aaronballman.com>
Date: Tue, 4 Jun 2024 10:46:49 -0400
Subject: [PATCH 5/5] Update based on review feedback

* lambda changed to a simple boolean
* reworked the way the option is exposed
---
 clang/include/clang/Basic/LangOptions.def |  9 +++++++--
 clang/include/clang/Driver/Options.td     | 22 ++++++++++++++++++----
 clang/lib/Frontend/CompilerInvocation.cpp |  9 +++------
 clang/lib/Sema/SemaDeclCXX.cpp            | 14 ++++++--------
 4 files changed, 34 insertions(+), 20 deletions(-)

diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def
index cd0c430850159..2dea3cd4d795b 100644
--- a/clang/include/clang/Basic/LangOptions.def
+++ b/clang/include/clang/Basic/LangOptions.def
@@ -505,9 +505,14 @@ 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")
 
+// FIXME: It would be better for us to find a way to encode the state of this
+// diagnostic in tablegen so that we can specify a particular diagnostic option
+// is disabled or enabled based on other language options or made it easier to
+// do this from the compiler invocation without hitting option round-tripping
+// issues.
 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.")
+               "Emit diagnostics for a constexpr function body that 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 904547a0a13de..5ab2d49c7a497 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -557,6 +557,17 @@ multiclass BoolMOption<string flag_base, KeyPathAndMacro kpm,
               Group<m_Group>;
 }
 
+/// Creates a BoolOption where both of the flags are prefixed with "W", are in
+/// the Group<W_Group>.
+/// Used for -cc1 frontend options. Driver-only options do not map to
+/// CompilerInvocation.
+multiclass BoolWOption<string flag_base, KeyPathAndMacro kpm,
+                       Default default, FlagDef flag1, FlagDef flag2,
+                       BothFlags both = BothFlags<[]>> {
+  defm NAME : BoolOption<"W", flag_base, kpm, default, flag1, flag2, both>,
+              Group<W_Group>;
+}
+
 // Works like BoolOption except without marshalling
 multiclass BoolOptionWithoutMarshalling<string prefix = "", string spelling_base,
                                         FlagDef flag1_base, FlagDef flag2_base,
@@ -606,6 +617,7 @@ defvar cpp11 = LangOpts<"CPlusPlus11">;
 defvar cpp14 = LangOpts<"CPlusPlus14">;
 defvar cpp17 = LangOpts<"CPlusPlus17">;
 defvar cpp20 = LangOpts<"CPlusPlus20">;
+defvar cpp23 = LangOpts<"CPlusPlus23">;
 defvar c99 = LangOpts<"C99">;
 defvar c23 = LangOpts<"C23">;
 defvar lang_std = LangOpts<"LangStd">;
@@ -961,10 +973,12 @@ 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]>;
+defm invalid_constexpr : BoolWOption<"invalid-constexpr",
+  LangOpts<"CheckConstexprFunctionBodies">,
+  Default<!strconcat("!", cpp23.KeyPath)>,
+  NegFlag<SetFalse, [], [ClangOption, CC1Option], "Disable">,
+  PosFlag<SetTrue, [], [ClangOption, CC1Option], "Enable">,
+  BothFlags<[], [ClangOption, CC1Option], " checking of constexpr function bodies for validity within a constant expression context">>;
 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 a5ced4791a8c7..58694e5399d58 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -593,12 +593,6 @@ 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())
@@ -2413,6 +2407,9 @@ void CompilerInvocationBase::GenerateDiagnosticArgs(
     // This option is automatically generated from UndefPrefixes.
     if (Warning == "undef-prefix")
       continue;
+    // This option is automatically generated from CheckConstexprFunctionBodies.
+    if (Warning == "invalid-constexpr" || Warning == "no-invalid-constexpr")
+      continue;
     Consumer(StringRef("-W") + Warning);
   }
 
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index ef34359347a95..3c28da1b077cd 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -2473,15 +2473,13 @@ 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).
-  auto SkipCheck = [&SemaRef, Dcl] {
-    return !SemaRef.getLangOpts().CheckConstexprFunctionBodies ||
-           SemaRef.getSourceManager().isInSystemHeader(Dcl->getLocation()) ||
-           SemaRef.getDiagnostics().isIgnored(
-               diag::ext_constexpr_function_never_constant_expr,
-               Dcl->getLocation());
-  };
+  bool SkipCheck =
+      !SemaRef.getLangOpts().CheckConstexprFunctionBodies ||
+      SemaRef.getSourceManager().isInSystemHeader(Dcl->getLocation()) ||
+      SemaRef.getDiagnostics().isIgnored(
+          diag::ext_constexpr_function_never_constant_expr, Dcl->getLocation());
   SmallVector<PartialDiagnosticAt, 8> Diags;
-  if (Kind == Sema::CheckConstexprKind::Diagnose && !SkipCheck() &&
+  if (Kind == Sema::CheckConstexprKind::Diagnose && !SkipCheck &&
       !Expr::isPotentialConstantExpr(Dcl, Diags)) {
     SemaRef.Diag(Dcl->getLocation(),
                  diag::ext_constexpr_function_never_constant_expr)



More information about the cfe-commits mailing list