Skip to content

Commit bc9dd6f

Browse files
author
git apple-llvm automerger
committed
Merge commit 'bd77a26e9a15' from llvm.org/main into next
2 parents 034177a + bd77a26 commit bc9dd6f

File tree

3 files changed

+111
-55
lines changed

3 files changed

+111
-55
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,9 @@ Bug Fixes to C++ Support
373373
and (`#74494 <https://github.com/llvm/llvm-project/issues/74494>`_)
374374
- Allow access to a public template alias declaration that refers to friend's
375375
private nested type. (#GH25708).
376+
- Fixed a crash in constant evaluation when trying to access a
377+
captured ``this`` pointer in a lambda with an explicit object parameter.
378+
Fixes (#GH80997)
376379

377380
Bug Fixes to AST Handling
378381
^^^^^^^^^^^^^^^^^^^^^^^^^

clang/lib/AST/ExprConstant.cpp

Lines changed: 74 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -8519,6 +8519,53 @@ class LValueExprEvaluator
85198519
};
85208520
} // end anonymous namespace
85218521

8522+
/// Get an lvalue to a field of a lambda's closure type.
8523+
static bool HandleLambdaCapture(EvalInfo &Info, const Expr *E, LValue &Result,
8524+
const CXXMethodDecl *MD, const FieldDecl *FD,
8525+
bool LValueToRValueConversion) {
8526+
// Static lambda function call operators can't have captures. We already
8527+
// diagnosed this, so bail out here.
8528+
if (MD->isStatic()) {
8529+
assert(Info.CurrentCall->This == nullptr &&
8530+
"This should not be set for a static call operator");
8531+
return false;
8532+
}
8533+
8534+
// Start with 'Result' referring to the complete closure object...
8535+
if (MD->isExplicitObjectMemberFunction()) {
8536+
// Self may be passed by reference or by value.
8537+
const ParmVarDecl *Self = MD->getParamDecl(0);
8538+
if (Self->getType()->isReferenceType()) {
8539+
APValue *RefValue = Info.getParamSlot(Info.CurrentCall->Arguments, Self);
8540+
Result.setFrom(Info.Ctx, *RefValue);
8541+
} else {
8542+
const ParmVarDecl *VD = Info.CurrentCall->Arguments.getOrigParam(Self);
8543+
CallStackFrame *Frame =
8544+
Info.getCallFrameAndDepth(Info.CurrentCall->Arguments.CallIndex)
8545+
.first;
8546+
unsigned Version = Info.CurrentCall->Arguments.Version;
8547+
Result.set({VD, Frame->Index, Version});
8548+
}
8549+
} else
8550+
Result = *Info.CurrentCall->This;
8551+
8552+
// ... then update it to refer to the field of the closure object
8553+
// that represents the capture.
8554+
if (!HandleLValueMember(Info, E, Result, FD))
8555+
return false;
8556+
8557+
// And if the field is of reference type (or if we captured '*this' by
8558+
// reference), update 'Result' to refer to what
8559+
// the field refers to.
8560+
if (LValueToRValueConversion) {
8561+
APValue RVal;
8562+
if (!handleLValueToRValueConversion(Info, E, FD->getType(), Result, RVal))
8563+
return false;
8564+
Result.setFrom(Info.Ctx, RVal);
8565+
}
8566+
return true;
8567+
}
8568+
85228569
/// Evaluate an expression as an lvalue. This can be legitimately called on
85238570
/// expressions which are not glvalues, in three cases:
85248571
/// * function designators in C, and
@@ -8563,37 +8610,8 @@ bool LValueExprEvaluator::VisitVarDecl(const Expr *E, const VarDecl *VD) {
85638610

85648611
if (auto *FD = Info.CurrentCall->LambdaCaptureFields.lookup(VD)) {
85658612
const auto *MD = cast<CXXMethodDecl>(Info.CurrentCall->Callee);
8566-
8567-
// Static lambda function call operators can't have captures. We already
8568-
// diagnosed this, so bail out here.
8569-
if (MD->isStatic()) {
8570-
assert(Info.CurrentCall->This == nullptr &&
8571-
"This should not be set for a static call operator");
8572-
return false;
8573-
}
8574-
8575-
// Start with 'Result' referring to the complete closure object...
8576-
if (MD->isExplicitObjectMemberFunction()) {
8577-
APValue *RefValue =
8578-
Info.getParamSlot(Info.CurrentCall->Arguments, MD->getParamDecl(0));
8579-
Result.setFrom(Info.Ctx, *RefValue);
8580-
} else
8581-
Result = *Info.CurrentCall->This;
8582-
8583-
// ... then update it to refer to the field of the closure object
8584-
// that represents the capture.
8585-
if (!HandleLValueMember(Info, E, Result, FD))
8586-
return false;
8587-
// And if the field is of reference type, update 'Result' to refer to what
8588-
// the field refers to.
8589-
if (FD->getType()->isReferenceType()) {
8590-
APValue RVal;
8591-
if (!handleLValueToRValueConversion(Info, E, FD->getType(), Result,
8592-
RVal))
8593-
return false;
8594-
Result.setFrom(Info.Ctx, RVal);
8595-
}
8596-
return true;
8613+
return HandleLambdaCapture(Info, E, Result, MD, FD,
8614+
FD->getType()->isReferenceType());
85978615
}
85988616
}
85998617

