From: Fariborz Jahanian Date: Mon, 28 Mar 2011 23:47:18 +0000 (+0000) Subject: Implements property of reference types. Adding X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=14086764e340267e17803d0f8243070ffae2c76e;p=clang Implements property of reference types. Adding an executable test to llvm test suite. // rdar://9070460. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@128435 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp index 0118537fbf..dcdd81d1f8 100644 --- a/lib/CodeGen/CGObjC.cpp +++ b/lib/CodeGen/CGObjC.cpp @@ -294,11 +294,17 @@ void CodeGenFunction::GenerateObjCGetter(ObjCImplementationDecl *IMP, else { LValue LV = EmitLValueForIvar(TypeOfSelfObject(), LoadObjCSelf(), Ivar, 0); - CodeGenTypes &Types = CGM.getTypes(); - RValue RV = EmitLoadOfLValue(LV, IVART); - RV = RValue::get(Builder.CreateBitCast(RV.getScalarVal(), + if (PD->getType()->isReferenceType()) { + RValue RV = RValue::get(LV.getAddress()); + EmitReturnOfRValue(RV, PD->getType()); + } + else { + CodeGenTypes &Types = CGM.getTypes(); + RValue RV = EmitLoadOfLValue(LV, IVART); + RV = RValue::get(Builder.CreateBitCast(RV.getScalarVal(), Types.ConvertType(PD->getType()))); - EmitReturnOfRValue(RV, PD->getType()); + EmitReturnOfRValue(RV, PD->getType()); + } } } @@ -436,7 +442,10 @@ void CodeGenFunction::GenerateObjCSetter(ObjCImplementationDecl *IMP, ObjCIvarDecl *Ivar = PID->getPropertyIvarDecl(); DeclRefExpr Base(Self, Self->getType(), VK_RValue, Loc); ParmVarDecl *ArgDecl = *OMD->param_begin(); - DeclRefExpr Arg(ArgDecl, ArgDecl->getType(), VK_LValue, Loc); + QualType T = ArgDecl->getType(); + if (T->isReferenceType()) + T = cast(T)->getPointeeType(); + DeclRefExpr Arg(ArgDecl, T, VK_LValue, Loc); ObjCIvarRefExpr IvarRef(Ivar, Ivar->getType(), Loc, &Base, true, true); // The property type can differ from the ivar type in some situations with diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 945d35e8ce..8b7324e966 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -7413,6 +7413,21 @@ static bool IsReadonlyProperty(Expr *E, Sema &S) { return false; } +static bool IsConstProperty(Expr *E, Sema &S) { + if (E->getStmtClass() == Expr::ObjCPropertyRefExprClass) { + const ObjCPropertyRefExpr* PropExpr = cast(E); + if (PropExpr->isImplicitProperty()) return false; + + ObjCPropertyDecl *PDecl = PropExpr->getExplicitProperty(); + QualType T = PDecl->getType(); + if (T->isReferenceType()) + T = cast(T)->getPointeeType(); + CanQualType CT = S.Context.getCanonicalType(T); + return CT.isConstQualified(); + } + return false; +} + static bool IsReadonlyMessage(Expr *E, Sema &S) { if (E->getStmtClass() != Expr::MemberExprClass) return false; @@ -7435,6 +7450,8 @@ static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) { &Loc); if (IsLV == Expr::MLV_Valid && IsReadonlyProperty(E, S)) IsLV = Expr::MLV_ReadonlyProperty; + else if (Expr::MLV_ConstQualified && IsConstProperty(E, S)) + IsLV = Expr::MLV_Valid; else if (IsLV == Expr::MLV_ClassTemporary && IsReadonlyMessage(E, S)) IsLV = Expr::MLV_InvalidMessageExpression; if (IsLV == Expr::MLV_Valid) diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp index cf38225de0..19215c6cfd 100644 --- a/lib/Sema/SemaExprObjC.cpp +++ b/lib/Sema/SemaExprObjC.cpp @@ -428,6 +428,7 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT, if (DiagnoseUseOfDecl(PD, MemberLoc)) return ExprError(); QualType ResTy = PD->getType(); + ResTy = ResTy.getNonLValueExprType(Context); Selector Sel = PP.getSelectorTable().getNullarySelector(Member); ObjCMethodDecl *Getter = IFace->lookupInstanceMethod(Sel); if (DiagnosePropertyAccessorMismatch(PD, Getter, MemberLoc)) diff --git a/lib/Sema/SemaObjCProperty.cpp b/lib/Sema/SemaObjCProperty.cpp index f607d65895..43e30275e2 100644 --- a/lib/Sema/SemaObjCProperty.cpp +++ b/lib/Sema/SemaObjCProperty.cpp @@ -45,11 +45,7 @@ Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc, !(Attributes & ObjCDeclSpec::DQ_PR_copy))); TypeSourceInfo *TSI = GetTypeForDeclarator(FD.D, S); - QualType T = TSI->getType(); - if (T->isReferenceType()) { - Diag(AtLoc, diag::error_reference_property); - return 0; - } + // Proceed with constructing the ObjCPropertDecls. ObjCContainerDecl *ClassDecl = cast(ClassCategory); @@ -404,13 +400,16 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, if (!PropertyIvar) PropertyIvar = PropertyId; QualType PropType = Context.getCanonicalType(property->getType()); + QualType PropertyIvarType = PropType; + if (PropType->isReferenceType()) + PropertyIvarType = cast(PropType)->getPointeeType(); // Check that this is a previously declared 'ivar' in 'IDecl' interface ObjCInterfaceDecl *ClassDeclared; Ivar = IDecl->lookupInstanceVariable(PropertyIvar, ClassDeclared); if (!Ivar) { Ivar = ObjCIvarDecl::Create(Context, ClassImpDecl, PropertyLoc, PropertyLoc, PropertyIvar, - PropType, /*Dinfo=*/0, + PropertyIvarType, /*Dinfo=*/0, ObjCIvarDecl::Private, (Expr *)0, true); ClassImpDecl->addDecl(Ivar); @@ -433,19 +432,19 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, QualType IvarType = Context.getCanonicalType(Ivar->getType()); // Check that type of property and its ivar are type compatible. - if (PropType != IvarType) { + if (PropertyIvarType != IvarType) { bool compat = false; - if (isa(PropType) + if (isa(PropertyIvarType) && isa(IvarType)) compat = Context.canAssignObjCInterfaces( - PropType->getAs(), + PropertyIvarType->getAs(), IvarType->getAs()); else { SourceLocation Loc = PropertyIvarLoc; if (Loc.isInvalid()) Loc = PropertyLoc; - compat = (CheckAssignmentConstraints(Loc, PropType, IvarType) + compat = (CheckAssignmentConstraints(Loc, PropertyIvarType, IvarType) == Compatible); } if (!compat) { @@ -460,7 +459,7 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, // FIXME! Rules for properties are somewhat different that those // for assignments. Use a new routine to consolidate all cases; // specifically for property redeclarations as well as for ivars. - QualType lhsType =Context.getCanonicalType(PropType).getUnqualifiedType(); + QualType lhsType =Context.getCanonicalType(PropertyIvarType).getUnqualifiedType(); QualType rhsType =Context.getCanonicalType(IvarType).getUnqualifiedType(); if (lhsType != rhsType && lhsType->isArithmeticType()) { @@ -539,7 +538,10 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, SelfExpr, true, true); ObjCMethodDecl::param_iterator P = setterMethod->param_begin(); ParmVarDecl *Param = (*P); - Expr *rhs = new (Context) DeclRefExpr(Param, Param->getType(), + QualType T = Param->getType(); + if (T->isReferenceType()) + T = cast(T)->getPointeeType(); + Expr *rhs = new (Context) DeclRefExpr(Param, T, VK_LValue, SourceLocation()); ExprResult Res = BuildBinOp(S, lhs->getLocEnd(), BO_Assign, lhs, rhs); diff --git a/test/SemaObjCXX/references.mm b/test/SemaObjCXX/references.mm index 15033f6bde..585c75f3cd 100644 --- a/test/SemaObjCXX/references.mm +++ b/test/SemaObjCXX/references.mm @@ -9,7 +9,7 @@ typedef struct { @interface A @property (assign) T p0; -@property (assign) T& p1; // expected-error {{property of reference type is not supported}} +@property (assign) T& p1; @end int f0(const T& t) { @@ -21,7 +21,7 @@ int f1(A *a) { } int f2(A *a) { - return f0(a.p1); // expected-error {{property 'p1' not found on object of type 'A *'}} + return f0(a.p1); } // PR7740