diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -153,6 +153,8 @@ - Fix __VA_OPT__ implementation so that it treats the concatenation of a non-placemaker token and placemaker token as a non-placemaker token. (`#60268 `_) +- Fix crash when taking the address of a consteval lambda call operator. + (`#57682 `_) Bug Fixes to Compiler Builtins ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -2648,7 +2648,7 @@ "in C++14; add 'const' to avoid a change in behavior">, InGroup>; 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 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -17985,10 +17985,13 @@ if (!CE.getInt()) EvaluateAndDiagnoseImmediateInvocation(SemaRef, CE); for (auto *DR : Rec.ReferenceToConsteval) { - auto *FD = cast(DR->getDecl()); + NamedDecl *ND = cast(DR->getDecl()); + if (auto *MD = llvm::dyn_cast(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(ND); + SemaRef.Diag(ND->getLocation(), diag::note_declared_at); } } diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp --- a/clang/lib/Sema/SemaLambda.cpp +++ b/clang/lib/Sema/SemaLambda.cpp @@ -1529,7 +1529,7 @@ 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 --- a/clang/test/AST/ast-dump-expr-json.cpp +++ b/clang/test/AST/ast-dump-expr-json.cpp @@ -6867,7 +6867,8 @@ // 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 --- a/clang/test/AST/ast-dump-expr.cpp +++ b/clang/test/AST/ast-dump-expr.cpp @@ -464,7 +464,7 @@ // CHECK-NEXT: CXXMethodDecl 0x{{[^ ]*}} col:3 constexpr operator() 'auto () const' inline // CHECK-NEXT: CompoundStmt // CHECK-NEXT: CXXConversionDecl 0x{{[^ ]*}} col:3 implicit constexpr operator auto (*)() 'auto (*() const noexcept)()' inline - // CHECK-NEXT: CXXMethodDecl 0x{{[^ ]*}} col:3 implicit __invoke 'auto ()' static inline + // CHECK-NEXT: CXXMethodDecl 0x{{[^ ]*}} col:3 implicit constexpr __invoke 'auto ()' static inline // CHECK-NEXT: CompoundStmt 0x{{[^ ]*}} []() mutable {}; diff --git a/clang/test/AST/ast-dump-lambda.cpp b/clang/test/AST/ast-dump-lambda.cpp --- a/clang/test/AST/ast-dump-lambda.cpp +++ b/clang/test/AST/ast-dump-lambda.cpp @@ -246,7 +246,7 @@ // CHECK-NEXT: | | |-CXXMethodDecl {{.*}} col:3{{( imported)?}} constexpr operator() 'auto () const' inline // CHECK-NEXT: | | | `-CompoundStmt {{.*}} // CHECK-NEXT: | | |-CXXConversionDecl {{.*}} col:3{{( imported)?}} implicit constexpr operator auto (*)() 'auto (*() const noexcept)()' inline -// CHECK-NEXT: | | `-CXXMethodDecl {{.*}} col:3{{( imported)?}} implicit __invoke 'auto ()' static inline +// CHECK-NEXT: | | `-CXXMethodDecl {{.*}} col:3{{( imported)?}} implicit constexpr __invoke 'auto ()' static inline // CHECK-NEXT: | `-CompoundStmt {{.*}} // CHECK-NEXT: |-LambdaExpr {{.*}} '(lambda at {{.*}}ast-dump-lambda.cpp:33:3)' // CHECK-NEXT: | |-CXXRecordDecl {{.*}} col:3{{( imported)?}} implicit{{( )?}} class definition diff --git a/clang/test/SemaCXX/cxx2a-consteval.cpp b/clang/test/SemaCXX/cxx2a-consteval.cpp --- a/clang/test/SemaCXX/cxx2a-consteval.cpp +++ b/clang/test/SemaCXX/cxx2a-consteval.cpp @@ -1029,3 +1029,24 @@ 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}} + +} +}