diff options
Diffstat (limited to 'clang/lib/Sema/SemaLambda.cpp')
| -rw-r--r-- | clang/lib/Sema/SemaLambda.cpp | 160 |
1 files changed, 136 insertions, 24 deletions
diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp index 4e11bb4c055..d647be37616 100644 --- a/clang/lib/Sema/SemaLambda.cpp +++ b/clang/lib/Sema/SemaLambda.cpp @@ -18,6 +18,7 @@ #include "clang/Sema/Scope.h" #include "clang/Sema/ScopeInfo.h" #include "clang/Sema/SemaInternal.h" +#include "TypeLocBuilder.h" using namespace clang; using namespace sema; @@ -429,6 +430,88 @@ void Sema::deduceClosureReturnType(CapturingScopeInfo &CSI) { } } +FieldDecl *Sema::checkInitCapture(SourceLocation Loc, bool ByRef, + IdentifierInfo *Id, Expr *InitExpr) { + LambdaScopeInfo *LSI = getCurLambda(); + + // C++1y [expr.prim.lambda]p11: + // The type of [the] member corresponds to the type of a hypothetical + // variable declaration of the form "auto init-capture;" + QualType DeductType = Context.getAutoDeductType(); + TypeLocBuilder TLB; + TLB.pushTypeSpec(DeductType).setNameLoc(Loc); + if (ByRef) { + DeductType = BuildReferenceType(DeductType, true, Loc, Id); + assert(!DeductType.isNull() && "can't build reference to auto"); + TLB.push<ReferenceTypeLoc>(DeductType).setSigilLoc(Loc); + } + + InitializationKind InitKind = InitializationKind::CreateDefault(Loc); + Expr *Init = InitExpr; + if (ParenListExpr *Parens = dyn_cast<ParenListExpr>(Init)) { + if (Parens->getNumExprs() == 1) { + Init = Parens->getExpr(0); + InitKind = InitializationKind::CreateDirect( + Loc, Parens->getLParenLoc(), Parens->getRParenLoc()); + } else { + // C++1y [dcl.spec.auto]p3: + // In an initializer of the form ( expression-list ), the + // expression-list shall be a single assignment-expression. + if (Parens->getNumExprs() == 0) + Diag(Parens->getLocStart(), diag::err_init_capture_no_expression) + << Id; + else if (Parens->getNumExprs() > 1) + Diag(Parens->getExpr(1)->getLocStart(), + diag::err_init_capture_multiple_expressions) + << Id; + return 0; + } + } else if (isa<InitListExpr>(Init)) + // We do not need to distinguish between direct-list-initialization + // and copy-list-initialization here, because we will always deduce + // std::initializer_list<T>, and direct- and copy-list-initialization + // always behave the same for such a type. + // FIXME: We should model whether an '=' was present. + InitKind = InitializationKind::CreateDirectList(Loc); + else + InitKind = InitializationKind::CreateCopy(Loc, Loc); + QualType DeducedType; + if (DeduceAutoType(TLB.getTemporaryTypeLoc(DeductType), + Init, DeducedType) == DAR_Failed) { + if (isa<InitListExpr>(Init)) + Diag(Loc, diag::err_init_capture_deduction_failure_from_init_list) + << Id << Init->getSourceRange(); + else + Diag(Loc, diag::err_init_capture_deduction_failure) + << Id << Init->getType() << Init->getSourceRange(); + } + if (DeducedType.isNull()) + return 0; + + // [...] a non-static data member named by the identifier is declared in + // the closure type. This member is not a bit-field and not mutable. + // Core issue: the member is (probably...) public. + FieldDecl *NewFD = CheckFieldDecl( + Id, DeducedType, TLB.getTypeSourceInfo(Context, DeductType), LSI->Lambda, + Loc, /*Mutable*/ false, /*BitWidth*/ 0, ICIS_NoInit, + Loc, AS_public, /*PrevDecl*/ 0, /*Declarator*/ 0); + LSI->Lambda->addDecl(NewFD); + + if (CurContext->isDependentContext()) { + LSI->addInitCapture(NewFD, InitExpr); + } else { + InitializedEntity Entity = InitializedEntity::InitializeMember(NewFD); + InitializationSequence InitSeq(*this, Entity, InitKind, Init); + if (!InitSeq.Diagnose(*this, Entity, InitKind, Init)) { + ExprResult InitResult = InitSeq.Perform(*this, Entity, InitKind, Init); + if (!InitResult.isInvalid()) + LSI->addInitCapture(NewFD, InitResult.take()); + } + } + + return NewFD; +} + void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, Declarator &ParamInfo, Scope *CurScope) { @@ -514,7 +597,10 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, = enterLambdaScope(Method, Intro.Range, Intro.Default, ExplicitParams, ExplicitResultType, !Method->isConst()); - + + // Distinct capture names, for diagnostics. + llvm::SmallSet<IdentifierInfo*, 8> CaptureNames; + // Handle explicit captures. SourceLocation PrevCaptureLoc = Intro.Default == LCD_None? Intro.Range.getBegin() : Intro.DefaultLoc; @@ -559,16 +645,32 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, continue; } - // FIXME: C++1y [expr.prim.lambda]p11 + assert(C->Id && "missing identifier for capture"); + if (C->Init.isInvalid()) continue; if (C->Init.isUsable()) { - Diag(C->Loc, diag::err_lambda_init_capture_unsupported); + // C++11 [expr.prim.lambda]p8: + // An identifier or this shall not appear more than once in a + // lambda-capture. + if (!CaptureNames.insert(C->Id)) + Diag(C->Loc, diag::err_capture_more_than_once) << C->Id; + + if (C->Init.get()->containsUnexpandedParameterPack()) + ContainsUnexpandedParameterPack = true; + + FieldDecl *NewFD = checkInitCapture(C->Loc, C->Kind == LCK_ByRef, + C->Id, C->Init.take()); + // C++1y [expr.prim.lambda]p11: + // Within the lambda-expression's lambda-declarator and + // compound-statement, the identifier in the init-capture + // hides any declaration of the same name in scopes enclosing + // the lambda-expression. + if (NewFD) + PushOnScopeChains(NewFD, CurScope, false); continue; } - assert(C->Id && "missing identifier for capture"); - // C++11 [expr.prim.lambda]p8: // If a lambda-capture includes a capture-default that is &, the // identifiers in the lambda-capture shall not be preceded by &. @@ -586,6 +688,9 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, continue; } + // C++11 [expr.prim.lambda]p10: + // The identifiers in a capture-list are looked up using the usual + // rules for unqualified name lookup (3.4.1) DeclarationNameInfo Name(C->Id, C->Loc); LookupResult R(*this, Name, LookupOrdinaryName); LookupName(R, CurScope); @@ -599,14 +704,27 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, continue; } + VarDecl *Var = R.getAsSingle<VarDecl>(); + + // C++11 [expr.prim.lambda]p8: + // An identifier or this shall not appear more than once in a + // lambda-capture. + if (!CaptureNames.insert(C->Id)) { + if (Var && LSI->isCaptured(Var)) { + Diag(C->Loc, diag::err_capture_more_than_once) + << C->Id << SourceRange(LSI->getCapture(Var).getLocation()) + << FixItHint::CreateRemoval( + SourceRange(PP.getLocForEndOfToken(PrevCaptureLoc), C->Loc)); + } else + // Previous capture was an init-capture: no fixit. + Diag(C->Loc, diag::err_capture_more_than_once) << C->Id; + continue; + } + // C++11 [expr.prim.lambda]p10: - // The identifiers in a capture-list are looked up using the usual rules - // for unqualified name lookup (3.4.1); each such lookup shall find a - // variable with automatic storage duration declared in the reaching - // scope of the local lambda expression. - // + // [...] each such lookup shall find a variable with automatic storage + // duration declared in the reaching scope of the local lambda expression. // Note that the 'reaching scope' check happens in tryCaptureVariable(). - VarDecl *Var = R.getAsSingle<VarDecl>(); if (!Var) { Diag(C->Loc, diag::err_capture_does_not_name_variable) << C->Id; continue; @@ -622,18 +740,6 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, continue; } - // C++11 [expr.prim.lambda]p8: - // An identifier or this shall not appear more than once in a - // lambda-capture. - if (LSI->isCaptured(Var)) { - Diag(C->Loc, diag::err_capture_more_than_once) - << C->Id - << SourceRange(LSI->getCapture(Var).getLocation()) - << FixItHint::CreateRemoval( - SourceRange(PP.getLocForEndOfToken(PrevCaptureLoc), C->Loc)); - continue; - } - // C++11 [expr.prim.lambda]p23: // A capture followed by an ellipsis is a pack expansion (14.5.3). SourceLocation EllipsisLoc; @@ -853,11 +959,17 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body, continue; } + if (From.isInitCapture()) { + Captures.push_back(LambdaExpr::Capture(From.getInitCaptureField())); + CaptureInits.push_back(From.getInitExpr()); + continue; + } + VarDecl *Var = From.getVariable(); LambdaCaptureKind Kind = From.isCopyCapture()? LCK_ByCopy : LCK_ByRef; Captures.push_back(LambdaExpr::Capture(From.getLocation(), IsImplicit, Kind, Var, From.getEllipsisLoc())); - CaptureInits.push_back(From.getCopyExpr()); + CaptureInits.push_back(From.getInitExpr()); } switch (LSI->ImpCaptureStyle) { |

