diff options
Diffstat (limited to 'clang')
| -rw-r--r-- | clang/lib/CodeGen/CGCall.cpp | 24 | ||||
| -rw-r--r-- | clang/test/CodeGenObjCXX/arc-attrs.mm | 21 |
2 files changed, 42 insertions, 3 deletions
diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp index 2fc16049f6b..54468d939d3 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -2912,12 +2912,30 @@ void CodeGenFunction::EmitDelegateCallArg(CallArgList &args, assert(!isInAllocaArgument(CGM.getCXXABI(), type) && "cannot emit delegate call arguments for inalloca arguments!"); + // GetAddrOfLocalVar returns a pointer-to-pointer for references, + // but the argument needs to be the original pointer. + if (type->isReferenceType()) { + args.add(RValue::get(Builder.CreateLoad(local)), type); + + // In ARC, move out of consumed arguments so that the release cleanup + // entered by StartFunction doesn't cause an over-release. This isn't + // optimal -O0 code generation, but it should get cleaned up when + // optimization is enabled. This also assumes that delegate calls are + // performed exactly once for a set of arguments, but that should be safe. + } else if (getLangOpts().ObjCAutoRefCount && + param->hasAttr<NSConsumedAttr>() && + type->isObjCRetainableType()) { + llvm::Value *ptr = Builder.CreateLoad(local); + auto null = + llvm::ConstantPointerNull::get(cast<llvm::PointerType>(ptr->getType())); + Builder.CreateStore(null, local); + args.add(RValue::get(ptr), type); + // For the most part, we just need to load the alloca, except that // aggregate r-values are actually pointers to temporaries. - if (type->isReferenceType()) - args.add(RValue::get(Builder.CreateLoad(local)), type); - else + } else { args.add(convertTempToRValue(local, type, loc), type); + } } static bool isProvablyNull(llvm::Value *addr) { diff --git a/clang/test/CodeGenObjCXX/arc-attrs.mm b/clang/test/CodeGenObjCXX/arc-attrs.mm index 0f0610f1721..0b64d775660 100644 --- a/clang/test/CodeGenObjCXX/arc-attrs.mm +++ b/clang/test/CodeGenObjCXX/arc-attrs.mm @@ -46,3 +46,24 @@ void templateTest() { // CHECK-NEXT: call void @objc_storeStrong(i8** [[X]], i8* null) // CHECK-NEXT: ret void } + +// PR27887 +struct ForwardConsumed { + ForwardConsumed(__attribute__((ns_consumed)) id x); +}; + +ForwardConsumed::ForwardConsumed(__attribute__((ns_consumed)) id x) {} + +// CHECK: define void @_ZN15ForwardConsumedC2EP11objc_object( +// CHECK-NOT: objc_retain +// CHECK: store i8* {{.*}}, i8** [[X:%.*]], +// CHECK-NOT: [[X]] +// CHECK: call void @objc_storeStrong(i8** [[X]], i8* null) + +// CHECK: define void @_ZN15ForwardConsumedC1EP11objc_object( +// CHECK-NOT: objc_retain +// CHECK: store i8* {{.*}}, i8** [[X:%.*]], +// CHECK: [[T0:%.*]] = load i8*, i8** [[X]], +// CHECK-NEXT: store i8* null, i8** [[X]], +// CHECK-NEXT: call void @_ZN15ForwardConsumedC2EP11objc_object({{.*}}, i8* [[T0]]) +// CHECK: call void @objc_storeStrong(i8** [[X]], i8* null) |

