diff options
Diffstat (limited to 'lib/Sema')
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 146 | ||||
-rw-r--r-- | lib/Sema/SemaExprCXX.cpp | 3 | ||||
-rw-r--r-- | lib/Sema/SemaExprObjC.cpp | 31 |
3 files changed, 114 insertions, 66 deletions
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index df17297e47..8e196fbfe2 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -8747,7 +8747,7 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, CapturingScopeInfo::Capture &Cap = BSI->Captures[i]; if (Cap.isThisCapture()) continue; - BlockDecl::Capture NewCap(Cap.getVariable(), Cap.isReferenceCapture(), + BlockDecl::Capture NewCap(Cap.getVariable(), Cap.isBlockCapture(), Cap.isNested(), Cap.getCopyExpr()); Captures.push_back(NewCap); } @@ -9440,10 +9440,21 @@ diagnoseUncapturableValueReference(Sema &S, SourceLocation loc, << var->getIdentifier(); } -static void tryCaptureVar(Sema &S, VarDecl *var, - SourceLocation loc) { - // Check if the variable needs to be captured. - DeclContext *DC = S.CurContext; +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)) + return !LSI->Mutable; + return false; +} + +// Check if the variable needs to be captured; if so, try to perform +// the capture. +// FIXME: Add support for explicit captures. +void Sema::TryCaptureVar(VarDecl *var, SourceLocation loc) { + DeclContext *DC = CurContext; if (var->getDeclContext() == DC) return; if (!var->hasLocalStorage()) return; @@ -9451,87 +9462,144 @@ static void tryCaptureVar(Sema &S, VarDecl *var, QualType type = var->getType(); bool Nested = false; - unsigned functionScopesIndex = S.FunctionScopes.size() - 1; + unsigned functionScopesIndex = FunctionScopes.size() - 1; do { - // Only blocks (and eventually C++0x closures) can capture; other + // Only block literals and lambda expressions can capture; other // scopes don't work. - // FIXME: Make this function support lambdas! - if (!isa<BlockDecl>(DC)) - return diagnoseUncapturableValueReference(S, loc, var, DC); + DeclContext *ParentDC; + if (isa<BlockDecl>(DC)) + ParentDC = DC->getParent(); + else if (isa<CXXMethodDecl>(DC) && + cast<CXXRecordDecl>(DC->getParent())->isLambda()) + ParentDC = DC->getParent()->getParent(); + else + return diagnoseUncapturableValueReference(*this, loc, var, DC); - BlockScopeInfo *blockScope = - cast<BlockScopeInfo>(S.FunctionScopes[functionScopesIndex]); - assert(blockScope->TheDecl == static_cast<BlockDecl*>(DC)); + CapturingScopeInfo *CSI = + cast<CapturingScopeInfo>(FunctionScopes[functionScopesIndex]); - // Check whether we've already captured it in this block. - if (blockScope->CaptureMap.count(var)) { + // Check whether we've already captured it. + if (CSI->CaptureMap.count(var)) { + // If we found a capture, any subcaptures are nested Nested = true; + + if (shouldAddConstForScope(CSI, var)) + type.addConst(); break; } functionScopesIndex--; - DC = cast<BlockDecl>(DC)->getDeclContext(); + DC = ParentDC; } while (var->getDeclContext() != DC); - bool byRef = var->hasAttr<BlocksAttr>(); + bool hasBlocksAttr = var->hasAttr<BlocksAttr>(); for (unsigned i = functionScopesIndex + 1, - e = S.FunctionScopes.size(); i != e; ++i) { - // Prohibit variably-modified types. + e = FunctionScopes.size(); i != e; ++i) { + CapturingScopeInfo *CSI = cast<CapturingScopeInfo>(FunctionScopes[i]); + bool isBlock = isa<BlockScopeInfo>(CSI); + bool isLambda = isa<LambdaScopeInfo>(CSI); + + // 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()) { + Diag(loc, diag::err_lambda_capture_anonymous_var); + Diag(var->getLocation(), diag::note_declared_at); + return; + } + + // Prohibit variably-modified types; they're difficult to deal with. if (type->isVariablyModifiedType()) { - S.Diag(loc, diag::err_ref_vm_type); - S.Diag(var->getLocation(), diag::note_declared_at); + if (isBlock) + Diag(loc, diag::err_ref_vm_type); + else + Diag(loc, diag::err_lambda_capture_vm_type) << var->getDeclName(); + Diag(var->getLocation(), diag::note_previous_decl) << var->getDeclName(); return; } - // Prohibit arrays, even in __block variables, but not references to - // them. - if (type->isArrayType()) { - S.Diag(loc, diag::err_ref_array_type); - S.Diag(var->getLocation(), diag::note_declared_at); + // Blocks are not allowed to capture arrays. + if (isBlock && type->isArrayType()) { + Diag(loc, diag::err_ref_array_type); + Diag(var->getLocation(), diag::note_previous_decl) << var->getDeclName(); return; } - // Build a copy expression. + // Lambdas are not allowed to capture __block variables; they don't + // support the expected semantics. + if (isLambda && hasBlocksAttr) { + Diag(loc, diag::err_lambda_capture_block) << var->getDeclName(); + Diag(var->getLocation(), diag::note_previous_decl) << var->getDeclName(); + return; + } + + bool byRef; + if (CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_None) { + // No capture-default + 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; + } else if (CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_LambdaByval) { + // capture-default '=' + byRef = false; + } else if (CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_LambdaByref) { + // capture-default '&' + byRef = true; + } 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 and the copy + // might be non-trivial. Expr *copyExpr = 0; const RecordType *rtype; - if (!byRef && S.getLangOptions().CPlusPlus && !type->isDependentType() && - (rtype = type->getAs<RecordType>())) { - + 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)) - S.FinalizeVarWithDestructor(var, rtype); + 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(); + // There is no equivalent language in the C++11 specification of lambdas. + if (isBlock) + type.addConst(); - Expr *declRef = new (S.Context) DeclRefExpr(var, type, VK_LValue, loc); + Expr *declRef = new (Context) DeclRefExpr(var, type, VK_LValue, loc); ExprResult result = - S.PerformCopyInitialization( + PerformCopyInitialization( InitializedEntity::InitializeBlock(var->getLocation(), type, false), - loc, S.Owned(declRef)); + 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 = S.MaybeCreateExprWithCleanups(result); + result = MaybeCreateExprWithCleanups(result); copyExpr = result.take(); } } - BlockScopeInfo *blockScope = cast<BlockScopeInfo>(S.FunctionScopes[i]); - blockScope->AddCapture(var, byRef, Nested, loc, copyExpr); + CSI->AddCapture(var, hasBlocksAttr, byRef, Nested, loc, copyExpr); Nested = true; + if (shouldAddConstForScope(CSI, var)) + type.addConst(); } } @@ -9544,7 +9612,7 @@ static void MarkVarDeclODRUsed(Sema &SemaRef, VarDecl *Var, if (old.isInvalid()) old = Loc; } - tryCaptureVar(SemaRef, Var, Loc); + SemaRef.TryCaptureVar(Var, Loc); Var->setUsed(true); } diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 1ff6f59bae..3dd271bb8a 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -5051,7 +5051,8 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, // the variable. // FIXME: Unify with normal capture path, so we get all of the necessary // nested captures. - LSI->AddCapture(Var, C->Kind == LCK_ByRef, /*isNested=*/false, C->Loc, 0); + LSI->AddCapture(Var, /*isBlock*/false, C->Kind == LCK_ByRef, + /*isNested=*/false, C->Loc, 0); } LSI->finishedExplicitCaptures(); diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp index 7e2180fe0e..04aa45576e 100644 --- a/lib/Sema/SemaExprObjC.cpp +++ b/lib/Sema/SemaExprObjC.cpp @@ -237,14 +237,8 @@ ExprResult Sema::ParseObjCProtocolExpression(IdentifierInfo *ProtocolId, } /// Try to capture an implicit reference to 'self'. -ObjCMethodDecl *Sema::tryCaptureObjCSelf() { - // Ignore block scopes: we can capture through them. - DeclContext *DC = CurContext; - while (true) { - if (isa<BlockDecl>(DC)) DC = cast<BlockDecl>(DC)->getDeclContext(); - else if (isa<EnumDecl>(DC)) DC = cast<EnumDecl>(DC)->getDeclContext(); - else break; - } +ObjCMethodDecl *Sema::tryCaptureObjCSelf(SourceLocation Loc) { + DeclContext *DC = getFunctionLevelDeclContext(); // If we're not in an ObjC method, error out. Note that, unlike the // C++ case, we don't require an instance method --- class methods @@ -253,22 +247,7 @@ ObjCMethodDecl *Sema::tryCaptureObjCSelf() { if (!method) return 0; - ImplicitParamDecl *self = method->getSelfDecl(); - assert(self && "capturing 'self' in non-definition?"); - - // Mark that we're closing on 'this' in all the block scopes, if applicable. - for (unsigned idx = FunctionScopes.size() - 1; - isa<BlockScopeInfo>(FunctionScopes[idx]); - --idx) { - BlockScopeInfo *blockScope = cast<BlockScopeInfo>(FunctionScopes[idx]); - unsigned &captureIndex = blockScope->CaptureMap[self]; - if (captureIndex) break; - - bool nested = isa<BlockScopeInfo>(FunctionScopes[idx-1]); - blockScope->AddCapture(self, /*byref*/ false, nested, self->getLocation(), - /*copy*/ 0); - captureIndex = blockScope->Captures.size(); // +1 - } + TryCaptureVar(method->getSelfDecl(), Loc); return method; } @@ -763,7 +742,7 @@ ActOnClassPropertyRefExpr(IdentifierInfo &receiverName, if (receiverNamePtr->isStr("super")) { IsSuper = true; - if (ObjCMethodDecl *CurMethod = tryCaptureObjCSelf()) { + if (ObjCMethodDecl *CurMethod = tryCaptureObjCSelf(receiverNameLoc)) { if (CurMethod->isInstanceMethod()) { QualType T = Context.getObjCInterfaceType(CurMethod->getClassInterface()); @@ -975,7 +954,7 @@ ExprResult Sema::ActOnSuperMessage(Scope *S, SourceLocation RBracLoc, MultiExprArg Args) { // Determine whether we are inside a method or not. - ObjCMethodDecl *Method = tryCaptureObjCSelf(); + ObjCMethodDecl *Method = tryCaptureObjCSelf(SuperLoc); if (!Method) { Diag(SuperLoc, diag::err_invalid_receiver_to_message_super); return ExprError(); |