cor3ntin updated this revision to Diff 421228.
cor3ntin added a comment.
Formatting.
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D119136/new/
https://reviews.llvm.org/D119136
Files:
clang/include/clang/AST/DeclCXX.h
clang/include/clang/Basic/DiagnosticSemaKinds.td
clang/include/clang/Sema/Scope.h
clang/include/clang/Sema/ScopeInfo.h
clang/include/clang/Sema/Sema.h
clang/lib/Parse/ParseExprCXX.cpp
clang/lib/Sema/Scope.cpp
clang/lib/Sema/Sema.cpp
clang/lib/Sema/SemaCXXScopeSpec.cpp
clang/lib/Sema/SemaDecl.cpp
clang/lib/Sema/SemaExpr.cpp
clang/lib/Sema/SemaExprCXX.cpp
clang/lib/Sema/SemaLambda.cpp
clang/lib/Sema/TreeTransform.h
clang/test/CXX/expr/expr.prim/expr.prim.lambda/p11-1y.cpp
clang/test/SemaCXX/lambda-capture-type-deduction.cpp
clang/test/SemaCXX/warn-shadow-in-lambdas.cpp
clang/www/cxx_status.html
Index: clang/www/cxx_status.html
===================================================================
--- clang/www/cxx_status.html
+++ clang/www/cxx_status.html
@@ -1356,7 +1356,7 @@
<tr>
<td>Change scope of lambda trailing-return-type</td>
<td><a href="https://wg21.link/P2036R3">P2036R3</a></td>
- <td class="none" align="center">No</td>
+ <td class="unreleased" align="center">Clang 15</td>
</tr>
<tr>
<td>Multidimensional subscript operator</td>
Index: clang/test/SemaCXX/warn-shadow-in-lambdas.cpp
===================================================================
--- clang/test/SemaCXX/warn-shadow-in-lambdas.cpp
+++ clang/test/SemaCXX/warn-shadow-in-lambdas.cpp
@@ -95,7 +95,7 @@
#ifdef AVOID
auto l4 = [var = param] (int param) { ; }; // no warning
#else
- auto l4 = [var = param] (int param) { ; }; // expected-warning {{declaration shadows a local variable}}
+ auto l4 = [var = param](int param) { ; }; // expected-warning 2{{declaration shadows a local variable}}
#endif
// Make sure that inner lambdas work as well.
Index: clang/test/SemaCXX/lambda-capture-type-deduction.cpp
===================================================================
--- /dev/null
+++ clang/test/SemaCXX/lambda-capture-type-deduction.cpp
@@ -0,0 +1,132 @@
+// RUN: %clang_cc1 -std=c++2b -verify -fsyntax-only %s
+
+template <typename T, typename U>
+constexpr bool is_same = false;
+
+template <typename T>
+constexpr bool is_same<T, T> = true;
+
+void f() {
+
+ int y;
+
+ static_assert(is_same<const int &,
+ decltype([x = 1] -> decltype((x)) { return x; }())>);
+
+ static_assert(is_same<int &,
+ decltype([x = 1] mutable -> decltype((x)) { return x; }())>);
+
+ static_assert(is_same<const int &,
+ decltype([=] -> decltype((y)) { return y; }())>);
+
+ static_assert(is_same<int &,
+ decltype([=] mutable -> decltype((y)) { return y; }())>);
+
+ static_assert(is_same<const int &,
+ decltype([=] -> decltype((y)) { return y; }())>);
+
+ static_assert(is_same<int &,
+ decltype([=] mutable -> decltype((y)) { return y; }())>);
+
+ auto ref = [&x = y](
+ decltype([&](decltype(x)) { return 0; }) y) {
+ return x;
+ };
+}
+
+void test_noexcept() {
+
+ int y;
+
+ static_assert(noexcept([x = 1] noexcept(is_same<const int &, decltype((x))>) {}()));
+ static_assert(noexcept([x = 1] mutable noexcept(is_same<int &, decltype((x))>) {}()));
+ static_assert(noexcept([y] noexcept(is_same<const int &, decltype((y))>) {}()));
+ static_assert(noexcept([y] mutable noexcept(is_same<int &, decltype((y))>) {}()));
+ static_assert(noexcept([=] noexcept(is_same<const int &, decltype((y))>) {}()));
+ static_assert(noexcept([=] mutable noexcept(is_same<int &, decltype((y))>) {}()));
+ static_assert(noexcept([&] noexcept(is_same<int &, decltype((y))>) {}()));
+ static_assert(noexcept([&] mutable noexcept(is_same<int &, decltype((y))>) {}()));
+
+ static_assert(noexcept([&] mutable noexcept(!is_same<int &, decltype((y))>) {}())); //expected-error {{static_assert failed due}}
+}
+
+void test_requires() {
+
+ int x;
+
+ [x = 1]() requires is_same<const int &, decltype((x))> {}
+ ();
+ [x = 1]() mutable requires is_same<int &, decltype((x))> {}
+ ();
+ [x]() requires is_same<const int &, decltype((x))> {}
+ ();
+ [x]() mutable requires is_same<int &, decltype((x))> {}
+ ();
+ [=]() requires is_same<const int &, decltype((x))> {}
+ ();
+ [=]() mutable requires is_same<int &, decltype((x))> {}
+ ();
+ [&]() requires is_same<int &, decltype((x))> {}
+ ();
+ [&]() mutable requires is_same<int &, decltype((x))> {}
+ ();
+ [&x]() requires is_same<int &, decltype((x))> {}
+ ();
+ [&x]() mutable requires is_same<int &, decltype((x))> {}
+ ();
+
+ [x = 1]() requires is_same<int &, decltype((x))> {} (); //expected-error {{no matching function for call to object of type}} \
+ // expected-note {{candidate function not viable}} \
+ // expected-note {{'is_same<int &, decltype((x))>' evaluated to false}}
+ [x = 1]() mutable requires is_same<const int &, decltype((x))> {} (); // expected-error {{no matching function for call to object of type}} \
+ // expected-note {{candidate function not viable}} \
+ // expected-note {{'is_same<const int &, decltype((x))>' evaluated to false}}
+}
+
+void err() {
+ int y, z; // expected-note 2{{declared here}}
+ auto implicit_tpl = [=]( // expected-note {{variable 'y' is captured here}}
+ decltype(
+ [&]<decltype(y)> { return 0; }) y) { //expected-error{{captured variable 'y' cannot appear}}
+ return y;
+ };
+
+ auto init_tpl = [x = 1]( // expected-note{{explicitly captured here}}
+ decltype([&]<decltype(x)> { return 0; }) y) { // expected-error {{captured variable 'x' cannot appear}}
+ return x;
+ };
+
+ auto implicit = [=]( // expected-note {{variable 'z' is captured here}}
+ decltype(
+ [&](decltype(z)) { return 0; }) z) { //expected-error{{captured variable 'z' cannot appear}}
+ return z;
+ };
+
+ auto init = [x = 1]( // expected-note{{explicitly captured here}}
+ decltype([&](decltype(x)) { return 0; }) y) { // expected-error {{captured variable 'x' cannot appear}}
+ return x;
+ };
+}
+
+void nested() {
+ int x, y, z; //expected-note {{'x' declared here}} expected-note {{'z' declared here}}
+ (void)[&](
+ decltype([&](
+ decltype([=]( // expected-note {{variable 'x' is captured here}}
+ decltype([&](
+ decltype([&](decltype(x)) {}) // expected-error{{captured variable 'x' cannot appear}}
+ ) {})) {})) {})){};
+
+ (void)[&](
+ decltype([&](
+ decltype([&](
+ decltype([&](
+ decltype([&](decltype(y)) {})) {})) {})) {})){};
+
+ (void)[=](
+ decltype([=](
+ decltype([=](
+ decltype([=]( // expected-note {{variable 'z' is captured here}}
+ decltype([&]<decltype(z)> {}) // expected-error{{captured variable 'z' cannot appear}}
+ ) {})) {})) {})){};
+}
Index: clang/test/CXX/expr/expr.prim/expr.prim.lambda/p11-1y.cpp
===================================================================
--- clang/test/CXX/expr/expr.prim/expr.prim.lambda/p11-1y.cpp
+++ clang/test/CXX/expr/expr.prim/expr.prim.lambda/p11-1y.cpp
@@ -12,16 +12,16 @@
using T = double&;
};
-// Within the lambda-expression's compound-statement,
-// the identifier in the init-capture hides any declaration
-// of the same name in scopes enclosing the lambda-expression.
+// Within the lambda-expression the identifier in the init-capture
+// hides any declaration of the same name in scopes enclosing
+// the lambda-expression.
void hiding() {
char c;
(void) [c("foo")] {
static_assert(sizeof(c) == sizeof(const char*), "");
};
- (void) [c("bar")] () -> decltype(c) { // outer c, not init-capture
- return "baz"; // expected-error {{cannot initialize}}
+ (void)[c("bar")]()->decltype(c) { // inner c
+ return "baz";
};
}
Index: clang/lib/Sema/TreeTransform.h
===================================================================
--- clang/lib/Sema/TreeTransform.h
+++ clang/lib/Sema/TreeTransform.h
@@ -13076,7 +13076,8 @@
}
VarDecl *NewVD = getSema().createLambdaInitCaptureVarDecl(
OldVD->getLocation(), InitQualType, NewC.EllipsisLoc,
- OldVD->getIdentifier(), OldVD->getInitStyle(), Init.get());
+ OldVD->getIdentifier(), OldVD->getInitStyle(), Init.get(),
+ getSema().CurContext);
if (!NewVD) {
Invalid = true;
break;
Index: clang/lib/Sema/SemaLambda.cpp
===================================================================
--- clang/lib/Sema/SemaLambda.cpp
+++ clang/lib/Sema/SemaLambda.cpp
@@ -245,8 +245,9 @@
DeclContext *DC = CurContext;
while (!(DC->isFunctionOrMethod() || DC->isRecord() || DC->isFileContext()))
DC = DC->getParent();
- bool IsGenericLambda = getGenericLambdaTemplateParameterList(getCurLambda(),
- *this);
+
+ bool IsGenericLambda =
+ Info && getGenericLambdaTemplateParameterList(getCurLambda(), *this);
// Start constructing the lambda class.
CXXRecordDecl *Class = CXXRecordDecl::CreateLambda(
Context, DC, Info, IntroducerRange.getBegin(), LambdaDependencyKind,
@@ -354,16 +355,13 @@
llvm_unreachable("unexpected context");
}
-CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class,
- SourceRange IntroducerRange,
- TypeSourceInfo *MethodTypeInfo,
- SourceLocation EndLoc,
- ArrayRef<ParmVarDecl *> Params,
- ConstexprSpecKind ConstexprKind,
- Expr *TrailingRequiresClause) {
+static QualType
+buildTypeForLambdaCallOperator(Sema &S, clang::CXXRecordDecl *Class,
+ TemplateParameterList *TemplateParams,
+ TypeSourceInfo *MethodTypeInfo) {
+ assert(MethodTypeInfo && "expected a non null type");
+
QualType MethodType = MethodTypeInfo->getType();
- TemplateParameterList *TemplateParams =
- getGenericLambdaTemplateParameterList(getCurLambda(), *this);
// If a lambda appears in a dependent context or is a generic lambda (has
// template parameters) and has an 'auto' return type, deduce it to a
// dependent type.
@@ -371,19 +369,43 @@
const FunctionProtoType *FPT = MethodType->castAs<FunctionProtoType>();
QualType Result = FPT->getReturnType();
if (Result->isUndeducedType()) {
- Result = SubstAutoTypeDependent(Result);
- MethodType = Context.getFunctionType(Result, FPT->getParamTypes(),
- FPT->getExtProtoInfo());
+ Result = S.SubstAutoTypeDependent(Result);
+ MethodType = S.Context.getFunctionType(Result, FPT->getParamTypes(),
+ FPT->getExtProtoInfo());
}
}
+ return MethodType;
+}
+
+/// Start the definition of a lambda expression.
+/// In this overload, we do not know the type yet
+CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class,
+ SourceRange IntroducerRange,
+ TypeSourceInfo *MethodTypeInfo,
+ SourceLocation EndLoc,
+ ArrayRef<ParmVarDecl *> Params,
+ ConstexprSpecKind ConstexprKind,
+ Expr *TrailingRequiresClause) {
+
+ LambdaScopeInfo *LSI = getCurLambda();
+
+ TemplateParameterList *TemplateParams =
+ getGenericLambdaTemplateParameterList(LSI, *this);
+
+ // At this point, we may not know the type of the lambda, if we have not
+ // parsed a trailing return type yet
+ QualType MethodType = MethodTypeInfo
+ ? buildTypeForLambdaCallOperator(
+ *this, Class, TemplateParams, MethodTypeInfo)
+ : QualType();
// C++11 [expr.prim.lambda]p5:
// The closure type for a lambda-expression has a public inline function
- // call operator (13.5.4) whose parameters and return type are described by
- // the lambda-expression's parameter-declaration-clause and
+ // call operator (13.5.4) whose parameters and return type are described
+ // by the lambda-expression's parameter-declaration-clause and
// trailing-return-type respectively.
- DeclarationName MethodName
- = Context.DeclarationNames.getCXXOperatorName(OO_Call);
+ DeclarationName MethodName =
+ Context.DeclarationNames.getCXXOperatorName(OO_Call);
DeclarationNameLoc MethodNameLoc =
DeclarationNameLoc::makeCXXOperatorNameLoc(IntroducerRange);
CXXMethodDecl *Method = CXXMethodDecl::Create(
@@ -400,11 +422,11 @@
// context, so that the Scope stack matches the lexical nesting.
Method->setLexicalDeclContext(CurContext);
// Create a function template if we have a template parameter list
- FunctionTemplateDecl *const TemplateMethod = TemplateParams ?
- FunctionTemplateDecl::Create(Context, Class,
- Method->getLocation(), MethodName,
- TemplateParams,
- Method) : nullptr;
+ FunctionTemplateDecl *const TemplateMethod =
+ TemplateParams
+ ? FunctionTemplateDecl::Create(Context, Class, Method->getLocation(),
+ MethodName, TemplateParams, Method)
+ : nullptr;
if (TemplateMethod) {
TemplateMethod->setAccess(AS_public);
Method->setDescribedFunctionTemplate(TemplateMethod);
@@ -480,14 +502,27 @@
}
}
-void Sema::buildLambdaScope(LambdaScopeInfo *LSI,
- CXXMethodDecl *CallOperator,
- SourceRange IntroducerRange,
- LambdaCaptureDefault CaptureDefault,
- SourceLocation CaptureDefaultLoc,
- bool ExplicitParams,
- bool ExplicitResultType,
- bool Mutable) {
+static void buildLambdaScopeReturnType(Sema &S, LambdaScopeInfo *LSI,
+ CXXMethodDecl *CallOperator,
+ bool ExplicitResultType) {
+ if (ExplicitResultType) {
+ LSI->HasImplicitReturnType = false;
+ LSI->ReturnType = CallOperator->getReturnType();
+ if (!LSI->ReturnType->isDependentType() && !LSI->ReturnType->isVoidType()) {
+ S.RequireCompleteType(CallOperator->getBeginLoc(), LSI->ReturnType,
+ diag::err_lambda_incomplete_result);
+ }
+ } else {
+ LSI->HasImplicitReturnType = true;
+ }
+}
+
+static void buildLambdaScopeCaptures(LambdaScopeInfo *LSI,
+ CXXMethodDecl *CallOperator,
+ SourceRange IntroducerRange,
+ LambdaCaptureDefault CaptureDefault,
+ SourceLocation CaptureDefaultLoc,
+ bool ExplicitParams, bool Mutable) {
LSI->CallOperator = CallOperator;
CXXRecordDecl *LambdaClass = CallOperator->getParent();
LSI->Lambda = LambdaClass;
@@ -499,30 +534,27 @@
LSI->IntroducerRange = IntroducerRange;
LSI->ExplicitParams = ExplicitParams;
LSI->Mutable = Mutable;
+}
- if (ExplicitResultType) {
- LSI->ReturnType = CallOperator->getReturnType();
-
- if (!LSI->ReturnType->isDependentType() &&
- !LSI->ReturnType->isVoidType()) {
- if (RequireCompleteType(CallOperator->getBeginLoc(), LSI->ReturnType,
- diag::err_lambda_incomplete_result)) {
- // Do nothing.
- }
- }
- } else {
- LSI->HasImplicitReturnType = true;
- }
+void Sema::buildLambdaScope(LambdaScopeInfo *LSI, CXXMethodDecl *CallOperator,
+ SourceRange IntroducerRange,
+ LambdaCaptureDefault CaptureDefault,
+ SourceLocation CaptureDefaultLoc,
+ bool ExplicitParams, bool ExplicitResultType,
+ bool Mutable) {
+ buildLambdaScopeCaptures(LSI, CallOperator, IntroducerRange, CaptureDefault,
+ CaptureDefaultLoc, ExplicitParams, Mutable);
+ buildLambdaScopeReturnType(*this, LSI, CallOperator, ExplicitResultType);
}
void Sema::finishLambdaExplicitCaptures(LambdaScopeInfo *LSI) {
LSI->finishedExplicitCaptures();
}
-void Sema::ActOnLambdaExplicitTemplateParameterList(SourceLocation LAngleLoc,
- ArrayRef<NamedDecl *> TParams,
- SourceLocation RAngleLoc,
- ExprResult RequiresClause) {
+void Sema::ActOnLambdaExplicitTemplateParameterList(
+ LambdaIntroducer &Intro, SourceLocation LAngleLoc,
+ ArrayRef<NamedDecl *> TParams, SourceLocation RAngleLoc,
+ ExprResult RequiresClause) {
LambdaScopeInfo *LSI = getCurLambda();
assert(LSI && "Expected a lambda scope");
assert(LSI->NumExplicitTemplateParams == 0 &&
@@ -538,35 +570,6 @@
LSI->RequiresClause = RequiresClause;
}
-void Sema::addLambdaParameters(
- ArrayRef<LambdaIntroducer::LambdaCapture> Captures,
- CXXMethodDecl *CallOperator, Scope *CurScope) {
- // Introduce our parameters into the function scope
- for (unsigned p = 0, NumParams = CallOperator->getNumParams();
- p < NumParams; ++p) {
- ParmVarDecl *Param = CallOperator->getParamDecl(p);
-
- // If this has an identifier, add it to the scope stack.
- if (CurScope && Param->getIdentifier()) {
- bool Error = false;
- // Resolution of CWG 2211 in C++17 renders shadowing ill-formed, but we
- // retroactively apply it.
- for (const auto &Capture : Captures) {
- if (Capture.Id == Param->getIdentifier()) {
- Error = true;
- Diag(Param->getLocation(), diag::err_parameter_shadow_capture);
- Diag(Capture.Loc, diag::note_var_explicitly_captured_here)
- << Capture.Id << true;
- }
- }
- if (!Error)
- CheckShadow(CurScope, Param);
-
- PushOnScopeChains(Param, CurScope);
- }
- }
-}
-
/// If this expression is an enumerator-like expression of some type
/// T, return the type T; otherwise, return null.
///
@@ -853,11 +856,9 @@
return DeducedType;
}
-VarDecl *Sema::createLambdaInitCaptureVarDecl(SourceLocation Loc,
- QualType InitCaptureType,
- SourceLocation EllipsisLoc,
- IdentifierInfo *Id,
- unsigned InitStyle, Expr *Init) {
+VarDecl *Sema::createLambdaInitCaptureVarDecl(
+ SourceLocation Loc, QualType InitCaptureType, SourceLocation EllipsisLoc,
+ IdentifierInfo *Id, unsigned InitStyle, Expr *Init, DeclContext *DeclCtx) {
// FIXME: Retain the TypeSourceInfo from buildLambdaInitCaptureInitialization
// rather than reconstructing it here.
TypeSourceInfo *TSI = Context.getTrivialTypeSourceInfo(InitCaptureType, Loc);
@@ -868,8 +869,8 @@
// used as a variable, and only exists as a way to name and refer to the
// init-capture.
// FIXME: Pass in separate source locations for '&' and identifier.
- VarDecl *NewVD = VarDecl::Create(Context, CurContext, Loc,
- Loc, Id, InitCaptureType, TSI, SC_Auto);
+ VarDecl *NewVD = VarDecl::Create(Context, DeclCtx, Loc, Loc, Id,
+ InitCaptureType, TSI, SC_Auto);
NewVD->setInitCapture(true);
NewVD->setReferenced(true);
// FIXME: Pass in a VarDecl::InitializationStyle.
@@ -888,12 +889,108 @@
Var->getType(), /*Invalid*/false);
}
-void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
- Declarator &ParamInfo,
- Scope *CurScope) {
+static LambdaScopeInfo *getCurrentLambdaScopeUnsafe(Sema &S) {
+ assert(!S.FunctionScopes.empty());
+ auto *CurLSI =
+ dyn_cast<LambdaScopeInfo>(S.FunctionScopes[S.FunctionScopes.size() - 1]);
+ assert(CurLSI);
+ return CurLSI;
+}
+
+static TypeSourceInfo *
+getDummyLambdaType(Sema &S, SourceLocation Loc = SourceLocation()) {
+ // C++11 [expr.prim.lambda]p4:
+ // If a lambda-expression does not include a lambda-declarator, it is as
+ // if the lambda-declarator were ().
+ FunctionProtoType::ExtProtoInfo EPI(S.Context.getDefaultCallingConvention(
+ /*IsVariadic=*/false, /*IsCXXMethod=*/true));
+ EPI.HasTrailingReturn = true;
+ EPI.TypeQuals.addConst();
+ LangAS AS = S.getDefaultCXXMethodAddrSpace();
+ if (AS != LangAS::Default)
+ EPI.TypeQuals.addAddressSpace(AS);
+
+ // C++1y [expr.prim.lambda]:
+ // The lambda return type is 'auto', which is replaced by the
+ // trailing-return type if provided and/or deduced from 'return'
+ // statements
+ // We don't do this before C++1y, because we don't support deduced return
+ // types there.
+ QualType DefaultTypeForNoTrailingReturn = S.getLangOpts().CPlusPlus14
+ ? S.Context.getAutoDeductType()
+ : S.Context.DependentTy;
+ QualType MethodTy =
+ S.Context.getFunctionType(DefaultTypeForNoTrailingReturn, None, EPI);
+ return S.Context.getTrivialTypeSourceInfo(MethodTy, Loc);
+}
+
+static TypeSourceInfo *getLambdaType(Sema &S, LambdaIntroducer &Intro,
+ Declarator &ParamInfo, Scope *CurScope,
+ SourceLocation Loc,
+ bool &ExplicitResultType) {
+
+ ExplicitResultType = false;
+
+ TypeSourceInfo *MethodTyInfo;
+
+ if (ParamInfo.getNumTypeObjects() == 0) {
+ MethodTyInfo = getDummyLambdaType(S, Loc);
+ } else {
+ DeclaratorChunk::FunctionTypeInfo &FTI = ParamInfo.getFunctionTypeInfo();
+ ExplicitResultType = FTI.hasTrailingReturnType();
+ if (!FTI.hasMutableQualifier()) {
+ FTI.getOrCreateMethodQualifiers().SetTypeQual(DeclSpec::TQ_const, Loc);
+ }
+
+ MethodTyInfo = S.GetTypeForDeclarator(ParamInfo, CurScope);
+
+ assert(MethodTyInfo && "no type from lambda-declarator");
+
+ // Check for unexpanded parameter packs in the method type.
+ if (MethodTyInfo->getType()->containsUnexpandedParameterPack())
+ S.DiagnoseUnexpandedParameterPack(Intro.Range.getBegin(), MethodTyInfo,
+ S.UPPC_DeclarationType);
+ }
+ return MethodTyInfo;
+}
+
+static CXXMethodDecl *CreateMethod(Sema &S, SourceRange IntroducerRange,
+ CXXRecordDecl *Class) {
+ // C++11 [expr.prim.lambda]p5:
+ // The closure type for a lambda-expression has a public inline function
+ // call operator (13.5.4) whose parameters and return type are described
+ // by the lambda-expression's parameter-declaration-clause and
+ // trailing-return-type respectively.
+ DeclarationName MethodName =
+ S.Context.DeclarationNames.getCXXOperatorName(OO_Call);
+ DeclarationNameLoc MethodNameLoc =
+ DeclarationNameLoc::makeCXXOperatorNameLoc(IntroducerRange.getBegin());
+ CXXMethodDecl *Method = CXXMethodDecl::Create(
+ S.Context, Class, SourceLocation(),
+ DeclarationNameInfo(MethodName, IntroducerRange.getBegin(),
+ MethodNameLoc),
+ QualType(), nullptr, SC_None, S.getCurFPFeatures().isFPConstrained(),
+ /*isInline=*/true, ConstexprSpecKind::Unspecified, SourceLocation(),
+ nullptr);
+ Method->setAccess(AS_public);
+ return Method;
+}
+
+void Sema::ActOnLambdaIntroducer(LambdaIntroducer &Intro, Scope *CurrentScope) {
+
LambdaScopeInfo *const LSI = getCurLambda();
assert(LSI && "LambdaScopeInfo should be on stack!");
+ if (Intro.Default == LCD_ByCopy)
+ LSI->ImpCaptureStyle = LambdaScopeInfo::ImpCap_LambdaByval;
+ else if (Intro.Default == LCD_ByRef)
+ LSI->ImpCaptureStyle = LambdaScopeInfo::ImpCap_LambdaByref;
+ LSI->CaptureDefaultLoc = Intro.DefaultLoc;
+ LSI->IntroducerRange = Intro.Range;
+ LSI->BeforeLambdaQualifiersScope = true;
+
+ assert(LSI->NumExplicitTemplateParams == 0);
+
// Determine if we're within a context where we know that the lambda will
// be dependent, because there are template parameters in scope.
CXXRecordDecl::LambdaDependencyKind LambdaDependencyKind =
@@ -910,181 +1007,37 @@
LambdaDependencyKind = CXXRecordDecl::LDK_AlwaysDependent;
}
- // Determine the signature of the call operator.
- TypeSourceInfo *MethodTyInfo;
- bool ExplicitParams = true;
- bool ExplicitResultType = true;
- bool ContainsUnexpandedParameterPack = false;
- SourceLocation EndLoc;
- SmallVector<ParmVarDecl *, 8> Params;
- if (ParamInfo.getNumTypeObjects() == 0) {
- // C++11 [expr.prim.lambda]p4:
- // If a lambda-expression does not include a lambda-declarator, it is as
- // if the lambda-declarator were ().
- FunctionProtoType::ExtProtoInfo EPI(Context.getDefaultCallingConvention(
- /*IsVariadic=*/false, /*IsCXXMethod=*/true));
- EPI.HasTrailingReturn = true;
- EPI.TypeQuals.addConst();
- LangAS AS = getDefaultCXXMethodAddrSpace();
- if (AS != LangAS::Default)
- EPI.TypeQuals.addAddressSpace(AS);
-
- // C++1y [expr.prim.lambda]:
- // The lambda return type is 'auto', which is replaced by the
- // trailing-return type if provided and/or deduced from 'return'
- // statements
- // We don't do this before C++1y, because we don't support deduced return
- // types there.
- QualType DefaultTypeForNoTrailingReturn =
- getLangOpts().CPlusPlus14 ? Context.getAutoDeductType()
- : Context.DependentTy;
- QualType MethodTy =
- Context.getFunctionType(DefaultTypeForNoTrailingReturn, None, EPI);
- MethodTyInfo = Context.getTrivialTypeSourceInfo(MethodTy);
- ExplicitParams = false;
- ExplicitResultType = false;
- EndLoc = Intro.Range.getEnd();
- } else {
- assert(ParamInfo.isFunctionDeclarator() &&
- "lambda-declarator is a function");
- DeclaratorChunk::FunctionTypeInfo &FTI = ParamInfo.getFunctionTypeInfo();
-
- // C++11 [expr.prim.lambda]p5:
- // This function call operator is declared const (9.3.1) if and only if
- // the lambda-expression's parameter-declaration-clause is not followed
- // by mutable. It is neither virtual nor declared volatile. [...]
- if (!FTI.hasMutableQualifier()) {
- FTI.getOrCreateMethodQualifiers().SetTypeQual(DeclSpec::TQ_const,
- SourceLocation());
- }
-
- MethodTyInfo = GetTypeForDeclarator(ParamInfo, CurScope);
- assert(MethodTyInfo && "no type from lambda-declarator");
- EndLoc = ParamInfo.getSourceRange().getEnd();
-
- ExplicitResultType = FTI.hasTrailingReturnType();
-
- if (FTIHasNonVoidParameters(FTI)) {
- Params.reserve(FTI.NumParams);
- for (unsigned i = 0, e = FTI.NumParams; i != e; ++i)
- Params.push_back(cast<ParmVarDecl>(FTI.Params[i].Param));
- }
-
- // Check for unexpanded parameter packs in the method type.
- if (MethodTyInfo->getType()->containsUnexpandedParameterPack())
- DiagnoseUnexpandedParameterPack(Intro.Range.getBegin(), MethodTyInfo,
- UPPC_DeclarationType);
- }
-
CXXRecordDecl *Class = createLambdaClosureType(
- Intro.Range, MethodTyInfo, LambdaDependencyKind, Intro.Default);
- CXXMethodDecl *Method =
- startLambdaDefinition(Class, Intro.Range, MethodTyInfo, EndLoc, Params,
- ParamInfo.getDeclSpec().getConstexprSpecifier(),
- ParamInfo.getTrailingRequiresClause());
- if (ExplicitParams)
- CheckCXXDefaultArguments(Method);
-
- // This represents the function body for the lambda function, check if we
- // have to apply optnone due to a pragma.
- AddRangeBasedOptnone(Method);
+ Intro.Range, nullptr, LambdaDependencyKind, Intro.Default);
+ LSI->Lambda = Class;
- // code_seg attribute on lambda apply to the method.
- if (Attr *A = getImplicitCodeSegOrSectionAttrForFunction(Method, /*IsDefinition=*/true))
- Method->addAttr(A);
-
- // Attributes on the lambda apply to the method.
- ProcessDeclAttributes(CurScope, Method, ParamInfo);
-
- // CUDA lambdas get implicit host and device attributes.
- if (getLangOpts().CUDA)
- CUDASetLambdaAttrs(Method);
-
- // OpenMP lambdas might get assumumption attributes.
- if (LangOpts.OpenMP)
- ActOnFinishedFunctionDefinitionInOpenMPAssumeScope(Method);
+ // C++11 [expr.prim.lambda]p5:
+ // The closure type for a lambda-expression has a public inline function
+ // call operator (13.5.4) whose parameters and return type are described
+ // by the lambda-expression's parameter-declaration-clause and
+ // trailing-return-type respectively.
- // Number the lambda for linkage purposes if necessary.
- handleLambdaNumbering(Class, Method);
+ CXXMethodDecl *Method = CreateMethod(*this, Intro.Range, Class);
+ LSI->CallOperator = Method;
+ Method->setLexicalDeclContext(CurContext);
- // Introduce the function call operator as the current declaration context.
PushDeclContext(CurScope, Method);
- // Build the lambda scope.
- buildLambdaScope(LSI, Method, Intro.Range, Intro.Default, Intro.DefaultLoc,
- ExplicitParams, ExplicitResultType, !Method->isConst());
-
- // C++11 [expr.prim.lambda]p9:
- // A lambda-expression whose smallest enclosing scope is a block scope is a
- // local lambda expression; any other lambda expression shall not have a
- // capture-default or simple-capture in its lambda-introducer.
- //
- // For simple-captures, this is covered by the check below that any named
- // entity is a variable that can be captured.
- //
- // For DR1632, we also allow a capture-default in any context where we can
- // odr-use 'this' (in particular, in a default initializer for a non-static
- // data member).
- if (Intro.Default != LCD_None && !Class->getParent()->isFunctionOrMethod() &&
- (getCurrentThisType().isNull() ||
- CheckCXXThisCapture(SourceLocation(), /*Explicit*/true,
- /*BuildAndDiagnose*/false)))
- Diag(Intro.DefaultLoc, diag::err_capture_default_non_local);
+ bool ContainsUnexpandedParameterPack = false;
// Distinct capture names, for diagnostics.
- llvm::SmallSet<IdentifierInfo*, 8> CaptureNames;
+ llvm::SmallSet<IdentifierInfo *, 8> CaptureNames;
// Handle explicit captures.
- SourceLocation PrevCaptureLoc
- = Intro.Default == LCD_None? Intro.Range.getBegin() : Intro.DefaultLoc;
+ SourceLocation PrevCaptureLoc =
+ Intro.Default == LCD_None ? Intro.Range.getBegin() : Intro.DefaultLoc;
+ unsigned I = 0;
for (auto C = Intro.Captures.begin(), E = Intro.Captures.end(); C != E;
- PrevCaptureLoc = C->Loc, ++C) {
+ PrevCaptureLoc = C->Loc, ++C, ++I) {
if (C->Kind == LCK_This || C->Kind == LCK_StarThis) {
- if (C->Kind == LCK_StarThis)
- Diag(C->Loc, !getLangOpts().CPlusPlus17
- ? diag::ext_star_this_lambda_capture_cxx17
- : diag::warn_cxx14_compat_star_this_lambda_capture);
-
- // C++11 [expr.prim.lambda]p8:
- // An identifier or this shall not appear more than once in a
- // lambda-capture.
- if (LSI->isCXXThisCaptured()) {
- Diag(C->Loc, diag::err_capture_more_than_once)
- << "'this'" << SourceRange(LSI->getCXXThisCapture().getLocation())
- << FixItHint::CreateRemoval(
- SourceRange(getLocForEndOfToken(PrevCaptureLoc), C->Loc));
continue;
- }
-
- // C++2a [expr.prim.lambda]p8:
- // If a lambda-capture includes a capture-default that is =,
- // each simple-capture of that lambda-capture shall be of the form
- // "&identifier", "this", or "* this". [ Note: The form [&,this] is
- // redundant but accepted for compatibility with ISO C++14. --end note ]
- if (Intro.Default == LCD_ByCopy && C->Kind != LCK_StarThis)
- Diag(C->Loc, !getLangOpts().CPlusPlus20
- ? diag::ext_equals_this_lambda_capture_cxx20
- : diag::warn_cxx17_compat_equals_this_lambda_capture);
-
- // C++11 [expr.prim.lambda]p12:
- // If this is captured by a local lambda expression, its nearest
- // enclosing function shall be a non-static member function.
- QualType ThisCaptureType = getCurrentThisType();
- if (ThisCaptureType.isNull()) {
- Diag(C->Loc, diag::err_this_capture) << true;
- continue;
- }
-
- CheckCXXThisCapture(C->Loc, /*Explicit=*/true, /*BuildAndDiagnose*/ true,
- /*FunctionScopeIndexToStopAtPtr*/ nullptr,
- C->Kind == LCK_StarThis);
- if (!LSI->Captures.empty())
- LSI->ExplicitCaptureRanges[LSI->Captures.size() - 1] = C->ExplicitRange;
- continue;
}
-
assert(C->Id && "missing identifier for capture");
-
if (C->Init.isInvalid())
continue;
@@ -1122,13 +1075,9 @@
}
Var = createLambdaInitCaptureVarDecl(C->Loc, C->InitCaptureType.get(),
C->EllipsisLoc, C->Id, InitStyle,
- C->Init.get());
- // C++1y [expr.prim.lambda]p11:
- // An init-capture behaves as if it declares and explicitly
- // captures a variable [...] whose declarative region is the
- // lambda-expression's compound-statement
- if (Var)
- PushOnScopeChains(Var, CurScope, false);
+ C->Init.get(), Method);
+ CheckShadow(CurrentScope, Var);
+ PushOnScopeChains(Var, CurrentScope, false);
} else {
assert(C->InitKind == LambdaCaptureInitKind::NoInit &&
"init capture has valid but null init?");
@@ -1175,9 +1124,16 @@
// An identifier or this shall not appear more than once in a
// lambda-capture.
if (!CaptureNames.insert(C->Id).second) {
- if (Var && LSI->isCaptured(Var)) {
+ auto FindVar = [LSI](VarDecl *V) {
+ auto it = std::find_if(
+ LSI->DelayedCaptures.begin(), LSI->DelayedCaptures.end(),
+ [&](auto &&Pair) { return Pair.second.Var == V; });
+ return it;
+ };
+ auto it = FindVar(Var);
+ if (Var && it != LSI->DelayedCaptures.end()) {
Diag(C->Loc, diag::err_capture_more_than_once)
- << C->Id << SourceRange(LSI->getCapture(Var).getLocation())
+ << C->Id << SourceRange(it->second.Loc)
<< FixItHint::CreateRemoval(
SourceRange(getLocForEndOfToken(PrevCaptureLoc), C->Loc));
} else
@@ -1223,22 +1179,246 @@
ContainsUnexpandedParameterPack = true;
}
- if (C->Init.isUsable()) {
- addInitCapture(LSI, Var);
+ if (Var)
+ LSI->DelayedCaptures[I] = LambdaScopeInfo::DelayedCapture{
+ Var, C->ExplicitRange.getBegin(), C->Kind};
+ }
+
+ LSI->ContainsUnexpandedParameterPack |= ContainsUnexpandedParameterPack;
+ PopDeclContext();
+}
+
+static void AddExplicitCapturesToContext(Sema &S, LambdaScopeInfo *LSI,
+ LambdaIntroducer &Intro) {
+ unsigned I = 0;
+ SourceLocation PrevCaptureLoc;
+ for (auto C = Intro.Captures.begin(), E = Intro.Captures.end(); C != E;
+ PrevCaptureLoc = C->Loc, ++C, ++I) {
+ if (C->Kind == LCK_This || C->Kind == LCK_StarThis) {
+ if (C->Kind == LCK_StarThis)
+ S.Diag(C->Loc, !S.getLangOpts().CPlusPlus17
+ ? diag::ext_star_this_lambda_capture_cxx17
+ : diag::warn_cxx14_compat_star_this_lambda_capture);
+
+ // C++11 [expr.prim.lambda]p8:
+ // An identifier or this shall not appear more than once in a
+ // lambda-capture.
+ if (LSI->isCXXThisCaptured()) {
+ S.Diag(C->Loc, diag::err_capture_more_than_once)
+ << "'this'" << SourceRange(LSI->getCXXThisCapture().getLocation())
+ << FixItHint::CreateRemoval(
+ SourceRange(S.getLocForEndOfToken(PrevCaptureLoc), C->Loc));
+ continue;
+ }
+
+ // C++2a [expr.prim.lambda]p8:
+ // If a lambda-capture includes a capture-default that is =,
+ // each simple-capture of that lambda-capture shall be of the form
+ // "&identifier", "this", or "* this". [ Note: The form [&,this] is
+ // redundant but accepted for compatibility with ISO C++14. --end note ]
+ if (Intro.Default == LCD_ByCopy && C->Kind != LCK_StarThis)
+ S.Diag(C->Loc,
+ !S.getLangOpts().CPlusPlus20
+ ? diag::ext_equals_this_lambda_capture_cxx20
+ : diag::warn_cxx17_compat_equals_this_lambda_capture);
+
+ // C++11 [expr.prim.lambda]p12:
+ // If this is captured by a local lambda expression, its nearest
+ // enclosing function shall be a non-static member function.
+ QualType ThisCaptureType = S.getCurrentThisType();
+ if (ThisCaptureType.isNull()) {
+ S.Diag(C->Loc, diag::err_this_capture) << true;
+ continue;
+ }
+ S.CheckCXXThisCapture(C->Loc, true, true, nullptr,
+ C->Kind == LCK_StarThis);
} else {
- TryCaptureKind Kind = C->Kind == LCK_ByRef ? TryCapture_ExplicitByRef :
- TryCapture_ExplicitByVal;
- tryCaptureVariable(Var, C->Loc, Kind, EllipsisLoc);
+ VarDecl *Var = LSI->DelayedCaptures[I].Var;
+ if (!Var)
+ continue;
+ if (Var->isInitCapture() && C->Init.isUsable()) {
+ S.addInitCapture(LSI, Var);
+ S.PushOnScopeChains(Var, S.getCurScope(), false);
+ } else {
+ Sema::TryCaptureKind Kind = C->Kind == LCK_ByRef
+ ? Sema::TryCapture_ExplicitByRef
+ : Sema::TryCapture_ExplicitByVal;
+ S.tryCaptureVariable(Var, C->Loc, Kind, C->EllipsisLoc);
+ }
}
if (!LSI->Captures.empty())
LSI->ExplicitCaptureRanges[LSI->Captures.size() - 1] = C->ExplicitRange;
}
- finishLambdaExplicitCaptures(LSI);
+ S.finishLambdaExplicitCaptures(LSI);
+}
- LSI->ContainsUnexpandedParameterPack |= ContainsUnexpandedParameterPack;
+void Sema::ActOnLambdaClosureQualifiers(LambdaIntroducer &Intro,
+ SourceLocation MutableLoc,
+ SourceLocation EndLoc,
+ const DeclSpec &DS) {
+
+ LambdaScopeInfo *const LSI = getCurrentLambdaScopeUnsafe(*this);
+ LSI->Mutable = MutableLoc.isValid();
+ LSI->BeforeLambdaQualifiersScope = false;
+ LSI->CallOperator->setConstexprKind(DS.getConstexprSpecifier());
+
+ // C++11 [expr.prim.lambda]p9:
+ // A lambda-expression whose smallest enclosing scope is a block scope is a
+ // local lambda expression; any other lambda expression shall not have a
+ // capture-default or simple-capture in its lambda-introducer.
+ //
+ // For simple-captures, this is covered by the check below that any named
+ // entity is a variable that can be captured.
+ //
+ // For DR1632, we also allow a capture-default in any context where we can
+ // odr-use 'this' (in particular, in a default initializer for a non-static
+ // data member).
+ if (Intro.Default != LCD_None &&
+ !LSI->Lambda->getParent()->isFunctionOrMethod() &&
+ (getCurrentThisType().isNull() ||
+ CheckCXXThisCapture(SourceLocation(), /*Explicit*/ true,
+ /*BuildAndDiagnose*/ false)))
+ Diag(Intro.DefaultLoc, diag::err_capture_default_non_local);
+
+ PushDeclContext(CurScope, LSI->CallOperator);
+ AddExplicitCapturesToContext(*this, LSI, Intro);
+}
+
+void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
+ Declarator &ParamInfo,
+ Scope *CurScope) {
+
+ LambdaScopeInfo *const LSI = getCurrentLambdaScopeUnsafe(*this);
+
+ SmallVector<ParmVarDecl *, 8> Params;
+ bool ExplicitResultType;
+
+ SourceLocation TypeLoc, LambdaLoc;
+ if (ParamInfo.getNumTypeObjects() == 0) {
+ LambdaLoc = TypeLoc = Intro.Range.getEnd();
+ } else {
+ unsigned index;
+ ParamInfo.isFunctionDeclarator(index);
+ const auto &Object = ParamInfo.getTypeObject(index);
+ TypeLoc =
+ Object.Loc.isValid() ? Object.Loc : ParamInfo.getSourceRange().getEnd();
+ LambdaLoc = ParamInfo.getSourceRange().getEnd();
+ }
+
+ CXXRecordDecl *Class = LSI->Lambda;
+ CXXMethodDecl *Method = LSI->CallOperator;
+
+ if (ParamInfo.getTrailingRequiresClause())
+ Method->setTrailingRequiresClause(ParamInfo.getTrailingRequiresClause());
+
+ TemplateParameterList *TemplateParams =
+ getGenericLambdaTemplateParameterList(LSI, *this);
+
+ auto DC = Method->getLexicalDeclContext();
+ Method->setLexicalDeclContext(Class);
+ if (TemplateParams) {
+ FunctionTemplateDecl *const TemplateMethod = FunctionTemplateDecl::Create(
+ Context, Class, Method->getLocation(), Method->getDeclName(),
+ TemplateParams, Method);
+ TemplateMethod->setAccess(AS_public);
+ Method->setDescribedFunctionTemplate(TemplateMethod);
+ Class->addDecl(TemplateMethod);
+ TemplateMethod->setLexicalDeclContext(DC);
+ } else {
+ Class->addDecl(Method);
+ }
+ Method->setLexicalDeclContext(DC);
+ Class->setLambdaIsGeneric(TemplateParams);
+
+ TypeSourceInfo *MethodTyInfo = getLambdaType(
+ *this, Intro, ParamInfo, getCurScope(), TypeLoc, ExplicitResultType);
+
+ Class->setLambdaTypeInfo(MethodTyInfo);
+ Method->setInnerLocStart(LambdaLoc);
+ Method->setLocation(Intro.Range.getBegin());
+ Method->setTypeSourceInfo(MethodTyInfo);
+ Method->setType(buildTypeForLambdaCallOperator(*this, Class, TemplateParams,
+ MethodTyInfo));
+ Method->setConstexprKind(ParamInfo.getDeclSpec().getConstexprSpecifier());
+ buildLambdaScopeReturnType(*this, LSI, Method, ExplicitResultType);
+
+ LSI->ExplicitParams = ParamInfo.getNumTypeObjects() != 0;
+
+ if (ParamInfo.isFunctionDeclarator() != 0 &&
+ !FTIHasSingleVoidParameter(ParamInfo.getFunctionTypeInfo())) {
+ const auto &FTI = ParamInfo.getFunctionTypeInfo();
+ Params.reserve(Params.size());
+ for (unsigned I = 0; I < FTI.NumParams; ++I) {
+ auto *Param = cast<ParmVarDecl>(FTI.Params[I].Param);
+ Param->setScopeInfo(0, Params.size());
+ Param->setOwningFunction(Method);
+ Params.push_back(Param);
+ }
+ }
+
+ ContextRAII ManglingContext(*this, Class->getDeclContext());
+
+ CheckParmsForFunctionDef(Params, /*CheckParameterNames=*/false);
- // Add lambda parameters into scope.
- addLambdaParameters(Intro.Captures, Method, CurScope);
+ if (LSI->ExplicitParams) {
+ Method->setParams(Params);
+ CheckCXXDefaultArguments(Method);
+ }
+
+ // This represents the function body for the lambda function, check if we
+ // have to apply optnone due to a pragma.
+ AddRangeBasedOptnone(Method);
+
+ // code_seg attribute on lambda apply to the method.
+ if (Attr *A = getImplicitCodeSegOrSectionAttrForFunction(
+ Method, /*IsDefinition=*/true))
+ Method->addAttr(A);
+
+ // Attributes on the lambda apply to the method.
+ ProcessDeclAttributes(CurScope, Method, ParamInfo);
+
+ // CUDA lambdas get implicit host and device attributes.
+ if (getLangOpts().CUDA)
+ CUDASetLambdaAttrs(Method);
+
+ // OpenMP lambdas might get assumumption attributes.
+ if (LangOpts.OpenMP)
+ ActOnFinishedFunctionDefinitionInOpenMPAssumeScope(Method);
+
+ handleLambdaNumbering(Class, Method);
+
+ ManglingContext.pop();
+
+ for (auto &&C : LSI->DelayedCaptures) {
+ VarDecl *Var = C.second.Var;
+ if (Var && Var->isInitCapture()) {
+ PushOnScopeChains(Var, CurScope, false);
+ }
+ }
+
+ LSI->DelayedCaptures.clear();
+
+ auto CheckRedefinition = [&](ParmVarDecl *Param) {
+ if (!Param->getIdentifier())
+ return true;
+ for (const auto &Capture : Intro.Captures) {
+ if (Capture.Id == Param->getIdentifier()) {
+ Diag(Param->getLocation(), diag::err_parameter_shadow_capture);
+ Diag(Capture.Loc, diag::note_var_explicitly_captured_here)
+ << Capture.Id << true;
+ return false;
+ }
+ }
+ return true;
+ };
+
+ for (auto &&P : Params) {
+ if (!P->getIdentifier())
+ continue;
+ if (CheckRedefinition(P))
+ CheckShadow(CurScope, P);
+ PushOnScopeChains(P, CurScope);
+ }
// Enter a new evaluation context to insulate the lambda from any
// cleanups from the enclosing full-expression.
Index: clang/lib/Sema/SemaExprCXX.cpp
===================================================================
--- clang/lib/Sema/SemaExprCXX.cpp
+++ clang/lib/Sema/SemaExprCXX.cpp
@@ -1130,7 +1130,7 @@
if (C.isCopyCapture()) {
ClassType.removeLocalCVRQualifiers(Qualifiers::CVRMask);
- if (CurLSI->CallOperator->isConst())
+ if (!CurLSI->Mutable)
ClassType.addConst();
return ASTCtx.getPointerType(ClassType);
}
Index: clang/lib/Sema/SemaExpr.cpp
===================================================================
--- clang/lib/Sema/SemaExpr.cpp
+++ clang/lib/Sema/SemaExpr.cpp
@@ -3383,7 +3383,7 @@
// FIXME: Support lambda-capture of BindingDecls, once CWG actually
// decides how that's supposed to work.
auto *BD = cast<BindingDecl>(VD);
- if (BD->getDeclContext() != CurContext) {
+ if (BD->getDeclContext() != CurContext && !isUnevaluatedContext()) {
auto *DD = dyn_cast_or_null<VarDecl>(BD->getDecomposedDecl());
if (DD && DD->hasLocalStorage())
diagnoseUncapturableValueReference(*this, Loc, BD);
@@ -18396,6 +18396,34 @@
}
}
+static bool CheckCaptureUseBeforeLambdaQualifiers(Sema &S, VarDecl *Var,
+ SourceLocation ExprLoc,
+ LambdaScopeInfo *LSI) {
+ bool ByCopy = LSI->ImpCaptureStyle == LambdaScopeInfo::ImpCap_LambdaByval;
+ SourceLocation Loc = LSI->IntroducerRange.getBegin();
+ bool Explicitly = false;
+ for (auto &&C : LSI->DelayedCaptures) {
+ VarDecl *CV = C.second.Var;
+ if (Var != CV)
+ continue;
+ ByCopy = C.second.Kind == LambdaCaptureKind::LCK_ByCopy;
+ Loc = C.second.Loc;
+ Explicitly = 1;
+ break;
+ }
+ if (ByCopy && LSI->BeforeLambdaQualifiersScope) {
+ // This can only occur in a non-ODR context, so we need to diagnose eagerly,
+ // even when BuildAndDiagnose is false
+ S.Diag(ExprLoc, diag::err_lambda_used_before_capture) << Var;
+ S.Diag(Loc, diag::note_var_explicitly_captured_here) << Var << Explicitly;
+ if (!Var->isInitCapture())
+ S.Diag(Var->getBeginLoc(), diag::note_entity_declared_at) << Var;
+ Var->setInvalidDecl();
+ return false;
+ }
+ return true;
+}
+
bool Sema::tryCaptureVariable(
VarDecl *Var, SourceLocation ExprLoc, TryCaptureKind Kind,
SourceLocation EllipsisLoc, bool BuildAndDiagnose, QualType &CaptureType,
@@ -18419,11 +18447,6 @@
}
}
-
- // If the variable is declared in the current context, there is no need to
- // capture it.
- if (VarDC == DC) return true;
-
// Capture global variables if it is required to use private copy of this
// variable.
bool IsGlobal = !Var->hasLocalStorage();
@@ -18446,13 +18469,36 @@
bool Nested = false;
bool Explicit = (Kind != TryCapture_Implicit);
unsigned FunctionScopesIndex = MaxFunctionScopesIndex;
+ bool IsInLambdaBeforeQualifiers;
do {
+ IsInLambdaBeforeQualifiers = false;
+
+ LambdaScopeInfo *LSI = nullptr;
+ if (!FunctionScopes.empty())
+ LSI = dyn_cast_or_null<LambdaScopeInfo>(
+ FunctionScopes[FunctionScopesIndex]);
+ if (LSI && LSI->BeforeLambdaQualifiersScope) {
+ if (isa<ParmVarDecl>(Var))
+ return true;
+ IsInLambdaBeforeQualifiers = true;
+ if (!CheckCaptureUseBeforeLambdaQualifiers(*this, Var, ExprLoc, LSI)) {
+ break;
+ }
+ }
+
+ // If the variable is declared in the current context, there is no need to
+ // capture it.
+ if (!IsInLambdaBeforeQualifiers &&
+ FunctionScopesIndex == MaxFunctionScopesIndex && VarDC == DC)
+ return true;
+
// Only block literals, captured statements, and lambda expressions can
// capture; other scopes don't work.
- DeclContext *ParentDC = getParentOfCapturingContextOrNull(DC, Var,
- ExprLoc,
- BuildAndDiagnose,
- *this);
+ DeclContext *ParentDC =
+ IsInLambdaBeforeQualifiers
+ ? DC->getParent()
+ : getParentOfCapturingContextOrNull(DC, Var, ExprLoc,
+ BuildAndDiagnose, *this);
// We need to check for the parent *first* because, if we *have*
// private-captured a global variable, we need to recursively capture it in
// intermediate blocks, lambdas, etc.
@@ -18467,9 +18513,9 @@
FunctionScopeInfo *FSI = FunctionScopes[FunctionScopesIndex];
CapturingScopeInfo *CSI = cast<CapturingScopeInfo>(FSI);
-
// Check whether we've already captured it.
- if (isVariableAlreadyCapturedInScopeInfo(CSI, Var, Nested, CaptureType,
+ if (!IsInLambdaBeforeQualifiers &&
+ isVariableAlreadyCapturedInScopeInfo(CSI, Var, Nested, CaptureType,
DeclRefType)) {
CSI->getCapture(Var).markUsed(BuildAndDiagnose);
break;
@@ -18478,7 +18524,8 @@
// we do not want to capture new variables. What was captured
// during either a lambdas transformation or initial parsing
// should be used.
- if (isGenericLambdaCallOperatorSpecialization(DC)) {
+ if (!IsInLambdaBeforeQualifiers &&
+ isGenericLambdaCallOperatorSpecialization(DC)) {
if (BuildAndDiagnose) {
LambdaScopeInfo *LSI = cast<LambdaScopeInfo>(CSI);
if (LSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_None) {
@@ -18493,7 +18540,8 @@
}
// Try to capture variable-length arrays types.
- if (Var->getType()->isVariablyModifiedType()) {
+ if (!IsInLambdaBeforeQualifiers &&
+ Var->getType()->isVariablyModifiedType()) {
// We're going to walk down into the type and look for VLA
// expressions.
QualType QTy = Var->getType();
@@ -18502,7 +18550,7 @@
captureVariablyModifiedType(Context, QTy, CSI);
}
- if (getLangOpts().OpenMP) {
+ if (!IsInLambdaBeforeQualifiers && getLangOpts().OpenMP) {
if (auto *RSI = dyn_cast<CapturedRegionScopeInfo>(CSI)) {
// OpenMP private variables should not be captured in outer scope, so
// just break here. Similarly, global variables that are captured in a
@@ -18583,11 +18631,11 @@
}
return true;
}
-
- FunctionScopesIndex--;
- DC = ParentDC;
Explicit = false;
- } while (!VarDC->Equals(DC));
+ FunctionScopesIndex--;
+ if (!IsInLambdaBeforeQualifiers)
+ DC = ParentDC;
+ } while (IsInLambdaBeforeQualifiers || !VarDC->Equals(DC));
// Walk back down the scope stack, (e.g. from outer lambda to inner lambda)
// computing the type of the capture at each step, checking type-specific
@@ -18622,6 +18670,9 @@
Nested = true;
} else {
LambdaScopeInfo *LSI = cast<LambdaScopeInfo>(CSI);
+ if (!CheckCaptureUseBeforeLambdaQualifiers(*this, Var, ExprLoc, LSI)) {
+ return true;
+ }
Invalid =
!captureInLambda(LSI, Var, ExprLoc, BuildAndDiagnose, CaptureType,
DeclRefType, Nested, Kind, EllipsisLoc,
Index: clang/lib/Sema/SemaDecl.cpp
===================================================================
--- clang/lib/Sema/SemaDecl.cpp
+++ clang/lib/Sema/SemaDecl.cpp
@@ -14349,7 +14349,6 @@
else if (LCD == LCD_ByRef)
LSI->ImpCaptureStyle = CapturingScopeInfo::ImpCap_LambdaByref;
DeclarationNameInfo DNI = CallOperator->getNameInfo();
-
LSI->IntroducerRange = DNI.getCXXOperatorNameRange();
LSI->Mutable = !CallOperator->isConst();
Index: clang/lib/Sema/SemaCXXScopeSpec.cpp
===================================================================
--- clang/lib/Sema/SemaCXXScopeSpec.cpp
+++ clang/lib/Sema/SemaCXXScopeSpec.cpp
@@ -292,6 +292,11 @@
bool Sema::ActOnSuperScopeSpecifier(SourceLocation SuperLoc,
SourceLocation ColonColonLoc,
CXXScopeSpec &SS) {
+ if (getCurLambda()) {
+ Diag(SuperLoc, diag::err_super_in_lambda_unsupported);
+ return true;
+ }
+
CXXRecordDecl *RD = nullptr;
for (Scope *S = getCurScope(); S; S = S->getParent()) {
if (S->isFunctionScope()) {
@@ -308,9 +313,6 @@
if (!RD) {
Diag(SuperLoc, diag::err_invalid_super_scope);
return true;
- } else if (RD->isLambda()) {
- Diag(SuperLoc, diag::err_super_in_lambda_unsupported);
- return true;
} else if (RD->getNumBases() == 0) {
Diag(SuperLoc, diag::err_no_base_classes) << RD->getName();
return true;
Index: clang/lib/Sema/Sema.cpp
===================================================================
--- clang/lib/Sema/Sema.cpp
+++ clang/lib/Sema/Sema.cpp
@@ -2297,7 +2297,8 @@
LambdaScopeInfo *Sema::getEnclosingLambda() const {
for (auto *Scope : llvm::reverse(FunctionScopes)) {
if (auto *LSI = dyn_cast<sema::LambdaScopeInfo>(Scope)) {
- if (LSI->Lambda && !LSI->Lambda->Encloses(CurContext)) {
+ if (LSI->Lambda && !LSI->Lambda->Encloses(CurContext) &&
+ !LSI->BeforeLambdaQualifiersScope) {
// We have switched contexts due to template instantiation.
// FIXME: We should swap out the FunctionScopes during code synthesis
// so that we don't need to check for this.
@@ -2323,8 +2324,9 @@
return nullptr;
}
auto *CurLSI = dyn_cast<LambdaScopeInfo>(*I);
- if (CurLSI && CurLSI->Lambda &&
- !CurLSI->Lambda->Encloses(CurContext)) {
+ if (CurLSI && CurLSI->Lambda && CurLSI->CallOperator &&
+ !CurLSI->Lambda->Encloses(CurContext) &&
+ !CurLSI->BeforeLambdaQualifiersScope) {
// We have switched contexts due to template instantiation.
assert(!CodeSynthesisContexts.empty());
return nullptr;
Index: clang/lib/Sema/Scope.cpp
===================================================================
--- clang/lib/Sema/Scope.cpp
+++ clang/lib/Sema/Scope.cpp
@@ -68,7 +68,9 @@
if (flags & TemplateParamScope) TemplateParamParent = this;
// If this is a prototype scope, record that.
- if (flags & FunctionPrototypeScope) PrototypeDepth++;
+ // Lambdas have an extra prototype scope that doesn't add any depth
+ if (flags & FunctionPrototypeScope && !(flags & LambdaScope))
+ PrototypeDepth++;
if (flags & DeclScope) {
if (flags & FunctionPrototypeScope)
Index: clang/lib/Parse/ParseExprCXX.cpp
===================================================================
--- clang/lib/Parse/ParseExprCXX.cpp
+++ clang/lib/Parse/ParseExprCXX.cpp
@@ -1250,7 +1250,13 @@
DeclSpec DS(AttrFactory);
Declarator D(DS, DeclaratorContext::LambdaExpr);
TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth);
+
+ ParseScope LambdaScope(this, Scope::LambdaScope | Scope::DeclScope |
+ Scope::FunctionDeclarationScope |
+ Scope::FunctionPrototypeScope);
+
Actions.PushLambdaScope();
+ Actions.ActOnLambdaIntroducer(Intro, getCurScope());
ParsedAttributes Attr(AttrFactory);
if (getLangOpts().CUDA) {
@@ -1300,7 +1306,7 @@
}
Actions.ActOnLambdaExplicitTemplateParameterList(
- LAngleLoc, TemplateParams, RAngleLoc, RequiresClause);
+ Intro, LAngleLoc, TemplateParams, RAngleLoc, RequiresClause);
++CurTemplateDepthTracker;
}
}
@@ -1318,28 +1324,31 @@
TypeResult TrailingReturnType;
SourceLocation TrailingReturnTypeLoc;
+ SourceLocation LParenLoc, RParenLoc;
+ SourceLocation DeclEndLoc;
+ bool HasParentheses = false;
+ bool HasSpecifiers = false;
+ SourceLocation MutableLoc;
+
+ auto ParseConstexprAndMutableSpecifiers = [&] {
+ // GNU-style attributes must be parsed before the mutable specifier to
+ // be compatible with GCC. MSVC-style attributes must be parsed before
+ // the mutable specifier to be compatible with MSVC.
+ MaybeParseAttributes(PAKM_GNU | PAKM_Declspec, Attr);
+ // Parse mutable-opt and/or constexpr-opt or consteval-opt, and update
+ // the DeclEndLoc.
+ SourceLocation ConstexprLoc;
+ SourceLocation ConstevalLoc;
+ tryConsumeLambdaSpecifierToken(*this, MutableLoc, ConstexprLoc,
+ ConstevalLoc, DeclEndLoc);
+
+ addConstexprToLambdaDeclSpecifier(*this, ConstexprLoc, DS);
+ addConstevalToLambdaDeclSpecifier(*this, ConstevalLoc, DS);
+ };
auto ParseLambdaSpecifiers =
- [&](SourceLocation LParenLoc, SourceLocation RParenLoc,
- MutableArrayRef<DeclaratorChunk::ParamInfo> ParamInfo,
+ [&](MutableArrayRef<DeclaratorChunk::ParamInfo> ParamInfo,
SourceLocation EllipsisLoc) {
- SourceLocation DeclEndLoc = RParenLoc;
-
- // GNU-style attributes must be parsed before the mutable specifier to
- // be compatible with GCC. MSVC-style attributes must be parsed before
- // the mutable specifier to be compatible with MSVC.
- MaybeParseAttributes(PAKM_GNU | PAKM_Declspec, Attr);
-
- // Parse mutable-opt and/or constexpr-opt or consteval-opt, and update
- // the DeclEndLoc.
- SourceLocation MutableLoc;
- SourceLocation ConstexprLoc;
- SourceLocation ConstevalLoc;
- tryConsumeLambdaSpecifierToken(*this, MutableLoc, ConstexprLoc,
- ConstevalLoc, DeclEndLoc);
-
- addConstexprToLambdaDeclSpecifier(*this, ConstexprLoc, DS);
- addConstevalToLambdaDeclSpecifier(*this, ConstevalLoc, DS);
// Parse exception-specification[opt].
ExceptionSpecificationType ESpecType = EST_None;
SourceRange ESpecRange;
@@ -1393,20 +1402,22 @@
/*DeclsInPrototype=*/None, LParenLoc, FunLocalRangeEnd, D,
TrailingReturnType, TrailingReturnTypeLoc, &DS),
std::move(Attr), DeclEndLoc);
+
+ if (HasParentheses && Tok.is(tok::kw_requires))
+ ParseTrailingRequiresClause(D);
};
- if (Tok.is(tok::l_paren)) {
- ParseScope PrototypeScope(this, Scope::FunctionPrototypeScope |
- Scope::FunctionDeclarationScope |
- Scope::DeclScope);
+ ParseScope Prototype(this, Scope::FunctionPrototypeScope |
+ Scope::FunctionDeclarationScope |
+ Scope::DeclScope);
+ // Parse parameter-declaration-clause.
+ SmallVector<DeclaratorChunk::ParamInfo, 16> ParamInfo;
+ SourceLocation EllipsisLoc;
+ if (Tok.is(tok::l_paren)) {
BalancedDelimiterTracker T(*this, tok::l_paren);
T.consumeOpen();
- SourceLocation LParenLoc = T.getOpenLocation();
-
- // Parse parameter-declaration-clause.
- SmallVector<DeclaratorChunk::ParamInfo, 16> ParamInfo;
- SourceLocation EllipsisLoc;
+ LParenLoc = T.getOpenLocation();
if (Tok.isNot(tok::r_paren)) {
Actions.RecordParsingTemplateParameterDepth(
@@ -1424,36 +1435,38 @@
}
T.consumeClose();
+ DeclEndLoc = RParenLoc = T.getCloseLocation();
+ HasParentheses = true;
+ }
- // Parse lambda-specifiers.
- ParseLambdaSpecifiers(LParenLoc, /*DeclEndLoc=*/T.getCloseLocation(),
- ParamInfo, EllipsisLoc);
-
- // Parse requires-clause[opt].
- if (Tok.is(tok::kw_requires))
- ParseTrailingRequiresClause(D);
- } else if (Tok.isOneOf(tok::kw_mutable, tok::arrow, tok::kw___attribute,
- tok::kw_constexpr, tok::kw_consteval,
- tok::kw___private, tok::kw___global, tok::kw___local,
- tok::kw___constant, tok::kw___generic,
- tok::kw_requires, tok::kw_noexcept) ||
- (Tok.is(tok::l_square) && NextToken().is(tok::l_square))) {
- if (!getLangOpts().CPlusPlus2b)
+ if (Tok.isOneOf(tok::kw_mutable, tok::arrow, tok::kw___attribute,
+ tok::kw_constexpr, tok::kw_consteval, tok::kw___private,
+ tok::kw___global, tok::kw___local, tok::kw___constant,
+ tok::kw___generic, tok::kw_requires, tok::kw_noexcept) ||
+ (Tok.is(tok::l_square) && NextToken().is(tok::l_square))) {
+ HasSpecifiers = true;
+ if (!HasParentheses && !getLangOpts().CPlusPlus2b) {
// It's common to forget that one needs '()' before 'mutable', an
// attribute specifier, the result type, or the requires clause. Deal with
// this.
Diag(Tok, diag::ext_lambda_missing_parens)
<< FixItHint::CreateInsertion(Tok.getLocation(), "() ");
+ }
+ }
- SourceLocation NoLoc;
- // Parse lambda-specifiers.
- std::vector<DeclaratorChunk::ParamInfo> EmptyParamInfo;
- ParseLambdaSpecifiers(/*LParenLoc=*/NoLoc, /*RParenLoc=*/NoLoc,
- EmptyParamInfo, /*EllipsisLoc=*/NoLoc);
+ if (HasParentheses || HasSpecifiers) {
+ ParseConstexprAndMutableSpecifiers();
}
+ Actions.ActOnLambdaClosureQualifiers(Intro, MutableLoc, DeclEndLoc, DS);
+
+ if (HasSpecifiers || HasParentheses)
+ ParseLambdaSpecifiers(ParamInfo, EllipsisLoc);
+
WarnIfHasCUDATargetAttr();
+ Prototype.Exit();
+
// FIXME: Rename BlockScope -> ClosureScope if we decide to continue using
// it.
unsigned ScopeFlags = Scope::BlockScope | Scope::FnScope | Scope::DeclScope |
@@ -1472,6 +1485,7 @@
StmtResult Stmt(ParseCompoundStatementBody());
BodyScope.Exit();
TemplateParamScope.Exit();
+ LambdaScope.Exit();
if (!Stmt.isInvalid() && !TrailingReturnType.isInvalid())
return Actions.ActOnLambdaExpr(LambdaBeginLoc, Stmt.get(), getCurScope());
Index: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -6837,11 +6837,9 @@
///
/// CodeGen handles emission of lambda captures, ignoring these dummy
/// variables appropriately.
- VarDecl *createLambdaInitCaptureVarDecl(SourceLocation Loc,
- QualType InitCaptureType,
- SourceLocation EllipsisLoc,
- IdentifierInfo *Id,
- unsigned InitStyle, Expr *Init);
+ VarDecl *createLambdaInitCaptureVarDecl(
+ SourceLocation Loc, QualType InitCaptureType, SourceLocation EllipsisLoc,
+ IdentifierInfo *Id, unsigned InitStyle, Expr *Init, DeclContext *DeclCtx);
/// Add an init-capture to a lambda scope.
void addInitCapture(sema::LambdaScopeInfo *LSI, VarDecl *Var);
@@ -6850,21 +6848,28 @@
/// given lambda.
void finishLambdaExplicitCaptures(sema::LambdaScopeInfo *LSI);
- /// \brief This is called after parsing the explicit template parameter list
+ /// Deduce a block or lambda's return type based on the return
+ /// statements present in the body.
+ void deduceClosureReturnType(sema::CapturingScopeInfo &CSI);
+
+ /// Once the Lambdas capture are known, we can
+ /// start to create the closure, call operator method,
+ /// and keep track of the captures.
+ /// We do the capture lookup here, but they are not actually captured
+ /// until after we know what the qualifiers of the call operator are.
+ void ActOnLambdaIntroducer(LambdaIntroducer &Intro, Scope *CurContext);
+
+ /// This is called after parsing the explicit template parameter list
/// on a lambda (if it exists) in C++2a.
- void ActOnLambdaExplicitTemplateParameterList(SourceLocation LAngleLoc,
+ void ActOnLambdaExplicitTemplateParameterList(LambdaIntroducer &Intro,
+ SourceLocation LAngleLoc,
ArrayRef<NamedDecl *> TParams,
SourceLocation RAngleLoc,
ExprResult RequiresClause);
- /// Introduce the lambda parameters into scope.
- void addLambdaParameters(
- ArrayRef<LambdaIntroducer::LambdaCapture> Captures,
- CXXMethodDecl *CallOperator, Scope *CurScope);
-
- /// Deduce a block or lambda's return type based on the return
- /// statements present in the body.
- void deduceClosureReturnType(sema::CapturingScopeInfo &CSI);
+ void ActOnLambdaClosureQualifiers(LambdaIntroducer &Intro,
+ SourceLocation MutableLoc,
+ SourceLocation EndLoc, const DeclSpec &DS);
/// ActOnStartOfLambdaDefinition - This is called just before we start
/// parsing the body of a lambda; it analyzes the explicit captures and
Index: clang/include/clang/Sema/ScopeInfo.h
===================================================================
--- clang/include/clang/Sema/ScopeInfo.h
+++ clang/include/clang/Sema/ScopeInfo.h
@@ -831,6 +831,25 @@
/// The lambda's compiler-generated \c operator().
CXXMethodDecl *CallOperator = nullptr;
+ struct DelayedCapture {
+ VarDecl *Var;
+ SourceLocation Loc;
+ LambdaCaptureKind Kind;
+ };
+
+ /// Holds the captures until we parsed the qualifiers,
+ /// as the cv qualified type of capture can only be computed at that point,
+ /// and the capture should not be visible before.
+ llvm::DenseMap<unsigned, DelayedCapture> DelayedCaptures;
+
+ /// Whether the current scope when parsing the lambda
+ /// is after the call operator qualifiers,
+ /// which is the point at which the captures are usable
+ /// per [expr.prim.id.unqual]/p3.2 and [expr.prim.lambda.capture]/6.
+ /// This is set to false by default as the lambda can be reconstructed during
+ /// instantiation
+ bool BeforeLambdaQualifiersScope = false;
+
/// Source range covering the lambda introducer [...].
SourceRange IntroducerRange;
Index: clang/include/clang/Sema/Scope.h
===================================================================
--- clang/include/clang/Sema/Scope.h
+++ clang/include/clang/Sema/Scope.h
@@ -44,11 +44,11 @@
enum ScopeFlags {
/// This indicates that the scope corresponds to a function, which
/// means that labels are set here.
- FnScope = 0x01,
+ FnScope = 0x01,
/// This is a while, do, switch, for, etc that can have break
/// statements embedded into it.
- BreakScope = 0x02,
+ BreakScope = 0x02,
/// This is a while, do, for, which can have continue statements
/// embedded into it.
@@ -140,6 +140,12 @@
/// parsed. If such a scope is a ContinueScope, it's invalid to jump to the
/// continue block from here.
ConditionVarScope = 0x2000000,
+
+ /// This is the scope for a lambda, after the lambda introducer.
+ /// Lambdas need 2 FunctionPrototypeScope scopes ( because there is a
+ /// template scope in between),
+ /// the outer scope does not increase the depth of recursion.
+ LambdaScope = 0x4000000,
};
private:
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -7698,6 +7698,8 @@
def err_lambda_impcap : Error<
"variable %0 cannot be implicitly captured in a lambda with no "
"capture-default specified">;
+ def err_lambda_used_before_capture: Error<
+ "captured variable %0 cannot appear before the end of the lambda's parameter list">;
def note_lambda_variable_capture_fixit : Note<
"capture %0 by %select{value|reference}1">;
def note_lambda_default_capture_fixit : Note<
Index: clang/include/clang/AST/DeclCXX.h
===================================================================
--- clang/include/clang/AST/DeclCXX.h
+++ clang/include/clang/AST/DeclCXX.h
@@ -1799,6 +1799,20 @@
return getLambdaData().MethodTyInfo;
}
+ void setLambdaTypeInfo(TypeSourceInfo *TS) {
+ auto *DD = DefinitionData;
+ assert(DD && DD->IsLambda && "setting lambda property of non-lambda class");
+ auto &DL = static_cast<LambdaDefinitionData &>(*DD);
+ DL.MethodTyInfo = TS;
+ }
+
+ void setLambdaIsGeneric(bool IsGeneric) {
+ auto *DD = DefinitionData;
+ assert(DD && DD->IsLambda && "setting lambda property of non-lambda class");
+ auto &DL = static_cast<LambdaDefinitionData &>(*DD);
+ DL.IsGenericLambda = IsGeneric;
+ }
+
// Determine whether this type is an Interface Like type for
// __interface inheritance purposes.
bool isInterfaceLike() const;
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits