[clang] [clang][ExprConst] Allow non-literal types in C++23 (PR #100062)
Timm Baeder via cfe-commits
cfe-commits at lists.llvm.org
Tue Jul 23 01:58:55 PDT 2024
Timm =?utf-8?q?Bäder?= <tbaeder at redhat.com>
Message-ID:
In-Reply-To: <llvm.org/llvm/llvm-project/pull/100062 at github.com>
https://github.com/tbaederr updated https://github.com/llvm/llvm-project/pull/100062
>From 18a4a08009ecd8e5a557d77028fc4efdbf5901ce Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbaeder at redhat.com>
Date: Tue, 23 Jul 2024 07:02:23 +0200
Subject: [PATCH 1/2] [clang][ExprConst] Allow non-literal types in C++23
Instead of diagnosing non-literal types in C++23, allow them
and later diagnose them differently, e.g. because they have a
non-constexpr constructor, destructor, etc.
---
clang/lib/AST/ExprConstant.cpp | 3 +++
clang/test/CXX/drs/cwg18xx.cpp | 12 ++++++++----
.../test/SemaCXX/constant-expression-cxx11.cpp | 18 +++++++++++-------
.../test/SemaCXX/constant-expression-cxx2b.cpp | 10 +++++-----
clang/test/SemaCXX/cxx23-invalid-constexpr.cpp | 13 ++++++-------
5 files changed, 33 insertions(+), 23 deletions(-)
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 5af712dd7257b..a402e6f204aaf 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -2404,6 +2404,9 @@ static bool CheckLiteralType(EvalInfo &Info, const Expr *E,
if (!E->isPRValue() || E->getType()->isLiteralType(Info.Ctx))
return true;
+ if (Info.getLangOpts().CPlusPlus23)
+ return true;
+
// C++1y: A constant initializer for an object o [...] may also invoke
// constexpr constructors for o and its subobjects even if those objects
// are of non-literal class types.
diff --git a/clang/test/CXX/drs/cwg18xx.cpp b/clang/test/CXX/drs/cwg18xx.cpp
index 323e56f9c5278..adfdb738e81c9 100644
--- a/clang/test/CXX/drs/cwg18xx.cpp
+++ b/clang/test/CXX/drs/cwg18xx.cpp
@@ -3,8 +3,8 @@
// RUN: %clang_cc1 -std=c++14 -triple x86_64-unknown-unknown %s -verify=expected,since-cxx14,cxx98-14,cxx11-17,since-cxx11,since-cxx14 -fexceptions -Wno-deprecated-builtins -fcxx-exceptions -pedantic-errors
// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-unknown %s -verify=expected,since-cxx14,since-cxx17,cxx11-17,since-cxx11,since-cxx14,cxx17 -fexceptions -Wno-deprecated-builtins -fcxx-exceptions -pedantic-errors
// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-unknown %s -verify=expected,since-cxx14,since-cxx17,since-cxx20,since-cxx11,since-cxx14 -fexceptions -Wno-deprecated-builtins -fcxx-exceptions -pedantic-errors
-// RUN: %clang_cc1 -std=c++23 -triple x86_64-unknown-unknown %s -verify=expected,since-cxx14,since-cxx17,since-cxx20,since-cxx11,since-cxx14 -fexceptions -Wno-deprecated-builtins -fcxx-exceptions -pedantic-errors
-// RUN: %clang_cc1 -std=c++2c -triple x86_64-unknown-unknown %s -verify=expected,since-cxx14,since-cxx17,since-cxx20,since-cxx11,since-cxx14 -fexceptions -Wno-deprecated-builtins -fcxx-exceptions -pedantic-errors
+// RUN: %clang_cc1 -std=c++23 -triple x86_64-unknown-unknown %s -verify=expected,since-cxx14,since-cxx17,since-cxx20,since-cxx23,since-cxx11,since-cxx14 -fexceptions -Wno-deprecated-builtins -fcxx-exceptions -pedantic-errors
+// RUN: %clang_cc1 -std=c++2c -triple x86_64-unknown-unknown %s -verify=expected,since-cxx14,since-cxx17,since-cxx20,since-cxx23,since-cxx11,since-cxx14 -fexceptions -Wno-deprecated-builtins -fcxx-exceptions -pedantic-errors
#if __cplusplus == 199711L
#define static_assert(...) __extension__ _Static_assert(__VA_ARGS__)
@@ -480,8 +480,12 @@ namespace cwg1872 { // cwg1872: 9
static_assert(y == 0);
#endif
constexpr int z = A<Z>().f();
- // since-cxx11-error at -1 {{constexpr variable 'z' must be initialized by a constant expression}}
- // since-cxx11-note at -2 {{non-literal type 'A<Z>' cannot be used in a constant expression}}
+ // since-cxx11-error at -1 {{constexpr variable 'z' must be initialized by a constant expression}}a
+#if __cplusplus < 202302L
+ // since-cxx11-note at -3 {{non-literal type 'A<Z>' cannot be used in a constant expression}}
+#else
+ // since-cxx23-note at -5 {{cannot construct object of type 'A<cwg1872::Z>' with virtual base class in a constant expression}}
+#endif
#endif
}
diff --git a/clang/test/SemaCXX/constant-expression-cxx11.cpp b/clang/test/SemaCXX/constant-expression-cxx11.cpp
index efb391ba0922d..6df8a4740d6cc 100644
--- a/clang/test/SemaCXX/constant-expression-cxx11.cpp
+++ b/clang/test/SemaCXX/constant-expression-cxx11.cpp
@@ -1,6 +1,6 @@
-// RUN: %clang_cc1 -std=c++23 -isystem %S/Inputs -fsyntax-only -verify=expected,cxx20_23,cxx23 -triple x86_64-linux -Wno-string-plus-int -Wno-pointer-arith -Wno-zero-length-array -Wno-c99-designator -fcxx-exceptions -pedantic %s -Wno-comment -Wno-tautological-pointer-compare -Wno-bool-conversion
-// RUN: %clang_cc1 -std=c++20 -isystem %S/Inputs -fsyntax-only -verify=expected,cxx11_20,cxx20_23 -triple x86_64-linux -Wno-string-plus-int -Wno-pointer-arith -Wno-zero-length-array -Wno-c99-designator -fcxx-exceptions -pedantic %s -Wno-comment -Wno-tautological-pointer-compare -Wno-bool-conversion
-// RUN: %clang_cc1 -std=c++11 -isystem %S/Inputs -fsyntax-only -verify=expected,cxx11_20,cxx11 -triple x86_64-linux -Wno-string-plus-int -Wno-pointer-arith -Wno-zero-length-array -Wno-c99-designator -fcxx-exceptions -pedantic %s -Wno-comment -Wno-tautological-pointer-compare -Wno-bool-conversion
+// RUN: %clang_cc1 -std=c++23 -isystem %S/Inputs -fsyntax-only -verify=expected,cxx20_23,cxx23 -triple x86_64-linux -Wno-string-plus-int -Wno-pointer-arith -Wno-zero-length-array -Wno-c99-designator -fcxx-exceptions -pedantic %s -Wno-comment -Wno-tautological-pointer-compare -Wno-bool-conversion
+// RUN: %clang_cc1 -std=c++20 -isystem %S/Inputs -fsyntax-only -verify=expected,cxx11_20,cxx20_23,pre-cxx23 -triple x86_64-linux -Wno-string-plus-int -Wno-pointer-arith -Wno-zero-length-array -Wno-c99-designator -fcxx-exceptions -pedantic %s -Wno-comment -Wno-tautological-pointer-compare -Wno-bool-conversion
+// RUN: %clang_cc1 -std=c++11 -isystem %S/Inputs -fsyntax-only -verify=expected,cxx11_20,cxx11,pre-cxx23 -triple x86_64-linux -Wno-string-plus-int -Wno-pointer-arith -Wno-zero-length-array -Wno-c99-designator -fcxx-exceptions -pedantic %s -Wno-comment -Wno-tautological-pointer-compare -Wno-bool-conversion
namespace StaticAssertFoldTest {
@@ -1011,10 +1011,12 @@ constexpr bool b(int n) { return &n; }
static_assert(b(0), "");
struct NonLiteral {
- NonLiteral();
+ NonLiteral(); // cxx23-note {{declared here}}
int f();
};
-constexpr int k = NonLiteral().f(); // expected-error {{constant expression}} expected-note {{non-literal type 'NonLiteral'}}
+constexpr int k = NonLiteral().f(); // expected-error {{constant expression}} \
+ // pre-cxx23-note {{non-literal type 'NonLiteral'}} \
+ // cxx23-note {{non-constexpr constructor 'NonLiteral' cannot be used in a constant expression}}
}
@@ -1270,8 +1272,10 @@ static_assert(makeComplexWrap(1,0) != complex(0, 1), "");
namespace PR11595 {
struct A { constexpr bool operator==(int x) const { return true; } };
- 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}}
+ struct B { B(); A& x; }; // cxx23-note {{declared here}}
+ static_assert(B().x == 3, ""); // expected-error {{constant expression}} \
+ // pre-cxx23-note {{non-literal type 'B' cannot be used in a constant expression}} \
+ // cxx23-note {{non-constexpr constructor '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}}
diff --git a/clang/test/SemaCXX/constant-expression-cxx2b.cpp b/clang/test/SemaCXX/constant-expression-cxx2b.cpp
index 2519839b7ac57..42b3f81cc713d 100644
--- a/clang/test/SemaCXX/constant-expression-cxx2b.cpp
+++ b/clang/test/SemaCXX/constant-expression-cxx2b.cpp
@@ -3,7 +3,7 @@
struct NonLiteral { // cxx2a-note {{'NonLiteral' is not literal}} \
// cxx23-note 2{{'NonLiteral' is not literal}}
- NonLiteral() {}
+ NonLiteral() {} // cxx23-note 2{{declared here}}
};
struct Constexpr{};
@@ -165,9 +165,9 @@ int test_in_lambdas() {
auto non_literal = [](bool b) constexpr {
if (!b)
- NonLiteral n; // cxx23-note {{non-literal type 'NonLiteral' cannot be used in a constant expression}} \
- // cxx2a-error {{variable of non-literal type 'NonLiteral' cannot be defined in a constexpr function before C++23}} \
- // cxx23-warning {{definition of a variable of non-literal type in a constexpr function is incompatible with C++ standards before C++23}}
+ NonLiteral n; // cxx2a-error {{variable of non-literal type 'NonLiteral' cannot be defined in a constexpr function before C++23}} \
+ // cxx23-warning {{definition of a variable of non-literal type in a constexpr function is incompatible with C++ standards before C++23}} \
+ // cxx23-note {{non-constexpr constructor 'NonLiteral' cannot be used in a constant expression}}
return 0;
};
@@ -217,7 +217,7 @@ int test_lambdas_implicitly_constexpr() {
auto non_literal = [](bool b) { // cxx2a-note 2{{declared here}}
if (b)
- NonLiteral n; // cxx23-note {{non-literal type 'NonLiteral' cannot be used in a constant expression}}
+ NonLiteral n; // cxx23-note {{non-constexpr constructor 'NonLiteral' cannot be used in a constant expression}}
return 0;
};
diff --git a/clang/test/SemaCXX/cxx23-invalid-constexpr.cpp b/clang/test/SemaCXX/cxx23-invalid-constexpr.cpp
index 4dc16c59d8058..3229a91fbcefb 100644
--- a/clang/test/SemaCXX/cxx23-invalid-constexpr.cpp
+++ b/clang/test/SemaCXX/cxx23-invalid-constexpr.cpp
@@ -25,14 +25,14 @@ constexpr int FT(T N) {
class NonLiteral { // expected-note {{'NonLiteral' is not literal because it is not an aggregate and has no constexpr constructors}}
public:
NonLiteral() {}
- ~NonLiteral() {}
+ ~NonLiteral() {} // expected-note {{declared here}}
};
constexpr NonLiteral F1() {
return NonLiteral{};
}
-constexpr int F2(NonLiteral N) {
+constexpr int F2(NonLiteral N) { // expected-note {{non-constexpr function '~NonLiteral' cannot be used in a constant expression}}
return 8;
}
@@ -46,7 +46,7 @@ class Derived1 : public NonLiteral {
struct X {
- X();
+ X(); // expected-note 2{{declared here}}
X(const X&);
X(X&&);
X& operator=(X&);
@@ -80,7 +80,7 @@ struct WrapperNonT {
};
struct NonDefaultMembers {
- constexpr NonDefaultMembers() {}; // expected-note {{non-literal type 'X' cannot be used in a constant expression}}
+ constexpr NonDefaultMembers() {}; // expected-note 2{{non-constexpr constructor 'X' cannot be used in a constant expression}}
constexpr NonDefaultMembers(NonDefaultMembers const&) {};
constexpr NonDefaultMembers(NonDefaultMembers &&) {};
constexpr NonDefaultMembers& operator=(NonDefaultMembers &other) {this->t = other.t; return *this;}
@@ -109,7 +109,6 @@ void test() {
F1();
NonLiteral L;
constexpr auto D = F2(L); // expected-error {{constexpr variable 'D' must be initialized by a constant expression}}
- // expected-note at -1 {{non-literal type 'NonLiteral' cannot be used in a constant expression}}
constexpr auto E = FT(1); // expected-error {{constexpr variable 'E' must be initialized by a constant expression}}
// expected-note at -1 {{in call}}
@@ -125,8 +124,8 @@ void test() {
static_assert((NonDefaultMembers(), true),""); // expected-error{{expression is not an integral constant expression}} \
// expected-note {{in call to}}
- constexpr bool FFF = (NonDefaultMembers() == NonDefaultMembers()); // expected-error{{must be initialized by a constant expression}} \
- // expected-note{{non-literal}}
+ constexpr bool FFF = (NonDefaultMembers() == NonDefaultMembers()); // expected-error {{must be initialized by a constant expression}} \
+ // expected-note {{in call to 'NonDefaultMembers()'}}
}
struct A {
>From f55d060fa24f05b6f1fd97cfb4702a146d66618c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbaeder at redhat.com>
Date: Tue, 23 Jul 2024 10:58:35 +0200
Subject: [PATCH 2/2] Address review comments
---
clang/docs/ReleaseNotes.rst | 2 ++
clang/lib/AST/ExprConstant.cpp | 5 +++--
2 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 8e24087b3dcdb..a8a033160df7b 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -269,6 +269,8 @@ C++23 Feature Support
- Implemented `P2797R0: Static and explicit object member functions with the same parameter-type-lists <https://wg21.link/P2797R0>`_.
This completes the support for "deducing this".
+- Removed the restriction to literal types in constexpr functions in C++23 mode.
+
C++2c Feature Support
^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index a402e6f204aaf..b87a21c55eba9 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -2401,10 +2401,11 @@ static bool CheckMemberPointerConstantExpression(EvalInfo &Info,
/// produce an appropriate diagnostic.
static bool CheckLiteralType(EvalInfo &Info, const Expr *E,
const LValue *This = nullptr) {
- if (!E->isPRValue() || E->getType()->isLiteralType(Info.Ctx))
+ // The restriction to literal types does not exist in C++23 anymore.
+ if (Info.getLangOpts().CPlusPlus23)
return true;
- if (Info.getLangOpts().CPlusPlus23)
+ if (!E->isPRValue() || E->getType()->isLiteralType(Info.Ctx))
return true;
// C++1y: A constant initializer for an object o [...] may also invoke
More information about the cfe-commits
mailing list