diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/CodeGen/CGObjC.cpp | 22 | ||||
-rw-r--r-- | lib/Parse/ParseStmt.cpp | 13 | ||||
-rw-r--r-- | lib/Sema/SemaStmt.cpp | 103 | ||||
-rw-r--r-- | lib/Sema/TreeTransform.h | 15 |
4 files changed, 115 insertions, 38 deletions
diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp index c817115cbe..f81b6b75e3 100644 --- a/lib/CodeGen/CGObjC.cpp +++ b/lib/CodeGen/CGObjC.cpp @@ -1020,8 +1020,16 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){ ArrayType::Normal, 0); llvm::Value *ItemsPtr = CreateMemTemp(ItemsTy, "items.ptr"); - // Emit the collection pointer. - llvm::Value *Collection = EmitScalarExpr(S.getCollection()); + // Emit the collection pointer. In ARC, we do a retain. + llvm::Value *Collection; + if (getLangOptions().ObjCAutoRefCount) { + Collection = EmitARCRetainScalarExpr(S.getCollection()); + + // Enter a cleanup to do the release. + EmitObjCConsumeObject(S.getCollection()->getType(), Collection); + } else { + Collection = EmitScalarExpr(S.getCollection()); + } // Send it our message: CallArgList Args; @@ -1236,6 +1244,10 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){ DI->EmitRegionEnd(Builder); } + // Leave the cleanup we entered in ARC. + if (getLangOptions().ObjCAutoRefCount) + PopCleanupBlock(); + EmitBlock(LoopEnd.getBlock()); } @@ -1967,6 +1979,12 @@ static llvm::Value *emitARCRetainAfterCall(CodeGenFunction &CGF, static TryEmitResult tryEmitARCRetainScalarExpr(CodeGenFunction &CGF, const Expr *e) { + // Look through cleanups. + if (const ExprWithCleanups *cleanups = dyn_cast<ExprWithCleanups>(e)) { + CodeGenFunction::RunCleanupsScope scope(CGF); + return tryEmitARCRetainScalarExpr(CGF, cleanups->getSubExpr()); + } + // The desired result type, if it differs from the type of the // ultimate opaque expression. llvm::Type *resultType = 0; diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index 622c8ea905..b34e4f8277 100644 --- a/lib/Parse/ParseStmt.cpp +++ b/lib/Parse/ParseStmt.cpp @@ -1405,13 +1405,22 @@ StmtResult Parser::ParseForStatement(ParsedAttributes &attrs) { // statememt before parsing the body, in order to be able to deduce the type // of an auto-typed loop variable. StmtResult ForRangeStmt; - if (ForRange) + if (ForRange) { ForRangeStmt = Actions.ActOnCXXForRangeStmt(ForLoc, LParenLoc, FirstPart.take(), ForRangeInit.ColonLoc, ForRangeInit.RangeExpr.get(), RParenLoc); + + // Similarly, we need to do the semantic analysis for a for-range + // statement immediately in order to close over temporaries correctly. + } else if (ForEach) { + if (!Collection.isInvalid()) + Collection = + Actions.ActOnObjCForCollectionOperand(ForLoc, Collection.take()); + } + // C99 6.8.5p5 - In C99, the body of the if statement is a scope, even if // there is no compound stmt. C90 does not have this clause. We only do this // if the body isn't a compound statement to avoid push/pop in common cases. @@ -1439,8 +1448,6 @@ StmtResult Parser::ParseForStatement(ParsedAttributes &attrs) { return StmtError(); if (ForEach) - // FIXME: It isn't clear how to communicate the late destruction of - // C++ temporaries used to create the collection. return Actions.ActOnObjCForCollectionStmt(ForLoc, LParenLoc, FirstPart.take(), Collection.take(), RParenLoc, diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index c22555e4dd..0fd3f03982 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -965,6 +965,76 @@ StmtResult Sema::ActOnForEachLValueExpr(Expr *E) { return Owned(static_cast<Stmt*>(Result.get())); } +ExprResult +Sema::ActOnObjCForCollectionOperand(SourceLocation forLoc, Expr *collection) { + assert(collection); + + // Bail out early if we've got a type-dependent expression. + if (collection->isTypeDependent()) return Owned(collection); + + // Perform normal l-value conversion. + ExprResult result = DefaultFunctionArrayLvalueConversion(collection); + if (result.isInvalid()) + return ExprError(); + collection = result.take(); + + // The operand needs to have object-pointer type. + // TODO: should we do a contextual conversion? + const ObjCObjectPointerType *pointerType = + collection->getType()->getAs<ObjCObjectPointerType>(); + if (!pointerType) + return Diag(forLoc, diag::err_collection_expr_type) + << collection->getType() << collection->getSourceRange(); + + // Check that the operand provides + // - countByEnumeratingWithState:objects:count: + const ObjCObjectType *objectType = pointerType->getObjectType(); + ObjCInterfaceDecl *iface = objectType->getInterface(); + + // If we have a forward-declared type, we can't do this check. + if (iface && iface->isForwardDecl()) { + // This is ill-formed under ARC. + if (getLangOptions().ObjCAutoRefCount) { + Diag(forLoc, diag::err_arc_collection_forward) + << pointerType->getPointeeType() << collection->getSourceRange(); + } + + // Otherwise, if we have any useful type information, check that + // the type declares the appropriate method. + } else if (iface || !objectType->qual_empty()) { + IdentifierInfo *selectorIdents[] = { + &Context.Idents.get("countByEnumeratingWithState"), + &Context.Idents.get("objects"), + &Context.Idents.get("count") + }; + Selector selector = Context.Selectors.getSelector(3, &selectorIdents[0]); + + ObjCMethodDecl *method = 0; + + // If there's an interface, look in both the public and private APIs. + if (iface) { + method = iface->lookupInstanceMethod(selector); + if (!method) method = LookupPrivateInstanceMethod(selector, iface); + } + + // Also check protocol qualifiers. + if (!method) + method = LookupMethodInQualifiedType(selector, pointerType, + /*instance*/ true); + + // If we didn't find it anywhere, give up. + if (!method) { + Diag(forLoc, diag::warn_collection_expr_type) + << collection->getType() << selector << collection->getSourceRange(); + } + + // TODO: check for an incompatible signature? + } + + // Wrap up any cleanups in the expression. + return Owned(MaybeCreateExprWithCleanups(collection)); +} + StmtResult Sema::ActOnObjCForCollectionStmt(SourceLocation ForLoc, SourceLocation LParenLoc, @@ -1000,38 +1070,7 @@ Sema::ActOnObjCForCollectionStmt(SourceLocation ForLoc, Diag(ForLoc, diag::err_selector_element_type) << FirstType << First->getSourceRange(); } - if (Second && !Second->isTypeDependent()) { - ExprResult Result = DefaultFunctionArrayLvalueConversion(Second); - if (Result.isInvalid()) - return StmtError(); - Second = Result.take(); - QualType SecondType = Second->getType(); - if (!SecondType->isObjCObjectPointerType()) - Diag(ForLoc, diag::err_collection_expr_type) - << SecondType << Second->getSourceRange(); - else if (const ObjCObjectPointerType *OPT = - SecondType->getAsObjCInterfacePointerType()) { - SmallVector<IdentifierInfo *, 4> KeyIdents; - IdentifierInfo* selIdent = - &Context.Idents.get("countByEnumeratingWithState"); - KeyIdents.push_back(selIdent); - selIdent = &Context.Idents.get("objects"); - KeyIdents.push_back(selIdent); - selIdent = &Context.Idents.get("count"); - KeyIdents.push_back(selIdent); - Selector CSelector = Context.Selectors.getSelector(3, &KeyIdents[0]); - if (ObjCInterfaceDecl *IDecl = OPT->getInterfaceDecl()) { - if (!IDecl->isForwardDecl() && - !IDecl->lookupInstanceMethod(CSelector) && - !LookupMethodInQualifiedType(CSelector, OPT, true)) { - // Must further look into private implementation methods. - if (!LookupPrivateInstanceMethod(CSelector, IDecl)) - Diag(ForLoc, diag::warn_collection_expr_type) - << SecondType << CSelector << Second->getSourceRange(); - } - } - } - } + return Owned(new (Context) ObjCForCollectionStmt(First, Second, Body, ForLoc, RParenLoc)); } diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 2221fc0c21..373339a2cb 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -1200,7 +1200,16 @@ public: Stmt *Body) { return getSema().ActOnObjCAutoreleasePoolStmt(AtLoc, Body); } - + + /// \brief Build the collection operand to a new Objective-C fast + /// enumeration statement. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + ExprResult RebuildObjCForCollectionOperand(SourceLocation forLoc, + Expr *collection) { + return getSema().ActOnObjCForCollectionOperand(forLoc, collection); + } /// \brief Build a new Objective-C fast enumeration statement. /// @@ -5519,6 +5528,10 @@ TreeTransform<Derived>::TransformObjCForCollectionStmt( ExprResult Collection = getDerived().TransformExpr(S->getCollection()); if (Collection.isInvalid()) return StmtError(); + Collection = getDerived().RebuildObjCForCollectionOperand(S->getForLoc(), + Collection.take()); + if (Collection.isInvalid()) + return StmtError(); // Transform the body. StmtResult Body = getDerived().TransformStmt(S->getBody()); |