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

llvm-svn: 176339
This commit is contained in:
John McCall 2013-03-01 09:20:14 +00:00
parent 323771b3f1
commit 80c93a0793
6 changed files with 72 additions and 51 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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