[clang] dbe308c - [clang][ExprConst] Allow non-literal types in C++23 (#100062)
via cfe-commits
cfe-commits at lists.llvm.org
Tue Jul 23 23:09:10 PDT 2024
Author: Timm Baeder
Date: 2024-07-24T08:09:06+02:00
New Revision: dbe308c000f3401cbf6bb55f2b8d606fe091dcfe
URL: https://github.com/llvm/llvm-project/commit/dbe308c000f3401cbf6bb55f2b8d606fe091dcfe
DIFF: https://github.com/llvm/llvm-project/commit/dbe308c000f3401cbf6bb55f2b8d606fe091dcfe.diff
LOG: [clang][ExprConst] Allow non-literal types in C++23 (#100062)
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.
For this test:
```c++
struct NonLiteral {
NonLiteral() {}
};
constexpr int foo() {
NonLiteral L;
return 1;
}
// static_assert(foo() == 1);
```
The current diagnostics with c++20/c++23 are:
```console
~/code/llvm-project/build » clang -c array.cpp -std=c++20
array.cpp:91:14: error: variable of non-literal type 'NonLiteral' cannot be defined in a constexpr function before C++23
91 | NonLiteral L;
| ^
array.cpp:87:8: note: 'NonLiteral' is not literal because it is not an aggregate and has no constexpr constructors other than copy or move constructors
87 | struct NonLiteral {
| ^
1 error generated.
------------------------------------------------------------
~/code/llvm-project/build » clang -c array.cpp -std=c++23
(no output)
```
With the `static_assert` enabled, compiling with `-std=c++23` prints:
```console
array.cpp:95:15: error: static assertion expression is not an integral constant expression
95 | static_assert(foo() == 1);
| ^~~~~~~~~~
array.cpp:91:14: note: non-literal type 'NonLiteral' cannot be used in a constant expression
91 | NonLiteral L;
| ^
array.cpp:95:15: note: in call to 'foo()'
95 | static_assert(foo() == 1);
| ^~~~~
1 error generated.
```
As mentioned in #60311, this is confusing. The output with c++20
suggests that using c++23 will make the problem go away, but it's
diagnosed the same when running the function.
With this commit, the output instead diagnoses _why_ the non-literal
type can't be used:
```console
array.cpp:95:15: error: static assertion expression is not an integral constant expression
95 | static_assert(foo() == 1);
| ^~~~~~~~~~
array.cpp:91:14: note: non-constexpr constructor 'NonLiteral' cannot be used in a constant expression
91 | NonLiteral L;
| ^
array.cpp:95:15: note: in call to 'foo()'
95 | static_assert(foo() == 1);
| ^~~~~
array.cpp:88:3: note: declared here
88 | NonLiteral() {}
| ^
1 error generated.
```
Fixes #60311
Added:
Modified:
clang/docs/ReleaseNotes.rst
clang/lib/AST/ExprConstant.cpp
clang/test/CXX/drs/cwg18xx.cpp
clang/test/SemaCXX/constant-expression-cxx11.cpp
clang/test/SemaCXX/constant-expression-cxx2b.cpp
clang/test/SemaCXX/cxx23-invalid-constexpr.cpp
Removed:
################################################################################
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index ac1de0db9ce48..c78e37b48713a 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -76,6 +76,7 @@ C++20 Feature Support
C++23 Feature Support
^^^^^^^^^^^^^^^^^^^^^
+- 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 fcb382474ea62..ec19bce283fd5 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -2401,6 +2401,10 @@ static bool CheckMemberPointerConstantExpression(EvalInfo &Info,
/// produce an appropriate diagnostic.
static bool CheckLiteralType(EvalInfo &Info, const Expr *E,
const LValue *This = nullptr) {
+ // The restriction to literal types does not exist in C++23 anymore.
+ if (Info.getLangOpts().CPlusPlus23)
+ return true;
+
if (!E->isPRValue() || E->getType()->isLiteralType(Info.Ctx))
return true;
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 {
More information about the cfe-commits
mailing list