[clang] 34abc5b - [Clang] Fix a crash when taking the address of a consteval lambda
Corentin Jabot via cfe-commits
cfe-commits at lists.llvm.org
Thu Feb 23 06:26:44 PST 2023
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}}
+
+}
+}
More information about the cfe-commits
mailing list