diff options
-rw-r--r-- | include/clang/Sema/ScopeInfo.h | 33 | ||||
-rw-r--r-- | include/clang/Sema/Sema.h | 62 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 401 | ||||
-rw-r--r-- | lib/Sema/SemaExprCXX.cpp | 4 | ||||
-rw-r--r-- | lib/Sema/SemaExprObjC.cpp | 2 | ||||
-rw-r--r-- | lib/Sema/SemaLambda.cpp | 4 | ||||
-rw-r--r-- | lib/Sema/TreeTransform.h | 4 | ||||
-rw-r--r-- | test/CXX/expr/expr.prim/expr.prim.lambda/blocks.cpp | 22 | ||||
-rw-r--r-- | test/CXX/expr/expr.prim/expr.prim.lambda/p16.cpp | 27 | ||||
-rw-r--r-- | test/CXX/expr/expr.prim/expr.prim.lambda/p18.cpp | 4 | ||||
-rw-r--r-- | test/SemaCXX/lambda-expressions.cpp | 2 |
11 files changed, 319 insertions, 246 deletions
diff --git a/include/clang/Sema/ScopeInfo.h b/include/clang/Sema/ScopeInfo.h index 2ccb37010c..ceaf586694 100644 --- a/include/clang/Sema/ScopeInfo.h +++ b/include/clang/Sema/ScopeInfo.h @@ -174,16 +174,23 @@ public: /// \brief The location of the ellipsis that expands a parameter pack. SourceLocation EllipsisLoc; + /// \brief The type as it was captured, which is in effect the type of the + /// non-static data member that would hold the capture. + QualType CaptureType; + public: Capture(VarDecl *Var, bool block, bool byRef, bool isNested, - SourceLocation Loc, SourceLocation EllipsisLoc, Expr *Cpy) + SourceLocation Loc, SourceLocation EllipsisLoc, + QualType CaptureType, Expr *Cpy) : VarAndKind(Var, block ? Cap_Block : byRef ? Cap_ByRef : Cap_ByCopy), - CopyExprAndNested(Cpy, isNested), Loc(Loc), EllipsisLoc(EllipsisLoc) {} + CopyExprAndNested(Cpy, isNested), Loc(Loc), EllipsisLoc(EllipsisLoc), + CaptureType(CaptureType){} enum IsThisCapture { ThisCapture }; - Capture(IsThisCapture, bool isNested, SourceLocation Loc, Expr *Cpy) + Capture(IsThisCapture, bool isNested, SourceLocation Loc, + QualType CaptureType, Expr *Cpy) : VarAndKind(0, Cap_This), CopyExprAndNested(Cpy, isNested), Loc(Loc), - EllipsisLoc() { } + EllipsisLoc(), CaptureType(CaptureType) { } bool isThisCapture() const { return VarAndKind.getInt() == Cap_This; } bool isVariableCapture() const { return !isThisCapture(); } @@ -203,6 +210,11 @@ public: /// indicates that the capture is a pack expansion. SourceLocation getEllipsisLoc() const { return EllipsisLoc; } + /// \brief Retrieve the capture type for this capture, which is effectively + /// the type of the non-static data member in the lambda/block structure + /// that would store this capture. + QualType getCaptureType() const { return CaptureType; } + Expr *getCopyExpr() const { return CopyExprAndNested.getPointer(); } @@ -231,15 +243,18 @@ public: /// or null if unknown. QualType ReturnType; - void AddCapture(VarDecl *Var, bool isBlock, bool isByref, bool isNested, - SourceLocation Loc, SourceLocation EllipsisLoc, Expr *Cpy) { + void addCapture(VarDecl *Var, bool isBlock, bool isByref, bool isNested, + SourceLocation Loc, SourceLocation EllipsisLoc, + QualType CaptureType, Expr *Cpy) { Captures.push_back(Capture(Var, isBlock, isByref, isNested, Loc, - EllipsisLoc, Cpy)); + EllipsisLoc, CaptureType, Cpy)); CaptureMap[Var] = Captures.size(); } - void AddThisCapture(bool isNested, SourceLocation Loc, Expr *Cpy) { - Captures.push_back(Capture(Capture::ThisCapture, isNested, Loc, Cpy)); + void addThisCapture(bool isNested, SourceLocation Loc, QualType CaptureType, + Expr *Cpy) { + Captures.push_back(Capture(Capture::ThisCapture, isNested, Loc, CaptureType, + Cpy)); CXXThisCaptureIndex = Captures.size(); } diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 87ec1aadef..97cd27f7ed 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -2306,45 +2306,51 @@ public: void UpdateMarkingForLValueToRValue(Expr *E); void CleanupVarDeclMarking(); - /// \brief Determine whether we can capture the given variable in - /// the given scope. + enum TryCaptureKind { + TryCapture_Implicit, TryCapture_ExplicitByVal, TryCapture_ExplicitByRef + }; + + /// \brief Try to capture the given variable. /// - /// \param Explicit Whether this is an explicit capture (vs. an - /// implicit capture). + /// \param Var The variable to capture. /// - /// \param Diagnose Diagnose errors that occur when attempting to perform - /// the capture. + /// \param Loc The location at which the capture occurs. /// - /// \param Var The variable to check for capture. + /// \param Kind The kind of capture, which may be implicit (for either a + /// block or a lambda), or explicit by-value or by-reference (for a lambda). /// - /// \param Type Will be set to the type used to perform the capture. + /// \param EllipsisLoc The location of the ellipsis, if one is provided in + /// an explicit lambda capture. /// - /// \param FunctionScopesIndex Will be set to the index of the first - /// scope in which capture will need to be performed. + /// \param BuildAndDiagnose Whether we are actually supposed to add the + /// captures or diagnose errors. If false, this routine merely check whether + /// the capture can occur without performing the capture itself or complaining + /// if the variable cannot be captured. /// - /// \param Nested Whether this will be a nested capture. - bool canCaptureVariable(VarDecl *Var, SourceLocation Loc, bool Explicit, - bool Diagnose, QualType &Type, - unsigned &FunctionScopesIndex, bool &Nested); + /// \param CaptureType Will be set to the type of the field used to capture + /// this variable in the innermost block or lambda. Only valid when the + /// variable can be captured. + /// + /// \param DeclRefType Will be set to the type of a refernce to the capture + /// from within the current scope. Only valid when the variable can be + /// captured. + /// + /// \returns true if an error occurred (i.e., the variable cannot be + /// captured) and false if the capture succeeded. + bool tryCaptureVariable(VarDecl *Var, SourceLocation Loc, TryCaptureKind Kind, + SourceLocation EllipsisLoc, bool BuildAndDiagnose, + QualType &CaptureType, + QualType &DeclRefType); + /// \brief Try to capture the given variable. + bool tryCaptureVariable(VarDecl *Var, SourceLocation Loc, + TryCaptureKind Kind = TryCapture_Implicit, + SourceLocation EllipsisLoc = SourceLocation()); + /// \brief Given a variable, determine the type that a reference to that /// variable will have in the given scope. QualType getCapturedDeclRefType(VarDecl *Var, SourceLocation Loc); - /// \brief Determine the type of the field that will capture the - /// given variable in a lambda expression. - /// - /// \param T The type of the variable being captured. - /// \param ByRef Whether we are capturing by reference or by value. - QualType getLambdaCaptureFieldType(QualType T, bool ByRef); - - enum TryCaptureKind { - TryCapture_Implicit, TryCapture_ExplicitByVal, TryCapture_ExplicitByRef - }; - void TryCaptureVar(VarDecl *var, SourceLocation loc, - TryCaptureKind Kind = TryCapture_Implicit, - SourceLocation EllipsisLoc = SourceLocation()); - void MarkDeclarationsReferencedInType(SourceLocation Loc, QualType T); void MarkDeclarationsReferencedInExpr(Expr *E); diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 38783eb865..8e6b6c5c53 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -9541,56 +9541,12 @@ diagnoseUncapturableValueReference(Sema &S, SourceLocation loc, // capture. } -static bool shouldAddConstForScope(CapturingScopeInfo *CSI, VarDecl *VD) { - if (VD->hasAttr<BlocksAttr>()) - return false; - if (isa<BlockScopeInfo>(CSI)) - return true; - if (LambdaScopeInfo *LSI = dyn_cast<LambdaScopeInfo>(CSI)) { - if (LSI->isCaptured(VD)) - return LSI->getCapture(VD).isCopyCapture() && !LSI->Mutable; - - return LSI->ImpCaptureStyle == LambdaScopeInfo::ImpCap_LambdaByval && - !LSI->Mutable; - } - return false; -} - -QualType Sema::getLambdaCaptureFieldType(QualType T, bool ByRef) { - if (ByRef) { - // C++11 [expr.prim.lambda]p15: - // An entity is captured by reference if it is implicitly or - // explicitly captured but not captured by copy. It is - // unspecified whether additional unnamed non-static data - // members are declared in the closure type for entities - // captured by reference. - return Context.getLValueReferenceType(T.getNonReferenceType()); - } - - // C++11 [expr.prim.lambda]p14: - // For each entity captured by copy, an unnamed non-static - // data member is declared in the closure type. The - // declaration order of these members is unspecified. The type - // of such a data member is the type of the corresponding - // captured entity if the entity is not a reference to an - // object, or the referenced type otherwise. [Note: If the - // captured entity is a reference to a function, the - // corresponding data member is also a reference to a - // function. - end note ] - if (const ReferenceType *RefType = T->getAs<ReferenceType>()) { - if (!RefType->getPointeeType()->isFunctionType()) - return RefType->getPointeeType(); - } - - return T; -} - /// \brief Capture the given variable in the given lambda expression. static ExprResult captureInLambda(Sema &S, LambdaScopeInfo *LSI, - VarDecl *Var, QualType Type, - SourceLocation Loc, bool ByRef) { + VarDecl *Var, QualType FieldType, + QualType DeclRefType, + SourceLocation Loc) { CXXRecordDecl *Lambda = LSI->Lambda; - QualType FieldType = S.getLambdaCaptureFieldType(Type, ByRef); // Build the non-static data member. FieldDecl *Field @@ -9618,8 +9574,7 @@ static ExprResult captureInLambda(Sema &S, LambdaScopeInfo *LSI, // 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, Type.getNonReferenceType(), - VK_LValue, Loc); + Expr *Ref = new (S.Context) DeclRefExpr(Var, DeclRefType, VK_LValue, Loc); Var->setUsed(true); // When the field has array type, create index variables for each @@ -9707,20 +9662,27 @@ static ExprResult captureInLambda(Sema &S, LambdaScopeInfo *LSI, return Result; } -bool Sema::canCaptureVariable(VarDecl *Var, SourceLocation Loc, bool Explicit, - bool Diagnose, QualType &Type, - unsigned &FunctionScopesIndex, bool &Nested) { - Type = Var->getType(); - FunctionScopesIndex = FunctionScopes.size() - 1; - Nested = false; +bool Sema::tryCaptureVariable(VarDecl *Var, SourceLocation Loc, + TryCaptureKind Kind, SourceLocation EllipsisLoc, + bool BuildAndDiagnose, + QualType &CaptureType, + QualType &DeclRefType) { + bool Nested = false; DeclContext *DC = CurContext; - if (Var->getDeclContext() == DC) return false; - if (!Var->hasLocalStorage()) return false; + if (Var->getDeclContext() == DC) return true; + if (!Var->hasLocalStorage()) return true; bool HasBlocksAttr = Var->hasAttr<BlocksAttr>(); - // Figure out whether we can capture the variable. + // Walk up the stack to determine whether we can capture the variable, + // performing the "simple" checks that don't depend on type. We stop when + // we've either hit the declared scope of the variable or find an existing + // capture of that variable. + CaptureType = Var->getType(); + DeclRefType = CaptureType.getNonReferenceType(); + bool Explicit = (Kind != TryCapture_Implicit); + unsigned FunctionScopesIndex = FunctionScopes.size() - 1; do { // Only block literals and lambda expressions can capture; other // scopes don't work. @@ -9732,9 +9694,9 @@ bool Sema::canCaptureVariable(VarDecl *Var, SourceLocation Loc, bool Explicit, cast<CXXRecordDecl>(DC->getParent())->isLambda()) ParentDC = DC->getParent()->getParent(); else { - if (Diagnose) + if (BuildAndDiagnose) diagnoseUncapturableValueReference(*this, Loc, Var, DC); - return false; + return true; } CapturingScopeInfo *CSI = @@ -9742,32 +9704,40 @@ bool Sema::canCaptureVariable(VarDecl *Var, SourceLocation Loc, bool Explicit, // Check whether we've already captured it. if (CSI->CaptureMap.count(Var)) { - // If we found a capture, any subcaptures are nested + // If we found a capture, any subcaptures are nested. Nested = true; - - if (shouldAddConstForScope(CSI, Var)) - Type.addConst(); + + // Retrieve the capture type for this variable. + CaptureType = CSI->getCapture(Var).getCaptureType(); + + // Compute the type of an expression that refers to this variable. + DeclRefType = CaptureType.getNonReferenceType(); + + const CapturingScopeInfo::Capture &Cap = CSI->getCapture(Var); + if (Cap.isCopyCapture() && + !(isa<LambdaScopeInfo>(CSI) && cast<LambdaScopeInfo>(CSI)->Mutable)) + DeclRefType.addConst(); break; } bool IsBlock = isa<BlockScopeInfo>(CSI); - bool IsLambda = isa<LambdaScopeInfo>(CSI); + bool IsLambda = !IsBlock; // Lambdas are not allowed to capture unnamed variables // (e.g. anonymous unions). // FIXME: The C++11 rule don't actually state this explicitly, but I'm // assuming that's the intent. if (IsLambda && !Var->getDeclName()) { - if (Diagnose) { + if (BuildAndDiagnose) { Diag(Loc, diag::err_lambda_capture_anonymous_var); Diag(Var->getLocation(), diag::note_declared_at); } - return false; + return true; } // Prohibit variably-modified types; they're difficult to deal with. - if (Type->isVariablyModifiedType()) { - if (Diagnose) { + if (Var->getType()->isVariablyModifiedType()) { + if (BuildAndDiagnose) { if (IsBlock) Diag(Loc, diag::err_ref_vm_type); else @@ -9775,41 +9745,31 @@ bool Sema::canCaptureVariable(VarDecl *Var, SourceLocation Loc, bool Explicit, Diag(Var->getLocation(), diag::note_previous_decl) << Var->getDeclName(); } - return false; - } - - // Blocks are not allowed to capture arrays. - if (IsBlock && Type->isArrayType()) { - if (Diagnose) { - Diag(Loc, diag::err_ref_array_type); - Diag(Var->getLocation(), diag::note_previous_decl) - << Var->getDeclName(); - } - return false; + return true; } // Lambdas are not allowed to capture __block variables; they don't // support the expected semantics. if (IsLambda && HasBlocksAttr) { - if (Diagnose) { + if (BuildAndDiagnose) { Diag(Loc, diag::err_lambda_capture_block) << Var->getDeclName(); Diag(Var->getLocation(), diag::note_previous_decl) << Var->getDeclName(); } - return false; + return true; } if (CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_None && !Explicit) { // No capture-default - if (Diagnose) { + if (BuildAndDiagnose) { Diag(Loc, diag::err_lambda_impcap) << Var->getDeclName(); Diag(Var->getLocation(), diag::note_previous_decl) << Var->getDeclName(); Diag(cast<LambdaScopeInfo>(CSI)->Lambda->getLocStart(), diag::note_lambda_decl); } - return false; + return true; } FunctionScopesIndex--; @@ -9817,126 +9777,175 @@ bool Sema::canCaptureVariable(VarDecl *Var, SourceLocation Loc, bool Explicit, Explicit = false; } while (!Var->getDeclContext()->Equals(DC)); - ++FunctionScopesIndex; - return !Type->isVariablyModifiedType(); -} + // Walk back down the scope stack, computing the type of the capture at + // each step, checking type-specific requirements, and adding captures if + // requested. + for (unsigned I = ++FunctionScopesIndex, N = FunctionScopes.size(); I != N; + ++I) { + CapturingScopeInfo *CSI = cast<CapturingScopeInfo>(FunctionScopes[I]); + + // Compute the type of the capture and of a reference to the capture within + // this scope. + if (isa<BlockScopeInfo>(CSI)) { + Expr *CopyExpr = 0; + bool ByRef = false; + + // Blocks are not allowed to capture arrays. + if (CaptureType->isArrayType()) { + if (BuildAndDiagnose) { + Diag(Loc, diag::err_ref_array_type); + Diag(Var->getLocation(), diag::note_previous_decl) + << Var->getDeclName(); + } + return true; + } -QualType Sema::getCapturedDeclRefType(VarDecl *Var, SourceLocation Loc) { - QualType T = Var->getType().getNonReferenceType(); - unsigned FunctionScopesIndex; - bool Nested; - // Determine whether we can capture this variable. - if (!canCaptureVariable(Var, Loc, /*Explicit=*/false, /*Diagnose=*/false, - T, FunctionScopesIndex, Nested)) - return QualType(); + if (HasBlocksAttr || CaptureType->isReferenceType()) { + // Block capture by reference does not change the capture or + // declaration reference types. + ByRef = true; + } else { + // Block capture by copy introduces 'const'. + CaptureType = CaptureType.getNonReferenceType().withConst(); + DeclRefType = CaptureType; + + if (getLangOptions().CPlusPlus && BuildAndDiagnose) { + if (const RecordType *Record = DeclRefType->getAs<RecordType>()) { + // The capture logic needs the destructor, so make sure we mark it. + // Usually this is unnecessary because most local variables have + // their destructors marked at declaration time, but parameters are + // an exception because it's technically only the call site that + // actually requires the destructor. + if (isa<ParmVarDecl>(Var)) + FinalizeVarWithDestructor(Var, Record); + + // According to the blocks spec, the capture of a variable from + // the stack requires a const copy constructor. This is not true + // of the copy/move done to move a __block variable to the heap. + Expr *DeclRef = new (Context) DeclRefExpr(Var, + DeclRefType.withConst(), + VK_LValue, Loc); + ExprResult Result + = PerformCopyInitialization( + InitializedEntity::InitializeBlock(Var->getLocation(), + CaptureType, false), + Loc, Owned(DeclRef)); + + // Build a full-expression copy expression if initialization + // succeeded and used a non-trivial constructor. Recover from + // errors by pretending that the copy isn't necessary. + if (!Result.isInvalid() && + !cast<CXXConstructExpr>(Result.get())->getConstructor() + ->isTrivial()) { + Result = MaybeCreateExprWithCleanups(Result); + CopyExpr = Result.take(); + } + } + } + } + + // Actually capture the variable. + if (BuildAndDiagnose) + CSI->addCapture(Var, HasBlocksAttr, ByRef, Nested, Loc, + SourceLocation(), CaptureType, CopyExpr); + Nested = true; + continue; + } - // Outer lambda scopes may have an effect on the type of a - // capture. Walk the captures outside-in to determine - // whether they can add 'const' to a capture by copy. - T = Var->getType().getNonReferenceType(); - if (FunctionScopesIndex == FunctionScopes.size()) - --FunctionScopesIndex; - for (unsigned I = FunctionScopesIndex, E = FunctionScopes.size(); - I != E; ++I) { - CapturingScopeInfo *CSI = dyn_cast<LambdaScopeInfo>(FunctionScopes[I]); - if (!CSI) - break; + LambdaScopeInfo *LSI = cast<LambdaScopeInfo>(CSI); - if (shouldAddConstForScope(CSI, Var)) - T.addConst(); - } - - return T; -} - -// Check if the variable needs to be captured; if so, try to perform -// the capture. -void Sema::TryCaptureVar(VarDecl *var, SourceLocation loc, - TryCaptureKind Kind, SourceLocation EllipsisLoc) { - QualType type; - unsigned functionScopesIndex; - bool Nested; - // Determine whether we can capture this variable, and where to - // start capturing. - if (!canCaptureVariable(var, loc, /*Explicit=*/Kind != TryCapture_Implicit, - /*Diagnose=*/true, type, functionScopesIndex, Nested)) - return; - - bool hasBlocksAttr = var->hasAttr<BlocksAttr>(); - - for (unsigned i = functionScopesIndex, - e = FunctionScopes.size(); i != e; ++i) { - CapturingScopeInfo *CSI = cast<CapturingScopeInfo>(FunctionScopes[i]); - bool isLambda = isa<LambdaScopeInfo>(CSI); - - bool byRef; - bool isInnermostCapture = (i == e - 1); - if (isInnermostCapture && Kind == TryCapture_ExplicitByVal) { - byRef = false; - } else if (isInnermostCapture && Kind == TryCapture_ExplicitByRef) { - byRef = true; - } else if (CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_LambdaByval) { - // capture-default '=' - byRef = false; - } else if (CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_LambdaByref) { - // capture-default '&' - byRef = true; + // Determine whether we are capturing by reference or by value. + bool ByRef = false; + if (I == N - 1 && Kind != TryCapture_Implicit) { + ByRef = (Kind == TryCapture_ExplicitByRef); } else { - // A block captures __block variables in a special __block fashion, - // variables of reference type by reference (in the sense of - // [expr.prim.lambda]), and other non-__block variables by copy. - assert(CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_Block); - byRef = hasBlocksAttr || type->isReferenceType(); - } - - // Build a copy expression if we are capturing by copy into a - // block and the copy might be non-trivial. - Expr *copyExpr = 0; - const RecordType *rtype; - if (isLambda) { - ExprResult Result = captureInLambda(*this, cast<LambdaScopeInfo>(CSI), - var, type, loc, byRef); - if (!Result.isInvalid()) - copyExpr = Result.take(); - } else if (!byRef && getLangOptions().CPlusPlus && - (rtype = type.getNonReferenceType()->getAs<RecordType>())) { - // The capture logic needs the destructor, so make sure we mark it. - // Usually this is unnecessary because most local variables have - // their destructors marked at declaration time, but parameters are - // an exception because it's technically only the call site that - // actually requires the destructor. - if (isa<ParmVarDecl>(var)) - FinalizeVarWithDestructor(var, rtype); - - // According to the blocks spec, the capture of a variable from - // the stack requires a const copy constructor. This is not true - // of the copy/move done to move a __block variable to the heap. - type.addConst(); - - Expr *declRef = new (Context) DeclRefExpr(var, type, VK_LValue, loc); - ExprResult result = - PerformCopyInitialization( - InitializedEntity::InitializeBlock(var->getLocation(), - type, false), - loc, Owned(declRef)); - - // Build a full-expression copy expression if initialization - // succeeded and used a non-trivial constructor. Recover from - // errors by pretending that the copy isn't necessary. - if (!result.isInvalid() && - !cast<CXXConstructExpr>(result.get())->getConstructor()->isTrivial()) { - result = MaybeCreateExprWithCleanups(result); - copyExpr = result.take(); + ByRef = (LSI->ImpCaptureStyle == LambdaScopeInfo::ImpCap_LambdaByref); + } + + // Compute the type of the field that will capture this variable. + if (ByRef) { + // C++11 [expr.prim.lambda]p15: + // An entity is captured by reference if it is implicitly or + // explicitly captured but not captured by copy. It is + // unspecified whether additional unnamed non-static data + // members are declared in the closure type for entities + // captured by reference. + // + // FIXME: It is not clear whether we want to build an lvalue reference + // to the DeclRefType or to CaptureType.getNonReferenceType(). GCC appears + // to do the former, while EDG does the latter. Core issue 1249 will + // clarify, but for now we follow GCC because it's a more permissive and + // easily defensible position. + CaptureType = Context.getLValueReferenceType(DeclRefType); + } else { + // C++11 [expr.prim.lambda]p14: + // For each entity captured by copy, an unnamed non-static + // data member is declared in the closure type. The + // declaration order of these members is unspecified. The type + // of such a data member is the type of the corresponding + // captured entity if the entity is not a reference to an + // object, or the referenced type otherwise. [Note: If the + // captured entity is a reference to a function, the + // corresponding data member is also a reference to a + // function. - end note ] + if (const ReferenceType *RefType = CaptureType->getAs<ReferenceType>()){ + if (!RefType->getPointeeType()->isFunctionType()) + CaptureType = RefType->getPointeeType(); } } - CSI->AddCapture(var, hasBlocksAttr, byRef, Nested, loc, EllipsisLoc, - copyExpr); - + // Capture this variable in the lambda. + Expr *CopyExpr = 0; + if (BuildAndDiagnose) { + ExprResult Result = captureInLambda(*this, LSI, Var, CaptureType, + DeclRefType, Loc); + if (!Result.isInvalid()) + CopyExpr = Result.take(); + } + + // Compute the type of a reference to this captured variable. + if (ByRef) + DeclRefType = CaptureType.getNonReferenceType(); + else { + // C++ [expr.prim.lambda]p5: + // The closure type for a lambda-expression has a public inline + // function call operator [...]. 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. + DeclRefType = CaptureType.getNonReferenceType(); + if (!LSI->Mutable && !CaptureType->isReferenceType()) + DeclRefType.addConst(); + } + + // Add the capture. + if (BuildAndDiagnose) + CSI->addCapture(Var, /*IsBlock=*/false, ByRef, Nested, Loc, + EllipsisLoc, CaptureType, CopyExpr); Nested = true; - if (shouldAddConstForScope(CSI, var)) - type.addConst(); } + + return false; +} + +bool Sema::tryCaptureVariable(VarDecl *Var, SourceLocation Loc, + TryCaptureKind Kind, SourceLocation EllipsisLoc) { + QualType CaptureType; + QualType DeclRefType; + return tryCaptureVariable(Var, Loc, Kind, EllipsisLoc, + /*BuildAndDiagnose=*/true, CaptureType, + DeclRefType); +} + +QualType Sema::getCapturedDeclRefType(VarDecl *Var, SourceLocation Loc) { + QualType CaptureType; + QualType DeclRefType; + + // Determine whether we can capture this variable. + if (tryCaptureVariable(Var, Loc, TryCapture_Implicit, SourceLocation(), + /*BuildAndDiagnose=*/false, CaptureType, DeclRefType)) + return QualType(); + + return DeclRefType; } static void MarkVarDeclODRUsed(Sema &SemaRef, VarDecl *Var, @@ -9950,7 +9959,7 @@ static void MarkVarDeclODRUsed(Sema &SemaRef, VarDecl *Var, if (old.isInvalid()) old = Loc; } - SemaRef.TryCaptureVar(Var, Loc); + SemaRef.tryCaptureVariable(Var, Loc); Var->setUsed(true); } diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 80078207da..5ec96be487 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -710,9 +710,9 @@ void Sema::CheckCXXThisCapture(SourceLocation Loc, bool Explicit) { NumClosures; --idx, --NumClosures) { CapturingScopeInfo *CSI = cast<CapturingScopeInfo>(FunctionScopes[idx]); Expr *ThisExpr = 0; + QualType ThisTy = getCurrentThisType(); if (LambdaScopeInfo *LSI = dyn_cast<LambdaScopeInfo>(CSI)) { // For lambda expressions, build a field and an initializing expression. - QualType ThisTy = getCurrentThisType(); CXXRecordDecl *Lambda = LSI->Lambda; FieldDecl *Field = FieldDecl::Create(Context, Lambda, Loc, Loc, 0, ThisTy, @@ -724,7 +724,7 @@ void Sema::CheckCXXThisCapture(SourceLocation Loc, bool Explicit) { ThisExpr = new (Context) CXXThisExpr(Loc, ThisTy, /*isImplicit=*/true); } bool isNested = NumClosures > 1; - CSI->AddThisCapture(isNested, Loc, ThisExpr); + CSI->addThisCapture(isNested, Loc, ThisTy, ThisExpr); } } diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp index 133c2d3de9..e0420c1faf 100644 --- a/lib/Sema/SemaExprObjC.cpp +++ b/lib/Sema/SemaExprObjC.cpp @@ -247,7 +247,7 @@ ObjCMethodDecl *Sema::tryCaptureObjCSelf(SourceLocation Loc) { if (!method) return 0; - TryCaptureVar(method->getSelfDecl(), Loc); + tryCaptureVariable(method->getSelfDecl(), Loc); return method; } diff --git a/lib/Sema/SemaLambda.cpp b/lib/Sema/SemaLambda.cpp index 2af946288f..1a362d48e2 100644 --- a/lib/Sema/SemaLambda.cpp +++ b/lib/Sema/SemaLambda.cpp @@ -288,7 +288,7 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, // variable with automatic storage duration declared in the reaching // scope of the local lambda expression. // - // Note that the 'reaching scope' check happens in TryCaptureVar. + // 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; @@ -332,7 +332,7 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, TryCaptureKind Kind = C->Kind == LCK_ByRef ? TryCapture_ExplicitByRef : TryCapture_ExplicitByVal; - TryCaptureVar(Var, C->Loc, Kind, EllipsisLoc); + tryCaptureVariable(Var, C->Loc, Kind, EllipsisLoc); } finishLambdaExplicitCaptures(LSI); diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 88173555e9..69e09e5ac3 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -7735,7 +7735,7 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) { } // Capture the transformed variable. - getSema().TryCaptureVar(CapturedVar, C->getLocation(), Kind); + getSema().tryCaptureVariable(CapturedVar, C->getLocation(), Kind); } continue; } @@ -7753,7 +7753,7 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) { } // Capture the transformed variable. - getSema().TryCaptureVar(CapturedVar, C->getLocation(), Kind); + getSema().tryCaptureVariable(CapturedVar, C->getLocation(), Kind); } if (!FinishedExplicitCaptures) getSema().finishLambdaExplicitCaptures(LSI); diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/blocks.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/blocks.cpp index 3301b29135..f6a8db23e9 100644 --- a/test/CXX/expr/expr.prim/expr.prim.lambda/blocks.cpp +++ b/test/CXX/expr/expr.prim/expr.prim.lambda/blocks.cpp @@ -33,3 +33,25 @@ void conversion_to_block_init(ConstCopyConstructorBoom<int> boom, const auto& lambda2([=] { boom2.foo(); }); // expected-note{{in instantiation of member function}} void (^block)(void) = lambda2; } + + +void nesting() { + int array[7]; // expected-note 2{{'array' declared here}} + [=] () mutable { + [&] { + ^ { + int i = array[2]; + i += array[3]; + }(); + }(); + }(); + + [&] { + [=] () mutable { + ^ { + int i = array[2]; // expected-error{{cannot refer to declaration with an array type inside block}} + i += array[3]; // expected-error{{cannot refer to declaration with an array type inside block}} + }(); + }(); + }(); +} diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/p16.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/p16.cpp index 1723ee39fd..0cf01ade43 100644 --- a/test/CXX/expr/expr.prim/expr.prim.lambda/p16.cpp +++ b/test/CXX/expr/expr.prim/expr.prim.lambda/p16.cpp @@ -2,7 +2,7 @@ struct X { - X(const X&) = delete; // expected-note{{explicitly marked deleted}} + X(const X&) = delete; // expected-note 2{{explicitly marked deleted}} X(X&); }; @@ -10,10 +10,31 @@ void test_capture(X x) { [x] { }(); // okay: non-const copy ctor [x] { - [x] { // expected-error{{call to deleted constructor of 'const X'}} + [x] { // expected-error{{call to deleted constructor of 'X'}} + }(); + }(); + + [x] { + [&x] { + [x] { // expected-error{{call to deleted constructor of 'const X'}} + }(); }(); }(); int a; - [=]{ [&] { int&x = a; }(); }(); // expected-error{{binding of reference to type 'int' to a value of type 'const int' drops qualifiers}} + [=]{ + [&] { + int &x = a; // expected-error{{binding of reference to type 'int' to a value of type 'const int' drops qualifiers}} + int &x2 = a; // expected-error{{binding of reference to type 'int' to a value of type 'const int' drops qualifiers}} + }(); + }(); + + [=]{ + [&a] { + [&] { + int &x = a; // expected-error{{binding of reference to type 'int' to a value of type 'const int' drops qualifiers}} + int &x2 = a; // expected-error{{binding of reference to type 'int' to a value of type 'const int' drops qualifiers}} + }(); + }(); + }(); } diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/p18.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/p18.cpp index e9356136c7..930a4b32fa 100644 --- a/test/CXX/expr/expr.prim/expr.prim.lambda/p18.cpp +++ b/test/CXX/expr/expr.prim/expr.prim.lambda/p18.cpp @@ -34,8 +34,8 @@ void f3() { [=] { [=] () mutable { static_assert(is_same<decltype(x), float>::value, "should be float"); |