@@ -9071,45 +9089,46 @@ class PointerExprEvaluator
90719089
return Error(E);
90729090
}
90739091
bool VisitCXXThisExpr(const CXXThisExpr *E) {
9074-
// Can't look at 'this' when checking a potential constant expression.
9075-
if (Info.checkingPotentialConstantExpression())
9076-
return false;
9077-
if (!Info.CurrentCall->This) {
9092+
auto DiagnoseInvalidUseOfThis = [&] {
90789093
if (Info.getLangOpts().CPlusPlus11)
90799094
Info.FFDiag(E, diag::note_constexpr_this) << E->isImplicit();
90809095
else
90819096
Info.FFDiag(E);
9097+
};
9098+
9099+
// Can't look at 'this' when checking a potential constant expression.
9100+
if (Info.checkingPotentialConstantExpression())
90829101
return false;
9102+
9103+
bool IsExplicitLambda =
9104+
isLambdaCallWithExplicitObjectParameter(Info.CurrentCall->Callee);
9105+
if (!IsExplicitLambda) {
9106+
if (!Info.CurrentCall->This) {
9107+
DiagnoseInvalidUseOfThis();
9108+
return false;
9109+
}
9110+
9111+
Result = *Info.CurrentCall->This;
90839112
}
9084-
Result = *Info.CurrentCall->This;
90859113

90869114
if (isLambdaCallOperator(Info.CurrentCall->Callee)) {
90879115
// Ensure we actually have captured 'this'. If something was wrong with
90889116
// 'this' capture, the error would have been previously reported.
90899117
// Otherwise we can be inside of a default initialization of an object
90909118
// declared by lambda's body, so no need to return false.
9091-
if (!Info.CurrentCall->LambdaThisCaptureField)
9092-
return true;
9093-
9094-
// If we have captured 'this', the 'this' expression refers
9095-
// to the enclosing '*this' object (either by value or reference) which is
9096-
// either copied into the closure object's field that represents the
9097-
// '*this' or refers to '*this'.
9098-
// Update 'Result' to refer to the data member/field of the closure object
9099-
// that represents the '*this' capture.
9100-
if (!HandleLValueMember(Info, E, Result,
9101-
Info.CurrentCall->LambdaThisCaptureField))
9102-
return false;
9103-
// If we captured '*this' by reference, replace the field with its referent.
9104-
if (Info.CurrentCall->LambdaThisCaptureField->getType()
9105-
->isPointerType()) {
9106-
APValue RVal;
9107-
if (!handleLValueToRValueConversion(Info, E, E->getType(), Result,
9108-
RVal))
9119+
if (!Info.CurrentCall->LambdaThisCaptureField) {
9120+
if (IsExplicitLambda && !Info.CurrentCall->This) {
9121+
DiagnoseInvalidUseOfThis();
91099122
return false;
9123+
}
91109124

9111-
Result.setFrom(Info.Ctx, RVal);
9125+
return true;
91129126
}
9127+
9128+
const auto *MD = cast<CXXMethodDecl>(Info.CurrentCall->Callee);
9129+
return HandleLambdaCapture(
9130+
Info, E, Result, MD, Info.CurrentCall->LambdaThisCaptureField,
9131+
Info.CurrentCall->LambdaThisCaptureField->getType()->isPointerType());
91139132
}
91149133
return true;
91159134
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// RUN: %clang_cc1 -std=c++23 -verify %s
2+
// expected-no-diagnostics
3+
4+
struct S {
5+
int i = 42;
6+
constexpr auto f1() {
7+
return [this](this auto) {
8+
return this->i;
9+
}();
10+
};
11+
12+
constexpr auto f2() {
13+
return [this](this auto&&) {
14+
return this->i;
15+
}();
16+
};
17+
18+
constexpr auto f3() {
19+
return [i = this->i](this auto) {
20+
return i;
21+
}();
22+
};
23+
24+
constexpr auto f4() {
25+
return [i = this->i](this auto&&) {
26+
return i;
27+
}();
28+
};
29+
};
30+
31+
static_assert(S().f1() == 42);
32+
static_assert(S().f2() == 42);
33+
static_assert(S().f3() == 42);
34+
static_assert(S().f4() == 42);

0 commit comments

Comments
 (0)