https://github.com/katzdm updated https://github.com/llvm/llvm-project/pull/89565
>From a3f8a8648e2002273d47d7886b29fb02c728b5b7 Mon Sep 17 00:00:00 2001 From: Dan Katz <kat...@gmail.com> Date: Tue, 16 Apr 2024 17:14:50 -0400 Subject: [PATCH 1/2] Fix bug with constexpr initialization. --- clang/lib/Parse/ParseDecl.cpp | 12 ++++++- clang/test/CXX/expr/expr.const/p6-2a.cpp | 7 ++-- clang/test/SemaCXX/builtin_vectorelements.cpp | 4 +-- clang/test/SemaCXX/cxx2a-consteval.cpp | 32 ++++++++++++------- clang/unittests/Support/TimeProfilerTest.cpp | 1 - 5 files changed, 36 insertions(+), 20 deletions(-) diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 583232f2d610d0..0ea6fccaa7eb34 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -2554,6 +2554,13 @@ Decl *Parser::ParseDeclarationAfterDeclarator( return ParseDeclarationAfterDeclaratorAndAttributes(D, TemplateInfo); } +static bool isConstexprVariable(const Decl *D) { + if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(D)) + return Var->isConstexpr(); + + return false; +} + Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes( Declarator &D, const ParsedTemplateInfo &TemplateInfo, ForRangeInit *FRI) { // RAII type used to track whether we're inside an initializer. @@ -2561,9 +2568,12 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes( Parser &P; Declarator &D; Decl *ThisDecl; + llvm::SaveAndRestore<bool> ConstantContext; InitializerScopeRAII(Parser &P, Declarator &D, Decl *ThisDecl) - : P(P), D(D), ThisDecl(ThisDecl) { + : P(P), D(D), ThisDecl(ThisDecl), + ConstantContext(P.Actions.isConstantEvaluatedOverride, + isConstexprVariable(ThisDecl)) { if (ThisDecl && P.getLangOpts().CPlusPlus) { Scope *S = nullptr; if (D.getCXXScopeSpec().isSet()) { diff --git a/clang/test/CXX/expr/expr.const/p6-2a.cpp b/clang/test/CXX/expr/expr.const/p6-2a.cpp index a937474d53b221..8b940b2ee9fb2a 100644 --- a/clang/test/CXX/expr/expr.const/p6-2a.cpp +++ b/clang/test/CXX/expr/expr.const/p6-2a.cpp @@ -43,12 +43,11 @@ struct Temporary { constexpr Temporary t = {3}; // expected-error {{must have constant destruction}} expected-note {{created here}} expected-note {{in call}} namespace P1073R3 { -consteval int f() { return 42; } // expected-note 2 {{declared here}} +consteval int f() { return 42; } // expected-note {{declared here}} consteval auto g() { return f; } consteval int h(int (*p)() = g()) { return p(); } constexpr int r = h(); -constexpr auto e = g(); // expected-error {{call to consteval function 'P1073R3::g' is not a constant expression}} \ - expected-error {{constexpr variable 'e' must be initialized by a constant expression}} \ - expected-note 2 {{pointer to a consteval declaration is not a constant expression}} +constexpr auto e = g(); // expected-error {{constexpr variable 'e' must be initialized by a constant expression}} \ + expected-note {{pointer to a consteval declaration is not a constant expression}} static_assert(r == 42); } // namespace P1073R3 diff --git a/clang/test/SemaCXX/builtin_vectorelements.cpp b/clang/test/SemaCXX/builtin_vectorelements.cpp index 59ff09ac72e42d..12f2cbe57bd47d 100644 --- a/clang/test/SemaCXX/builtin_vectorelements.cpp +++ b/clang/test/SemaCXX/builtin_vectorelements.cpp @@ -42,11 +42,11 @@ void test_builtin_vectorelements() { #include <arm_sve.h> consteval int consteval_elements() { // expected-error {{consteval function never produces a constant expression}} - return __builtin_vectorelements(svuint64_t); // expected-note {{cannot determine number of elements for sizeless vectors in a constant expression}} // expected-note {{cannot determine number of elements for sizeless vectors in a constant expression}} // expected-note {{cannot determine number of elements for sizeless vectors in a constant expression}} + return __builtin_vectorelements(svuint64_t); // expected-note {{cannot determine number of elements for sizeless vectors in a constant expression}} // expected-note {{cannot determine number of elements for sizeless vectors in a constant expression}} } void test_bad_constexpr() { - constexpr int eval = consteval_elements(); // expected-error {{initialized by a constant expression}} // expected-error {{not a constant expression}} // expected-note {{in call}} // expected-note {{in call}} + constexpr int eval = consteval_elements(); // expected-error {{initialized by a constant expression}} // expected-note {{in call}} constexpr int i32 = __builtin_vectorelements(svuint32_t); // expected-error {{initialized by a constant expression}} // expected-note {{cannot determine number of elements for sizeless vectors in a constant expression}} constexpr int i16p8 = __builtin_vectorelements(svuint16_t) + 16; // expected-error {{initialized by a constant expression}} // expected-note {{cannot determine number of elements for sizeless vectors in a constant expression}} constexpr int lambda = [] { return __builtin_vectorelements(svuint16_t); }(); // expected-error {{initialized by a constant expression}} // expected-note {{cannot determine number of elements for sizeless vectors in a constant expression}} // expected-note {{in call}} diff --git a/clang/test/SemaCXX/cxx2a-consteval.cpp b/clang/test/SemaCXX/cxx2a-consteval.cpp index 192621225a543c..d1f3b094f8afd5 100644 --- a/clang/test/SemaCXX/cxx2a-consteval.cpp +++ b/clang/test/SemaCXX/cxx2a-consteval.cpp @@ -260,6 +260,18 @@ int(*test)(int) = l1; } +namespace lvalue_to_rvalue_init_from_heap { + +struct S { + int *value; + constexpr S(int v) : value(new int {v}) {} + constexpr ~S() { delete value; } +}; +consteval S fn() { return S(5); } + +constexpr int a = *fn().value; +} + namespace std { template <typename T> struct remove_reference { using type = T; }; @@ -713,7 +725,7 @@ constexpr derp d; struct test { consteval int operator[](int i) const { return {}; } consteval const derp * operator->() const { return &d; } - consteval int f() const { return 12; } // expected-note 2{{declared here}} + consteval int f() const { return 12; } // expected-note {{declared here}} }; constexpr test a; @@ -726,8 +738,7 @@ constexpr int s = a.operator[](1); constexpr int t = a[1]; constexpr int u = a.operator->()->b; constexpr int v = a->b; -// FIXME: I believe this case should work, but we currently reject. -constexpr int w = (a.*&test::f)(); // expected-error {{cannot take address of consteval function 'f' outside of an immediate invocation}} +constexpr int w = (a.*&test::f)(); constexpr int x = a.f(); // Show that we reject when not in an immediate context. @@ -1032,17 +1043,15 @@ int f() { namespace GH57682 { void test() { - constexpr auto l1 = []() consteval { // expected-error {{cannot take address of consteval call operator of '(lambda at}} \ - // expected-note 2{{declared here}} + constexpr auto l1 = []() consteval { // expected-note {{declared here}} return 3; }; constexpr int (*f1)(void) = l1; // expected-error {{constexpr variable 'f1' must be initialized by a constant expression}} \ // expected-note {{pointer to a consteval declaration is not a constant expression}} - constexpr auto lstatic = []() static consteval { // expected-error {{cannot take address of consteval call operator of '(lambda at}} \ - // expected-note 2{{declared here}} \ - // expected-warning {{extension}} + constexpr auto lstatic = []() static consteval { // expected-note {{declared here}} \ + // expected-warning {{extension}} return 3; }; constexpr int (*f2)(void) = lstatic; // expected-error {{constexpr variable 'f2' must be initialized by a constant expression}} \ @@ -1073,7 +1082,7 @@ struct tester { consteval const char* make_name(const char* name) { return name;} consteval const char* pad(int P) { return "thestring"; } -int bad = 10; // expected-note 6{{declared here}} +int bad = 10; // expected-note 5{{declared here}} tester glob1(make_name("glob1")); tester glob2(make_name("glob2")); @@ -1082,9 +1091,8 @@ tester paddedglob(make_name(pad(bad))); // expected-error {{call to consteval fu // expected-note {{read of non-const variable 'bad' is not allowed in a constant expression}} constexpr tester glob3 = { make_name("glob3") }; -constexpr tester glob4 = { make_name(pad(bad)) }; // expected-error {{call to consteval function 'GH58207::make_name' is not a constant expression}} \ - // expected-error {{constexpr variable 'glob4' must be initialized by a constant expression}} \ - // expected-note 2{{read of non-const variable 'bad' is not allowed in a constant expression}} +constexpr tester glob4 = { make_name(pad(bad)) }; // expected-error {{constexpr variable 'glob4' must be initialized by a constant expression}} \ + // expected-note 1{{read of non-const variable 'bad' is not allowed in a constant expression}} auto V = make_name(pad(3)); auto V1 = make_name(pad(bad)); // expected-error {{call to consteval function 'GH58207::make_name' is not a constant expression}} \ diff --git a/clang/unittests/Support/TimeProfilerTest.cpp b/clang/unittests/Support/TimeProfilerTest.cpp index 97fdbb7232b135..9c1a955743f1ee 100644 --- a/clang/unittests/Support/TimeProfilerTest.cpp +++ b/clang/unittests/Support/TimeProfilerTest.cpp @@ -193,7 +193,6 @@ Frontend | ParseDeclarationOrFunctionDefinition (test.cc:16:1) | | ParseFunctionDefinition (slow_test) | | | EvaluateAsInitializer (slow_value) -| | | EvaluateAsConstantExpr (<test.cc:17:33, col:59>) | | | EvaluateAsConstantExpr (<test.cc:18:11, col:37>) | ParseDeclarationOrFunctionDefinition (test.cc:22:1) | | EvaluateAsConstantExpr (<test.cc:23:31, col:57>) >From c9eaffe0538dd9435fe6824253fd9bef0b1eff3b Mon Sep 17 00:00:00 2001 From: "Daniel M. Katz" <kat...@gmail.com> Date: Mon, 22 Apr 2024 08:59:55 -0400 Subject: [PATCH 2/2] Use dyn_cast without checking for null Co-authored-by: cor3ntin <corentinja...@gmail.com> --- clang/lib/Parse/ParseDecl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 0ea6fccaa7eb34..c8c876bf1fffea 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -2555,7 +2555,7 @@ Decl *Parser::ParseDeclarationAfterDeclarator( } static bool isConstexprVariable(const Decl *D) { - if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(D)) + if (const VarDecl *Var = dyn_cast<VarDecl>(D)) return Var->isConstexpr(); return false; _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits