Skip to content

Commit 00bb658

Browse files
author
git apple-llvm automerger
committed
Merge commit '3d361b225fe8' from llvm.org/main into next
2 parents 5ad554d + 3d361b2 commit 00bb658

File tree

7 files changed

+116
-11
lines changed

7 files changed

+116
-11
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -824,6 +824,8 @@ Bug Fixes to C++ Support
824824
- Fix a crash when a variable is captured by a block nested inside a lambda. (Fixes #GH93625).
825825
- Fixed a type constraint substitution issue involving a generic lambda expression. (#GH93821)
826826
- Fix a crash caused by improper use of ``__array_extent``. (#GH80474)
827+
- Fixed several bugs in capturing variables within unevaluated contexts. (#GH63845), (#GH67260), (#GH69307),
828+
(#GH88081), (#GH89496), (#GH90669) and (#GH91633).
827829

828830
Bug Fixes to AST Handling
829831
^^^^^^^^^^^^^^^^^^^^^^^^^

clang/include/clang/AST/DeclBase.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2148,6 +2148,10 @@ class DeclContext {
21482148
getDeclKind() <= Decl::lastRecord;
21492149
}
21502150

2151+
bool isRequiresExprBody() const {
2152+
return getDeclKind() == Decl::RequiresExprBody;
2153+
}
2154+
21512155
bool isNamespace() const { return getDeclKind() == Decl::Namespace; }
21522156

21532157
bool isStdNamespace() const;

clang/lib/Parse/ParseExprCXX.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1581,7 +1581,10 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
15811581
TrailingReturnTypeLoc, &DS),
15821582
std::move(Attributes), DeclEndLoc);
15831583

1584-
Actions.ActOnLambdaClosureQualifiers(Intro, MutableLoc);
1584+
// We have called ActOnLambdaClosureQualifiers for parentheses-less cases
1585+
// above.
1586+
if (HasParentheses)
1587+
Actions.ActOnLambdaClosureQualifiers(Intro, MutableLoc);
15851588

15861589
if (HasParentheses && Tok.is(tok::kw_requires))
15871590
ParseTrailingRequiresClause(D);

clang/lib/Sema/SemaExpr.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18838,13 +18838,23 @@ bool Sema::tryCaptureVariable(
1883818838
DeclContext *VarDC = Var->getDeclContext();
1883918839
DeclContext *DC = CurContext;
1884018840

18841+
// Skip past RequiresExprBodys because they don't constitute function scopes.
18842+
while (DC->isRequiresExprBody())
18843+
DC = DC->getParent();
18844+
1884118845
// tryCaptureVariable is called every time a DeclRef is formed,
1884218846
// it can therefore have non-negigible impact on performances.
1884318847
// For local variables and when there is no capturing scope,
1884418848
// we can bailout early.
1884518849
if (CapturingFunctionScopes == 0 && (!BuildAndDiagnose || VarDC == DC))
1884618850
return true;
1884718851

18852+
// Exception: Function parameters are not tied to the function's DeclContext
18853+
// until we enter the function definition. Capturing them anyway would result
18854+
// in an out-of-bounds error while traversing DC and its parents.
18855+
if (isa<ParmVarDecl>(Var) && !VarDC->isFunctionOrMethod())
18856+
return true;
18857+
1884818858
const auto *VD = dyn_cast<VarDecl>(Var);
1884918859
if (VD) {
1885018860
if (VD->isInitCapture())

clang/lib/Sema/SemaLambda.cpp

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1076,16 +1076,27 @@ void Sema::ActOnLambdaExpressionAfterIntroducer(LambdaIntroducer &Intro,
10761076
// be dependent, because there are template parameters in scope.
10771077
CXXRecordDecl::LambdaDependencyKind LambdaDependencyKind =
10781078
CXXRecordDecl::LDK_Unknown;
1079-
if (LSI->NumExplicitTemplateParams > 0) {
1080-
Scope *TemplateParamScope = CurScope->getTemplateParamParent();
1081-
assert(TemplateParamScope &&
1082-
"Lambda with explicit template param list should establish a "
1083-
"template param scope");
1084-
assert(TemplateParamScope->getParent());
1085-
if (TemplateParamScope->getParent()->getTemplateParamParent() != nullptr)
1086-
LambdaDependencyKind = CXXRecordDecl::LDK_AlwaysDependent;
1087-
} else if (CurScope->getTemplateParamParent() != nullptr) {
1079+
if (CurScope->getTemplateParamParent() != nullptr) {
10881080
LambdaDependencyKind = CXXRecordDecl::LDK_AlwaysDependent;
1081+
} else if (Scope *P = CurScope->getParent()) {
1082+
// Given a lambda defined inside a requires expression,
1083+
//
1084+
// struct S {
1085+
// S(auto var) requires requires { [&] -> decltype(var) { }; }
1086+
// {}
1087+
// };
1088+
//
1089+
// The parameter var is not injected into the function Decl at the point of
1090+
// parsing lambda. In such scenarios, perceiving it as dependent could
1091+
// result in the constraint being evaluated, which matches what GCC does.
1092+
while (P->getEntity() && P->getEntity()->isRequiresExprBody())
1093+
P = P->getParent();
1094+
if (P->isFunctionDeclarationScope() &&
1095+
llvm::any_of(P->decls(), [](Decl *D) {
1096+
return isa<ParmVarDecl>(D) &&
1097+
cast<ParmVarDecl>(D)->getType()->isTemplateTypeParmType();
1098+
}))
1099+
LambdaDependencyKind = CXXRecordDecl::LDK_AlwaysDependent;
10891100
}
10901101

10911102
CXXRecordDecl *Class = createLambdaClosureType(

clang/lib/Sema/TreeTransform.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14248,7 +14248,7 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
1424814248
// will be deemed as dependent even if there are no dependent template
1424914249
// arguments.
1425014250
// (A ClassTemplateSpecializationDecl is always a dependent context.)
14251-
while (DC->getDeclKind() == Decl::Kind::RequiresExprBody)
14251+
while (DC->isRequiresExprBody())
1425214252
DC = DC->getParent();
1425314253
if ((getSema().isUnevaluatedContext() ||
1425414254
getSema().isConstantEvaluatedContext()) &&

clang/test/SemaCXX/lambda-unevaluated.cpp

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,3 +189,78 @@ void recursive() {
189189

190190
}
191191
}
192+
193+
// GH63845: Test if we have skipped past RequiresExprBodyDecls in tryCaptureVariable().
194+
namespace GH63845 {
195+
196+
template <bool> struct A {};
197+
198+
struct true_type {
199+
constexpr operator bool() noexcept { return true; }
200+
};
201+
202+
constexpr bool foo() {
203+
true_type x{};
204+
return requires { typename A<x>; };
205+
}
206+
207+
static_assert(foo());
208+
209+
} // namespace GH63845
210+
211+
// GH69307: Test if we can correctly handle param decls that have yet to get into the function scope.
212+
namespace GH69307 {
213+
214+
constexpr auto ICE() {
215+
constexpr auto b = 1;
216+
return [=](auto c) -> int
217+
requires requires { b + c; }
218+
{ return 1; };
219+
};
220+
221+
constexpr auto Ret = ICE()(1);
222+
223+
} // namespace GH69307
224+
225+
// GH88081: Test if we evaluate the requires expression with lambda captures properly.
226+
namespace GH88081 {
227+
228+
// Test that ActOnLambdaClosureQualifiers() is called only once.
229+
void foo(auto value)
230+
requires requires { [&] -> decltype(value) {}; }
231+
// expected-error@-1 {{non-local lambda expression cannot have a capture-default}}
232+
{}
233+
234+
struct S { //#S
235+
S(auto value) //#S-ctor
236+
requires requires { [&] -> decltype(value) { return 2; }; } {} // #S-requires
237+
238+
static auto foo(auto value) -> decltype([&]() -> decltype(value) {}()) { return {}; } // #S-foo
239+
240+
// FIXME: 'value' does not constitute an ODR use here. Add a diagnostic for it.
241+
static auto bar(auto value) -> decltype([&] { return value; }()) {
242+
return "a"; // #bar-body
243+
}
244+
};
245+
246+
S s("a"); // #use
247+
// expected-error@#S-requires {{cannot initialize return object of type 'decltype(value)' (aka 'const char *') with an rvalue of type 'int'}}
248+
// expected-error@#use {{no matching constructor}}
249+
// expected-note@#S-requires {{substituting into a lambda expression here}}
250+
// expected-note@#S-requires {{substituting template arguments into constraint expression here}}
251+
// expected-note@#S-requires {{in instantiation of requirement here}}
252+
// expected-note@#use {{checking constraint satisfaction for template 'S<const char *>' required here}}
253+
// expected-note@#use {{requested here}}
254+
// expected-note-re@#S 2{{candidate constructor {{.*}} not viable}}
255+
// expected-note@#S-ctor {{constraints not satisfied}}
256+
// expected-note-re@#S-requires {{because {{.*}} would be invalid}}
257+
258+
void func() {
259+
S::foo(42);
260+
S::bar("str");
261+
S::bar(0.618);
262+
// expected-error-re@#bar-body {{cannot initialize return object of type {{.*}} (aka 'double') with an lvalue of type 'const char[2]'}}
263+
// expected-note@-2 {{requested here}}
264+
}
265+
266+
} // namespace GH88081

0 commit comments

Comments
 (0)