Skip to content

Commit 34abc5b

Browse files
committed
[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 llvm#57682 Reviewed By: aaron.ballman, #clang-language-wg Differential Revision: https://reviews.llvm.org/D144627
1 parent 0eb45cd commit 34abc5b

File tree

8 files changed

+35
-8
lines changed

8 files changed

+35
-8
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,8 @@ Bug Fixes in This Version
153153
- Fix __VA_OPT__ implementation so that it treats the concatenation of a
154154
non-placemaker token and placemaker token as a non-placemaker token.
155155
(`#60268 <https://github.com/llvm/llvm-project/issues/60268>`_)
156+
- Fix crash when taking the address of a consteval lambda call operator.
157+
(`#57682 <https://github.com/llvm/llvm-project/issues/57682>`_)
156158

157159
Bug Fixes to Compiler Builtins
158160
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2648,7 +2648,7 @@ def warn_cxx14_compat_constexpr_not_const : Warning<
26482648
"in C++14; add 'const' to avoid a change in behavior">,
26492649
InGroup<DiagGroup<"constexpr-not-const">>;
26502650
def err_invalid_consteval_take_address : Error<
2651-
"cannot take address of consteval function %0 outside"
2651+
"cannot take address of consteval %select{function|call operator of}1 %0 outside"
26522652
" of an immediate invocation">;
26532653
def err_invalid_consteval_call : Error<
26542654
"call to consteval function %q0 is not a constant expression">;

clang/lib/Sema/SemaExpr.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17985,10 +17985,13 @@ HandleImmediateInvocations(Sema &SemaRef,
1798517985
if (!CE.getInt())
1798617986
EvaluateAndDiagnoseImmediateInvocation(SemaRef, CE);
1798717987
for (auto *DR : Rec.ReferenceToConsteval) {
17988-
auto *FD = cast<FunctionDecl>(DR->getDecl());
17988+
NamedDecl *ND = cast<FunctionDecl>(DR->getDecl());
17989+
if (auto *MD = llvm::dyn_cast<CXXMethodDecl>(ND);
17990+
MD && (MD->isLambdaStaticInvoker() || isLambdaCallOperator(MD)))
17991+
ND = MD->getParent();
1798917992
SemaRef.Diag(DR->getBeginLoc(), diag::err_invalid_consteval_take_address)
17990-
<< FD;
17991-
SemaRef.Diag(FD->getLocation(), diag::note_declared_at);
17993+
<< ND << isa<CXXRecordDecl>(ND);
17994+
SemaRef.Diag(ND->getLocation(), diag::note_declared_at);
1799217995
}
1799317996
}
1799417997

clang/lib/Sema/SemaLambda.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1529,7 +1529,7 @@ static void addFunctionPointerConversion(Sema &S, SourceRange IntroducerRange,
15291529
S.Context, Class, Loc, DeclarationNameInfo(InvokerName, Loc),
15301530
InvokerFunctionTy, CallOperator->getTypeSourceInfo(), SC_Static,
15311531
S.getCurFPFeatures().isFPConstrained(),
1532-
/*isInline=*/true, ConstexprSpecKind::Unspecified,
1532+
/*isInline=*/true, CallOperator->getConstexprKind(),
15331533
CallOperator->getBody()->getEndLoc());
15341534
for (unsigned I = 0, N = CallOperator->getNumParams(); I != N; ++I)
15351535
InvokerParams[I]->setOwningFunction(Invoke);

clang/test/AST/ast-dump-expr-json.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6867,7 +6867,8 @@ void TestNonADLCall3() {
68676867
// CHECK-NEXT: "qualType": "auto ()"
68686868
// CHECK-NEXT: },
68696869
// CHECK-NEXT: "storageClass": "static",
6870-
// CHECK-NEXT: "inline": true
6870+
// CHECK-NEXT: "inline": true,
6871+
// CHECK-NEXT: "constexpr": true
68716872
// CHECK-NEXT: }
68726873
// CHECK-NEXT: ]
68736874
// CHECK-NEXT: },

clang/test/AST/ast-dump-expr.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -464,7 +464,7 @@ void PrimaryExpressions(Ts... a) {
464464
// CHECK-NEXT: CXXMethodDecl 0x{{[^ ]*}} <col:8, col:19> col:3 constexpr operator() 'auto () const' inline
465465
// CHECK-NEXT: CompoundStmt
466466
// CHECK-NEXT: CXXConversionDecl 0x{{[^ ]*}} <col:3, col:19> col:3 implicit constexpr operator auto (*)() 'auto (*() const noexcept)()' inline
467-
// CHECK-NEXT: CXXMethodDecl 0x{{[^ ]*}} <col:3, col:19> col:3 implicit __invoke 'auto ()' static inline
467+
// CHECK-NEXT: CXXMethodDecl 0x{{[^ ]*}} <col:3, col:19> col:3 implicit constexpr __invoke 'auto ()' static inline
468468
// CHECK-NEXT: CompoundStmt 0x{{[^ ]*}} <col:18, col:19>
469469

470470
[]() mutable {};

clang/test/AST/ast-dump-lambda.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@ template <typename... Ts> void test(Ts... a) {
246246
// CHECK-NEXT: | | |-CXXMethodDecl {{.*}} <col:8, col:19> col:3{{( imported)?}} constexpr operator() 'auto () const' inline
247247
// CHECK-NEXT: | | | `-CompoundStmt {{.*}} <col:18, col:19>
248248
// CHECK-NEXT: | | |-CXXConversionDecl {{.*}} <col:3, col:19> col:3{{( imported)?}} implicit constexpr operator auto (*)() 'auto (*() const noexcept)()' inline
249-
// CHECK-NEXT: | | `-CXXMethodDecl {{.*}} <col:3, col:19> col:3{{( imported)?}} implicit __invoke 'auto ()' static inline
249+
// CHECK-NEXT: | | `-CXXMethodDecl {{.*}} <col:3, col:19> col:3{{( imported)?}} implicit constexpr __invoke 'auto ()' static inline
250250
// CHECK-NEXT: | `-CompoundStmt {{.*}} <col:18, col:19>
251251
// CHECK-NEXT: |-LambdaExpr {{.*}} <line:33:3, col:17> '(lambda at {{.*}}ast-dump-lambda.cpp:33:3)'
252252
// CHECK-NEXT: | |-CXXRecordDecl {{.*}} <col:3> col:3{{( imported)?}} implicit{{( <undeserialized declarations>)?}} class definition

clang/test/SemaCXX/cxx2a-consteval.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1029,3 +1029,24 @@ int f() {
10291029
int x = A{};
10301030
}
10311031
}
1032+
1033+
namespace GH57682 {
1034+
void test() {
1035+
constexpr auto l1 = []() consteval { // expected-error {{cannot take address of consteval call operator of '(lambda at}} \
1036+
// expected-note 2{{declared here}}
1037+
return 3;
1038+
};
1039+
constexpr int (*f1)(void) = l1; // expected-error {{constexpr variable 'f1' must be initialized by a constant expression}} \
1040+
// expected-note {{pointer to a consteval declaration is not a constant expression}}
1041+
1042+
1043+
constexpr auto lstatic = []() static consteval { // expected-error {{cannot take address of consteval call operator of '(lambda at}} \
1044+
// expected-note 2{{declared here}} \
1045+
// expected-warning {{extension}}
1046+
return 3;
1047+
};
1048+
constexpr int (*f2)(void) = lstatic; // expected-error {{constexpr variable 'f2' must be initialized by a constant expression}} \
1049+
// expected-note {{pointer to a consteval declaration is not a constant expression}}
1050+
1051+
}
1052+
}

0 commit comments

Comments
 (0)