[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