Skip to content

[clang][ExprConst] Allow non-literal types in C++23 #100062

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jul 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
^^^^^^^^^^^^^^^^^^^^^
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/AST/ExprConstant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
12 changes: 8 additions & 4 deletions clang/test/CXX/drs/cwg18xx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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__)
Expand Down Expand Up @@ -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
}

Expand Down
18 changes: 11 additions & 7 deletions clang/test/SemaCXX/constant-expression-cxx11.cpp
Original file line number Diff line number Diff line change
@@ -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 {

Expand Down Expand Up @@ -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}}

}

Expand Down Expand Up @@ -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}}
Expand Down
10 changes: 5 additions & 5 deletions clang/test/SemaCXX/constant-expression-cxx2b.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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{};
Expand Down Expand Up @@ -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;
};

Expand Down Expand Up @@ -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;
};

Expand Down
13 changes: 6 additions & 7 deletions clang/test/SemaCXX/cxx23-invalid-constexpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand All @@ -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&);
Expand Down Expand Up @@ -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;}
Expand Down Expand Up @@ -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}}
Expand All @@ -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 {
Expand Down
Loading