Patch to add semantics check for ObjC2's foreacn statement.

llvm-svn: 45561
This commit is contained in:
Fariborz Jahanian 2008-01-04 00:27:46 +00:00
parent 816dea2fc5
commit 775d5d02af
7 changed files with 115 additions and 11 deletions

View File

@ -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) {

View File

@ -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

View File

@ -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)

View File

@ -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);
}

View File

@ -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

View File

@ -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

View File

@ -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