From: Steve Naroff Date: Wed, 4 Mar 2009 15:11:40 +0000 (+0000) Subject: Finish up some fixes related to Message lookup is sometimes... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=6b9dfd4257b85c388a9e3cd345cf28acb7351006;p=clang Finish up some fixes related to Message lookup is sometimes different than gcc's. - Disallow casting 'super'. GCC allows this, however it doesn't make sense (super isn't an expression and the cast won't alter lookup/dispatch). - Tighten up lookup when messaging 'self'. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@66033 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticSemaKinds.def b/include/clang/Basic/DiagnosticSemaKinds.def index 5fb7fe2b29..38977a3ed8 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.def +++ b/include/clang/Basic/DiagnosticSemaKinds.def @@ -966,6 +966,8 @@ DIAG(err_catch_param_not_objc_type, ERROR, "@catch parameter is not an Objective-C class type") DIAG(err_illegal_qualifiers_on_catch_parm, ERROR, "illegal qualifiers on @catch parameter") +DIAG(err_illegal_super_cast, ERROR, + "cannot cast 'super' (it isn't an expression)") // C++ casts diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 14b72874f7..9cb47cce4b 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -226,6 +226,9 @@ public: /// extremely uncommon (only 1% of selectors are "overloaded"). llvm::DenseMap InstanceMethodPool; llvm::DenseMap FactoryMethodPool; + + /// Private Helper predicate to check for 'self'. + bool isSelfExpr(Expr *RExpr); public: Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer); ~Sema() { diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 6252bcaef5..43909b9afe 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -2302,6 +2302,8 @@ bool Sema::CheckCastTypes(SourceRange TyR, QualType castType, Expr *&castExpr) { } else if (castType->isVectorType()) { if (CheckVectorCast(TyR, castType, castExpr->getType())) return true; + } else if (getLangOptions().ObjC1 && isa(castExpr)) { + return Diag(castExpr->getLocStart(), diag::err_illegal_super_cast); } return false; } diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp index 39a89d6d94..8705baffcb 100644 --- a/lib/Sema/SemaExprObjC.cpp +++ b/lib/Sema/SemaExprObjC.cpp @@ -202,6 +202,13 @@ bool Sema::CheckMessageArgumentTypes(Expr **Args, unsigned NumArgs, return anyIncompatibleArgs; } +bool Sema::isSelfExpr(Expr *RExpr) { + if (DeclRefExpr *DRE = dyn_cast(RExpr)) + if (DRE->getDecl()->getIdentifier() == &Context.Idents.get("self")) + return true; + return false; +} + // Helper method for ActOnClassMethod/ActOnInstanceMethod. // Will search "local" class/category implementations for a method decl. // Returns 0 if no method is found. @@ -385,6 +392,7 @@ Sema::ExprResult Sema::ActOnInstanceMessage(ExprTy *receiver, Selector Sel, // Handle messages to Class. if (ReceiverCType == Context.getCanonicalType(Context.getObjCClassType())) { ObjCMethodDecl *Method = 0; + if (ObjCMethodDecl *CurMeth = getCurMethodDecl()) { if (ObjCInterfaceDecl *ClassDecl = CurMeth->getClassInterface()) { // First check the public methods in the class interface. @@ -396,12 +404,15 @@ Sema::ExprResult Sema::ActOnInstanceMessage(ExprTy *receiver, Selector Sel, if (Method && DiagnoseUseOfDecl(Method, receiverLoc)) return true; } - // Look for any factory method named 'Sel'. - if (!Method) - Method = FactoryMethodPool[Sel].Method; - if (!Method) - Method = LookupInstanceMethodInGlobalPool( - Sel, SourceRange(lbrac,rbrac)); + if (!Method) { + // If not messaging 'self', look for any factory method named 'Sel'. + if (!isSelfExpr(RExpr)) { + Method = FactoryMethodPool[Sel].Method; + if (!Method) + Method = LookupInstanceMethodInGlobalPool( + Sel, SourceRange(lbrac,rbrac)); + } + } if (CheckMessageArgumentTypes(ArgExprs, NumArgs, Sel, Method, false, lbrac, rbrac, returnType)) return true; @@ -462,15 +473,17 @@ Sema::ExprResult Sema::ActOnInstanceMessage(ExprTy *receiver, Selector Sel, } } } - // If we still haven't found a method, look in the global pool. This - // behavior isn't very desirable, however we need it for GCC - // compatibility. FIXME: should we deviate?? - if (!Method && OCIType->qual_empty()) { - Method = LookupInstanceMethodInGlobalPool( - Sel, SourceRange(lbrac,rbrac)); - if (Method && !OCIType->getDecl()->isForwardDecl()) - Diag(lbrac, diag::warn_maynot_respond) - << OCIType->getDecl()->getIdentifier()->getName() << Sel; + if (!isSelfExpr(RExpr)) { + // If we still haven't found a method, look in the global pool. This + // behavior isn't very desirable, however we need it for GCC + // compatibility. FIXME: should we deviate?? + if (!Method && OCIType->qual_empty()) { + Method = LookupInstanceMethodInGlobalPool( + Sel, SourceRange(lbrac,rbrac)); + if (Method && !OCIType->getDecl()->isForwardDecl()) + Diag(lbrac, diag::warn_maynot_respond) + << OCIType->getDecl()->getIdentifier()->getName() << Sel; + } } } if (Method && DiagnoseUseOfDecl(Method, receiverLoc)) diff --git a/test/SemaObjC/call-super-2.m b/test/SemaObjC/call-super-2.m new file mode 100644 index 0000000000..98e4e08857 --- /dev/null +++ b/test/SemaObjC/call-super-2.m @@ -0,0 +1,98 @@ +// RUN: clang -fsyntax-only -verify %s + +#include + +typedef struct objc_object *id; +id objc_getClass(const char *s); + +@interface Object +@end + +@protocol Func ++ (int) class_func0; +- (int) instance_func0; +@end + +@interface Derived: Object ++ (int) class_func1; ++ (int) class_func2; ++ (int) class_func3; ++ (int) class_func4; ++ (int) class_func5; ++ (int) class_func6; ++ (int) class_func7; +- (int) instance_func1; +- (int) instance_func2; +- (int) instance_func3; +- (int) instance_func4; +- (int) instance_func5; +- (int) instance_func6; +- (int) instance_func7; +@end + +@implementation Derived ++ (int) class_func1 +{ + int i = (size_t)[self class_func0]; // expected-warning {{method '-class_func0' not found (return type defaults to 'id')}} + return i + (size_t)[super class_func0]; // expected-warning {{method '+class_func0' not found (return type defaults to 'id')}} +} ++ (int) class_func2 +{ + int i = [(id )self class_func0]; // expected-warning {{method '-class_func0' not found (return type defaults to 'id')}} // expected-warning {{incompatible pointer to integer conversion initializing 'id', expected 'int'}} + i += [(id )super class_func0]; // expected-error {{cannot cast 'super' (it isn't an expression)}} + i += [(Class )self class_func0]; // expected-error {{protocol qualified 'Class' is unsupported}} + return i + [(Class )super class_func0]; // expected-error {{protocol qualified 'Class' is unsupported}} // expected-error {{cannot cast 'super' (it isn't an expression)}} +} ++ (int) class_func3 +{ + return [(Object *)super class_func0]; // expected-error {{cannot cast 'super' (it isn't an expression)}} +} ++ (int) class_func4 +{ + return [(Derived *)super class_func0]; // expected-error {{cannot cast 'super' (it isn't an expression)}} +} ++ (int) class_func5 +{ + int i = (size_t)[Derived class_func0]; // expected-warning {{method '+class_func0' not found (return type defaults to 'id')}} + return i + (size_t)[Object class_func0]; // expected-warning {{method '+class_func0' not found (return type defaults to 'id')}} +} ++ (int) class_func6 +{ + return (size_t)[objc_getClass("Object") class_func1]; // GCC warns about this +} ++ (int) class_func7 +{ + return [objc_getClass("Derived") class_func1]; +} +- (int) instance_func1 +{ + int i = (size_t)[self instance_func0]; // expected-warning {{method '-instance_func0' not found (return type defaults to 'id'))}} + return i + (size_t)[super instance_func0]; // expected-warning {{method '-instance_func0' not found (return type defaults to 'id')}} +} +- (int) instance_func2 +{ + return [(id )super instance_func0]; // expected-error {{cannot cast 'super' (it isn't an expression)}} +} +- (int) instance_func3 +{ + return [(Object *)super instance_func0]; // expected-error {{cannot cast 'super' (it isn't an expression)}} +} +- (int) instance_func4 +{ + return [(Derived *)super instance_func0]; // expected-error {{cannot cast 'super' (it isn't an expression)}} +} +- (int) instance_func5 +{ + int i = (size_t)[Derived instance_func1]; // GCC currently warns. + return i + (size_t)[Object instance_func1]; // expected-warning {{method '+instance_func1' not found (return type defaults to 'id')}} +} +- (int) instance_func6 +{ + return (size_t)[objc_getClass("Object") class_func1]; +} +- (int) instance_func7 +{ + return [objc_getClass("Derived") class_func1]; +} +@end + diff --git a/test/SemaObjC/conditional-expr.m b/test/SemaObjC/conditional-expr.m index 76656717e1..4792fa6644 100644 --- a/test/SemaObjC/conditional-expr.m +++ b/test/SemaObjC/conditional-expr.m @@ -36,7 +36,7 @@ // No @interface declaration for DTFilterOutputStream3 @implementation DTFilterOutputStream3 // expected-warning {{cannot find interface declaration for 'DTFilterOutputStream3'}} - (id)initWithNextOutputStream:(id ) outputStream { - id nextOutputStream = [self nextOutputStream]; // expected-warning {{DTFilterOutputStream3 may not respond to 'nextOutputStream'}} + id nextOutputStream = [self nextOutputStream]; // expected-warning {{method '-nextOutputStream' not found (return type defaults to 'id')}} // GCC warns about both of these as well (no errors). self = nextOutputStream; // expected-warning {{incompatible type assigning 'id', expected 'DTFilterOutputStream3 *'}} return nextOutputStream ? nextOutputStream : self; diff --git a/test/SemaObjC/property-category-1.m b/test/SemaObjC/property-category-1.m index 926f964202..243b774870 100644 --- a/test/SemaObjC/property-category-1.m +++ b/test/SemaObjC/property-category-1.m @@ -1,7 +1,7 @@ // RUN: clang -fsyntax-only -verify %s @interface Object -- (id)new; ++ (id)new; @end @interface ReadOnly : Object diff --git a/test/SemaObjC/property-noprotocol-warning.m b/test/SemaObjC/property-noprotocol-warning.m index 021c7874a9..211185f2b6 100644 --- a/test/SemaObjC/property-noprotocol-warning.m +++ b/test/SemaObjC/property-noprotocol-warning.m @@ -2,7 +2,7 @@ @interface Object -- (id) new; ++ (id) new; @end @protocol GCObject