forked from OSchip/llvm-project
ARC: Fix the precise-lifetime suppression of returns_inner_pointer
receiver extension for message sends via property syntax. rdar://22172983 llvm-svn: 247209
This commit is contained in:
parent
15d5563cea
commit
6380a28248
|
@ -273,10 +273,23 @@ shouldExtendReceiverForInnerPointerMessage(const ObjCMessageExpr *message) {
|
|||
// receiver is loaded from a variable with precise lifetime.
|
||||
case ObjCMessageExpr::Instance: {
|
||||
const Expr *receiver = message->getInstanceReceiver();
|
||||
|
||||
// Look through OVEs.
|
||||
if (auto opaque = dyn_cast<OpaqueValueExpr>(receiver)) {
|
||||
if (opaque->getSourceExpr())
|
||||
receiver = opaque->getSourceExpr()->IgnoreParens();
|
||||
}
|
||||
|
||||
const ImplicitCastExpr *ice = dyn_cast<ImplicitCastExpr>(receiver);
|
||||
if (!ice || ice->getCastKind() != CK_LValueToRValue) return true;
|
||||
receiver = ice->getSubExpr()->IgnoreParens();
|
||||
|
||||
// Look through OVEs.
|
||||
if (auto opaque = dyn_cast<OpaqueValueExpr>(receiver)) {
|
||||
if (opaque->getSourceExpr())
|
||||
receiver = opaque->getSourceExpr()->IgnoreParens();
|
||||
}
|
||||
|
||||
// Only __strong variables.
|
||||
if (receiver->getType().getObjCLifetime() != Qualifiers::OCL_Strong)
|
||||
return true;
|
||||
|
|
|
@ -26,7 +26,8 @@ void test0() {
|
|||
// CHECK-NEXT: ret void
|
||||
}
|
||||
|
||||
// rdar://problem/9821110
|
||||
// rdar://problem/9821110 - precise lifetime should suppress extension
|
||||
// rdar://problem/22172983 - should work for calls via property syntax, too
|
||||
@interface Test1
|
||||
- (char*) interior __attribute__((objc_returns_inner_pointer));
|
||||
// Should we allow this on properties? Yes! see // rdar://14990439
|
||||
|
@ -34,8 +35,8 @@ void test0() {
|
|||
@end
|
||||
extern Test1 *test1_helper(void);
|
||||
|
||||
// CHECK-LABEL: define void @test1a()
|
||||
void test1a(void) {
|
||||
// CHECK-LABEL: define void @test1a_message()
|
||||
void test1a_message(void) {
|
||||
// CHECK: [[PTR:%.*]] = alloca [[PTR_T:%.*]]*, align 8
|
||||
// CHECK: [[C:%.*]] = alloca i8*, align 8
|
||||
// CHECK: [[PTRPTR1:%.*]] = bitcast [[PTR_T]]** [[PTR]] to i8*
|
||||
|
@ -67,8 +68,43 @@ void test1a(void) {
|
|||
char *c = [(ptr) interior];
|
||||
}
|
||||
|
||||
// CHECK-LABEL: define void @test1b()
|
||||
void test1b(void) {
|
||||
|
||||
// CHECK-LABEL: define void @test1a_property()
|
||||
void test1a_property(void) {
|
||||
// CHECK: [[PTR:%.*]] = alloca [[PTR_T:%.*]]*, align 8
|
||||
// CHECK: [[C:%.*]] = alloca i8*, align 8
|
||||
// CHECK: [[PTRPTR1:%.*]] = bitcast [[PTR_T]]** [[PTR]] to i8*
|
||||
// CHECK: call void @llvm.lifetime.start(i64 8, i8* [[PTRPTR1]])
|
||||
// CHECK: [[T0:%.*]] = call [[TEST1:%.*]]* @test1_helper()
|
||||
// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*
|
||||
// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T1]])
|
||||
// CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[TEST1]]*
|
||||
// CHECK-NEXT: store [[TEST1]]* [[T3]]
|
||||
// CHECK-NEXT: [[CPTR1:%.*]] = bitcast i8** [[C]] to i8*
|
||||
// CHECK-NEXT: call void @llvm.lifetime.start(i64 8, i8* [[CPTR1]])
|
||||
// CHECK-NEXT: [[T0:%.*]] = load [[TEST1]]*, [[TEST1]]**
|
||||
// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*
|
||||
// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutorelease(i8* [[T1]])
|
||||
// CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[TEST1]]*
|
||||
// CHECK-NEXT: [[T4:%.*]] = load i8*, i8** @OBJC_SELECTOR_REFERENCES_
|
||||
// CHECK-NEXT: [[T5:%.*]] = bitcast [[TEST1]]* [[T3]] to i8*
|
||||
// CHECK-NEXT: [[T6:%.*]] = call i8* bitcast
|
||||
// CHECK-NEXT: store i8* [[T6]], i8**
|
||||
// CHECK-NEXT: [[CPTR2:%.*]] = bitcast i8** [[C]] to i8*
|
||||
// CHECK-NEXT: call void @llvm.lifetime.end(i64 8, i8* [[CPTR2]])
|
||||
// CHECK-NEXT: [[T0:%.*]] = load [[TEST1]]*, [[TEST1]]**
|
||||
// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*
|
||||
// CHECK-NEXT: call void @objc_release(i8* [[T1]]) [[NUW]], !clang.imprecise_release
|
||||
// CHECK-NEXT: [[PTRPTR2:%.*]] = bitcast [[PTR_T]]** [[PTR]] to i8*
|
||||
// CHECK-NEXT: call void @llvm.lifetime.end(i64 8, i8* [[PTRPTR2]])
|
||||
// CHECK-NEXT: ret void
|
||||
Test1 *ptr = test1_helper();
|
||||
char *c = ptr.interior;
|
||||
}
|
||||
|
||||
|
||||
// CHECK-LABEL: define void @test1b_message()
|
||||
void test1b_message(void) {
|
||||
// CHECK: [[PTR:%.*]] = alloca [[PTR_T:%.*]]*, align 8
|
||||
// CHECK: [[C:%.*]] = alloca i8*, align 8
|
||||
// CHECK: [[PTRPTR1:%.*]] = bitcast [[PTR_T]]** [[PTR]] to i8*
|
||||
|
@ -94,11 +130,76 @@ void test1b(void) {
|
|||
// CHECK-NEXT: [[PTRPTR2:%.*]] = bitcast [[PTR_T]]** [[PTR]] to i8*
|
||||
// CHECK-NEXT: call void @llvm.lifetime.end(i64 8, i8* [[PTRPTR2]])
|
||||
// CHECK-NEXT: ret void
|
||||
__attribute__((objc_precise_lifetime)) Test1 *ptr = test1_helper();
|
||||
PRECISE_LIFETIME Test1 *ptr = test1_helper();
|
||||
char *c = [ptr interior];
|
||||
}
|
||||
|
||||
void test1c(void) {
|
||||
// CHECK-LABEL: define void @test1b_property()
|
||||
void test1b_property(void) {
|
||||
// CHECK: [[PTR:%.*]] = alloca [[PTR_T:%.*]]*, align 8
|
||||
// CHECK: [[C:%.*]] = alloca i8*, align 8
|
||||
// CHECK: [[PTRPTR1:%.*]] = bitcast [[PTR_T]]** [[PTR]] to i8*
|
||||
// CHECK: call void @llvm.lifetime.start(i64 8, i8* [[PTRPTR1]])
|
||||
// CHECK: [[T0:%.*]] = call [[TEST1:%.*]]* @test1_helper()
|
||||
// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*
|
||||
// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T1]])
|
||||
// CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[TEST1]]*
|
||||
// CHECK-NEXT: store [[TEST1]]* [[T3]]
|
||||
// CHECK-NEXT: [[CPTR1:%.*]] = bitcast i8** [[C]] to i8*
|
||||
// CHECK-NEXT: call void @llvm.lifetime.start(i64 8, i8* [[CPTR1]])
|
||||
// CHECK-NEXT: [[T0:%.*]] = load [[TEST1]]*, [[TEST1]]**
|
||||
// CHECK-NEXT: [[T1:%.*]] = load i8*, i8** @OBJC_SELECTOR_REFERENCES_
|
||||
// CHECK-NEXT: [[T2:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*
|
||||
// CHECK-NEXT: [[T3:%.*]] = call i8* bitcast
|
||||
// CHECK-NEXT: store i8* [[T3]], i8**
|
||||
// CHECK-NEXT: [[CPTR2:%.*]] = bitcast i8** [[C]] to i8*
|
||||
// CHECK-NEXT: call void @llvm.lifetime.end(i64 8, i8* [[CPTR2]])
|
||||
// CHECK-NEXT: [[T0:%.*]] = load [[TEST1]]*, [[TEST1]]**
|
||||
// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*
|
||||
// CHECK-NEXT: call void @objc_release(i8* [[T1]]) [[NUW]]
|
||||
// CHECK-NOT: clang.imprecise_release
|
||||
// CHECK-NEXT: [[PTRPTR2:%.*]] = bitcast [[PTR_T]]** [[PTR]] to i8*
|
||||
// CHECK-NEXT: call void @llvm.lifetime.end(i64 8, i8* [[PTRPTR2]])
|
||||
// CHECK-NEXT: ret void
|
||||
PRECISE_LIFETIME Test1 *ptr = test1_helper();
|
||||
char *c = ptr.interior;
|
||||
}
|
||||
|
||||
// CHECK-LABEL: define void @test1c_message()
|
||||
void test1c_message(void) {
|
||||
// CHECK: [[PTR:%.*]] = alloca [[PTR_T:%.*]]*, align 8
|
||||
// CHECK: [[PC:%.*]] = alloca i8*, align 8
|
||||
// CHECK: [[PTRPTR1:%.*]] = bitcast [[PTR_T]]** [[PTR]] to i8*
|
||||
// CHECK: call void @llvm.lifetime.start(i64 8, i8* [[PTRPTR1]])
|
||||
// CHECK: [[T0:%.*]] = call [[TEST1:%.*]]* @test1_helper()
|
||||
// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*
|
||||
// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T1]])
|
||||
// CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[TEST1]]*
|
||||
// CHECK-NEXT: store [[TEST1]]* [[T3]]
|
||||
// CHECK-NEXT: [[PCPTR1:%.*]] = bitcast i8** [[PC]] to i8*
|
||||
// CHECK-NEXT: call void @llvm.lifetime.start(i64 8, i8* [[PCPTR1]])
|
||||
// CHECK-NEXT: [[T0:%.*]] = load [[TEST1]]*, [[TEST1]]**
|
||||
// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*
|
||||
// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutorelease(i8* [[T1]])
|
||||
// CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[TEST1]]*
|
||||
// CHECK-NEXT: [[T4:%.*]] = load i8*, i8** @OBJC_SELECTOR_REFERENCES_
|
||||
// CHECK-NEXT: [[T5:%.*]] = bitcast [[TEST1]]* [[T3]] to i8*
|
||||
// CHECK-NEXT: [[T6:%.*]] = call i8* bitcast
|
||||
// CHECK-NEXT: store i8* [[T6]], i8**
|
||||
// CHECK-NEXT: [[PCPTR2:%.*]] = bitcast i8** [[PC]] to i8*
|
||||
// CHECK-NEXT: call void @llvm.lifetime.end(i64 8, i8* [[PCPTR2]])
|
||||
// CHECK-NEXT: [[T0:%.*]] = load [[TEST1]]*, [[TEST1]]**
|
||||
// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*
|
||||
// CHECK-NEXT: call void @objc_release(i8* [[T1]]) [[NUW]], !clang.imprecise_release
|
||||
// CHECK-NEXT: [[PTRPTR2:%.*]] = bitcast [[PTR_T]]** [[PTR]] to i8*
|
||||
// CHECK-NEXT: call void @llvm.lifetime.end(i64 8, i8* [[PTRPTR2]])
|
||||
// CHECK-NEXT: ret void
|
||||
Test1 *ptr = test1_helper();
|
||||
char *pc = [ptr PropertyReturnsInnerPointer];
|
||||
}
|
||||
|
||||
// CHECK-LABEL: define void @test1c_property()
|
||||
void test1c_property(void) {
|
||||
// CHECK: [[PTR:%.*]] = alloca [[PTR_T:%.*]]*, align 8
|
||||
// CHECK: [[PC:%.*]] = alloca i8*, align 8
|
||||
// CHECK: [[PTRPTR1:%.*]] = bitcast [[PTR_T]]** [[PTR]] to i8*
|
||||
|
@ -130,7 +231,8 @@ void test1c(void) {
|
|||
char *pc = ptr.PropertyReturnsInnerPointer;
|
||||
}
|
||||
|
||||
void test1d(void) {
|
||||
// CHECK-LABEL: define void @test1d_message()
|
||||
void test1d_message(void) {
|
||||
// CHECK: [[PTR:%.*]] = alloca [[PTR_T:%.*]]*, align 8
|
||||
// CHECK: [[PC:%.*]] = alloca i8*, align 8
|
||||
// CHECK: [[PTRPTR1:%.*]] = bitcast [[PTR_T]]** [[PTR]] to i8*
|
||||
|
@ -143,11 +245,8 @@ void test1d(void) {
|
|||
// CHECK-NEXT: [[PCPTR1:%.*]] = bitcast i8** [[PC]] to i8*
|
||||
// CHECK-NEXT: call void @llvm.lifetime.start(i64 8, i8* [[PCPTR1]])
|
||||
// CHECK-NEXT: [[T0:%.*]] = load [[TEST1]]*, [[TEST1]]**
|
||||
// CHECK-NEXT: [[T2:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*
|
||||
// CHECK-NEXT: [[T3:%.*]] = call i8* @objc_retainAutorelease
|
||||
// CHECK-NEXT: [[SIX:%.*]] = bitcast i8* [[T3]] to [[TEST1]]*
|
||||
// CHECK-NEXT: [[SEVEN:%.*]] = load i8*, i8** @OBJC_SELECTOR_REFERENCES_
|
||||
// CHECK-NEXT: [[EIGHT:%.*]] = bitcast [[TEST1]]* [[SIX]] to i8*
|
||||
// CHECK-NEXT: [[EIGHT:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*
|
||||
// CHECK-NEXT: [[CALL1:%.*]] = call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i8* (i8*, i8*)*)(i8* [[EIGHT]], i8* [[SEVEN]])
|
||||
// CHECK-NEXT: store i8* [[CALL1]], i8**
|
||||
// CHECK-NEXT: [[PCPTR2:%.*]] = bitcast i8** [[PC]] to i8*
|
||||
|
@ -158,7 +257,37 @@ void test1d(void) {
|
|||
// CHECK-NEXT: [[PTRPTR2:%.*]] = bitcast [[PTR_T]]** [[PTR]] to i8*
|
||||
// CHECK-NEXT: call void @llvm.lifetime.end(i64 8, i8* [[PTRPTR2]])
|
||||
// CHECK-NEXT: ret void
|
||||
__attribute__((objc_precise_lifetime)) Test1 *ptr = test1_helper();
|
||||
PRECISE_LIFETIME Test1 *ptr = test1_helper();
|
||||
char *pc = [ptr PropertyReturnsInnerPointer];
|
||||
}
|
||||
|
||||
// CHECK-LABEL: define void @test1d_property()
|
||||
void test1d_property(void) {
|
||||
// CHECK: [[PTR:%.*]] = alloca [[PTR_T:%.*]]*, align 8
|
||||
// CHECK: [[PC:%.*]] = alloca i8*, align 8
|
||||
// CHECK: [[PTRPTR1:%.*]] = bitcast [[PTR_T]]** [[PTR]] to i8*
|
||||
// CHECK: call void @llvm.lifetime.start(i64 8, i8* [[PTRPTR1]])
|
||||
// CHECK: [[T0:%.*]] = call [[TEST1:%.*]]* @test1_helper()
|
||||
// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*
|
||||
// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T1]])
|
||||
// CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[TEST1]]*
|
||||
// CHECK-NEXT: store [[TEST1]]* [[T3]]
|
||||
// CHECK-NEXT: [[PCPTR1:%.*]] = bitcast i8** [[PC]] to i8*
|
||||
// CHECK-NEXT: call void @llvm.lifetime.start(i64 8, i8* [[PCPTR1]])
|
||||
// CHECK-NEXT: [[T0:%.*]] = load [[TEST1]]*, [[TEST1]]**
|
||||
// CHECK-NEXT: [[SEVEN:%.*]] = load i8*, i8** @OBJC_SELECTOR_REFERENCES_
|
||||
// CHECK-NEXT: [[EIGHT:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*
|
||||
// CHECK-NEXT: [[CALL1:%.*]] = call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i8* (i8*, i8*)*)(i8* [[EIGHT]], i8* [[SEVEN]])
|
||||
// CHECK-NEXT: store i8* [[CALL1]], i8**
|
||||
// CHECK-NEXT: [[PCPTR2:%.*]] = bitcast i8** [[PC]] to i8*
|
||||
// CHECK-NEXT: call void @llvm.lifetime.end(i64 8, i8* [[PCPTR2]])
|
||||
// CHECK-NEXT: [[NINE:%.*]] = load [[TEST1]]*, [[TEST1]]**
|
||||
// CHECK-NEXT: [[TEN:%.*]] = bitcast [[TEST1]]* [[NINE]] to i8*
|
||||
// CHECK-NEXT: call void @objc_release(i8* [[TEN]])
|
||||
// CHECK-NEXT: [[PTRPTR2:%.*]] = bitcast [[PTR_T]]** [[PTR]] to i8*
|
||||
// CHECK-NEXT: call void @llvm.lifetime.end(i64 8, i8* [[PTRPTR2]])
|
||||
// CHECK-NEXT: ret void
|
||||
PRECISE_LIFETIME Test1 *ptr = test1_helper();
|
||||
char *pc = ptr.PropertyReturnsInnerPointer;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue