From: John McCall Date: Tue, 13 Sep 2011 06:00:03 +0000 (+0000) Subject: Handle reference properties correctly in the trivial-getter check. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=6c11f0b3106263600af2ea0438ebb372821514aa;p=clang Handle reference properties correctly in the trivial-getter check. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@139585 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp index f0a47af909..ca04a7b178 100644 --- a/lib/CodeGen/CGObjC.cpp +++ b/lib/CodeGen/CGObjC.cpp @@ -564,13 +564,19 @@ void CodeGenFunction::GenerateObjCGetter(ObjCImplementationDecl *IMP, FinishFunction(); } -static bool hasTrivialGetExpr(const ObjCPropertyImplDecl *PID) { - const Expr *getter = PID->getGetterCXXConstructor(); +static bool hasTrivialGetExpr(const ObjCPropertyImplDecl *propImpl) { + const Expr *getter = propImpl->getGetterCXXConstructor(); if (!getter) return true; // Sema only makes only of these when the ivar has a C++ class type, // so the form is pretty constrained. + // If the property has a reference type, we might just be binding a + // reference, in which case the result will be a gl-value. We should + // treat this as a non-trivial operation. + if (getter->isGLValue()) + return false; + // If we selected a trivial copy-constructor, we're okay. if (const CXXConstructExpr *construct = dyn_cast(getter)) return (construct->getConstructor()->isTrivial()); diff --git a/test/CodeGenObjCXX/property-reference.mm b/test/CodeGenObjCXX/property-reference.mm index 7c235cb9b4..0ba2c430d5 100644 --- a/test/CodeGenObjCXX/property-reference.mm +++ b/test/CodeGenObjCXX/property-reference.mm @@ -1,16 +1,14 @@ // RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s // rdar://9208606 -struct MyStruct -{ - int x; - int y; - int z; +struct MyStruct { + int x; + int y; + int z; }; -@interface MyClass -{ - MyStruct _foo; +@interface MyClass { + MyStruct _foo; } @property (assign, readwrite) const MyStruct& foo; @@ -19,16 +17,38 @@ struct MyStruct - (void) setFoo:(const MyStruct&)inFoo; @end -int main() -{ - MyClass* myClass; - MyStruct myStruct; +void test0() { + MyClass* myClass; + MyStruct myStruct; - myClass.foo = myStruct; + myClass.foo = myStruct; - const MyStruct& currentMyStruct = myClass.foo; - return 0; + const MyStruct& currentMyStruct = myClass.foo; } // CHECK: [[C:%.*]] = call %struct.MyStruct* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend // CHECK: store %struct.MyStruct* [[C]], %struct.MyStruct** [[D:%.*]] + +namespace test1 { + struct A { A(); A(const A&); A&operator=(const A&); ~A(); }; +} +@interface Test1 { + test1::A ivar; +} +@property const test1::A &prop1; +@end +@implementation Test1 +@synthesize prop1 = ivar; +@end +// CHECK: define internal [[A:%.*]]* @"\01-[Test1 prop1]"( +// CHECK: [[SELF:%.*]] = alloca [[TEST1:%.*]]*, align 8 +// CHECK: [[T0:%.*]] = load [[TEST1]]** [[SELF]] +// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8* +// CHECK-NEXT: [[T2:%.*]] = getelementptr inbounds i8* [[T1]], i64 0 +// CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[A]]* +// CHECK-NEXT: ret [[A]]* [[T3]] + +// CHECK: define internal void @"\01-[Test1 setProp1:]"( +// CHECK: call [[A]]* @_ZN5test11AaSERKS0_( +// CHECK-NEXT: ret void +