diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Sema/SemaObjCProperty.cpp')
-rw-r--r-- | contrib/llvm/tools/clang/lib/Sema/SemaObjCProperty.cpp | 382 |
1 files changed, 270 insertions, 112 deletions
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaObjCProperty.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaObjCProperty.cpp index 751f553..5ece8f1 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaObjCProperty.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaObjCProperty.cpp @@ -17,7 +17,9 @@ #include "clang/AST/DeclObjC.h" #include "clang/AST/ExprObjC.h" #include "clang/AST/ExprCXX.h" +#include "clang/AST/ASTMutationListener.h" #include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/SmallString.h" using namespace clang; @@ -99,6 +101,7 @@ static void checkARCPropertyDecl(Sema &S, ObjCPropertyDecl *property) { } Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc, + SourceLocation LParenLoc, FieldDeclarator &FD, ObjCDeclSpec &ODS, Selector GetterSel, @@ -109,9 +112,9 @@ Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc, unsigned Attributes = ODS.getPropertyAttributes(); TypeSourceInfo *TSI = GetTypeForDeclarator(FD.D, S); QualType T = TSI->getType(); - if ((getLangOptions().getGC() != LangOptions::NonGC && + if ((getLangOpts().getGC() != LangOptions::NonGC && T.isObjCGCWeak()) || - (getLangOptions().ObjCAutoRefCount && + (getLangOpts().ObjCAutoRefCount && T.getObjCLifetime() == Qualifiers::OCL_Weak)) Attributes |= ObjCDeclSpec::DQ_PR_weak; @@ -133,43 +136,80 @@ Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc, if (ObjCCategoryDecl *CDecl = dyn_cast<ObjCCategoryDecl>(ClassDecl)) if (CDecl->IsClassExtension()) { - Decl *Res = HandlePropertyInClassExtension(S, AtLoc, + Decl *Res = HandlePropertyInClassExtension(S, AtLoc, LParenLoc, FD, GetterSel, SetterSel, isAssign, isReadWrite, Attributes, + ODS.getPropertyAttributes(), isOverridingProperty, TSI, MethodImplKind); if (Res) { CheckObjCPropertyAttributes(Res, AtLoc, Attributes); - if (getLangOptions().ObjCAutoRefCount) + if (getLangOpts().ObjCAutoRefCount) checkARCPropertyDecl(*this, cast<ObjCPropertyDecl>(Res)); } return Res; } - ObjCPropertyDecl *Res = CreatePropertyDecl(S, ClassDecl, AtLoc, FD, + ObjCPropertyDecl *Res = CreatePropertyDecl(S, ClassDecl, AtLoc, LParenLoc, FD, GetterSel, SetterSel, isAssign, isReadWrite, - Attributes, TSI, MethodImplKind); + Attributes, + ODS.getPropertyAttributes(), + TSI, MethodImplKind); if (lexicalDC) Res->setLexicalDeclContext(lexicalDC); // Validate the attributes on the @property. CheckObjCPropertyAttributes(Res, AtLoc, Attributes); - if (getLangOptions().ObjCAutoRefCount) + if (getLangOpts().ObjCAutoRefCount) checkARCPropertyDecl(*this, Res); return Res; } +static ObjCPropertyDecl::PropertyAttributeKind +makePropertyAttributesAsWritten(unsigned Attributes) { + unsigned attributesAsWritten = 0; + if (Attributes & ObjCDeclSpec::DQ_PR_readonly) + attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_readonly; + if (Attributes & ObjCDeclSpec::DQ_PR_readwrite) + attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_readwrite; + if (Attributes & ObjCDeclSpec::DQ_PR_getter) + attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_getter; + if (Attributes & ObjCDeclSpec::DQ_PR_setter) + attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_setter; + if (Attributes & ObjCDeclSpec::DQ_PR_assign) + attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_assign; + if (Attributes & ObjCDeclSpec::DQ_PR_retain) + attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_retain; + if (Attributes & ObjCDeclSpec::DQ_PR_strong) + attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_strong; + if (Attributes & ObjCDeclSpec::DQ_PR_weak) + attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_weak; + if (Attributes & ObjCDeclSpec::DQ_PR_copy) + attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_copy; + if (Attributes & ObjCDeclSpec::DQ_PR_unsafe_unretained) + attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_unsafe_unretained; + if (Attributes & ObjCDeclSpec::DQ_PR_nonatomic) + attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_nonatomic; + if (Attributes & ObjCDeclSpec::DQ_PR_atomic) + attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_atomic; + + return (ObjCPropertyDecl::PropertyAttributeKind)attributesAsWritten; +} + Decl * Sema::HandlePropertyInClassExtension(Scope *S, - SourceLocation AtLoc, FieldDeclarator &FD, + SourceLocation AtLoc, + SourceLocation LParenLoc, + FieldDeclarator &FD, Selector GetterSel, Selector SetterSel, const bool isAssign, const bool isReadWrite, const unsigned Attributes, + const unsigned AttributesAsWritten, bool *isOverridingProperty, TypeSourceInfo *T, tok::ObjCKeywordKind MethodImplKind) { @@ -198,7 +238,9 @@ Sema::HandlePropertyInClassExtension(Scope *S, // FIXME. We should really be using CreatePropertyDecl for this. ObjCPropertyDecl *PDecl = ObjCPropertyDecl::Create(Context, DC, FD.D.getIdentifierLoc(), - PropertyId, AtLoc, T); + PropertyId, AtLoc, LParenLoc, T); + PDecl->setPropertyAttributesAsWritten( + makePropertyAttributesAsWritten(AttributesAsWritten)); if (Attributes & ObjCDeclSpec::DQ_PR_readonly) PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_readonly); if (Attributes & ObjCDeclSpec::DQ_PR_readwrite) @@ -224,23 +266,40 @@ Sema::HandlePropertyInClassExtension(Scope *S, if (!PIDecl) { // No matching property found in the primary class. Just fall thru // and add property to continuation class's primary class. - ObjCPropertyDecl *PDecl = - CreatePropertyDecl(S, CCPrimary, AtLoc, + ObjCPropertyDecl *PrimaryPDecl = + CreatePropertyDecl(S, CCPrimary, AtLoc, LParenLoc, FD, GetterSel, SetterSel, isAssign, isReadWrite, - Attributes, T, MethodImplKind, DC); + Attributes,AttributesAsWritten, T, MethodImplKind, DC); // A case of continuation class adding a new property in the class. This // is not what it was meant for. However, gcc supports it and so should we. // Make sure setter/getters are declared here. - ProcessPropertyDecl(PDecl, CCPrimary, /* redeclaredProperty = */ 0, + ProcessPropertyDecl(PrimaryPDecl, CCPrimary, /* redeclaredProperty = */ 0, /* lexicalDC = */ CDecl); - return PDecl; + PDecl->setGetterMethodDecl(PrimaryPDecl->getGetterMethodDecl()); + PDecl->setSetterMethodDecl(PrimaryPDecl->getSetterMethodDecl()); + if (ASTMutationListener *L = Context.getASTMutationListener()) + L->AddedObjCPropertyInClassExtension(PrimaryPDecl, /*OrigProp=*/0, CDecl); + return PrimaryPDecl; } - if (PIDecl->getType().getCanonicalType() - != PDecl->getType().getCanonicalType()) { - Diag(AtLoc, - diag::warn_type_mismatch_continuation_class) << PDecl->getType(); - Diag(PIDecl->getLocation(), diag::note_property_declare); + if (!Context.hasSameType(PIDecl->getType(), PDecl->getType())) { + bool IncompatibleObjC = false; + QualType ConvertedType; + // Relax the strict type matching for property type in continuation class. + // Allow property object type of continuation class to be different as long + // as it narrows the object type in its primary class property. Note that + // this conversion is safe only because the wider type is for a 'readonly' + // property in primary class and 'narrowed' type for a 'readwrite' property + // in continuation class. + if (!isa<ObjCObjectPointerType>(PIDecl->getType()) || + !isa<ObjCObjectPointerType>(PDecl->getType()) || + (!isObjCPointerConversion(PDecl->getType(), PIDecl->getType(), + ConvertedType, IncompatibleObjC)) + || IncompatibleObjC) { + Diag(AtLoc, + diag::err_type_mismatch_continuation_class) << PDecl->getType(); + Diag(PIDecl->getLocation(), diag::note_property_declare); + } } // The property 'PIDecl's readonly attribute will be over-ridden @@ -273,7 +332,7 @@ Sema::HandlePropertyInClassExtension(Scope *S, ContextRAII SavedContext(*this, CCPrimary); Decl *ProtocolPtrTy = - ActOnProperty(S, AtLoc, FD, ProtocolPropertyODS, + ActOnProperty(S, AtLoc, LParenLoc, FD, ProtocolPropertyODS, PIDecl->getGetterName(), PIDecl->getSetterName(), isOverridingProperty, @@ -306,18 +365,24 @@ Sema::HandlePropertyInClassExtension(Scope *S, *isOverridingProperty = true; // Make sure setter decl is synthesized, and added to primary class's list. ProcessPropertyDecl(PIDecl, CCPrimary, PDecl, CDecl); + PDecl->setGetterMethodDecl(PIDecl->getGetterMethodDecl()); + PDecl->setSetterMethodDecl(PIDecl->getSetterMethodDecl()); + if (ASTMutationListener *L = Context.getASTMutationListener()) + L->AddedObjCPropertyInClassExtension(PDecl, PIDecl, CDecl); return 0; } ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S, ObjCContainerDecl *CDecl, SourceLocation AtLoc, + SourceLocation LParenLoc, FieldDeclarator &FD, Selector GetterSel, Selector SetterSel, const bool isAssign, const bool isReadWrite, const unsigned Attributes, + const unsigned AttributesAsWritten, TypeSourceInfo *TInfo, tok::ObjCKeywordKind MethodImplKind, DeclContext *lexicalDC){ @@ -326,7 +391,7 @@ ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S, // Issue a warning if property is 'assign' as default and its object, which is // gc'able conforms to NSCopying protocol - if (getLangOptions().getGC() != LangOptions::NonGC && + if (getLangOpts().getGC() != LangOptions::NonGC && isAssign && !(Attributes & ObjCDeclSpec::DQ_PR_assign)) if (const ObjCObjectPointerType *ObjPtrTy = T->getAs<ObjCObjectPointerType>()) { @@ -343,7 +408,7 @@ ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S, DeclContext *DC = cast<DeclContext>(CDecl); ObjCPropertyDecl *PDecl = ObjCPropertyDecl::Create(Context, DC, FD.D.getIdentifierLoc(), - PropertyId, AtLoc, TInfo); + PropertyId, AtLoc, LParenLoc, TInfo); if (ObjCPropertyDecl *prevDecl = ObjCPropertyDecl::findPropertyDecl(DC, PropertyId)) { @@ -368,35 +433,8 @@ ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S, // selector names in anticipation of declaration of setter/getter methods. PDecl->setGetterName(GetterSel); PDecl->setSetterName(SetterSel); - - unsigned attributesAsWritten = 0; - if (Attributes & ObjCDeclSpec::DQ_PR_readonly) - attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_readonly; - if (Attributes & ObjCDeclSpec::DQ_PR_readwrite) - attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_readwrite; - if (Attributes & ObjCDeclSpec::DQ_PR_getter) - attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_getter; - if (Attributes & ObjCDeclSpec::DQ_PR_setter) - attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_setter; - if (Attributes & ObjCDeclSpec::DQ_PR_assign) - attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_assign; - if (Attributes & ObjCDeclSpec::DQ_PR_retain) - attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_retain; - if (Attributes & ObjCDeclSpec::DQ_PR_strong) - attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_strong; - if (Attributes & ObjCDeclSpec::DQ_PR_weak) - attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_weak; - if (Attributes & ObjCDeclSpec::DQ_PR_copy) - attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_copy; - if (Attributes & ObjCDeclSpec::DQ_PR_unsafe_unretained) - attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_unsafe_unretained; - if (Attributes & ObjCDeclSpec::DQ_PR_nonatomic) - attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_nonatomic; - if (Attributes & ObjCDeclSpec::DQ_PR_atomic) - attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_atomic; - PDecl->setPropertyAttributesAsWritten( - (ObjCPropertyDecl::PropertyAttributeKind)attributesAsWritten); + makePropertyAttributesAsWritten(AttributesAsWritten)); if (Attributes & ObjCDeclSpec::DQ_PR_readonly) PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_readonly); @@ -502,6 +540,33 @@ static void checkARCPropertyImpl(Sema &S, SourceLocation propertyImplLoc, S.Diag(property->getLocation(), diag::note_property_declare); } +/// setImpliedPropertyAttributeForReadOnlyProperty - +/// This routine evaludates life-time attributes for a 'readonly' +/// property with no known lifetime of its own, using backing +/// 'ivar's attribute, if any. If no backing 'ivar', property's +/// life-time is assumed 'strong'. +static void setImpliedPropertyAttributeForReadOnlyProperty( + ObjCPropertyDecl *property, ObjCIvarDecl *ivar) { + Qualifiers::ObjCLifetime propertyLifetime = + getImpliedARCOwnership(property->getPropertyAttributes(), + property->getType()); + if (propertyLifetime != Qualifiers::OCL_None) + return; + + if (!ivar) { + // if no backing ivar, make property 'strong'. + property->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_strong); + return; + } + // property assumes owenership of backing ivar. + QualType ivarType = ivar->getType(); + Qualifiers::ObjCLifetime ivarLifetime = ivarType.getObjCLifetime(); + if (ivarLifetime == Qualifiers::OCL_Strong) + property->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_strong); + else if (ivarLifetime == Qualifiers::OCL_Weak) + property->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_weak); + return; +} /// ActOnPropertyImplDecl - This routine performs semantic checks and /// builds the AST node for a property implementation declaration; declared @@ -521,6 +586,8 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, Diag(AtLoc, diag::error_missing_property_context); return 0; } + if (PropertyIvarLoc.isInvalid()) + PropertyIvarLoc = PropertyLoc; ObjCPropertyDecl *property = 0; ObjCInterfaceDecl* IDecl = 0; // Find the class or category class where this property must have @@ -592,16 +659,26 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, // @synthesize if (!PropertyIvar) PropertyIvar = PropertyId; - ObjCPropertyDecl::PropertyAttributeKind kind - = property->getPropertyAttributes(); + // Check that this is a previously declared 'ivar' in 'IDecl' interface + ObjCInterfaceDecl *ClassDeclared; + Ivar = IDecl->lookupInstanceVariable(PropertyIvar, ClassDeclared); QualType PropType = property->getType(); - QualType PropertyIvarType = PropType.getNonReferenceType(); + + if (getLangOpts().ObjCAutoRefCount && + (property->getPropertyAttributesAsWritten() & + ObjCPropertyDecl::OBJC_PR_readonly) && + PropertyIvarType->isObjCRetainableType()) { + setImpliedPropertyAttributeForReadOnlyProperty(property, Ivar); + } + + ObjCPropertyDecl::PropertyAttributeKind kind + = property->getPropertyAttributes(); // Add GC __weak to the ivar type if the property is weak. if ((kind & ObjCPropertyDecl::OBJC_PR_weak) && - getLangOptions().getGC() != LangOptions::NonGC) { - assert(!getLangOptions().ObjCAutoRefCount); + getLangOpts().getGC() != LangOptions::NonGC) { + assert(!getLangOpts().ObjCAutoRefCount); if (PropertyIvarType.isObjCGCStrong()) { Diag(PropertyLoc, diag::err_gc_weak_property_strong_type); Diag(property->getLocation(), diag::note_property_declare); @@ -611,13 +688,10 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, } } - // Check that this is a previously declared 'ivar' in 'IDecl' interface - ObjCInterfaceDecl *ClassDeclared; - Ivar = IDecl->lookupInstanceVariable(PropertyIvar, ClassDeclared); if (!Ivar) { // In ARC, give the ivar a lifetime qualifier based on the // property attributes. - if (getLangOptions().ObjCAutoRefCount && + if (getLangOpts().ObjCAutoRefCount && !PropertyIvarType.getObjCLifetime() && PropertyIvarType->isObjCRetainableType()) { @@ -632,13 +706,21 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, Qualifiers::ObjCLifetime lifetime = getImpliedARCOwnership(kind, PropertyIvarType); assert(lifetime && "no lifetime for property?"); - - if (lifetime == Qualifiers::OCL_Weak && - !getLangOptions().ObjCRuntimeHasWeak) { - Diag(PropertyLoc, diag::err_arc_weak_no_runtime); - Diag(property->getLocation(), diag::note_property_declare); + if (lifetime == Qualifiers::OCL_Weak) { + bool err = false; + if (const ObjCObjectPointerType *ObjT = + PropertyIvarType->getAs<ObjCObjectPointerType>()) + if (ObjT->getInterfaceDecl()->isArcWeakrefUnavailable()) { + Diag(PropertyLoc, diag::err_arc_weak_unavailable_property); + Diag(property->getLocation(), diag::note_property_declare); + err = true; + } + if (!err && !getLangOpts().ObjCRuntimeHasWeak) { + Diag(PropertyLoc, diag::err_arc_weak_no_runtime); + Diag(property->getLocation(), diag::note_property_declare); + } } - + Qualifiers qs; qs.addObjCLifetime(lifetime); PropertyIvarType = Context.getQualifiedType(PropertyIvarType, qs); @@ -646,27 +728,27 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, } if (kind & ObjCPropertyDecl::OBJC_PR_weak && - !getLangOptions().ObjCAutoRefCount && - getLangOptions().getGC() == LangOptions::NonGC) { + !getLangOpts().ObjCAutoRefCount && + getLangOpts().getGC() == LangOptions::NonGC) { Diag(PropertyLoc, diag::error_synthesize_weak_non_arc_or_gc); Diag(property->getLocation(), diag::note_property_declare); } Ivar = ObjCIvarDecl::Create(Context, ClassImpDecl, - PropertyLoc, PropertyLoc, PropertyIvar, + PropertyIvarLoc,PropertyIvarLoc, PropertyIvar, PropertyIvarType, /*Dinfo=*/0, ObjCIvarDecl::Private, (Expr *)0, true); ClassImpDecl->addDecl(Ivar); - IDecl->makeDeclVisibleInContext(Ivar, false); + IDecl->makeDeclVisibleInContext(Ivar); property->setPropertyIvarDecl(Ivar); - if (!getLangOptions().ObjCNonFragileABI) + if (!getLangOpts().ObjCNonFragileABI) Diag(PropertyLoc, diag::error_missing_property_ivar_decl) << PropertyId; // Note! I deliberately want it to fall thru so, we have a // a property implementation and to avoid future warnings. - } else if (getLangOptions().ObjCNonFragileABI && - ClassDeclared != IDecl) { + } else if (getLangOpts().ObjCNonFragileABI && + !declaresSameEntity(ClassDeclared, IDecl)) { Diag(PropertyLoc, diag::error_ivar_in_superclass_use) << property->getDeclName() << Ivar->getDeclName() << ClassDeclared->getDeclName(); @@ -686,10 +768,8 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, PropertyIvarType->getAs<ObjCObjectPointerType>(), IvarType->getAs<ObjCObjectPointerType>()); else { - SourceLocation Loc = PropertyIvarLoc; - if (Loc.isInvalid()) - Loc = PropertyLoc; - compat = (CheckAssignmentConstraints(Loc, PropertyIvarType, IvarType) + compat = (CheckAssignmentConstraints(PropertyIvarLoc, PropertyIvarType, + IvarType) == Compatible); } if (!compat) { @@ -716,7 +796,7 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, } // __weak is explicit. So it works on Canonical type. if ((PropType.isObjCGCWeak() && !IvarType.isObjCGCWeak() && - getLangOptions().getGC() != LangOptions::NonGC)) { + getLangOpts().getGC() != LangOptions::NonGC)) { Diag(PropertyLoc, diag::error_weak_property) << property->getDeclName() << Ivar->getDeclName(); Diag(Ivar->getLocation(), diag::note_ivar_decl); @@ -725,13 +805,13 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, // Fall thru - see previous comment if ((property->getType()->isObjCObjectPointerType() || PropType.isObjCGCStrong()) && IvarType.isObjCGCWeak() && - getLangOptions().getGC() != LangOptions::NonGC) { + getLangOpts().getGC() != LangOptions::NonGC) { Diag(PropertyLoc, diag::error_strong_property) << property->getDeclName() << Ivar->getDeclName(); // Fall thru - see previous comment } } - if (getLangOptions().ObjCAutoRefCount) + if (getLangOpts().ObjCAutoRefCount) checkARCPropertyImpl(*this, PropertyLoc, property, Ivar); } else if (PropertyIvar) // @dynamic @@ -747,14 +827,14 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, Ivar, PropertyIvarLoc); if (ObjCMethodDecl *getterMethod = property->getGetterMethodDecl()) { getterMethod->createImplicitParams(Context, IDecl); - if (getLangOptions().CPlusPlus && Synthesize && + if (getLangOpts().CPlusPlus && Synthesize && Ivar->getType()->isRecordType()) { // For Objective-C++, need to synthesize the AST for the IVAR object to be // returned by the getter as it must conform to C++'s copy-return rules. // FIXME. Eventually we want to do this for Objective-C as well. ImplicitParamDecl *SelfDecl = getterMethod->getSelfDecl(); DeclRefExpr *SelfExpr = - new (Context) DeclRefExpr(SelfDecl, SelfDecl->getType(), + new (Context) DeclRefExpr(SelfDecl, false, SelfDecl->getType(), VK_RValue, SourceLocation()); Expr *IvarRefExpr = new (Context) ObjCIvarRefExpr(Ivar, Ivar->getType(), AtLoc, @@ -782,22 +862,20 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, } if (ObjCMethodDecl *setterMethod = property->getSetterMethodDecl()) { setterMethod->createImplicitParams(Context, IDecl); - if (getLangOptions().CPlusPlus && Synthesize + if (getLangOpts().CPlusPlus && Synthesize && Ivar->getType()->isRecordType()) { // FIXME. Eventually we want to do this for Objective-C as well. ImplicitParamDecl *SelfDecl = setterMethod->getSelfDecl(); DeclRefExpr *SelfExpr = - new (Context) DeclRefExpr(SelfDecl, SelfDecl->getType(), + new (Context) DeclRefExpr(SelfDecl, false, SelfDecl->getType(), VK_RValue, SourceLocation()); Expr *lhs = new (Context) ObjCIvarRefExpr(Ivar, Ivar->getType(), AtLoc, SelfExpr, true, true); ObjCMethodDecl::param_iterator P = setterMethod->param_begin(); ParmVarDecl *Param = (*P); - QualType T = Param->getType(); - if (T->isReferenceType()) - T = T->getAs<ReferenceType>()->getPointeeType(); - Expr *rhs = new (Context) DeclRefExpr(Param, T, + QualType T = Param->getType().getNonReferenceType(); + Expr *rhs = new (Context) DeclRefExpr(Param, false, T, VK_LValue, SourceLocation()); ExprResult Res = BuildBinOp(S, lhs->getLocEnd(), BO_Assign, lhs, rhs); @@ -808,9 +886,13 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, dyn_cast_or_null<CXXOperatorCallExpr>(callExpr)) if (const FunctionDecl *FuncDecl = CXXCE->getDirectCallee()) if (!FuncDecl->isTrivial()) - Diag(PropertyLoc, - diag::warn_atomic_property_nontrivial_assign_op) + if (property->getType()->isReferenceType()) { + Diag(PropertyLoc, + diag::err_atomic_property_nontrivial_assign_op) << property->getType(); + Diag(FuncDecl->getLocStart(), + diag::note_callee_decl) << FuncDecl; + } } PIDecl->setSetterCXXAssignment(Res.takeAs<Expr>()); } @@ -833,8 +915,9 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, return 0; } IC->addPropertyImplementation(PIDecl); - if (getLangOptions().ObjCDefaultSynthProperties && - getLangOptions().ObjCNonFragileABI2) { + if (getLangOpts().ObjCDefaultSynthProperties && + getLangOpts().ObjCNonFragileABI2 && + !IDecl->isObjCRequiresPropertyDefs()) { // Diagnose if an ivar was lazily synthesdized due to a previous // use and if 1) property is @dynamic or 2) property is synthesized // but it requires an ivar of different name. @@ -848,7 +931,7 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, } // Issue diagnostics only if Ivar belongs to current class. if (Ivar && Ivar->getSynthesize() && - IC->getClassInterface() == ClassDeclared) { + declaresSameEntity(IC->getClassInterface(), ClassDeclared)) { Diag(Ivar->getLocation(), diag::err_undeclared_var_use) << PropertyId; Ivar->setInvalidDecl(); @@ -948,7 +1031,8 @@ bool Sema::DiagnosePropertyAccessorMismatch(ObjCPropertyDecl *property, ObjCMethodDecl *GetterMethod, SourceLocation Loc) { if (GetterMethod && - GetterMethod->getResultType() != property->getType()) { + !Context.hasSameType(GetterMethod->getResultType().getNonReferenceType(), + property->getType().getNonReferenceType())) { AssignConvertType result = Incompatible; if (property->getType()->isObjCObjectPointerType()) result = CheckAssignmentConstraints(Loc, GetterMethod->getResultType(), @@ -1201,7 +1285,8 @@ static void CollectClassPropertyImplementations(ObjCContainerDecl *CDecl, for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(), E = PDecl->prop_end(); P != E; ++P) { ObjCPropertyDecl *Prop = (*P); - PropMap[Prop->getIdentifier()] = Prop; + if (!PropMap.count(Prop->getIdentifier())) + PropMap[Prop->getIdentifier()] = Prop; } // scan through protocol's protocols. for (ObjCProtocolDecl::protocol_iterator PI = PDecl->protocol_begin(), @@ -1265,7 +1350,7 @@ ObjCPropertyDecl *Sema::LookupPropertyDecl(const ObjCContainerDecl *CDecl, static IdentifierInfo * getDefaultSynthIvarName(ObjCPropertyDecl *Prop, ASTContext &Ctx) { - llvm::SmallString<128> ivarName; + SmallString<128> ivarName; { llvm::raw_svector_ostream os(ivarName); os << '_' << Prop->getIdentifier()->getName(); @@ -1305,7 +1390,13 @@ void Sema::DefaultSynthesizeProperties(Scope *S, ObjCImplDecl* IMPDecl, if (IMPDecl->getInstanceMethod(Prop->getSetterName())) continue; } - + if (isa<ObjCProtocolDecl>(Prop->getDeclContext())) { + // We won't auto-synthesize properties declared in protocols. + Diag(IMPDecl->getLocation(), + diag::warn_auto_synthesizing_protocol_property); + Diag(Prop->getLocation(), diag::note_property_declare); + continue; + } // We use invalid SourceLocations for the synthesized ivars since they // aren't really synthesized at a particular location; they just exist. @@ -1326,7 +1417,8 @@ void Sema::DefaultSynthesizeProperties(Scope *S, Decl *D) { if (!IC) return; if (ObjCInterfaceDecl* IDecl = IC->getClassInterface()) - DefaultSynthesizeProperties(S, IC, IDecl); + if (!IDecl->isObjCRequiresPropertyDefs()) + DefaultSynthesizeProperties(S, IC, IDecl); } void Sema::DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl, @@ -1363,6 +1455,11 @@ void Sema::DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl, << Prop->getDeclName() << Prop->getGetterName(); Diag(Prop->getLocation(), diag::note_property_declare); + if (LangOpts.ObjCDefaultSynthProperties && LangOpts.ObjCNonFragileABI2) + if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(CDecl)) + if (const ObjCInterfaceDecl *RID = ID->isObjCRequiresPropertyDefs()) + Diag(RID->getLocation(), diag::note_suppressed_class_declare); + } if (!Prop->isReadOnly() && !InsMap.count(Prop->getSetterName())) { @@ -1373,6 +1470,10 @@ void Sema::DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl, << Prop->getDeclName() << Prop->getSetterName(); Diag(Prop->getLocation(), diag::note_property_declare); + if (LangOpts.ObjCDefaultSynthProperties && LangOpts.ObjCNonFragileABI2) + if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(CDecl)) + if (const ObjCInterfaceDecl *RID = ID->isObjCRequiresPropertyDefs()) + Diag(RID->getLocation(), diag::note_suppressed_class_declare); } } } @@ -1381,7 +1482,7 @@ void Sema::AtomicPropertySetterGetterRules (ObjCImplDecl* IMPDecl, ObjCContainerDecl* IDecl) { // Rules apply in non-GC mode only - if (getLangOptions().getGC() != LangOptions::NonGC) + if (getLangOpts().getGC() != LangOptions::NonGC) return; for (ObjCContainerDecl::prop_iterator I = IDecl->prop_begin(), E = IDecl->prop_end(); @@ -1433,7 +1534,34 @@ Sema::AtomicPropertySetterGetterRules (ObjCImplDecl* IMPDecl, Diag(MethodLoc, diag::warn_atomic_property_rule) << Property->getIdentifier() << (GetterMethod != 0) << (SetterMethod != 0); - Diag(MethodLoc, diag::note_atomic_property_fixup_suggest); + // fixit stuff. + if (!AttributesAsWritten) { + if (Property->getLParenLoc().isValid()) { + // @property () ... case. + SourceRange PropSourceRange(Property->getAtLoc(), + Property->getLParenLoc()); + Diag(Property->getLocation(), diag::note_atomic_property_fixup_suggest) << + FixItHint::CreateReplacement(PropSourceRange, "@property (nonatomic"); + } + else { + //@property id etc. + SourceLocation endLoc = + Property->getTypeSourceInfo()->getTypeLoc().getBeginLoc(); + endLoc = endLoc.getLocWithOffset(-1); + SourceRange PropSourceRange(Property->getAtLoc(), endLoc); + Diag(Property->getLocation(), diag::note_atomic_property_fixup_suggest) << + FixItHint::CreateReplacement(PropSourceRange, "@property (nonatomic) "); + } + } + else if (!(AttributesAsWritten & ObjCPropertyDecl::OBJC_PR_atomic)) { + // @property () ... case. + SourceLocation endLoc = Property->getLParenLoc(); + SourceRange PropSourceRange(Property->getAtLoc(), endLoc); + Diag(Property->getLocation(), diag::note_atomic_property_fixup_suggest) << + FixItHint::CreateReplacement(PropSourceRange, "@property (nonatomic, "); + } + else + Diag(MethodLoc, diag::note_atomic_property_fixup_suggest); Diag(Property->getLocation(), diag::note_property_declare); } } @@ -1441,7 +1569,7 @@ Sema::AtomicPropertySetterGetterRules (ObjCImplDecl* IMPDecl, } void Sema::DiagnoseOwningPropertyGetterSynthesis(const ObjCImplementationDecl *D) { - if (getLangOptions().getGC() == LangOptions::GCOnly) + if (getLangOpts().getGC() == LangOptions::GCOnly) return; for (ObjCImplementationDecl::propimpl_iterator @@ -1459,7 +1587,7 @@ void Sema::DiagnoseOwningPropertyGetterSynthesis(const ObjCImplementationDecl *D ObjCMethodFamily family = method->getMethodFamily(); if (family == OMF_alloc || family == OMF_copy || family == OMF_mutableCopy || family == OMF_new) { - if (getLangOptions().ObjCAutoRefCount) + if (getLangOpts().ObjCAutoRefCount) Diag(PID->getLocation(), diag::err_ownin_getter_rule); else Diag(PID->getLocation(), diag::warn_owning_getter_rule); @@ -1510,7 +1638,8 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property, Diag(SetterMethod->getLocation(), diag::err_setter_type_void); if (SetterMethod->param_size() != 1 || !Context.hasSameUnqualifiedType( - (*SetterMethod->param_begin())->getType(), property->getType())) { + (*SetterMethod->param_begin())->getType().getNonReferenceType(), + property->getType().getNonReferenceType())) { Diag(property->getLocation(), diag::warn_accessor_property_type_mismatch) << property->getDeclName() @@ -1636,6 +1765,21 @@ void Sema::CheckObjCPropertyAttributes(Decl *PDecl, ObjCPropertyDecl *PropertyDecl = cast<ObjCPropertyDecl>(PDecl); QualType PropertyTy = PropertyDecl->getType(); + if (getLangOpts().ObjCAutoRefCount && + (Attributes & ObjCDeclSpec::DQ_PR_readonly) && + PropertyTy->isObjCRetainableType()) { + // 'readonly' property with no obvious lifetime. + // its life time will be determined by its backing ivar. + unsigned rel = (ObjCDeclSpec::DQ_PR_unsafe_unretained | + ObjCDeclSpec::DQ_PR_copy | + ObjCDeclSpec::DQ_PR_retain | + ObjCDeclSpec::DQ_PR_strong | + ObjCDeclSpec::DQ_PR_weak | + ObjCDeclSpec::DQ_PR_assign); + if ((Attributes & rel) == 0) + return; + } + // readonly and readwrite/assign/retain/copy conflict. if ((Attributes & ObjCDeclSpec::DQ_PR_readonly) && (Attributes & (ObjCDeclSpec::DQ_PR_readwrite | @@ -1669,6 +1813,7 @@ void Sema::CheckObjCPropertyAttributes(Decl *PDecl, Attributes & ObjCDeclSpec::DQ_PR_copy ? "copy" : "retain (or strong)"); Attributes &= ~(ObjCDeclSpec::DQ_PR_weak | ObjCDeclSpec::DQ_PR_copy | ObjCDeclSpec::DQ_PR_retain | ObjCDeclSpec::DQ_PR_strong); + PropertyDecl->setInvalidDecl(); } // Check for more than one of { assign, copy, retain }. @@ -1688,7 +1833,7 @@ void Sema::CheckObjCPropertyAttributes(Decl *PDecl, << "assign" << "strong"; Attributes &= ~ObjCDeclSpec::DQ_PR_strong; } - if (getLangOptions().ObjCAutoRefCount && + if (getLangOpts().ObjCAutoRefCount && (Attributes & ObjCDeclSpec::DQ_PR_weak)) { Diag(Loc, diag::err_objc_property_attr_mutually_exclusive) << "assign" << "weak"; @@ -1710,7 +1855,7 @@ void Sema::CheckObjCPropertyAttributes(Decl *PDecl, << "unsafe_unretained" << "strong"; Attributes &= ~ObjCDeclSpec::DQ_PR_strong; } - if (getLangOptions().ObjCAutoRefCount && + if (getLangOpts().ObjCAutoRefCount && (Attributes & ObjCDeclSpec::DQ_PR_weak)) { Diag(Loc, diag::err_objc_property_attr_mutually_exclusive) << "unsafe_unretained" << "weak"; @@ -1759,20 +1904,28 @@ void Sema::CheckObjCPropertyAttributes(Decl *PDecl, ObjCDeclSpec::DQ_PR_unsafe_unretained | ObjCDeclSpec::DQ_PR_retain | ObjCDeclSpec::DQ_PR_strong | ObjCDeclSpec::DQ_PR_weak)) && - !(Attributes & ObjCDeclSpec::DQ_PR_readonly) && PropertyTy->isObjCObjectPointerType()) { - if (getLangOptions().ObjCAutoRefCount) + if (getLangOpts().ObjCAutoRefCount) // With arc, @property definitions should default to (strong) when - // not specified + // not specified; including when property is 'readonly'. PropertyDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_strong); - else { + else if (!(Attributes & ObjCDeclSpec::DQ_PR_readonly)) { + bool isAnyClassTy = + (PropertyTy->isObjCClassType() || + PropertyTy->isObjCQualifiedClassType()); + // In non-gc, non-arc mode, 'Class' is treated as a 'void *' no need to + // issue any warning. + if (isAnyClassTy && getLangOpts().getGC() == LangOptions::NonGC) + ; + else { // Skip this warning in gc-only mode. - if (getLangOptions().getGC() != LangOptions::GCOnly) + if (getLangOpts().getGC() != LangOptions::GCOnly) Diag(Loc, diag::warn_objc_property_no_assignment_attribute); // If non-gc code warn that this is likely inappropriate. - if (getLangOptions().getGC() == LangOptions::NonGC) + if (getLangOpts().getGC() == LangOptions::NonGC) Diag(Loc, diag::warn_objc_property_default_assign_on_object); + } } // FIXME: Implement warning dependent on NSCopying being @@ -1783,13 +1936,18 @@ void Sema::CheckObjCPropertyAttributes(Decl *PDecl, if (!(Attributes & ObjCDeclSpec::DQ_PR_copy) &&!(Attributes & ObjCDeclSpec::DQ_PR_readonly) - && getLangOptions().getGC() == LangOptions::GCOnly + && getLangOpts().getGC() == LangOptions::GCOnly && PropertyTy->isBlockPointerType()) Diag(Loc, diag::warn_objc_property_copy_missing_on_block); - else if (getLangOptions().ObjCAutoRefCount && + else if (getLangOpts().ObjCAutoRefCount && (Attributes & ObjCDeclSpec::DQ_PR_retain) && !(Attributes & ObjCDeclSpec::DQ_PR_readonly) && !(Attributes & ObjCDeclSpec::DQ_PR_strong) && PropertyTy->isBlockPointerType()) Diag(Loc, diag::warn_objc_property_retain_of_block); + + if ((Attributes & ObjCDeclSpec::DQ_PR_readonly) && + (Attributes & ObjCDeclSpec::DQ_PR_setter)) + Diag(Loc, diag::warn_objc_readonly_property_has_setter); + } |