diff options
author | Fariborz Jahanian <fjahanian@apple.com> | 2008-01-04 00:27:46 +0000 |
---|---|---|
committer | Fariborz Jahanian <fjahanian@apple.com> | 2008-01-04 00:27:46 +0000 |
commit | 1f990d67c2d24cb330434f42dd62a3a0cc4aa6e9 (patch) | |
tree | 117f3ee51befc88a230ce6fe3d3673decc943c1e | |
parent | 4667ac39be4a96725373c0317ad6827e1bb71502 (diff) |
Patch to add semantics check for ObjC2's foreacn statement.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@45561 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | Sema/Sema.cpp | 14 | ||||
-rw-r--r-- | Sema/Sema.h | 4 | ||||
-rw-r--r-- | Sema/SemaExpr.cpp | 3 | ||||
-rw-r--r-- | Sema/SemaStmt.cpp | 21 | ||||
-rw-r--r-- | include/clang/Basic/DiagnosticKinds.def | 4 | ||||
-rw-r--r-- | test/Parser/objc-forcollection-1.m | 43 | ||||
-rw-r--r-- | test/Parser/objc-forcollection-neg.m | 37 |
7 files changed, 115 insertions, 11 deletions
diff --git a/Sema/Sema.cpp b/Sema/Sema.cpp index bca3ec508b..8f340db14e 100644 --- a/Sema/Sema.cpp +++ b/Sema/Sema.cpp @@ -26,6 +26,20 @@ bool Sema::isBuiltinObjcType(TypedefDecl *TD) { strcmp(typeName, "SEL") == 0 || strcmp(typeName, "Protocol") == 0; } +bool Sema::isObjcObjectPointerType(QualType type) const { + if (!type->isPointerType() && !type->isObjcQualifiedIdType()) + return false; + if (type == Context.getObjcIdType() || type == Context.getObjcClassType() || + type->isObjcQualifiedIdType()) + return true; + + while (type->isPointerType()) { + PointerType *pointerType = static_cast<PointerType*>(type.getTypePtr()); + type = pointerType->getPointeeType(); + } + return (type->isObjcInterfaceType() || type->isObjcQualifiedIdType()); +} + void Sema::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) { TUScope = S; if (PP.getLangOptions().ObjC1) { diff --git a/Sema/Sema.h b/Sema/Sema.h index 8846d15813..6f546514db 100644 --- a/Sema/Sema.h +++ b/Sema/Sema.h @@ -285,6 +285,10 @@ private: /// isBuiltinObjcType - Returns true of the type is "id", "SEL", "Class" /// or "Protocol". bool isBuiltinObjcType(TypedefDecl *TD); + + /// isObjcObjectPointerType - Returns tru if type is an objective-c pointer + /// to an object type; such as "id", "Class", Intf*, id<P>, etc. + bool isObjcObjectPointerType(QualType type) const; /// AddInstanceMethodToGlobalPool - All instance methods in a translation /// unit are added to a global pool. This allows us to efficiently associate diff --git a/Sema/SemaExpr.cpp b/Sema/SemaExpr.cpp index de642c6e65..3a3cfc18bc 100644 --- a/Sema/SemaExpr.cpp +++ b/Sema/SemaExpr.cpp @@ -2350,8 +2350,7 @@ Sema::ExprResult Sema::ActOnInstanceMessage( return true; } } else { - bool receiverIsQualId = - dyn_cast<ObjcQualifiedIdType>(RExpr->getType()) != 0; + bool receiverIsQualId = dyn_cast<ObjcQualifiedIdType>(receiverType) != 0; // FIXME (snaroff): checking in this code from Patrick. Needs to be // revisited. how do we get the ClassDecl from the receiver expression? if (!receiverIsQualId) diff --git a/Sema/SemaStmt.cpp b/Sema/SemaStmt.cpp index 2c2dc5e3f0..6b60bd0274 100644 --- a/Sema/SemaStmt.cpp +++ b/Sema/SemaStmt.cpp @@ -538,8 +538,9 @@ Sema::ActOnObjcForCollectionStmt(SourceLocation ForColLoc, Stmt *First = static_cast<Stmt*>(first); Expr *Second = static_cast<Expr*>(second); Stmt *Body = static_cast<Stmt*>(body); - + QualType FirstType; if (DeclStmt *DS = dyn_cast_or_null<DeclStmt>(First)) { + FirstType = dyn_cast<ValueDecl>(DS->getDecl())->getType(); // C99 6.8.5p3: The declaration part of a 'for' statement shall only declare // identifiers for objects having storage class 'auto' or 'register'. for (ScopedDecl *D = DS->getDecl(); D; D = D->getNextDeclarator()) { @@ -547,19 +548,21 @@ Sema::ActOnObjcForCollectionStmt(SourceLocation ForColLoc, if (BVD && !BVD->hasLocalStorage()) BVD = 0; if (BVD == 0) - Diag(dyn_cast<ScopedDecl>(D)->getLocation(), - diag::err_non_variable_decl_in_for); - // FIXME: mark decl erroneous! + return Diag(dyn_cast<ScopedDecl>(D)->getLocation(), + diag::err_non_variable_decl_in_for); } } + else + FirstType = static_cast<Expr*>(first)->getType(); + if (!isObjcObjectPointerType(FirstType)) + Diag(ForColLoc, diag::err_selector_element_type, + FirstType.getAsString(), First->getSourceRange()); if (Second) { DefaultFunctionArrayConversion(Second); QualType SecondType = Second->getType(); -#if 0 - if (!SecondType->isScalarType()) // C99 6.8.5p2 - return Diag(ForColLoc, diag::err_typecheck_statement_requires_scalar, - SecondType.getAsString(), Second->getSourceRange()); -#endif + if (!isObjcObjectPointerType(SecondType)) + Diag(ForColLoc, diag::err_collection_expr_type, + SecondType.getAsString(), Second->getSourceRange()); } return new ObjcForCollectionStmt(First, Second, Body, ForColLoc); } diff --git a/include/clang/Basic/DiagnosticKinds.def b/include/clang/Basic/DiagnosticKinds.def index 136f6021bb..e07245659e 100644 --- a/include/clang/Basic/DiagnosticKinds.def +++ b/include/clang/Basic/DiagnosticKinds.def @@ -472,6 +472,10 @@ DIAG(warn_method_not_found, WARNING, "method '%0%1' not found (return type defaults to 'id')") DIAG(warn_method_not_found_in_protocol, WARNING, "method '%0%1' not found in protocol (return type defaults to 'id')") +DIAG(err_collection_expr_type, ERROR, + "collection expression is not of valid object type (its type is '%0')") +DIAG(err_selector_element_type, ERROR, + "selector element is not of valid object type (its type is '%0')") //===----------------------------------------------------------------------===// // Semantic Analysis diff --git a/test/Parser/objc-forcollection-1.m b/test/Parser/objc-forcollection-1.m new file mode 100644 index 0000000000..6db74dc952 --- /dev/null +++ b/test/Parser/objc-forcollection-1.m @@ -0,0 +1,43 @@ +// RUN: clang -fsyntax-only %s + +typedef struct objc_class *Class; +typedef struct objc_object { + Class isa; +} *id; + + +@protocol P @end + +@interface MyList +@end + +@implementation MyList +- (unsigned int)countByEnumeratingWithState: (struct __objcFastEnumerationState *)state objects: (id *)items count:(unsigned int)stackcount +{ + return 0; +} +@end + +@interface MyList (BasicTest) +- (void)compilerTestAgainst; +@end + +@implementation MyList (BasicTest) +- (void)compilerTestAgainst { + int i; + for (id elem in self) + ++i; + for (MyList *elem in self) + ++i; + for (id<P> se in self) + ++i; + + MyList<P> *p; + for (p in self) + ++i; + + for (p in p) + ++i; +} +@end + diff --git a/test/Parser/objc-forcollection-neg.m b/test/Parser/objc-forcollection-neg.m new file mode 100644 index 0000000000..4137e6304b --- /dev/null +++ b/test/Parser/objc-forcollection-neg.m @@ -0,0 +1,37 @@ +// RUN: clang -fsyntax-only -verify %s + +typedef struct objc_class *Class; +typedef struct objc_object { + Class isa; +} *id; + + +@interface MyList +@end + +@implementation MyList +- (unsigned int)countByEnumeratingWithState: (struct __objcFastEnumerationState *)state objects: (id *)items count:(unsigned int)stackcount +{ + return 0; +} +@end + +@interface MyList (BasicTest) +- (void)compilerTestAgainst; +@end + +@implementation MyList (BasicTest) +- (void)compilerTestAgainst { + + int i=0; + for (int * elem in elem) // expected-error {{selector element is not of valid object type (its type is 'int *')}} \ + expected-error {{collection expression is not of valid object type (its type is 'int *')}} + ++i; + for (i in elem) // expected-error {{use of undeclared identifier 'elem'}} \ + expected-error {{selector element is not of valid object type (its type is 'int')}} + ++i; + for (id se in i) // expected-error {{collection expression is not of valid object type (its type is 'int')}} + ++i; +} +@end + |