/// ActOnLambdaExpr - This is called when the body of a lambda expression
/// was successfully completed.
ExprResult ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body,
- Scope *CurScope,
- bool IsInstantiation = false);
+ Scope *CurScope);
+
+ /// \brief Complete a lambda-expression having processed and attached the
+ /// lambda body.
+ ExprResult BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc,
+ sema::LambdaScopeInfo *LSI);
/// \brief Define the "body" of the conversion from a lambda object to a
/// function pointer.
static bool isTrackedVar(const VarDecl *vd, const DeclContext *dc) {
if (vd->isLocalVarDecl() && !vd->hasGlobalStorage() &&
!vd->isExceptionVariable() && !vd->isInitCapture() &&
- vd->getDeclContext() == dc) {
+ !vd->isImplicit() && vd->getDeclContext() == dc) {
QualType ty = vd->getType();
return ty->isScalarType() || ty->isVectorType() || ty->isRecordType();
}
Context.adjustDeducedFunctionResultType(
FD, SubstAutoType(ResultType.getType(), Context.VoidTy));
}
+ } else if (getLangOpts().CPlusPlus11 && isLambdaCallOperator(FD)) {
+ auto *LSI = getCurLambda();
+ if (LSI->HasImplicitReturnType) {
+ deduceClosureReturnType(*LSI);
+
+ // C++11 [expr.prim.lambda]p4:
+ // [...] if there are no return statements in the compound-statement
+ // [the deduced type is] the type void
+ QualType RetType =
+ LSI->ReturnType.isNull() ? Context.VoidTy : LSI->ReturnType;
+
+ // Update the return type to the deduced type.
+ const FunctionProtoType *Proto =
+ FD->getType()->getAs<FunctionProtoType>();
+ FD->setType(Context.getFunctionType(RetType, Proto->getParamTypes(),
+ Proto->getExtProtoInfo()));
+ }
}
// The only way to be included in UndefinedButUsed is if there is an
}
/// \brief Create a field within the lambda class for the variable
-/// being captured. Handle Array captures.
-static ExprResult addAsFieldToClosureType(Sema &S,
- LambdaScopeInfo *LSI,
- VarDecl *Var, QualType FieldType,
- QualType DeclRefType,
- SourceLocation Loc,
- bool RefersToCapturedVariable) {
+/// being captured.
+static void addAsFieldToClosureType(Sema &S, LambdaScopeInfo *LSI, VarDecl *Var,
+ QualType FieldType, QualType DeclRefType,
+ SourceLocation Loc,
+ bool RefersToCapturedVariable) {
CXXRecordDecl *Lambda = LSI->Lambda;
// Build the non-static data member.
Field->setImplicit(true);
Field->setAccess(AS_private);
Lambda->addDecl(Field);
-
- // C++11 [expr.prim.lambda]p21:
- // When the lambda-expression is evaluated, the entities that
- // are captured by copy are used to direct-initialize each
- // corresponding non-static data member of the resulting closure
- // object. (For array members, the array elements are
- // direct-initialized in increasing subscript order.) These
- // initializations are performed in the (unspecified) order in
- // which the non-static data members are declared.
-
- // Introduce a new evaluation context for the initialization, so
- // that temporaries introduced as part of the capture are retained
- // to be re-"exported" from the lambda expression itself.
- EnterExpressionEvaluationContext scope(S, Sema::PotentiallyEvaluated);
-
- // C++ [expr.prim.labda]p12:
- // An entity captured by a lambda-expression is odr-used (3.2) in
- // the scope containing the lambda-expression.
- Expr *Ref = new (S.Context) DeclRefExpr(Var, RefersToCapturedVariable,
- DeclRefType, VK_LValue, Loc);
- Var->setReferenced(true);
- Var->markUsed(S.Context);
-
- // When the field has array type, create index variables for each
- // dimension of the array. We use these index variables to subscript
- // the source array, and other clients (e.g., CodeGen) will perform
- // the necessary iteration with these index variables.
- SmallVector<VarDecl *, 4> IndexVariables;
- QualType BaseType = FieldType;
- QualType SizeType = S.Context.getSizeType();
- LSI->ArrayIndexStarts.push_back(LSI->ArrayIndexVars.size());
- while (const ConstantArrayType *Array
- = S.Context.getAsConstantArrayType(BaseType)) {
- // Create the iteration variable for this array index.
- IdentifierInfo *IterationVarName = nullptr;
- {
- SmallString<8> Str;
- llvm::raw_svector_ostream OS(Str);
- OS << "__i" << IndexVariables.size();
- IterationVarName = &S.Context.Idents.get(OS.str());
- }
- VarDecl *IterationVar
- = VarDecl::Create(S.Context, S.CurContext, Loc, Loc,
- IterationVarName, SizeType,
- S.Context.getTrivialTypeSourceInfo(SizeType, Loc),
- SC_None);
- IndexVariables.push_back(IterationVar);
- LSI->ArrayIndexVars.push_back(IterationVar);
-
- // Create a reference to the iteration variable.
- ExprResult IterationVarRef
- = S.BuildDeclRefExpr(IterationVar, SizeType, VK_LValue, Loc);
- assert(!IterationVarRef.isInvalid() &&
- "Reference to invented variable cannot fail!");
- IterationVarRef = S.DefaultLvalueConversion(IterationVarRef.get());
- assert(!IterationVarRef.isInvalid() &&
- "Conversion of invented variable cannot fail!");
-
- // Subscript the array with this iteration variable.
- ExprResult Subscript = S.CreateBuiltinArraySubscriptExpr(
- Ref, Loc, IterationVarRef.get(), Loc);
- if (Subscript.isInvalid()) {
- S.CleanupVarDeclMarking();
- S.DiscardCleanupsInEvaluationContext();
- return ExprError();
- }
-
- Ref = Subscript.get();
- BaseType = Array->getElementType();
- }
-
- // Construct the entity that we will be initializing. For an array, this
- // will be first element in the array, which may require several levels
- // of array-subscript entities.
- SmallVector<InitializedEntity, 4> Entities;
- Entities.reserve(1 + IndexVariables.size());
- Entities.push_back(
- InitializedEntity::InitializeLambdaCapture(Var->getIdentifier(),
- Field->getType(), Loc));
- for (unsigned I = 0, N = IndexVariables.size(); I != N; ++I)
- Entities.push_back(InitializedEntity::InitializeElement(S.Context,
- 0,
- Entities.back()));
-
- InitializationKind InitKind
- = InitializationKind::CreateDirect(Loc, Loc, Loc);
- InitializationSequence Init(S, Entities.back(), InitKind, Ref);
- ExprResult Result(true);
- if (!Init.Diagnose(S, Entities.back(), InitKind, Ref))
- Result = Init.Perform(S, Entities.back(), InitKind, Ref);
-
- // If this initialization requires any cleanups (e.g., due to a
- // default argument to a copy constructor), note that for the
- // lambda.
- if (S.ExprNeedsCleanups)
- LSI->ExprNeedsCleanups = true;
-
- // Exit the expression evaluation context used for the capture.
- S.CleanupVarDeclMarking();
- S.DiscardCleanupsInEvaluationContext();
- return Result;
}
-
-
/// \brief Capture the given variable in the lambda.
static bool captureInLambda(LambdaScopeInfo *LSI,
VarDecl *Var,
}
// Capture this variable in the lambda.
- Expr *CopyExpr = nullptr;
- if (BuildAndDiagnose) {
- ExprResult Result = addAsFieldToClosureType(S, LSI, Var,
- CaptureType, DeclRefType, Loc,
- RefersToCapturedVariable);
- if (!Result.isInvalid())
- CopyExpr = Result.get();
- }
+ if (BuildAndDiagnose)
+ addAsFieldToClosureType(S, LSI, Var, CaptureType, DeclRefType, Loc,
+ RefersToCapturedVariable);
// Compute the type of a reference to this captured variable.
if (ByRef)
// Add the capture.
if (BuildAndDiagnose)
LSI->addCapture(Var, /*IsBlock=*/false, ByRef, RefersToCapturedVariable,
- Loc, EllipsisLoc, CaptureType, CopyExpr);
+ Loc, EllipsisLoc, CaptureType, /*CopyExpr=*/nullptr);
return true;
}
-bool Sema::tryCaptureVariable(VarDecl *Var, SourceLocation ExprLoc,
- TryCaptureKind Kind, SourceLocation EllipsisLoc,
- bool BuildAndDiagnose,
- QualType &CaptureType,
- QualType &DeclRefType,
- const unsigned *const FunctionScopeIndexToStopAt) {
- bool Nested = Var->isInitCapture();
+bool Sema::tryCaptureVariable(
+ VarDecl *Var, SourceLocation ExprLoc, TryCaptureKind Kind,
+ SourceLocation EllipsisLoc, bool BuildAndDiagnose, QualType &CaptureType,
+ QualType &DeclRefType, const unsigned *const FunctionScopeIndexToStopAt) {
+ // An init-capture is notionally from the context surrounding its
+ // declaration, but its parent DC is the lambda class.
+ DeclContext *VarDC = Var->getDeclContext();
+ if (Var->isInitCapture())
+ VarDC = VarDC->getParent();
DeclContext *DC = CurContext;
const unsigned MaxFunctionScopesIndex = FunctionScopeIndexToStopAt
}
- // If the variable is declared in the current context (and is not an
- // init-capture), there is no need to capture it.
- if (!Nested && Var->getDeclContext() == DC) return true;
+ // 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.
// the variable.
CaptureType = Var->getType();
DeclRefType = CaptureType.getNonReferenceType();
+ bool Nested = false;
bool Explicit = (Kind != TryCapture_Implicit);
unsigned FunctionScopesIndex = MaxFunctionScopesIndex;
do {
FunctionScopesIndex--;
DC = ParentDC;
Explicit = false;
- } while (!Var->getDeclContext()->Equals(DC));
+ } while (!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
}
void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
- Declarator &ParamInfo, Scope *CurScope) {
+ Declarator &ParamInfo,
+ Scope *CurScope) {
// Determine if we're within a context where we know that the lambda will
// be dependent, because there are template parameters in scope.
bool KnownDependent = false;
PushDeclContext(CurScope, Method);
// Build the lambda scope.
- buildLambdaScope(LSI, Method,
- Intro.Range,
- Intro.Default, Intro.DefaultLoc,
- ExplicitParams,
- ExplicitResultType,
- !Method->isConst());
+ 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
void Sema::ActOnLambdaError(SourceLocation StartLoc, Scope *CurScope,
bool IsInstantiation) {
- LambdaScopeInfo *LSI = getCurLambda();
+ LambdaScopeInfo *LSI = cast<LambdaScopeInfo>(FunctionScopes.back());
// Leave the expression-evaluation context.
DiscardCleanupsInEvaluationContext();
Conversion->setImplicit(true);
Class->addDecl(Conversion);
}
+
+static ExprResult performLambdaVarCaptureInitialization(
+ Sema &S, LambdaScopeInfo::Capture &Capture,
+ FieldDecl *Field,
+ SmallVectorImpl<VarDecl *> &ArrayIndexVars,
+ SmallVectorImpl<unsigned> &ArrayIndexStarts) {
+ assert(Capture.isVariableCapture() && "not a variable capture");
+
+ auto *Var = Capture.getVariable();
+ SourceLocation Loc = Capture.getLocation();
+
+ // C++11 [expr.prim.lambda]p21:
+ // When the lambda-expression is evaluated, the entities that
+ // are captured by copy are used to direct-initialize each
+ // corresponding non-static data member of the resulting closure
+ // object. (For array members, the array elements are
+ // direct-initialized in increasing subscript order.) These
+ // initializations are performed in the (unspecified) order in
+ // which the non-static data members are declared.
+
+ // C++ [expr.prim.lambda]p12:
+ // An entity captured by a lambda-expression is odr-used (3.2) in
+ // the scope containing the lambda-expression.
+ ExprResult RefResult = S.BuildDeclarationNameExpr(
+ CXXScopeSpec(), DeclarationNameInfo(Var->getDeclName(), Loc), Var);
+ if (RefResult.isInvalid())
+ return ExprError();
+ Expr *Ref = RefResult.get();
+
+ QualType FieldType = Field->getType();
+
+ // When the variable has array type, create index variables for each
+ // dimension of the array. We use these index variables to subscript
+ // the source array, and other clients (e.g., CodeGen) will perform
+ // the necessary iteration with these index variables.
+ //
+ // FIXME: This is dumb. Add a proper AST representation for array
+ // copy-construction and use it here.
+ SmallVector<VarDecl *, 4> IndexVariables;
+ QualType BaseType = FieldType;
+ QualType SizeType = S.Context.getSizeType();
+ ArrayIndexStarts.push_back(ArrayIndexVars.size());
+ while (const ConstantArrayType *Array
+ = S.Context.getAsConstantArrayType(BaseType)) {
+ // Create the iteration variable for this array index.
+ IdentifierInfo *IterationVarName = nullptr;
+ {
+ SmallString<8> Str;
+ llvm::raw_svector_ostream OS(Str);
+ OS << "__i" << IndexVariables.size();
+ IterationVarName = &S.Context.Idents.get(OS.str());
+ }
+ VarDecl *IterationVar = VarDecl::Create(
+ S.Context, S.CurContext, Loc, Loc, IterationVarName, SizeType,
+ S.Context.getTrivialTypeSourceInfo(SizeType, Loc), SC_None);
+ IterationVar->setImplicit();
+ IndexVariables.push_back(IterationVar);
+ ArrayIndexVars.push_back(IterationVar);
+
+ // Create a reference to the iteration variable.
+ ExprResult IterationVarRef =
+ S.BuildDeclRefExpr(IterationVar, SizeType, VK_LValue, Loc);
+ assert(!IterationVarRef.isInvalid() &&
+ "Reference to invented variable cannot fail!");
+ IterationVarRef = S.DefaultLvalueConversion(IterationVarRef.get());
+ assert(!IterationVarRef.isInvalid() &&
+ "Conversion of invented variable cannot fail!");
+
+ // Subscript the array with this iteration variable.
+ ExprResult Subscript =
+ S.CreateBuiltinArraySubscriptExpr(Ref, Loc, IterationVarRef.get(), Loc);
+ if (Subscript.isInvalid())
+ return ExprError();
+
+ Ref = Subscript.get();
+ BaseType = Array->getElementType();
+ }
+
+ // Construct the entity that we will be initializing. For an array, this
+ // will be first element in the array, which may require several levels
+ // of array-subscript entities.
+ SmallVector<InitializedEntity, 4> Entities;
+ Entities.reserve(1 + IndexVariables.size());
+ Entities.push_back(InitializedEntity::InitializeLambdaCapture(
+ Var->getIdentifier(), FieldType, Loc));
+ for (unsigned I = 0, N = IndexVariables.size(); I != N; ++I)
+ Entities.push_back(
+ InitializedEntity::InitializeElement(S.Context, 0, Entities.back()));
+
+ InitializationKind InitKind = InitializationKind::CreateDirect(Loc, Loc, Loc);
+ InitializationSequence Init(S, Entities.back(), InitKind, Ref);
+ return Init.Perform(S, Entities.back(), InitKind, Ref);
+}
ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body,
- Scope *CurScope,
- bool IsInstantiation) {
+ Scope *CurScope) {
+ LambdaScopeInfo LSI = *cast<LambdaScopeInfo>(FunctionScopes.back());
+ ActOnFinishFunctionBody(LSI.CallOperator, Body);
+ return BuildLambdaExpr(StartLoc, Body->getLocEnd(), &LSI);
+}
+
+ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc,
+ LambdaScopeInfo *LSI) {
// Collect information from the lambda scope.
SmallVector<LambdaCapture, 4> Captures;
SmallVector<Expr *, 4> CaptureInits;
SmallVector<VarDecl *, 4> ArrayIndexVars;
SmallVector<unsigned, 4> ArrayIndexStarts;
{
- LambdaScopeInfo *LSI = getCurLambda();
CallOperator = LSI->CallOperator;
Class = LSI->Lambda;
IntroducerRange = LSI->IntroducerRange;
ArrayIndexVars.swap(LSI->ArrayIndexVars);
ArrayIndexStarts.swap(LSI->ArrayIndexStarts);
+ CallOperator->setLexicalDeclContext(Class);
+ Decl *TemplateOrNonTemplateCallOperatorDecl =
+ CallOperator->getDescribedFunctionTemplate()
+ ? CallOperator->getDescribedFunctionTemplate()
+ : cast<Decl>(CallOperator);
+
+ TemplateOrNonTemplateCallOperatorDecl->setLexicalDeclContext(Class);
+ Class->addDecl(TemplateOrNonTemplateCallOperatorDecl);
+
+ PopExpressionEvaluationContext();
+
// Translate captures.
- for (unsigned I = 0, N = LSI->Captures.size(); I != N; ++I) {
+ auto CurField = Class->field_begin();
+ for (unsigned I = 0, N = LSI->Captures.size(); I != N; ++I, ++CurField) {
LambdaScopeInfo::Capture From = LSI->Captures[I];
assert(!From.isBlockCapture() && "Cannot capture __block variables");
bool IsImplicit = I >= LSI->NumExplicitCaptures;
}
VarDecl *Var = From.getVariable();
- LambdaCaptureKind Kind = From.isCopyCapture()? LCK_ByCopy : LCK_ByRef;
+ LambdaCaptureKind Kind = From.isCopyCapture() ? LCK_ByCopy : LCK_ByRef;
Captures.push_back(LambdaCapture(From.getLocation(), IsImplicit, Kind,
Var, From.getEllipsisLoc()));
- CaptureInits.push_back(From.getInitExpr());
+ Expr *Init = From.getInitExpr();
+ if (!Init) {
+ auto InitResult = performLambdaVarCaptureInitialization(
+ *this, From, *CurField, ArrayIndexVars, ArrayIndexStarts);
+ if (InitResult.isInvalid())
+ return ExprError();
+ Init = InitResult.get();
+ }
+ CaptureInits.push_back(Init);
}
switch (LSI->ImpCaptureStyle) {
}
CaptureDefaultLoc = LSI->CaptureDefaultLoc;
- // C++11 [expr.prim.lambda]p4:
- // If a lambda-expression does not include a
- // trailing-return-type, it is as if the trailing-return-type
- // denotes the following type:
- //
- // Skip for C++1y return type deduction semantics which uses
- // different machinery.
- // FIXME: Refactor and Merge the return type deduction machinery.
- // FIXME: Assumes current resolution to core issue 975.
- if (LSI->HasImplicitReturnType && !getLangOpts().CPlusPlus14) {
- deduceClosureReturnType(*LSI);
-
- // - if there are no return statements in the
- // compound-statement, or all return statements return
- // either an expression of type void or no expression or
- // braced-init-list, the type void;
- if (LSI->ReturnType.isNull()) {
- LSI->ReturnType = Context.VoidTy;
- }
-
- // Create a function type with the inferred return type.
- const FunctionProtoType *Proto
- = CallOperator->getType()->getAs<FunctionProtoType>();
- QualType FunctionTy = Context.getFunctionType(
- LSI->ReturnType, Proto->getParamTypes(), Proto->getExtProtoInfo());
- CallOperator->setType(FunctionTy);
- }
- // C++ [expr.prim.lambda]p7:
- // The lambda-expression's compound-statement yields the
- // function-body (8.4) of the function call operator [...].
- ActOnFinishFunctionBody(CallOperator, Body, IsInstantiation);
- CallOperator->setLexicalDeclContext(Class);
- Decl *TemplateOrNonTemplateCallOperatorDecl =
- CallOperator->getDescribedFunctionTemplate()
- ? CallOperator->getDescribedFunctionTemplate()
- : cast<Decl>(CallOperator);
-
- TemplateOrNonTemplateCallOperatorDecl->setLexicalDeclContext(Class);
- Class->addDecl(TemplateOrNonTemplateCallOperatorDecl);
-
- PopExpressionEvaluationContext();
-
// C++11 [expr.prim.lambda]p6:
// The closure type for a lambda-expression with no lambda-capture
// has a public non-virtual non-explicit const conversion function
Captures,
ExplicitParams, ExplicitResultType,
CaptureInits, ArrayIndexVars,
- ArrayIndexStarts, Body->getLocEnd(),
+ ArrayIndexStarts, EndLoc,
ContainsUnexpandedParameterPack);
if (!CurContext->isDependentContext()) {
}
void transformedLocalDecl(Decl *Old, Decl *New) {
+ // If we've instantiated the call operator of a lambda or the call
+ // operator template of a generic lambda, update the "instantiation of"
+ // information.
+ auto *NewMD = dyn_cast<CXXMethodDecl>(New);
+ if (NewMD && isLambdaCallOperator(NewMD)) {
+ auto *OldMD = dyn_cast<CXXMethodDecl>(Old);
+ if (auto *NewTD = NewMD->getDescribedFunctionTemplate())
+ NewTD->setInstantiatedFromMemberTemplate(
+ OldMD->getDescribedFunctionTemplate());
+ else
+ NewMD->setInstantiationOfMemberFunction(OldMD,
+ TSK_ImplicitInstantiation);
+ }
+
SemaRef.CurrentInstantiationScope->InstantiatedLocal(Old, New);
}
return TreeTransform<TemplateInstantiator>::TransformLambdaExpr(E);
}
- ExprResult TransformLambdaScope(LambdaExpr *E,
- CXXMethodDecl *NewCallOperator,
- ArrayRef<InitCaptureInfoTy> InitCaptureExprsAndTypes) {
- CXXMethodDecl *const OldCallOperator = E->getCallOperator();
- // In the generic lambda case, we set the NewTemplate to be considered
- // an "instantiation" of the OldTemplate.
- if (FunctionTemplateDecl *const NewCallOperatorTemplate =
- NewCallOperator->getDescribedFunctionTemplate()) {
-
- FunctionTemplateDecl *const OldCallOperatorTemplate =
- OldCallOperator->getDescribedFunctionTemplate();
- NewCallOperatorTemplate->setInstantiatedFromMemberTemplate(
- OldCallOperatorTemplate);
- } else
- // For a non-generic lambda we set the NewCallOperator to
- // be an instantiation of the OldCallOperator.
- NewCallOperator->setInstantiationOfMemberFunction(OldCallOperator,
- TSK_ImplicitInstantiation);
-
- return inherited::TransformLambdaScope(E, NewCallOperator,
- InitCaptureExprsAndTypes);
- }
TemplateParameterList *TransformTemplateParameterList(
TemplateParameterList *OrigTPL) {
if (!OrigTPL || !OrigTPL->size()) return OrigTPL;
StmtResult TransformCompoundStmt(CompoundStmt *S, bool IsStmtExpr);
ExprResult TransformCXXNamedCastExpr(CXXNamedCastExpr *E);
-
- typedef std::pair<ExprResult, QualType> InitCaptureInfoTy;
- /// \brief Transform the captures and body of a lambda expression.
- ExprResult TransformLambdaScope(LambdaExpr *E, CXXMethodDecl *CallOperator,
- ArrayRef<InitCaptureInfoTy> InitCaptureExprsAndTypes);
TemplateParameterList *TransformTemplateParameterList(
TemplateParameterList *TPL) {
TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
// Transform any init-capture expressions before entering the scope of the
// lambda body, because they are not semantically within that scope.
+ typedef std::pair<ExprResult, QualType> InitCaptureInfoTy;
SmallVector<InitCaptureInfoTy, 8> InitCaptureExprsAndTypes;
InitCaptureExprsAndTypes.resize(E->explicit_capture_end() -
- E->explicit_capture_begin());
+ E->explicit_capture_begin());
for (LambdaExpr::capture_iterator C = E->capture_begin(),
CEnd = E->capture_end();
C != CEnd; ++C) {
std::make_pair(NewExprInitResult, NewInitCaptureType);
}
- LambdaScopeInfo *LSI = getSema().PushLambdaScope();
- Sema::FunctionScopeRAII FuncScopeCleanup(getSema());
-
// Transform the template parameters, and add them to the current
// instantiation scope. The null case is handled correctly.
- LSI->GLTemplateParameterList = getDerived().TransformTemplateParameterList(
+ auto TPL = getDerived().TransformTemplateParameterList(
E->getTemplateParameterList());
// Transform the type of the original lambda's call operator.
NewCallOpType);
}
+ LambdaScopeInfo *LSI = getSema().PushLambdaScope();
+ Sema::FunctionScopeRAII FuncScopeCleanup(getSema());
+ LSI->GLTemplateParameterList = TPL;
+
// Create the local class that will describe the lambda.
CXXRecordDecl *Class
= getSema().createLambdaClosureType(E->getIntroducerRange(),
LSI->CallOperator = NewCallOperator;
getDerived().transformAttrs(E->getCallOperator(), NewCallOperator);
-
- // TransformLambdaScope will manage the function scope, so we can disable the
- // cleanup.
- FuncScopeCleanup.disable();
-
- return getDerived().TransformLambdaScope(E, NewCallOperator,
- InitCaptureExprsAndTypes);
-}
-
-template<typename Derived>
-ExprResult
-TreeTransform<Derived>::TransformLambdaScope(LambdaExpr *E,
- CXXMethodDecl *CallOperator,
- ArrayRef<InitCaptureInfoTy> InitCaptureExprsAndTypes) {
- bool Invalid = false;
+ getDerived().transformedLocalDecl(E->getCallOperator(), NewCallOperator);
// Introduce the context of the call operator.
- Sema::ContextRAII SavedContext(getSema(), CallOperator,
+ Sema::ContextRAII SavedContext(getSema(), NewCallOperator,
/*NewThisContext*/false);
- LambdaScopeInfo *const LSI = getSema().getCurLambda();
// Enter the scope of the lambda.
- getSema().buildLambdaScope(LSI, CallOperator, E->getIntroducerRange(),
- E->getCaptureDefault(),
- E->getCaptureDefaultLoc(),
- E->hasExplicitParameters(),
- E->hasExplicitResultType(),
- E->isMutable());
+ getSema().buildLambdaScope(LSI, NewCallOperator,
+ E->getIntroducerRange(),
+ E->getCaptureDefault(),
+ E->getCaptureDefaultLoc(),
+ E->hasExplicitParameters(),
+ E->hasExplicitResultType(),
+ E->isMutable());
+
+ bool Invalid = false;
// Transform captures.
bool FinishedExplicitCaptures = false;
// Rebuild init-captures, including the implied field declaration.
if (C->isInitCapture()) {
-
InitCaptureInfoTy InitExprTypePair =
InitCaptureExprsAndTypes[C - E->capture_begin()];
ExprResult Init = InitExprTypePair.first;
if (!FinishedExplicitCaptures)
getSema().finishLambdaExplicitCaptures(LSI);
-
// Enter a new evaluation context to insulate the lambda from any
// cleanups from the enclosing full-expression.
getSema().PushExpressionEvaluationContext(Sema::PotentiallyEvaluated);
- if (Invalid) {
- getSema().ActOnLambdaError(E->getLocStart(), /*CurScope=*/nullptr,
- /*IsInstantiation=*/true);
- return ExprError();
- }
-
// Instantiate the body of the lambda expression.
- StmtResult Body = getDerived().TransformStmt(E->getBody());
+ StmtResult Body =
+ Invalid ? StmtError() : getDerived().TransformStmt(E->getBody());
+
+ // ActOnLambda* will pop the function scope for us.
+ FuncScopeCleanup.disable();
+
if (Body.isInvalid()) {
+ SavedContext.pop();
getSema().ActOnLambdaError(E->getLocStart(), /*CurScope=*/nullptr,
/*IsInstantiation=*/true);
return ExprError();
}
- return getSema().ActOnLambdaExpr(E->getLocStart(), Body.get(),
- /*CurScope=*/nullptr,
- /*IsInstantiation=*/true);
+ // Copy the LSI before ActOnFinishFunctionBody removes it.
+ // FIXME: This is dumb. Store the lambda information somewhere that outlives
+ // the call operator.
+ auto LSICopy = *LSI;
+ getSema().ActOnFinishFunctionBody(NewCallOperator, Body.get(),
+ /*IsInstantiation*/ true);
+ SavedContext.pop();
+
+ return getSema().BuildLambdaExpr(E->getLocStart(), Body.get()->getLocEnd(),
+ &LSICopy);
}
template<typename Derived>
struct Boom {
Boom(const Boom&) {
T* x = 1; // expected-error{{cannot initialize a variable of type 'int *' with an rvalue of type 'int'}} \
- // expected-error{{cannot initialize a variable of type 'float *' with an rvalue of type 'int'}} \
// expected-error{{cannot initialize a variable of type 'double *' with an rvalue of type 'int'}}
}
void tickle() const;
Boom<double> boom_double) {
const std::type_info &ti1
= typeid([=,&p]() -> P& { boom_int.tickle(); return p; }()); // expected-note{{in instantiation of member function 'Boom<int>::Boom' requested here}}
+ // This does not cause the instantiation of the Boom copy constructor,
+ // because the copy-initialization of the capture of boom_float occurs in an
+ // unevaluated operand.
const std::type_info &ti2
- = typeid([=]() -> int { boom_float.tickle(); return 0; }()); // expected-error{{lambda expression in an unevaluated operand}} \
- // expected-note{{in instantiation of member function 'Boom<float>::Boom' requested here}}
+ = typeid([=]() -> int { boom_float.tickle(); return 0; }()); // expected-error{{lambda expression in an unevaluated operand}}
auto foo = [=]() -> int { boom_double.tickle(); return 0; }; // expected-note{{in instantiation of member function 'Boom<double>::Boom' requested here}}
}
template<typename T>
struct Boom {
Boom(const Boom&) {
- T* x = 1; // expected-error{{cannot initialize a variable of type 'int *' with an rvalue of type 'int'}} \
- // expected-error{{cannot initialize a variable of type 'float *' with an rvalue of type 'int'}}
+ T* x = 1; // expected-error{{cannot initialize a variable of type 'float *' with an rvalue of type 'int'}}
}
void tickle() const;
};
void odr_used(R &r, Boom<T> boom) {
const std::type_info &ti
= typeid([=,&r] () -> R& { // expected-error{{lambda expression in an unevaluated operand}}
- boom.tickle(); // expected-note{{in instantiation of member function}}
+ boom.tickle();
return r;
}());
}
--- /dev/null
+// RUN: %clang_cc1 -std=c++11 -verify %s -Wno-unused
+
+// This must be at the start of the file (the failure depends on a SmallPtrSet
+// not having been reallocated yet).
+void fn1() {
+ // expected-no-diagnostics
+ constexpr int kIsolationClass = 0;
+ const int kBytesPerConnection = 0;
+ [=] { kIsolationClass, kBytesPerConnection, kBytesPerConnection; };
+}
int L2 = ([](auto i) { return i; })(2);
void fooG(T i = ([] (auto i) { return i; })(2)) { }
int BG : ([](auto i) { return i; })(3); //expected-error{{not an integral constant}}\
- //expected-note{{non-literal type}}
- int arrG[([](auto i) { return i; })(3)]; //expected-error{{must have a constant size}}
+ //expected-note{{non-literal type}}\
+ //expected-error{{inside of a constant expression}}
+ int arrG[([](auto i) { return i; })(3)]; //expected-error{{must have a constant size}} \
+ //expected-error{{inside of a constant expression}}
int (*fpG)(T) = [](auto i) { return i; };
void fooptrG(T (*fp)(char) = [](auto c) { return 0; }) { }
template<class U = char> int fooG2(T (*fp)(U) = [](auto a) { return 0; }) { return 0; }
A(int (*) [7]) : a(rvalueref::notmove(a)) {}
};
}
+
+void array_capture(bool b) {
+ const char fname[] = "array_capture";
+ if (b) {
+ int unused; // expected-warning {{unused variable}}
+ } else {
+ [fname]{};
+ }
+}