cor3ntin created this revision. Herald added a project: All. cor3ntin requested review of this revision. Herald added a project: clang. Herald added a subscriber: cfe-commits.
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 Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D144627 Files: 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
Index: clang/test/SemaCXX/cxx2a-consteval.cpp =================================================================== --- clang/test/SemaCXX/cxx2a-consteval.cpp +++ 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}} + +} +} Index: clang/test/AST/ast-dump-lambda.cpp =================================================================== --- clang/test/AST/ast-dump-lambda.cpp +++ clang/test/AST/ast-dump-lambda.cpp @@ -246,7 +246,7 @@ // 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 Index: clang/test/AST/ast-dump-expr.cpp =================================================================== --- clang/test/AST/ast-dump-expr.cpp +++ clang/test/AST/ast-dump-expr.cpp @@ -464,7 +464,7 @@ // 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 {}; Index: clang/test/AST/ast-dump-expr-json.cpp =================================================================== --- clang/test/AST/ast-dump-expr-json.cpp +++ 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: }, Index: clang/lib/Sema/SemaLambda.cpp =================================================================== --- clang/lib/Sema/SemaLambda.cpp +++ 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); Index: clang/lib/Sema/SemaExpr.cpp =================================================================== --- clang/lib/Sema/SemaExpr.cpp +++ clang/lib/Sema/SemaExpr.cpp @@ -17974,8 +17974,13 @@ EvaluateAndDiagnoseImmediateInvocation(SemaRef, CE); for (auto *DR : Rec.ReferenceToConsteval) { auto *FD = cast<FunctionDecl>(DR->getDecl()); - SemaRef.Diag(DR->getBeginLoc(), diag::err_invalid_consteval_take_address) - << FD; + if(auto* MD = llvm::dyn_cast<CXXMethodDecl>(FD); MD && (MD->isLambdaStaticInvoker() || isLambdaCallOperator(MD))) + SemaRef.Diag(DR->getBeginLoc(), diag::err_invalid_consteval_take_address) + << MD->getParent() << 1; + else + SemaRef.Diag(DR->getBeginLoc(), diag::err_invalid_consteval_take_address) + << FD << 0; + SemaRef.Diag(FD->getLocation(), diag::note_declared_at); } } Index: clang/include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticSemaKinds.td +++ clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -2648,7 +2648,7 @@ "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">;
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits