Timm =?utf-8?q?Bäder?= <tbae...@redhat.com> Message-ID: In-Reply-To: <llvm.org/llvm/llvm-project/pull/100...@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?= <tbae...@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@-1 {{constexpr variable 'z' must be initialized by a constant expression}} - // since-cxx11-note@-2 {{non-literal type 'A<Z>' cannot be used in a constant expression}} + // since-cxx11-error@-1 {{constexpr variable 'z' must be initialized by a constant expression}}a +#if __cplusplus < 202302L + // since-cxx11-note@-3 {{non-literal type 'A<Z>' cannot be used in a constant expression}} +#else + // since-cxx23-note@-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@-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@-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?= <tbae...@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 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits