aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/Sema/SemaStmt.cpp9
-rw-r--r--lib/Sema/TreeTransform.h50
-rw-r--r--test/SemaObjCXX/instantiate-stmt.mm35
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}}