From: Chris Lattner Date: Mon, 21 Jul 2008 06:12:56 +0000 (+0000) Subject: continue cleaning up code, and disable sending a message directly to an X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=2b1cc8be4dda4cd122485be0168b3c43d7dff15f;p=clang continue cleaning up code, and disable sending a message directly to an interface. This fixes a bug where we used to accept: void test2(NSNumber x) { [x METH]; } which doesn't make sense and GCC rejects. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@53841 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index e35f0aae11..22f7abaf49 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -362,6 +362,10 @@ public: const ObjCQualifiedInterfaceType *getAsObjCQualifiedInterfaceType() const; const ObjCQualifiedIdType *getAsObjCQualifiedIdType() const; + /// getAsPointerToObjCInterfaceType - If this is a pointer to an ObjC + /// interface, return the interface type, otherwise return null. + const ObjCInterfaceType *getAsPointerToObjCInterfaceType() const; + /// getDesugaredType - Return the specified type with any "sugar" removed from /// the type. This takes off typedefs, typeof's etc. If the outer level of @@ -1289,6 +1293,12 @@ inline unsigned QualType::getAddressSpace() const { inline const TypedefType* Type::getAsTypedefType() const { return dyn_cast(this); } +inline const ObjCInterfaceType *Type::getAsPointerToObjCInterfaceType() const { + if (const PointerType *PT = getAsPointerType()) + return PT->getPointeeType()->getAsObjCInterfaceType(); + return 0; +} + inline bool Type::isFunctionType() const { return isa(CanonicalType.getUnqualifiedType()); diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp index bcd3975b20..0e5de3ab14 100644 --- a/lib/Sema/SemaExprObjC.cpp +++ b/lib/Sema/SemaExprObjC.cpp @@ -226,14 +226,13 @@ Sema::ExprResult Sema::ActOnInstanceMessage( Expr **ArgExprs = reinterpret_cast(Args); Expr *RExpr = static_cast(receiver); QualType returnType; - ObjCMethodDecl *Method = 0; QualType receiverType = RExpr->getType().getCanonicalType().getUnqualifiedType(); // Handle messages to id. if (receiverType == Context.getObjCIdType().getCanonicalType()) { - Method = InstanceMethodPool[Sel].Method; + ObjCMethodDecl *Method = InstanceMethodPool[Sel].Method; if (!Method) Method = FactoryMethodPool[Sel].Method; if (!Method) { @@ -252,6 +251,7 @@ Sema::ExprResult Sema::ActOnInstanceMessage( // Handle messages to Class. if (receiverType == Context.getObjCClassType().getCanonicalType()) { + ObjCMethodDecl *Method = 0; if (getCurMethodDecl()) { ObjCInterfaceDecl* ClassDecl = getCurMethodDecl()->getClassInterface(); // If we have an implementation in scope, check "private" methods. @@ -279,18 +279,14 @@ Sema::ExprResult Sema::ActOnInstanceMessage( ArgExprs, NumArgs); } - // We allow sending a message to a qualified ID ("id") to an interface - // directly ("[NSNumber foo]") and to a pointer to an interface (an object). - if (!isa(receiverType) && - !isa(receiverType)) - if (const PointerType *PTy = receiverType->getAsPointerType()) - receiverType = PTy->getPointeeType(); - // else error, invalid receiver. - + ObjCMethodDecl *Method = 0; ObjCInterfaceDecl* ClassDecl = 0; + + // We allow sending a message to a qualified ID ("id"), which is ok as + // long as one of the protocols implements the selector (if not, warn). if (ObjCQualifiedIdType *QIT = dyn_cast(receiverType)) { - // search protocols + // Search protocols for (unsigned i = 0; i < QIT->getNumProtocols(); i++) { ObjCProtocolDecl *PDecl = QIT->getProtocols(i); if (PDecl && (Method = PDecl->lookupInstanceMethod(Sel))) @@ -300,13 +296,9 @@ Sema::ExprResult Sema::ActOnInstanceMessage( Diag(lbrac, diag::warn_method_not_found_in_protocol, std::string("-"), Sel.getName(), SourceRange(lbrac, rbrac)); - } else { - ObjCInterfaceType *OCIReceiver =dyn_cast(receiverType); - if (OCIReceiver == 0) { - Diag(lbrac, diag::error_bad_receiver_type, - RExpr->getType().getAsString()); - return true; - } + } else if (const ObjCInterfaceType *OCIReceiver = + receiverType->getAsPointerToObjCInterfaceType()) { + // We allow sending a message to a pointer to an interface (an object). ClassDecl = OCIReceiver->getDecl(); // FIXME: consider using InstanceMethodPool, since it will be faster @@ -327,6 +319,10 @@ Sema::ExprResult Sema::ActOnInstanceMessage( Diag(lbrac, diag::warn_method_not_found_in_protocol, std::string("-"), Sel.getName(), SourceRange(lbrac, rbrac)); + } else { + Diag(lbrac, diag::error_bad_receiver_type, + RExpr->getType().getAsString()); + return true; } if (!Method) { diff --git a/test/Parser/objc-init.m b/test/Parser/objc-init.m index 303d80cf7c..4478665f7a 100644 --- a/test/Parser/objc-init.m +++ b/test/Parser/objc-init.m @@ -11,13 +11,16 @@ void test1() { } void test2(NSNumber x) { + id objects[] = {[x METH]}; // expected-error {{bad receiver type}} +} + +void test3(NSNumber *x) { id objects[] = {[x METH]}; - return 0; } // rdar://5977581 -void test3() { +void test4() { unsigned x[] = {[NSNumber METH2]+2}; }