From: Fariborz Jahanian Date: Wed, 30 Mar 2011 16:11:20 +0000 (+0000) Subject: Fix IRGen issues related to using property-dot syntax X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=68af13f3ca39947e3f285f864fe3b76640fddf69;p=clang Fix IRGen issues related to using property-dot syntax for prperty reference types. // rdar://9208606. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@128551 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/ExprObjC.h b/include/clang/AST/ExprObjC.h index 0068ee499a..3ee6d1f229 100644 --- a/include/clang/AST/ExprObjC.h +++ b/include/clang/AST/ExprObjC.h @@ -337,6 +337,39 @@ public: QualType getSuperReceiverType() const { return QualType(Receiver.get(), 0); } + QualType getGetterResultType() const { + QualType ResultType; + if (isExplicitProperty()) { + const ObjCPropertyDecl *PDecl = getExplicitProperty(); + if (const ObjCMethodDecl *Getter = PDecl->getGetterMethodDecl()) + ResultType = Getter->getResultType(); + else + ResultType = getType(); + } else { + const ObjCMethodDecl *Getter = getImplicitPropertyGetter(); + ResultType = Getter->getResultType(); // with reference! + } + return ResultType; + } + + QualType getSetterArgType() const { + QualType ArgType; + if (isImplicitProperty()) { + const ObjCMethodDecl *Setter = getImplicitPropertySetter(); + ObjCMethodDecl::param_iterator P = Setter->param_begin(); + ArgType = (*P)->getType(); + } else { + if (ObjCPropertyDecl *PDecl = getExplicitProperty()) + if (const ObjCMethodDecl *Setter = PDecl->getSetterMethodDecl()) { + ObjCMethodDecl::param_iterator P = Setter->param_begin(); + ArgType = (*P)->getType(); + } + if (ArgType.isNull()) + ArgType = getType(); + } + return ArgType; + } + ObjCInterfaceDecl *getClassReceiver() const { return Receiver.get(); } diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp index 6a7be0fe6e..ab88a38bab 100644 --- a/lib/CodeGen/CGExpr.cpp +++ b/lib/CodeGen/CGExpr.cpp @@ -216,10 +216,19 @@ EmitExprForReferenceBinding(CodeGenFunction &CGF, const Expr *E, InitializedDecl); } + if (const ObjCPropertyRefExpr *PRE = + dyn_cast(E->IgnoreParenImpCasts())) + if (PRE->getGetterResultType()->isReferenceType()) + E = PRE; + RValue RV; if (E->isGLValue()) { // Emit the expression as an lvalue. LValue LV = CGF.EmitLValue(E); + if (LV.isPropertyRef()) { + RV = CGF.EmitLoadOfPropertyRefLValue(LV); + return RV.getScalarVal(); + } if (LV.isSimple()) return LV.getAddress(); diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp index f992dc7c9c..eb64996bd3 100644 --- a/lib/CodeGen/CGExprAgg.cpp +++ b/lib/CodeGen/CGExprAgg.cpp @@ -403,9 +403,17 @@ void AggExprEmitter::VisitBinAssign(const BinaryOperator *E) { // We have to special case property setters, otherwise we must have // a simple lvalue (no aggregates inside vectors, bitfields). if (LHS.isPropertyRef()) { - AggValueSlot Slot = EnsureSlot(E->getRHS()->getType()); - CGF.EmitAggExpr(E->getRHS(), Slot); - CGF.EmitStoreThroughPropertyRefLValue(Slot.asRValue(), LHS); + const ObjCPropertyRefExpr *RE = LHS.getPropertyRefExpr(); + QualType ArgType = RE->getSetterArgType(); + RValue Src; + if (ArgType->isReferenceType()) + Src = CGF.EmitReferenceBindingToExpr(E->getRHS(), 0); + else { + AggValueSlot Slot = EnsureSlot(E->getRHS()->getType()); + CGF.EmitAggExpr(E->getRHS(), Slot); + Src = Slot.asRValue(); + } + CGF.EmitStoreThroughPropertyRefLValue(Src, LHS); } else { bool GCollection = false; if (CGF.getContext().getLangOptions().getGCMode()) diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp index 99b8b57eb9..ac4e763f89 100644 --- a/lib/CodeGen/CGObjC.cpp +++ b/lib/CodeGen/CGObjC.cpp @@ -651,16 +651,14 @@ static RValue GenerateMessageSendSuper(CodeGenFunction &CGF, RValue CodeGenFunction::EmitLoadOfPropertyRefLValue(LValue LV, ReturnValueSlot Return) { const ObjCPropertyRefExpr *E = LV.getPropertyRefExpr(); - QualType ResultType; + QualType ResultType = E->getGetterResultType(); Selector S; if (E->isExplicitProperty()) { const ObjCPropertyDecl *Property = E->getExplicitProperty(); S = Property->getGetterName(); - ResultType = E->getType(); } else { const ObjCMethodDecl *Getter = E->getImplicitPropertyGetter(); S = Getter->getSelector(); - ResultType = Getter->getResultType(); // with reference! } llvm::Value *Receiver = LV.getPropertyRefBaseAddr(); @@ -681,14 +679,8 @@ void CodeGenFunction::EmitStoreThroughPropertyRefLValue(RValue Src, LValue Dst) { const ObjCPropertyRefExpr *E = Dst.getPropertyRefExpr(); Selector S = E->getSetterSelector(); - QualType ArgType; - if (E->isImplicitProperty()) { - const ObjCMethodDecl *Setter = E->getImplicitPropertySetter(); - ObjCMethodDecl::param_iterator P = Setter->param_begin(); - ArgType = (*P)->getType(); - } else { - ArgType = E->getType(); - } + QualType ArgType = E->getSetterArgType(); + // FIXME. Other than scalars, AST is not adequate for setter and // getter type mismatches which require conversion. if (Src.isScalar()) { diff --git a/test/CodeGenObjCXX/property-reference.mm b/test/CodeGenObjCXX/property-reference.mm new file mode 100644 index 0000000000..7c235cb9b4 --- /dev/null +++ b/test/CodeGenObjCXX/property-reference.mm @@ -0,0 +1,34 @@ +// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s +// rdar://9208606 + +struct MyStruct +{ + int x; + int y; + int z; +}; + +@interface MyClass +{ + MyStruct _foo; +} + +@property (assign, readwrite) const MyStruct& foo; + +- (const MyStruct&) foo; +- (void) setFoo:(const MyStruct&)inFoo; +@end + +int main() +{ + MyClass* myClass; + MyStruct myStruct; + + myClass.foo = myStruct; + + const MyStruct& currentMyStruct = myClass.foo; + return 0; +} + +// CHECK: [[C:%.*]] = call %struct.MyStruct* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend +// CHECK: store %struct.MyStruct* [[C]], %struct.MyStruct** [[D:%.*]]