diff options
author | John McCall <rjmccall@apple.com> | 2013-03-01 09:20:14 +0000 |
---|---|---|
committer | John McCall <rjmccall@apple.com> | 2013-03-01 09:20:14 +0000 |
commit | 2fbe92cc2464c77825209df9a262d9d13e5ba64c (patch) | |
tree | 28570f428cfee5347b731d2319943141d3d7be0e | |
parent | b2381b1c91ac5dc2407e98f36e3a6ba93d771791 (diff) |
Perform the receiver-expression transformations regardless of
whether we already have a method. Fixes a bug where we were
failing to properly contextually convert a message receiver
during template instantiation.
As a side-effect, we now actually perform correct method lookup
after adjusting a message-send to integral or non-ObjC pointer
types (legal outside of ARC).
rdar://13305374
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@176339 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | lib/Sema/SemaExprObjC.cpp | 83 | ||||
-rw-r--r-- | test/CodeGenObjCXX/message.mm | 24 | ||||
-rw-r--r-- | test/SemaObjC/bad-receiver-1.m | 3 | ||||
-rw-r--r-- | test/SemaObjC/message.m | 2 | ||||
-rw-r--r-- | test/SemaObjC/super.m | 3 | ||||
-rw-r--r-- | test/SemaObjC/warn-isa-ref.m | 8 |
6 files changed, 72 insertions, 51 deletions
diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp index b26fa7661c..74a3292054 100644 --- a/lib/Sema/SemaExprObjC.cpp +++ b/lib/Sema/SemaExprObjC.cpp @@ -2119,8 +2119,46 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, return ExprError(); Receiver = Result.take(); ReceiverType = Receiver->getType(); + + // If the receiver is an ObjC pointer, a block pointer, or an + // __attribute__((NSObject)) pointer, we don't need to do any + // special conversion in order to look up a receiver. + if (ReceiverType->isObjCRetainableType()) { + // do nothing + } else if (!getLangOpts().ObjCAutoRefCount && + !Context.getObjCIdType().isNull() && + (ReceiverType->isPointerType() || + ReceiverType->isIntegerType())) { + // Implicitly convert integers and pointers to 'id' but emit a warning. + // But not in ARC. + Diag(Loc, diag::warn_bad_receiver_type) + << ReceiverType + << Receiver->getSourceRange(); + if (ReceiverType->isPointerType()) { + Receiver = ImpCastExprToType(Receiver, Context.getObjCIdType(), + CK_CPointerToObjCPointerCast).take(); + } else { + // TODO: specialized warning on null receivers? + bool IsNull = Receiver->isNullPointerConstant(Context, + Expr::NPC_ValueDependentIsNull); + CastKind Kind = IsNull ? CK_NullToPointer : CK_IntegralToPointer; + Receiver = ImpCastExprToType(Receiver, Context.getObjCIdType(), + Kind).take(); + } + ReceiverType = Receiver->getType(); + } else if (getLangOpts().CPlusPlus) { + ExprResult result = PerformContextuallyConvertToObjCPointer(Receiver); + if (result.isUsable()) { + Receiver = result.take(); + ReceiverType = Receiver->getType(); + } + } } + // There's a somewhat weird interaction here where we assume that we + // won't actually have a method unless we also don't need to do some + // of the more detailed type-checking on the receiver. + if (!Method) { // Handle messages to id. bool receiverIsId = ReceiverType->isObjCIdType(); @@ -2256,48 +2294,11 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, } if (Method && DiagnoseUseOfDecl(Method, Loc, forwardClass)) return ExprError(); - } else if (!getLangOpts().ObjCAutoRefCount && - !Context.getObjCIdType().isNull() && - (ReceiverType->isPointerType() || - ReceiverType->isIntegerType())) { - // Implicitly convert integers and pointers to 'id' but emit a warning. - // But not in ARC. - Diag(Loc, diag::warn_bad_receiver_type) - << ReceiverType - << Receiver->getSourceRange(); - if (ReceiverType->isPointerType()) - Receiver = ImpCastExprToType(Receiver, Context.getObjCIdType(), - CK_CPointerToObjCPointerCast).take(); - else { - // TODO: specialized warning on null receivers? - bool IsNull = Receiver->isNullPointerConstant(Context, - Expr::NPC_ValueDependentIsNull); - CastKind Kind = IsNull ? CK_NullToPointer : CK_IntegralToPointer; - Receiver = ImpCastExprToType(Receiver, Context.getObjCIdType(), - Kind).take(); - } - ReceiverType = Receiver->getType(); } else { - ExprResult ReceiverRes; - if (getLangOpts().CPlusPlus) - ReceiverRes = PerformContextuallyConvertToObjCPointer(Receiver); - if (ReceiverRes.isUsable()) { - Receiver = ReceiverRes.take(); - return BuildInstanceMessage(Receiver, - ReceiverType, - SuperLoc, - Sel, - Method, - LBracLoc, - SelectorLocs, - RBracLoc, - ArgsIn); - } else { - // Reject other random receiver types (e.g. structs). - Diag(Loc, diag::err_bad_receiver_type) - << ReceiverType << Receiver->getSourceRange(); - return ExprError(); - } + // Reject other random receiver types (e.g. structs). + Diag(Loc, diag::err_bad_receiver_type) + << ReceiverType << Receiver->getSourceRange(); + return ExprError(); } } } diff --git a/test/CodeGenObjCXX/message.mm b/test/CodeGenObjCXX/message.mm new file mode 100644 index 0000000000..1268a79d63 --- /dev/null +++ b/test/CodeGenObjCXX/message.mm @@ -0,0 +1,24 @@ +// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin10 -fobjc-runtime=macosx-10.7 -emit-llvm -o - %s | FileCheck %s + +// Properly instantiate a non-dependent message expression which +// requires a contextual conversion to ObjC pointer type. +// <rdar://13305374> +@interface Test0 +- (void) foo; +@end +namespace test0 { + struct A { + operator Test0*(); + }; + template <class T> void foo() { + A a; + [a foo]; + } + template void foo<int>(); + // CHECK: define weak_odr void @_ZN5test03fooIiEEvv() + // CHECK: [[T0:%.*]] = call [[TEST0:%.*]]* @_ZN5test01AcvP5Test0Ev( + // CHECK-NEXT: [[T1:%.*]] = load i8** + // CHECK-NEXT: [[T2:%.*]] = bitcast [[TEST0]]* [[T0]] to i8* + // CHECK-NEXT: call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*, i8*)*)(i8* [[T2]], i8* [[T1]]) + // CHECK-NEXT: ret void +} diff --git a/test/SemaObjC/bad-receiver-1.m b/test/SemaObjC/bad-receiver-1.m index fe3eecff2b..fe7f7f5b44 100644 --- a/test/SemaObjC/bad-receiver-1.m +++ b/test/SemaObjC/bad-receiver-1.m @@ -7,8 +7,7 @@ int objc_lookUpClass(const char*); void __raiseExc1() { - [objc_lookUpClass("NSString") retain]; // expected-warning {{receiver type 'int' is not 'id'}} \ - expected-warning {{method '-retain' not found}} + [objc_lookUpClass("NSString") retain]; // expected-warning {{receiver type 'int' is not 'id'}} } typedef const struct __CFString * CFStringRef; diff --git a/test/SemaObjC/message.m b/test/SemaObjC/message.m index 4015690bd0..f43bdf9885 100644 --- a/test/SemaObjC/message.m +++ b/test/SemaObjC/message.m @@ -95,7 +95,7 @@ int test5(int X) { void foo4() { struct objc_object X[10]; - [X rect]; // expected-warning {{receiver type 'struct objc_object *' is not 'id' or interface pointer, consider casting it to 'id'}} expected-warning {{method '-rect' not found (return type defaults to 'id')}} + [X rect]; // expected-warning {{receiver type 'struct objc_object *' is not 'id' or interface pointer, consider casting it to 'id'}} } // rdar://13207886 diff --git a/test/SemaObjC/super.m b/test/SemaObjC/super.m index cf48c196db..fd069af7b0 100644 --- a/test/SemaObjC/super.m +++ b/test/SemaObjC/super.m @@ -51,8 +51,7 @@ void f(id super) { [super m]; } void f0(int super) { - [super m]; // expected-warning{{receiver type 'int' is not 'id'}} \ - expected-warning {{method '-m' not found (return type defaults to 'id')}} + [super m]; // expected-warning{{receiver type 'int' is not 'id'}} } void f1(id puper) { // expected-note {{'puper' declared here}} [super m]; // expected-error{{use of undeclared identifier 'super'}} diff --git a/test/SemaObjC/warn-isa-ref.m b/test/SemaObjC/warn-isa-ref.m index c20474d5b0..39a5e45496 100644 --- a/test/SemaObjC/warn-isa-ref.m +++ b/test/SemaObjC/warn-isa-ref.m @@ -26,13 +26,11 @@ static void func() { // GCC allows this, with the following warning: // instance variable 'isa' is @protected; this will be a hard error in the future // - // FIXME: see if we can avoid the 2 warnings that follow the error. + // FIXME: see if we can avoid the warning that follows the error. [(*y).isa self]; // expected-error {{instance variable 'isa' is protected}} \ - expected-warning{{receiver type 'struct objc_class *' is not 'id' or interface pointer, consider casting it to 'id'}} \ - expected-warning{{method '-self' not found (return type defaults to 'id')}} + expected-warning{{receiver type 'struct objc_class *' is not 'id' or interface pointer, consider casting it to 'id'}} [y->isa self]; // expected-error {{instance variable 'isa' is protected}} \ - expected-warning{{receiver type 'struct objc_class *' is not 'id' or interface pointer, consider casting it to 'id'}} \ - expected-warning{{method '-self' not found (return type defaults to 'id')}} + expected-warning{{receiver type 'struct objc_class *' is not 'id' or interface pointer, consider casting it to 'id'}} } // rdar://11702488 |