Skip to content

Commit 8fa3dc4

Browse files
committed
[clang] reject to capture variable in RequiresExprBodyDecl
Expression in `RequiresExprBodyDecl` is resolved as constants and should not be captured. Fixes: #69307, #76593.
1 parent e611a4c commit 8fa3dc4

File tree

2 files changed

+38
-8
lines changed

2 files changed

+38
-8
lines changed

clang/lib/Sema/SemaExpr.cpp

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19704,22 +19704,28 @@ static void buildLambdaCaptureFixit(Sema &Sema, LambdaScopeInfo *LSI,
1970419704
}
1970519705
}
1970619706

19707+
static DeclContext *ignoreReuquiresBodyDecl(DeclContext *DC) {
19708+
if (isa_and_present<RequiresExprBodyDecl>(DC))
19709+
return DC->getParent();
19710+
return DC;
19711+
}
19712+
1970719713
bool Sema::tryCaptureVariable(
1970819714
ValueDecl *Var, SourceLocation ExprLoc, TryCaptureKind Kind,
1970919715
SourceLocation EllipsisLoc, bool BuildAndDiagnose, QualType &CaptureType,
1971019716
QualType &DeclRefType, const unsigned *const FunctionScopeIndexToStopAt) {
1971119717
// An init-capture is notionally from the context surrounding its
1971219718
// declaration, but its parent DC is the lambda class.
1971319719
DeclContext *VarDC = Var->getDeclContext();
19714-
DeclContext *DC = CurContext;
19715-
1971619720
// tryCaptureVariable is called every time a DeclRef is formed,
1971719721
// it can therefore have non-negigible impact on performances.
1971819722
// For local variables and when there is no capturing scope,
1971919723
// we can bailout early.
19720-
if (CapturingFunctionScopes == 0 && (!BuildAndDiagnose || VarDC == DC))
19724+
if (CapturingFunctionScopes == 0 && (!BuildAndDiagnose || VarDC == CurContext))
1972119725
return true;
1972219726

19727+
DeclContext *DC = ignoreReuquiresBodyDecl(CurContext);
19728+
1972319729
const auto *VD = dyn_cast<VarDecl>(Var);
1972419730
if (VD) {
1972519731
if (VD->isInitCapture())
@@ -19789,11 +19795,10 @@ bool Sema::tryCaptureVariable(
1978919795

1979019796
// Only block literals, captured statements, and lambda expressions can
1979119797
// capture; other scopes don't work.
19792-
DeclContext *ParentDC =
19793-
!IsInScopeDeclarationContext
19794-
? DC->getParent()
19795-
: getParentOfCapturingContextOrNull(DC, Var, ExprLoc,
19796-
BuildAndDiagnose, *this);
19798+
DeclContext *ParentDC = IsInScopeDeclarationContext
19799+
? getParentOfCapturingContextOrNull(
19800+
DC, Var, ExprLoc, BuildAndDiagnose, *this)
19801+
: DC->getParent();
1979719802
// We need to check for the parent *first* because, if we *have*
1979819803
// private-captured a global variable, we need to recursively capture it in
1979919804
// intermediate blocks, lambdas, etc.
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// RUN: %clang -fsyntax-only -std=c++20 -Xclang -verify %s
2+
3+
// expected-no-diagnostics
4+
5+
auto GH69307_Func_1() {
6+
constexpr auto b = 1;
7+
return [&](auto c) -> int
8+
requires requires { b + c; }
9+
{ return 1; };
10+
};
11+
auto GH69307_Func_Ret = GH69307_Func_1()(1);
12+
13+
auto GH69307_Lambda_1 = []() {
14+
return [&](auto c) -> int
15+
requires requires { c; }
16+
{ return 1; };
17+
};
18+
auto GH69307_Lambda_1_Ret = GH69307_Lambda_1()(1);
19+
20+
auto GH69307_Lambda_2 = [](auto c) {
21+
return [&]() -> int
22+
requires requires { c; }
23+
{ return 1; };
24+
};
25+
auto GH69307_Lambda_2_Ret = GH69307_Lambda_2(1)();

0 commit comments

Comments
 (0)