forked from OSchip/llvm-project
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:
parent
323771b3f1
commit
80c93a0793
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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'}}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue