Author: Corentin Jabot Date: 2023-02-23T15:26:37+01:00 New Revision: 34abc5b75d9d995ded56a9534c230300b06f1439
URL: https://github.com/llvm/llvm-project/commit/34abc5b75d9d995ded56a9534c230300b06f1439 DIFF: https://github.com/llvm/llvm-project/commit/34abc5b75d9d995ded56a9534c230300b06f1439.diff LOG: [Clang] Fix a crash when taking the address of a consteval lambda The `_invoke` function of lambdas was not respecting the constexpr/consteval specifier of the call operator, so it was possible to take its address in a non-immmediately invoked context, even if the call operator was itself consteval. In addition, we improve the diagnostic emmited in the lambda case not to show that `invoke` method. Fixes #57682 Reviewed By: aaron.ballman, #clang-language-wg Differential Revision: https://reviews.llvm.org/D144627 Added: Modified: clang/docs/ReleaseNotes.rst clang/include/clang/Basic/DiagnosticSemaKinds.td clang/lib/Sema/SemaExpr.cpp clang/lib/Sema/SemaLambda.cpp clang/test/AST/ast-dump-expr-json.cpp clang/test/AST/ast-dump-expr.cpp clang/test/AST/ast-dump-lambda.cpp clang/test/SemaCXX/cxx2a-consteval.cpp Removed: ################################################################################ diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index be3ea5ff63cde..0c8d3d9411b12 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -153,6 +153,8 @@ Bug Fixes in This Version - Fix __VA_OPT__ implementation so that it treats the concatenation of a non-placemaker token and placemaker token as a non-placemaker token. (`#60268 <https://github.com/llvm/llvm-project/issues/60268>`_) +- Fix crash when taking the address of a consteval lambda call operator. + (`#57682 <https://github.com/llvm/llvm-project/issues/57682>`_) Bug Fixes to Compiler Builtins ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index b69920b001cc9..86c5c4e288c99 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -2648,7 +2648,7 @@ def warn_cxx14_compat_constexpr_not_const : Warning< "in C++14; add 'const' to avoid a change in behavior">, InGroup<DiagGroup<"constexpr-not-const">>; def err_invalid_consteval_take_address : Error< - "cannot take address of consteval function %0 outside" + "cannot take address of consteval %select{function|call operator of}1 %0 outside" " of an immediate invocation">; def err_invalid_consteval_call : Error< "call to consteval function %q0 is not a constant expression">; diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index a5e8e664ab160..922f102f29872 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -17985,10 +17985,13 @@ HandleImmediateInvocations(Sema &SemaRef, if (!CE.getInt()) EvaluateAndDiagnoseImmediateInvocation(SemaRef, CE); for (auto *DR : Rec.ReferenceToConsteval) { - auto *FD = cast<FunctionDecl>(DR->getDecl()); + NamedDecl *ND = cast<FunctionDecl>(DR->getDecl()); + if (auto *MD = llvm::dyn_cast<CXXMethodDecl>(ND); + MD && (MD->isLambdaStaticInvoker() || isLambdaCallOperator(MD))) + ND = MD->getParent(); SemaRef.Diag(DR->getBeginLoc(), diag::err_invalid_consteval_take_address) - << FD; - SemaRef.Diag(FD->getLocation(), diag::note_declared_at); + << ND << isa<CXXRecordDecl>(ND); + SemaRef.Diag(ND->getLocation(), diag::note_declared_at); } } diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp index 00ab6ba580bfe..e3614b254737e 100644 --- a/clang/lib/Sema/SemaLambda.cpp +++ b/clang/lib/Sema/SemaLambda.cpp @@ -1529,7 +1529,7 @@ static void addFunctionPointerConversion(Sema &S, SourceRange IntroducerRange, S.Context, Class, Loc, DeclarationNameInfo(InvokerName, Loc), InvokerFunctionTy, CallOperator->getTypeSourceInfo(), SC_Static, S.getCurFPFeatures().isFPConstrained(), - /*isInline=*/true, ConstexprSpecKind::Unspecified, + /*isInline=*/true, CallOperator->getConstexprKind(), CallOperator->getBody()->getEndLoc()); for (unsigned I = 0, N = CallOperator->getNumParams(); I != N; ++I) InvokerParams[I]->setOwningFunction(Invoke); diff --git a/clang/test/AST/ast-dump-expr-json.cpp b/clang/test/AST/ast-dump-expr-json.cpp index f166698556acc..eac0346d64319 100644 --- a/clang/test/AST/ast-dump-expr-json.cpp +++ b/clang/test/AST/ast-dump-expr-json.cpp @@ -6867,7 +6867,8 @@ void TestNonADLCall3() { // CHECK-NEXT: "qualType": "auto ()" // CHECK-NEXT: }, // CHECK-NEXT: "storageClass": "static", -// CHECK-NEXT: "inline": true +// CHECK-NEXT: "inline": true, +// CHECK-NEXT: "constexpr": true // CHECK-NEXT: } // CHECK-NEXT: ] // CHECK-NEXT: }, diff --git a/clang/test/AST/ast-dump-expr.cpp b/clang/test/AST/ast-dump-expr.cpp index a0324e602f670..490698e9a9426 100644 --- a/clang/test/AST/ast-dump-expr.cpp +++ b/clang/test/AST/ast-dump-expr.cpp @@ -464,7 +464,7 @@ void PrimaryExpressions(Ts... a) { // CHECK-NEXT: CXXMethodDecl 0x{{[^ ]*}} <col:8, col:19> col:3 constexpr operator() 'auto () const' inline // CHECK-NEXT: CompoundStmt // CHECK-NEXT: CXXConversionDecl 0x{{[^ ]*}} <col:3, col:19> col:3 implicit constexpr operator auto (*)() 'auto (*() const noexcept)()' inline - // CHECK-NEXT: CXXMethodDecl 0x{{[^ ]*}} <col:3, col:19> col:3 implicit __invoke 'auto ()' static inline + // CHECK-NEXT: CXXMethodDecl 0x{{[^ ]*}} <col:3, col:19> col:3 implicit constexpr __invoke 'auto ()' static inline // CHECK-NEXT: CompoundStmt 0x{{[^ ]*}} <col:18, col:19> []() mutable {}; diff --git a/clang/test/AST/ast-dump-lambda.cpp b/clang/test/AST/ast-dump-lambda.cpp index bd1b1beef15fb..7150a3f1eab64 100644 --- a/clang/test/AST/ast-dump-lambda.cpp +++ b/clang/test/AST/ast-dump-lambda.cpp @@ -246,7 +246,7 @@ template <typename... Ts> void test(Ts... a) { // CHECK-NEXT: | | |-CXXMethodDecl {{.*}} <col:8, col:19> col:3{{( imported)?}} constexpr operator() 'auto () const' inline // CHECK-NEXT: | | | `-CompoundStmt {{.*}} <col:18, col:19> // CHECK-NEXT: | | |-CXXConversionDecl {{.*}} <col:3, col:19> col:3{{( imported)?}} implicit constexpr operator auto (*)() 'auto (*() const noexcept)()' inline -// CHECK-NEXT: | | `-CXXMethodDecl {{.*}} <col:3, col:19> col:3{{( imported)?}} implicit __invoke 'auto ()' static inline +// CHECK-NEXT: | | `-CXXMethodDecl {{.*}} <col:3, col:19> col:3{{( imported)?}} implicit constexpr __invoke 'auto ()' static inline // CHECK-NEXT: | `-CompoundStmt {{.*}} <col:18, col:19> // CHECK-NEXT: |-LambdaExpr {{.*}} <line:33:3, col:17> '(lambda at {{.*}}ast-dump-lambda.cpp:33:3)' // CHECK-NEXT: | |-CXXRecordDecl {{.*}} <col:3> col:3{{( imported)?}} implicit{{( <undeserialized declarations>)?}} class definition diff --git a/clang/test/SemaCXX/cxx2a-consteval.cpp b/clang/test/SemaCXX/cxx2a-consteval.cpp index 6ae2664046d71..3047c3f51b5ec 100644 --- a/clang/test/SemaCXX/cxx2a-consteval.cpp +++ b/clang/test/SemaCXX/cxx2a-consteval.cpp @@ -1029,3 +1029,24 @@ int f() { int x = A{}; } } + +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}} + 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}} + return 3; + }; + constexpr int (*f2)(void) = lstatic; // expected-error {{constexpr variable 'f2' must be initialized by a constant expression}} \ + // expected-note {{pointer to a consteval declaration is not a constant expression}} + +} +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits