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:
John McCall 2015-09-09 23:37:17 +00:00
parent 15d5563cea
commit 6380a28248
2 changed files with 155 additions and 13 deletions

View File

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

View File

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