diff options
-rw-r--r-- | lib/Sema/SemaStmt.cpp | 9 | ||||
-rw-r--r-- | lib/Sema/TreeTransform.h | 50 | ||||
-rw-r--r-- | test/SemaObjCXX/instantiate-stmt.mm | 35 |
3 files changed, 87 insertions, 7 deletions
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index c7bb3c827c..9c7affdb96 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -988,19 +988,22 @@ Sema::ActOnObjCForCollectionStmt(SourceLocation ForLoc, return StmtError(Diag(VD->getLocation(), diag::err_non_variable_decl_in_for)); } else { - if (cast<Expr>(First)->isLvalue(Context) != Expr::LV_Valid) + Expr *FirstE = cast<Expr>(First); + if (!FirstE->isTypeDependent() && + FirstE->isLvalue(Context) != Expr::LV_Valid) return StmtError(Diag(First->getLocStart(), diag::err_selector_element_not_lvalue) << First->getSourceRange()); FirstType = static_cast<Expr*>(First)->getType(); } - if (!FirstType->isObjCObjectPointerType() && + if (!FirstType->isDependentType() && + !FirstType->isObjCObjectPointerType() && !FirstType->isBlockPointerType()) Diag(ForLoc, diag::err_selector_element_type) << FirstType << First->getSourceRange(); } - if (Second) { + if (Second && !Second->isTypeDependent()) { DefaultFunctionArrayLvalueConversion(Second); QualType SecondType = Second->getType(); if (!SecondType->isObjCObjectPointerType()) diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 9d7f936bd7..7bcfeb1006 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -901,7 +901,6 @@ public: /// \brief Build a new Objective-C @synchronized statement. /// - /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. OwningStmtResult RebuildObjCAtSynchronizedStmt(SourceLocation AtLoc, @@ -910,6 +909,23 @@ public: return getSema().ActOnObjCAtSynchronizedStmt(AtLoc, move(Object), move(Body)); } + + /// \brief Build 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. + OwningStmtResult RebuildObjCForCollectionStmt(SourceLocation ForLoc, + SourceLocation LParenLoc, + StmtArg Element, + ExprArg Collection, + SourceLocation RParenLoc, + StmtArg Body) { + return getSema().ActOnObjCForCollectionStmt(ForLoc, LParenLoc, + move(Element), + move(Collection), + RParenLoc, + move(Body)); + } /// \brief Build a new C++ exception declaration. /// @@ -3713,9 +3729,35 @@ template<typename Derived> Sema::OwningStmtResult TreeTransform<Derived>::TransformObjCForCollectionStmt( ObjCForCollectionStmt *S) { - // FIXME: Implement this - assert(false && "Cannot transform an Objective-C for-each statement"); - return SemaRef.Owned(S->Retain()); + // Transform the element statement. + OwningStmtResult Element = getDerived().TransformStmt(S->getElement()); + if (Element.isInvalid()) + return SemaRef.StmtError(); + + // Transform the collection expression. + OwningExprResult Collection = getDerived().TransformExpr(S->getCollection()); + if (Collection.isInvalid()) + return SemaRef.StmtError(); + + // Transform the body. + OwningStmtResult Body = getDerived().TransformStmt(S->getBody()); + if (Body.isInvalid()) + return SemaRef.StmtError(); + + // If nothing changed, just retain this statement. + if (!getDerived().AlwaysRebuild() && + Element.get() == S->getElement() && + Collection.get() == S->getCollection() && + Body.get() == S->getBody()) + return SemaRef.Owned(S->Retain()); + + // Build a new statement. + return getDerived().RebuildObjCForCollectionStmt(S->getForLoc(), + /*FIXME:*/S->getForLoc(), + move(Element), + move(Collection), + S->getRParenLoc(), + move(Body)); } diff --git a/test/SemaObjCXX/instantiate-stmt.mm b/test/SemaObjCXX/instantiate-stmt.mm index 3d5c86ff91..5e9abecc6d 100644 --- a/test/SemaObjCXX/instantiate-stmt.mm +++ b/test/SemaObjCXX/instantiate-stmt.mm @@ -22,3 +22,38 @@ void synchronized_test(T value) { template void synchronized_test(NSException *); template void synchronized_test(int); // expected-note{{in instantiation of}} + +// fast enumeration +@interface NSArray +@end + +@interface NSString +@end + +struct vector {}; + +template<typename T> void eat(T); + +template<typename E, typename T> +void fast_enumeration_test(T collection) { + for (E element in collection) { // expected-error{{selector element type 'int' is not a valid object}} \ + // expected-error{{collection expression type 'vector' is not a valid object}} + eat(element); + } + + E element; + for (element in collection) // expected-error{{selector element type 'int' is not a valid object}} \ + // expected-error{{collection expression type 'vector' is not a valid object}} + eat(element); + + for (NSString *str in collection) // expected-error{{collection expression type 'vector' is not a valid object}} + eat(str); + + NSString *str; + for (str in collection) // expected-error{{collection expression type 'vector' is not a valid object}} + eat(str); +} + +template void fast_enumeration_test<NSString *>(NSArray*); +template void fast_enumeration_test<int>(NSArray*); // expected-note{{in instantiation of}} +template void fast_enumeration_test<NSString *>(vector); // expected-note{{in instantiation of}} |