diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2015-12-30 13:34:49 +0000 | 
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2015-12-30 13:34:49 +0000 | 
| commit | 0623d7483df5fc17b32ba7bc5cb9c7beebf6db9c (patch) | |
| tree | 28726ef2038e86121e353aabf52297b35a48efa2 /contrib/llvm/tools/clang/lib/Sema/SemaObjCProperty.cpp | |
| parent | 7d523365ff1a3cc95bc058b33102500f61e8166d (diff) | |
| parent | 45b533945f0851ec234ca846e1af5ee1e4df0b6e (diff) | |
Notes
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Sema/SemaObjCProperty.cpp')
| -rw-r--r-- | contrib/llvm/tools/clang/lib/Sema/SemaObjCProperty.cpp | 743 | 
1 files changed, 413 insertions, 330 deletions
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaObjCProperty.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaObjCProperty.cpp index f139c83c734b..1cb84e448067 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaObjCProperty.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaObjCProperty.cpp @@ -61,8 +61,10 @@ static Qualifiers::ObjCLifetime getImpliedARCOwnership(    return Qualifiers::OCL_None;  } -/// Check the internal consistency of a property declaration. -static void checkARCPropertyDecl(Sema &S, ObjCPropertyDecl *property) { +/// Check the internal consistency of a property declaration with +/// an explicit ownership qualifier. +static void checkPropertyDeclWithOwnership(Sema &S, +                                           ObjCPropertyDecl *property) {    if (property->isInvalidDecl()) return;    ObjCPropertyDecl::PropertyAttributeKind propertyKind @@ -70,8 +72,7 @@ static void checkARCPropertyDecl(Sema &S, ObjCPropertyDecl *property) {    Qualifiers::ObjCLifetime propertyLifetime      = property->getType().getObjCLifetime(); -  // Nothing to do if we don't have a lifetime. -  if (propertyLifetime == Qualifiers::OCL_None) return; +  assert(propertyLifetime != Qualifiers::OCL_None);    Qualifiers::ObjCLifetime expectedLifetime      = getImpliedARCOwnership(propertyKind, property->getType()); @@ -127,32 +128,71 @@ CheckPropertyAgainstProtocol(Sema &S, ObjCPropertyDecl *Prop,      CheckPropertyAgainstProtocol(S, Prop, P, Known);  } +static unsigned deducePropertyOwnershipFromType(Sema &S, QualType T) { +  // In GC mode, just look for the __weak qualifier. +  if (S.getLangOpts().getGC() != LangOptions::NonGC) { +    if (T.isObjCGCWeak()) return ObjCDeclSpec::DQ_PR_weak; + +  // In ARC/MRC, look for an explicit ownership qualifier. +  // For some reason, this only applies to __weak. +  } else if (auto ownership = T.getObjCLifetime()) { +    switch (ownership) { +    case Qualifiers::OCL_Weak: +      return ObjCDeclSpec::DQ_PR_weak; +    case Qualifiers::OCL_Strong: +      return ObjCDeclSpec::DQ_PR_strong; +    case Qualifiers::OCL_ExplicitNone: +      return ObjCDeclSpec::DQ_PR_unsafe_unretained; +    case Qualifiers::OCL_Autoreleasing: +    case Qualifiers::OCL_None: +      return 0; +    } +    llvm_unreachable("bad qualifier"); +  } + +  return 0; +} + +static const unsigned OwnershipMask = +  (ObjCPropertyDecl::OBJC_PR_assign | +   ObjCPropertyDecl::OBJC_PR_retain | +   ObjCPropertyDecl::OBJC_PR_copy   | +   ObjCPropertyDecl::OBJC_PR_weak   | +   ObjCPropertyDecl::OBJC_PR_strong | +   ObjCPropertyDecl::OBJC_PR_unsafe_unretained); + +static unsigned getOwnershipRule(unsigned attr) { +  unsigned result = attr & OwnershipMask; + +  // From an ownership perspective, assign and unsafe_unretained are +  // identical; make sure one also implies the other. +  if (result & (ObjCPropertyDecl::OBJC_PR_assign | +                ObjCPropertyDecl::OBJC_PR_unsafe_unretained)) { +    result |= ObjCPropertyDecl::OBJC_PR_assign | +              ObjCPropertyDecl::OBJC_PR_unsafe_unretained; +  } + +  return result; +} +  Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,                            SourceLocation LParenLoc,                            FieldDeclarator &FD,                            ObjCDeclSpec &ODS,                            Selector GetterSel,                            Selector SetterSel, -                          bool *isOverridingProperty,                            tok::ObjCKeywordKind MethodImplKind,                            DeclContext *lexicalDC) {    unsigned Attributes = ODS.getPropertyAttributes();    FD.D.setObjCWeakProperty((Attributes & ObjCDeclSpec::DQ_PR_weak) != 0);    TypeSourceInfo *TSI = GetTypeForDeclarator(FD.D, S);    QualType T = TSI->getType(); -  Attributes |= deduceWeakPropertyFromType(T); +  if (!getOwnershipRule(Attributes)) { +    Attributes |= deducePropertyOwnershipFromType(*this, T); +  }    bool isReadWrite = ((Attributes & ObjCDeclSpec::DQ_PR_readwrite) ||                        // default is readwrite!                        !(Attributes & ObjCDeclSpec::DQ_PR_readonly)); -  // property is defaulted to 'assign' if it is readwrite and is -  // not retain or copy -  bool isAssign = ((Attributes & ObjCDeclSpec::DQ_PR_assign) || -                   (isReadWrite && -                    !(Attributes & ObjCDeclSpec::DQ_PR_retain) && -                    !(Attributes & ObjCDeclSpec::DQ_PR_strong) && -                    !(Attributes & ObjCDeclSpec::DQ_PR_copy) && -                    !(Attributes & ObjCDeclSpec::DQ_PR_unsafe_unretained) && -                    !(Attributes & ObjCDeclSpec::DQ_PR_weak)));    // Proceed with constructing the ObjCPropertyDecls.    ObjCContainerDecl *ClassDecl = cast<ObjCContainerDecl>(CurContext); @@ -161,11 +201,10 @@ Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,      if (CDecl->IsClassExtension()) {        Res = HandlePropertyInClassExtension(S, AtLoc, LParenLoc,                                             FD, GetterSel, SetterSel, -                                           isAssign, isReadWrite, +                                           isReadWrite,                                             Attributes,                                             ODS.getPropertyAttributes(), -                                           isOverridingProperty, T, TSI, -                                           MethodImplKind); +                                           T, TSI, MethodImplKind);        if (!Res)          return nullptr;      } @@ -173,7 +212,7 @@ Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,    if (!Res) {      Res = CreatePropertyDecl(S, ClassDecl, AtLoc, LParenLoc, FD, -                             GetterSel, SetterSel, isAssign, isReadWrite, +                             GetterSel, SetterSel, isReadWrite,                               Attributes, ODS.getPropertyAttributes(),                               T, TSI, MethodImplKind);      if (lexicalDC) @@ -181,12 +220,13 @@ Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,    }    // Validate the attributes on the @property. -  CheckObjCPropertyAttributes(Res, AtLoc, Attributes,  +  CheckObjCPropertyAttributes(Res, AtLoc, Attributes,                                (isa<ObjCInterfaceDecl>(ClassDecl) ||                                 isa<ObjCProtocolDecl>(ClassDecl))); -  if (getLangOpts().ObjCAutoRefCount) -    checkARCPropertyDecl(*this, Res); +  // Check consistency if the type has explicit ownership qualification. +  if (Res->getType().getObjCLifetime()) +    checkPropertyDeclWithOwnership(*this, Res);    llvm::SmallPtrSet<ObjCProtocolDecl *, 16> KnownProtos;    if (ObjCInterfaceDecl *IFace = dyn_cast<ObjCInterfaceDecl>(ClassDecl)) { @@ -220,8 +260,12 @@ Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,        }      }    } else if (ObjCCategoryDecl *Cat = dyn_cast<ObjCCategoryDecl>(ClassDecl)) { -    for (auto *P : Cat->protocols()) -      CheckPropertyAgainstProtocol(*this, Res, P, KnownProtos); +    // We don't check if class extension. Because properties in class extension +    // are meant to override some of the attributes and checking has already done +    // when property in class extension is constructed. +    if (!Cat->IsClassExtension()) +      for (auto *P : Cat->protocols()) +        CheckPropertyAgainstProtocol(*this, Res, P, KnownProtos);    } else {      ObjCProtocolDecl *Proto = cast<ObjCProtocolDecl>(ClassDecl);      for (auto *P : Proto->protocols()) @@ -293,13 +337,73 @@ static bool LocPropertyAttribute( ASTContext &Context, const char *attrName,  } -static unsigned getOwnershipRule(unsigned attr) { -  return attr & (ObjCPropertyDecl::OBJC_PR_assign | -                 ObjCPropertyDecl::OBJC_PR_retain | -                 ObjCPropertyDecl::OBJC_PR_copy   | -                 ObjCPropertyDecl::OBJC_PR_weak   | -                 ObjCPropertyDecl::OBJC_PR_strong | -                 ObjCPropertyDecl::OBJC_PR_unsafe_unretained); +/// Check for a mismatch in the atomicity of the given properties. +static void checkAtomicPropertyMismatch(Sema &S, +                                        ObjCPropertyDecl *OldProperty, +                                        ObjCPropertyDecl *NewProperty, +                                        bool PropagateAtomicity) { +  // If the atomicity of both matches, we're done. +  bool OldIsAtomic = +    (OldProperty->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_nonatomic) +      == 0; +  bool NewIsAtomic = +    (NewProperty->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_nonatomic) +      == 0; +  if (OldIsAtomic == NewIsAtomic) return; + +  // Determine whether the given property is readonly and implicitly +  // atomic. +  auto isImplicitlyReadonlyAtomic = [](ObjCPropertyDecl *Property) -> bool { +    // Is it readonly? +    auto Attrs = Property->getPropertyAttributes(); +    if ((Attrs & ObjCPropertyDecl::OBJC_PR_readonly) == 0) return false; + +    // Is it nonatomic? +    if (Attrs & ObjCPropertyDecl::OBJC_PR_nonatomic) return false; + +    // Was 'atomic' specified directly? +    if (Property->getPropertyAttributesAsWritten() &  +          ObjCPropertyDecl::OBJC_PR_atomic) +      return false; + +    return true; +  }; + +  // If we're allowed to propagate atomicity, and the new property did +  // not specify atomicity at all, propagate. +  const unsigned AtomicityMask = +    (ObjCPropertyDecl::OBJC_PR_atomic | ObjCPropertyDecl::OBJC_PR_nonatomic); +  if (PropagateAtomicity && +      ((NewProperty->getPropertyAttributesAsWritten() & AtomicityMask) == 0)) { +    unsigned Attrs = NewProperty->getPropertyAttributes(); +    Attrs = Attrs & ~AtomicityMask; +    if (OldIsAtomic) +      Attrs |= ObjCPropertyDecl::OBJC_PR_atomic; +    else  +      Attrs |= ObjCPropertyDecl::OBJC_PR_nonatomic; + +    NewProperty->overwritePropertyAttributes(Attrs); +    return; +  } + +  // One of the properties is atomic; if it's a readonly property, and +  // 'atomic' wasn't explicitly specified, we're okay. +  if ((OldIsAtomic && isImplicitlyReadonlyAtomic(OldProperty)) || +      (NewIsAtomic && isImplicitlyReadonlyAtomic(NewProperty))) +    return; + +  // Diagnose the conflict. +  const IdentifierInfo *OldContextName; +  auto *OldDC = OldProperty->getDeclContext(); +  if (auto Category = dyn_cast<ObjCCategoryDecl>(OldDC)) +    OldContextName = Category->getClassInterface()->getIdentifier(); +  else +    OldContextName = cast<ObjCContainerDecl>(OldDC)->getIdentifier(); + +  S.Diag(NewProperty->getLocation(), diag::warn_property_attribute) +    << NewProperty->getDeclName() << "atomic" +    << OldContextName; +  S.Diag(OldProperty->getLocation(), diag::note_property_declare);  }  ObjCPropertyDecl * @@ -308,11 +412,9 @@ Sema::HandlePropertyInClassExtension(Scope *S,                                       SourceLocation LParenLoc,                                       FieldDeclarator &FD,                                       Selector GetterSel, Selector SetterSel, -                                     const bool isAssign,                                       const bool isReadWrite, -                                     const unsigned Attributes, +                                     unsigned &Attributes,                                       const unsigned AttributesAsWritten, -                                     bool *isOverridingProperty,                                       QualType T,                                       TypeSourceInfo *TSI,                                       tok::ObjCKeywordKind MethodImplKind) { @@ -322,80 +424,102 @@ Sema::HandlePropertyInClassExtension(Scope *S,    IdentifierInfo *PropertyId = FD.D.getIdentifier();    ObjCInterfaceDecl *CCPrimary = CDecl->getClassInterface(); -  if (CCPrimary) { -    // Check for duplicate declaration of this property in current and -    // other class extensions. -    for (const auto *Ext : CCPrimary->known_extensions()) { -      if (ObjCPropertyDecl *prevDecl -            = ObjCPropertyDecl::findPropertyDecl(Ext, PropertyId)) { -        Diag(AtLoc, diag::err_duplicate_property); -        Diag(prevDecl->getLocation(), diag::note_property_declare); -        return nullptr; -      } -    } -  } - -  // Create a new ObjCPropertyDecl with the DeclContext being -  // the class extension. -  // FIXME. We should really be using CreatePropertyDecl for this. -  ObjCPropertyDecl *PDecl = -    ObjCPropertyDecl::Create(Context, DC, FD.D.getIdentifierLoc(), -                             PropertyId, AtLoc, LParenLoc, T, TSI); -  PDecl->setPropertyAttributesAsWritten( -                          makePropertyAttributesAsWritten(AttributesAsWritten)); -  if (Attributes & ObjCDeclSpec::DQ_PR_readonly) -    PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_readonly); -  if (Attributes & ObjCDeclSpec::DQ_PR_readwrite) -    PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_readwrite); -  if (Attributes & ObjCDeclSpec::DQ_PR_nonatomic) -    PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_nonatomic); -  if (Attributes & ObjCDeclSpec::DQ_PR_atomic) -    PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_atomic); -  if (Attributes & ObjCDeclSpec::DQ_PR_nullability) -    PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_nullability); -  if (Attributes & ObjCDeclSpec::DQ_PR_null_resettable) -    PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_null_resettable); - -  // Set setter/getter selector name. Needed later. -  PDecl->setGetterName(GetterSel); -  PDecl->setSetterName(SetterSel); -  ProcessDeclAttributes(S, PDecl, FD.D); -  DC->addDecl(PDecl); -    // We need to look in the @interface to see if the @property was    // already declared.    if (!CCPrimary) {      Diag(CDecl->getLocation(), diag::err_continuation_class); -    *isOverridingProperty = true;      return nullptr;    } -  // Find the property in continuation class's primary class only. +  // Find the property in the extended class's primary class or +  // extensions.    ObjCPropertyDecl *PIDecl =      CCPrimary->FindPropertyVisibleInPrimaryClass(PropertyId); +  // If we found a property in an extension, complain.  +  if (PIDecl && isa<ObjCCategoryDecl>(PIDecl->getDeclContext())) { +    Diag(AtLoc, diag::err_duplicate_property); +    Diag(PIDecl->getLocation(), diag::note_property_declare); +    return nullptr; +  } + +  // Check for consistency with the previous declaration, if there is one. +  if (PIDecl) { +    // A readonly property declared in the primary class can be refined +    // by adding a readwrite property within an extension. +    // Anything else is an error. +    if (!(PIDecl->isReadOnly() && isReadWrite)) { +      // Tailor the diagnostics for the common case where a readwrite +      // property is declared both in the @interface and the continuation. +      // This is a common error where the user often intended the original +      // declaration to be readonly. +      unsigned diag = +        (Attributes & ObjCDeclSpec::DQ_PR_readwrite) && +        (PIDecl->getPropertyAttributesAsWritten() & +           ObjCPropertyDecl::OBJC_PR_readwrite) +        ? diag::err_use_continuation_class_redeclaration_readwrite +        : diag::err_use_continuation_class; +      Diag(AtLoc, diag) +        << CCPrimary->getDeclName(); +      Diag(PIDecl->getLocation(), diag::note_property_declare); +      return nullptr; +    } + +    // Check for consistency of getters. +    if (PIDecl->getGetterName() != GetterSel) { +     // If the getter was written explicitly, complain. +      if (AttributesAsWritten & ObjCDeclSpec::DQ_PR_getter) { +        Diag(AtLoc, diag::warn_property_redecl_getter_mismatch) +          << PIDecl->getGetterName() << GetterSel; +        Diag(PIDecl->getLocation(), diag::note_property_declare); +      } +       +      // Always adopt the getter from the original declaration. +      GetterSel = PIDecl->getGetterName(); +      Attributes |= ObjCDeclSpec::DQ_PR_getter; +    } + +    // Check consistency of ownership. +    unsigned ExistingOwnership +      = getOwnershipRule(PIDecl->getPropertyAttributes()); +    unsigned NewOwnership = getOwnershipRule(Attributes); +    if (ExistingOwnership && NewOwnership != ExistingOwnership) { +      // If the ownership was written explicitly, complain. +      if (getOwnershipRule(AttributesAsWritten)) { +        Diag(AtLoc, diag::warn_property_attr_mismatch); +        Diag(PIDecl->getLocation(), diag::note_property_declare); +      } + +      // Take the ownership from the original property. +      Attributes = (Attributes & ~OwnershipMask) | ExistingOwnership; +    } + +    // If the redeclaration is 'weak' but the original property is not,  +    if ((Attributes & ObjCPropertyDecl::OBJC_PR_weak) && +        !(PIDecl->getPropertyAttributesAsWritten() +            & ObjCPropertyDecl::OBJC_PR_weak) && +        PIDecl->getType()->getAs<ObjCObjectPointerType>() && +        PIDecl->getType().getObjCLifetime() == Qualifiers::OCL_None) { +      Diag(AtLoc, diag::warn_property_implicitly_mismatched); +      Diag(PIDecl->getLocation(), diag::note_property_declare); +    }         +  } + +  // Create a new ObjCPropertyDecl with the DeclContext being +  // the class extension. +  ObjCPropertyDecl *PDecl = CreatePropertyDecl(S, CDecl, AtLoc, LParenLoc, +                                               FD, GetterSel, SetterSel, +                                               isReadWrite, +                                               Attributes, AttributesAsWritten, +                                               T, TSI, MethodImplKind, DC); + +  // If there was no declaration of a property with the same name in +  // the primary class, we're done.    if (!PIDecl) { -    // No matching property found in the primary class. Just fall thru -    // and add property to continuation class's primary class. -    ObjCPropertyDecl *PrimaryPDecl = -      CreatePropertyDecl(S, CCPrimary, AtLoc, LParenLoc, -                         FD, GetterSel, SetterSel, isAssign, isReadWrite, -                         Attributes,AttributesAsWritten, T, TSI, 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(PrimaryPDecl, CCPrimary, -                        /* redeclaredProperty = */ nullptr, -                        /* lexicalDC = */ CDecl); -    PDecl->setGetterMethodDecl(PrimaryPDecl->getGetterMethodDecl()); -    PDecl->setSetterMethodDecl(PrimaryPDecl->getSetterMethodDecl()); -    if (ASTMutationListener *L = Context.getASTMutationListener()) -      L->AddedObjCPropertyInClassExtension(PrimaryPDecl, /*OrigProp=*/nullptr, -                                           CDecl); -    return PrimaryPDecl; +    ProcessPropertyDecl(PDecl); +    return PDecl;    } +    if (!Context.hasSameType(PIDecl->getType(), PDecl->getType())) {      bool IncompatibleObjC = false;      QualType ConvertedType; @@ -418,103 +542,13 @@ Sema::HandlePropertyInClassExtension(Scope *S,        return nullptr;      }    } -     -  // The property 'PIDecl's readonly attribute will be over-ridden -  // with continuation class's readwrite property attribute! -  unsigned PIkind = PIDecl->getPropertyAttributesAsWritten(); -  if (isReadWrite && (PIkind & ObjCPropertyDecl::OBJC_PR_readonly)) { -    PIkind &= ~ObjCPropertyDecl::OBJC_PR_readonly; -    PIkind |= ObjCPropertyDecl::OBJC_PR_readwrite; -    PIkind |= deduceWeakPropertyFromType(PIDecl->getType()); -    unsigned ClassExtensionMemoryModel = getOwnershipRule(Attributes); -    unsigned PrimaryClassMemoryModel = getOwnershipRule(PIkind); -    if (PrimaryClassMemoryModel && ClassExtensionMemoryModel && -        (PrimaryClassMemoryModel != ClassExtensionMemoryModel)) { -      Diag(AtLoc, diag::warn_property_attr_mismatch); -      Diag(PIDecl->getLocation(), diag::note_property_declare); -    } -    else if (getLangOpts().ObjCAutoRefCount) { -      QualType PrimaryPropertyQT = -        Context.getCanonicalType(PIDecl->getType()).getUnqualifiedType(); -      if (isa<ObjCObjectPointerType>(PrimaryPropertyQT)) { -        bool PropertyIsWeak = ((PIkind & ObjCPropertyDecl::OBJC_PR_weak) != 0); -        Qualifiers::ObjCLifetime PrimaryPropertyLifeTime = -          PrimaryPropertyQT.getObjCLifetime(); -        if (PrimaryPropertyLifeTime == Qualifiers::OCL_None && -            (Attributes & ObjCDeclSpec::DQ_PR_weak) && -            !PropertyIsWeak) { -              Diag(AtLoc, diag::warn_property_implicitly_mismatched); -              Diag(PIDecl->getLocation(), diag::note_property_declare); -            } -        } -    } -     -    DeclContext *DC = cast<DeclContext>(CCPrimary); -    if (!ObjCPropertyDecl::findPropertyDecl(DC, -                                 PIDecl->getDeclName().getAsIdentifierInfo())) { -      // In mrr mode, 'readwrite' property must have an explicit -      // memory attribute. If none specified, select the default (assign). -      if (!getLangOpts().ObjCAutoRefCount) { -        if (!(PIkind & (ObjCDeclSpec::DQ_PR_assign | -                        ObjCDeclSpec::DQ_PR_retain | -                        ObjCDeclSpec::DQ_PR_strong | -                        ObjCDeclSpec::DQ_PR_copy | -                        ObjCDeclSpec::DQ_PR_unsafe_unretained | -                        ObjCDeclSpec::DQ_PR_weak))) -          PIkind |= ObjCPropertyDecl::OBJC_PR_assign; -      } -       -      // Protocol is not in the primary class. Must build one for it. -      ObjCDeclSpec ProtocolPropertyODS; -      // FIXME. Assuming that ObjCDeclSpec::ObjCPropertyAttributeKind -      // and ObjCPropertyDecl::PropertyAttributeKind have identical -      // values.  Should consolidate both into one enum type. -      ProtocolPropertyODS. -      setPropertyAttributes((ObjCDeclSpec::ObjCPropertyAttributeKind) -                            PIkind); -      // Must re-establish the context from class extension to primary -      // class context. -      ContextRAII SavedContext(*this, CCPrimary); -       -      Decl *ProtocolPtrTy = -        ActOnProperty(S, AtLoc, LParenLoc, FD, ProtocolPropertyODS, -                      PIDecl->getGetterName(), -                      PIDecl->getSetterName(), -                      isOverridingProperty, -                      MethodImplKind, -                      /* lexicalDC = */ CDecl); -      PIDecl = cast<ObjCPropertyDecl>(ProtocolPtrTy); -    } -    PIDecl->makeitReadWriteAttribute(); -    if (Attributes & ObjCDeclSpec::DQ_PR_retain) -      PIDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_retain); -    if (Attributes & ObjCDeclSpec::DQ_PR_strong) -      PIDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_strong); -    if (Attributes & ObjCDeclSpec::DQ_PR_copy) -      PIDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_copy); -    PIDecl->setSetterName(SetterSel); -  } else { -    // Tailor the diagnostics for the common case where a readwrite -    // property is declared both in the @interface and the continuation. -    // This is a common error where the user often intended the original -    // declaration to be readonly. -    unsigned diag = -      (Attributes & ObjCDeclSpec::DQ_PR_readwrite) && -      (PIkind & ObjCPropertyDecl::OBJC_PR_readwrite) -      ? diag::err_use_continuation_class_redeclaration_readwrite -      : diag::err_use_continuation_class; -    Diag(AtLoc, diag) -      << CCPrimary->getDeclName(); -    Diag(PIDecl->getLocation(), diag::note_property_declare); -    return nullptr; -  } -  *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); +   +  // Check that atomicity of property in class extension matches the previous +  // declaration. +  checkAtomicPropertyMismatch(*this, PIDecl, PDecl, true); + +  // Make sure getter/setter are appropriately synthesized. +  ProcessPropertyDecl(PDecl);    return PDecl;  } @@ -525,7 +559,6 @@ ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S,                                             FieldDeclarator &FD,                                             Selector GetterSel,                                             Selector SetterSel, -                                           const bool isAssign,                                             const bool isReadWrite,                                             const unsigned Attributes,                                             const unsigned AttributesAsWritten, @@ -535,10 +568,23 @@ ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S,                                             DeclContext *lexicalDC){    IdentifierInfo *PropertyId = FD.D.getIdentifier(); -  // Issue a warning if property is 'assign' as default and its object, which is -  // gc'able conforms to NSCopying protocol +  // Property defaults to 'assign' if it is readwrite, unless this is ARC +  // and the type is retainable. +  bool isAssign; +  if (Attributes & (ObjCDeclSpec::DQ_PR_assign | +                    ObjCDeclSpec::DQ_PR_unsafe_unretained)) { +    isAssign = true; +  } else if (getOwnershipRule(Attributes) || !isReadWrite) { +    isAssign = false; +  } else { +    isAssign = (!getLangOpts().ObjCAutoRefCount || +                !T->isObjCRetainableType()); +  } + +  // Issue a warning if property is 'assign' as default and its +  // object, which is gc'able conforms to NSCopying protocol    if (getLangOpts().getGC() != LangOptions::NonGC && -      isAssign && !(Attributes & ObjCDeclSpec::DQ_PR_assign)) +      isAssign && !(Attributes & ObjCDeclSpec::DQ_PR_assign)) {      if (const ObjCObjectPointerType *ObjPtrTy =            T->getAs<ObjCObjectPointerType>()) {        ObjCInterfaceDecl *IDecl = ObjPtrTy->getObjectType()->getInterface(); @@ -548,6 +594,7 @@ ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S,            if (IDecl->ClassImplementsProtocol(PNSCopying, true))              Diag(AtLoc, diag::warn_implements_nscopying) << PropertyId;      } +  }    if (T->isObjCObjectType()) {      SourceLocation StarLoc = TInfo->getTypeLoc().getLocEnd(); @@ -663,8 +710,10 @@ static void checkARCPropertyImpl(Sema &S, SourceLocation propertyImplLoc,    // We're fine if they match.    if (propertyLifetime == ivarLifetime) return; -  // These aren't valid lifetimes for object ivars;  don't diagnose twice. -  if (ivarLifetime == Qualifiers::OCL_None || +  // None isn't a valid lifetime for an object ivar in ARC, and +  // __autoreleasing is never valid; don't diagnose twice. +  if ((ivarLifetime == Qualifiers::OCL_None && +       S.getLangOpts().ObjCAutoRefCount) ||        ivarLifetime == Qualifiers::OCL_Autoreleasing)      return; @@ -797,6 +846,38 @@ DiagnosePropertyMismatchDeclInProtocols(Sema &S, SourceLocation AtLoc,      S.Diag(AtLoc, diag::note_property_synthesize);  } +/// Determine whether any storage attributes were written on the property. +static bool hasWrittenStorageAttribute(ObjCPropertyDecl *Prop) { +  if (Prop->getPropertyAttributesAsWritten() & OwnershipMask) return true; + +  // If this is a readwrite property in a class extension that refines +  // a readonly property in the original class definition, check it as +  // well. + +  // If it's a readonly property, we're not interested. +  if (Prop->isReadOnly()) return false; + +  // Is it declared in an extension? +  auto Category = dyn_cast<ObjCCategoryDecl>(Prop->getDeclContext()); +  if (!Category || !Category->IsClassExtension()) return false; + +  // Find the corresponding property in the primary class definition. +  auto OrigClass = Category->getClassInterface(); +  for (auto Found : OrigClass->lookup(Prop->getDeclName())) { +    if (ObjCPropertyDecl *OrigProp = dyn_cast<ObjCPropertyDecl>(Found)) +      return OrigProp->getPropertyAttributesAsWritten() & OwnershipMask; +  } + +  // Look through all of the protocols. +  for (const auto *Proto : OrigClass->all_referenced_protocols()) { +    if (ObjCPropertyDecl *OrigProp = +          Proto->FindPropertyDeclaration(Prop->getIdentifier())) +      return OrigProp->getPropertyAttributesAsWritten() & OwnershipMask; +  } + +  return false; +} +  /// ActOnPropertyImplDecl - This routine performs semantic checks and  /// builds the AST node for a property implementation declaration; declared  /// as \@synthesize or \@dynamic. @@ -953,18 +1034,49 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,      ObjCPropertyDecl::PropertyAttributeKind kind         = property->getPropertyAttributes(); -    // Add GC __weak to the ivar type if the property is weak. -    if ((kind & ObjCPropertyDecl::OBJC_PR_weak) &&  -        getLangOpts().getGC() != LangOptions::NonGC) { -      assert(!getLangOpts().ObjCAutoRefCount); -      if (PropertyIvarType.isObjCGCStrong()) { -        Diag(PropertyDiagLoc, diag::err_gc_weak_property_strong_type); -        Diag(property->getLocation(), diag::note_property_declare); +    bool isARCWeak = false; +    if (kind & ObjCPropertyDecl::OBJC_PR_weak) { +      // Add GC __weak to the ivar type if the property is weak. +      if (getLangOpts().getGC() != LangOptions::NonGC) { +        assert(!getLangOpts().ObjCAutoRefCount); +        if (PropertyIvarType.isObjCGCStrong()) { +          Diag(PropertyDiagLoc, diag::err_gc_weak_property_strong_type); +          Diag(property->getLocation(), diag::note_property_declare); +        } else { +          PropertyIvarType = +            Context.getObjCGCQualType(PropertyIvarType, Qualifiers::Weak); +        } + +      // Otherwise, check whether ARC __weak is enabled and works with +      // the property type.        } else { -        PropertyIvarType = -          Context.getObjCGCQualType(PropertyIvarType, Qualifiers::Weak); +        if (!getLangOpts().ObjCWeak) { +          // Only complain here when synthesizing an ivar. +          if (!Ivar) { +            Diag(PropertyDiagLoc, +                 getLangOpts().ObjCWeakRuntime +                   ? diag::err_synthesizing_arc_weak_property_disabled +                   : diag::err_synthesizing_arc_weak_property_no_runtime); +            Diag(property->getLocation(), diag::note_property_declare); +          } +          CompleteTypeErr = true; // suppress later diagnostics about the ivar +        } else { +          isARCWeak = true; +          if (const ObjCObjectPointerType *ObjT = +                PropertyIvarType->getAs<ObjCObjectPointerType>()) { +            const ObjCInterfaceDecl *ObjI = ObjT->getInterfaceDecl(); +            if (ObjI && ObjI->isArcWeakrefUnavailable()) { +              Diag(property->getLocation(), +                   diag::err_arc_weak_unavailable_property) +                << PropertyIvarType; +              Diag(ClassImpDecl->getLocation(), diag::note_implemented_by_class) +                << ClassImpDecl->getName(); +            } +          } +        }        }      } +      if (AtLoc.isInvalid()) {        // Check when default synthesizing a property that there is         // an ivar matching property name and issue warning; since this @@ -987,13 +1099,13 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,      if (!Ivar) {        // In ARC, give the ivar a lifetime qualifier based on the        // property attributes. -      if (getLangOpts().ObjCAutoRefCount && +      if ((getLangOpts().ObjCAutoRefCount || isARCWeak) &&            !PropertyIvarType.getObjCLifetime() &&            PropertyIvarType->isObjCRetainableType()) {          // It's an error if we have to do this and the user didn't          // explicitly write an ownership attribute on the property. -        if (!property->hasWrittenStorageAttribute() && +        if (!hasWrittenStorageAttribute(property) &&              !(kind & ObjCPropertyDecl::OBJC_PR_strong)) {            Diag(PropertyDiagLoc,                 diag::err_arc_objc_property_default_assign_on_object); @@ -1002,24 +1114,6 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,            Qualifiers::ObjCLifetime lifetime =              getImpliedARCOwnership(kind, PropertyIvarType);            assert(lifetime && "no lifetime for property?"); -          if (lifetime == Qualifiers::OCL_Weak) { -            bool err = false; -            if (const ObjCObjectPointerType *ObjT = -                PropertyIvarType->getAs<ObjCObjectPointerType>()) { -              const ObjCInterfaceDecl *ObjI = ObjT->getInterfaceDecl(); -              if (ObjI && ObjI->isArcWeakrefUnavailable()) { -                Diag(property->getLocation(), -                     diag::err_arc_weak_unavailable_property) << PropertyIvarType; -                Diag(ClassImpDecl->getLocation(), diag::note_implemented_by_class) -                  << ClassImpDecl->getName(); -                err = true; -              } -            } -            if (!err && !getLangOpts().ObjCARCWeak) { -              Diag(PropertyDiagLoc, diag::err_arc_weak_no_runtime); -              Diag(property->getLocation(), diag::note_property_declare); -            } -          }            Qualifiers qs;            qs.addObjCLifetime(lifetime); @@ -1027,13 +1121,6 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,          }        } -      if (kind & ObjCPropertyDecl::OBJC_PR_weak && -          !getLangOpts().ObjCAutoRefCount && -          getLangOpts().getGC() == LangOptions::NonGC) { -        Diag(PropertyDiagLoc, diag::error_synthesize_weak_non_arc_or_gc); -        Diag(property->getLocation(), diag::note_property_declare); -      } -        Ivar = ObjCIvarDecl::Create(Context, ClassImpDecl,                                    PropertyIvarLoc,PropertyIvarLoc, PropertyIvar,                                    PropertyIvarType, /*Dinfo=*/nullptr, @@ -1121,7 +1208,8 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,          // Fall thru - see previous comment        }      } -    if (getLangOpts().ObjCAutoRefCount) +    if (getLangOpts().ObjCAutoRefCount || isARCWeak || +        Ivar->getType().getObjCLifetime())        checkARCPropertyImpl(*this, PropertyLoc, property, Ivar);    } else if (PropertyIvar)      // @dynamic @@ -1349,12 +1437,10 @@ Sema::DiagnosePropertyMismatch(ObjCPropertyDecl *Property,      }    } -  if ((CAttr & ObjCPropertyDecl::OBJC_PR_nonatomic) -      != (SAttr & ObjCPropertyDecl::OBJC_PR_nonatomic)) { -    Diag(Property->getLocation(), diag::warn_property_attribute) -      << Property->getDeclName() << "atomic" << inheritedName; -    Diag(SuperProperty->getLocation(), diag::note_property_declare); -  } +  // Check for nonatomic; note that nonatomic is effectively +  // meaningless for readonly properties, so don't diagnose if the +  // atomic property is 'readonly'. +  checkAtomicPropertyMismatch(*this, SuperProperty, Property, false);    if (Property->getSetterName() != SuperProperty->getSetterName()) {      Diag(Property->getLocation(), diag::warn_property_attribute)        << Property->getDeclName() << "setter" << inheritedName; @@ -1395,12 +1481,11 @@ bool Sema::DiagnosePropertyAccessorMismatch(ObjCPropertyDecl *property,    QualType PropertyIvarType = property->getType().getNonReferenceType();    bool compat = Context.hasSameType(PropertyIvarType, GetterType);    if (!compat) { -    if (isa<ObjCObjectPointerType>(PropertyIvarType) &&  -        isa<ObjCObjectPointerType>(GetterType)) -      compat = -        Context.canAssignObjCInterfaces( -                                      GetterType->getAs<ObjCObjectPointerType>(), -                                      PropertyIvarType->getAs<ObjCObjectPointerType>()); +    const ObjCObjectPointerType *propertyObjCPtr = nullptr; +    const ObjCObjectPointerType *getterObjCPtr = nullptr; +    if ((propertyObjCPtr = PropertyIvarType->getAs<ObjCObjectPointerType>()) &&  +        (getterObjCPtr = GetterType->getAs<ObjCObjectPointerType>())) +      compat = Context.canAssignObjCInterfaces(getterObjCPtr, propertyObjCPtr);      else if (CheckAssignmentConstraints(Loc, GetterType, PropertyIvarType)                 != Compatible) {            Diag(Loc, diag::error_property_accessor_type) @@ -1438,6 +1523,11 @@ static void CollectImmediateProperties(ObjCContainerDecl *CDecl,    if (ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl)) {      for (auto *Prop : IDecl->properties())        PropMap[Prop->getIdentifier()] = Prop; + +    // Collect the properties from visible extensions. +    for (auto *Ext : IDecl->visible_extensions()) +      CollectImmediateProperties(Ext, PropMap, SuperPropMap, IncludeProtocols); +      if (IncludeProtocols) {        // Scan through class's protocols.        for (auto *PI : IDecl->all_referenced_protocols()) @@ -1445,9 +1535,8 @@ static void CollectImmediateProperties(ObjCContainerDecl *CDecl,      }    }    if (ObjCCategoryDecl *CATDecl = dyn_cast<ObjCCategoryDecl>(CDecl)) { -    if (!CATDecl->IsClassExtension()) -      for (auto *Prop : CATDecl->properties()) -        PropMap[Prop->getIdentifier()] = Prop; +    for (auto *Prop : CATDecl->properties()) +      PropMap[Prop->getIdentifier()] = Prop;      if (IncludeProtocols) {        // Scan through class's protocols.        for (auto *PI : CATDecl->protocols()) @@ -1507,6 +1596,14 @@ Sema::IvarBacksCurrentMethodAccessor(ObjCInterfaceDecl *IFace,          (Property->getPropertyIvarDecl() == IV))        return true;    } +  // Also look up property declaration in class extension whose one of its +  // accessors is implemented by this method. +  for (const auto *Ext : IFace->known_extensions()) +    for (const auto *Property : Ext->properties()) +      if ((Property->getGetterName() == IMD->getSelector() || +           Property->getSetterName() == IMD->getSelector()) && +          (Property->getPropertyIvarDecl() == IV)) +        return true;    return false;  } @@ -1563,7 +1660,7 @@ void Sema::DefaultSynthesizeProperties(Scope *S, ObjCImplDecl* IMPDecl,          IMPDecl->FindPropertyImplIvarDecl(Prop->getIdentifier())) {        Diag(Prop->getLocation(), diag::warn_no_autosynthesis_shared_ivar_property)          << Prop->getIdentifier(); -      if (!PID->getLocation().isInvalid()) +      if (PID->getLocation().isValid())          Diag(PID->getLocation(), diag::note_property_synthesize);        continue;      } @@ -1791,11 +1888,20 @@ void Sema::diagnoseNullResettableSynthesizedSetters(const ObjCImplDecl *impDecl)  void  Sema::AtomicPropertySetterGetterRules (ObjCImplDecl* IMPDecl, -                                       ObjCContainerDecl* IDecl) { +                                       ObjCInterfaceDecl* IDecl) {    // Rules apply in non-GC mode only    if (getLangOpts().getGC() != LangOptions::NonGC)      return; -  for (const auto *Property : IDecl->properties()) { +  ObjCContainerDecl::PropertyMap PM; +  for (auto *Prop : IDecl->properties()) +    PM[Prop->getIdentifier()] = Prop; +  for (const auto *Ext : IDecl->known_extensions()) +    for (auto *Prop : Ext->properties()) +      PM[Prop->getIdentifier()] = Prop; +     +    for (ObjCContainerDecl::PropertyMap::iterator I = PM.begin(), E = PM.end(); +         I != E; ++I) { +    const ObjCPropertyDecl *Property = I->second;      ObjCMethodDecl *GetterMethod = nullptr;      ObjCMethodDecl *SetterMethod = nullptr;      bool LookedUpGetterSetter = false; @@ -1842,30 +1948,23 @@ Sema::AtomicPropertySetterGetterRules (ObjCImplDecl* IMPDecl,            << Property->getIdentifier() << (GetterMethod != nullptr)            << (SetterMethod != nullptr);          // 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)) { +        if (Property->getLParenLoc().isValid() && +            !(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, "); +          SourceLocation AfterLParen = +            getLocForEndOfToken(Property->getLParenLoc()); +          StringRef NonatomicStr = AttributesAsWritten? "nonatomic, " +                                                      : "nonatomic"; +          Diag(Property->getLocation(), +               diag::note_atomic_property_fixup_suggest) +            << FixItHint::CreateInsertion(AfterLParen, NonatomicStr); +        } else if (Property->getLParenLoc().isInvalid()) { +          //@property id etc. +          SourceLocation startLoc =  +            Property->getTypeSourceInfo()->getTypeLoc().getBeginLoc(); +          Diag(Property->getLocation(), +               diag::note_atomic_property_fixup_suggest) +            << FixItHint::CreateInsertion(startLoc, "(nonatomic) ");          }          else            Diag(MethodLoc, diag::note_atomic_property_fixup_suggest); @@ -1950,10 +2049,16 @@ void Sema::DiagnoseMissingDesignatedInitOverrides(           I = DesignatedInits.begin(), E = DesignatedInits.end(); I != E; ++I) {      const ObjCMethodDecl *MD = *I;      if (!InitSelSet.count(MD->getSelector())) { -      Diag(ImplD->getLocation(), -           diag::warn_objc_implementation_missing_designated_init_override) -        << MD->getSelector(); -      Diag(MD->getLocation(), diag::note_objc_designated_init_marked_here); +      bool Ignore = false; +      if (auto *IMD = IFD->getInstanceMethod(MD->getSelector())) { +        Ignore = IMD->isUnavailable(); +      } +      if (!Ignore) { +        Diag(ImplD->getLocation(), +             diag::warn_objc_implementation_missing_designated_init_override) +          << MD->getSelector(); +        Diag(MD->getLocation(), diag::note_objc_designated_init_marked_here); +      }      }    }  } @@ -1974,20 +2079,28 @@ static void AddPropertyAttrs(Sema &S, ObjCMethodDecl *PropertyMethod,  /// ProcessPropertyDecl - Make sure that any user-defined setter/getter methods  /// have the property type and issue diagnostics if they don't.  /// Also synthesize a getter/setter method if none exist (and update the -/// appropriate lookup tables. FIXME: Should reconsider if adding synthesized -/// methods is the "right" thing to do. -void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property, -                               ObjCContainerDecl *CD, -                               ObjCPropertyDecl *redeclaredProperty, -                               ObjCContainerDecl *lexicalDC) { - +/// appropriate lookup tables. +void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property) {    ObjCMethodDecl *GetterMethod, *SetterMethod; - +  ObjCContainerDecl *CD = cast<ObjCContainerDecl>(property->getDeclContext());    if (CD->isInvalidDecl())      return;    GetterMethod = CD->getInstanceMethod(property->getGetterName()); +  // if setter or getter is not found in class extension, it might be +  // in the primary class. +  if (!GetterMethod) +    if (const ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(CD)) +      if (CatDecl->IsClassExtension()) +        GetterMethod = CatDecl->getClassInterface()-> +                         getInstanceMethod(property->getGetterName()); +            SetterMethod = CD->getInstanceMethod(property->getSetterName()); +  if (!SetterMethod) +    if (const ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(CD)) +      if (CatDecl->IsClassExtension()) +        SetterMethod = CatDecl->getClassInterface()-> +                          getInstanceMethod(property->getSetterName());    DiagnosePropertyAccessorMismatch(property, GetterMethod,                                     property->getLocation()); @@ -2020,9 +2133,7 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property,      // No instance method of same name as property getter name was found.      // Declare a getter method and add it to the list of methods      // for this class. -    SourceLocation Loc = redeclaredProperty ?  -      redeclaredProperty->getLocation() : -      property->getLocation(); +    SourceLocation Loc = property->getLocation();      // If the property is null_resettable, the getter returns nonnull.      QualType resultTy = property->getType(); @@ -2050,10 +2161,6 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property,      AddPropertyAttrs(*this, GetterMethod, property); -    // FIXME: Eventually this shouldn't be needed, as the lexical context -    // and the real context should be the same. -    if (lexicalDC) -      GetterMethod->setLexicalDeclContext(lexicalDC);      if (property->hasAttr<NSReturnsNotRetainedAttr>())        GetterMethod->addAttr(NSReturnsNotRetainedAttr::CreateImplicit(Context,                                                                       Loc)); @@ -2082,9 +2189,7 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property,        // No instance method of same name as property setter name was found.        // Declare a setter method and add it to the list of methods        // for this class. -      SourceLocation Loc = redeclaredProperty ?  -        redeclaredProperty->getLocation() : -        property->getLocation(); +      SourceLocation Loc = property->getLocation();        SetterMethod =          ObjCMethodDecl::Create(Context, Loc, Loc, @@ -2126,10 +2231,6 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property,        AddPropertyAttrs(*this, SetterMethod, property);        CD->addDecl(SetterMethod); -      // FIXME: Eventually this shouldn't be needed, as the lexical context -      // and the real context should be the same. -      if (lexicalDC) -        SetterMethod->setLexicalDeclContext(lexicalDC);        if (const SectionAttr *SA = property->getAttr<SectionAttr>())          SetterMethod->addAttr(              SectionAttr::CreateImplicit(Context, SectionAttr::GNU_section, @@ -2189,15 +2290,6 @@ void Sema::CheckObjCPropertyAttributes(Decl *PDecl,    ObjCPropertyDecl *PropertyDecl = cast<ObjCPropertyDecl>(PDecl);    QualType PropertyTy = PropertyDecl->getType(); -  unsigned PropertyOwnership = getOwnershipRule(Attributes); - -  // 'readonly' property with no obvious lifetime. -  // its life time will be determined by its backing ivar. -  if (getLangOpts().ObjCAutoRefCount && -      Attributes & ObjCDeclSpec::DQ_PR_readonly && -      PropertyTy->isObjCRetainableType() && -      !PropertyOwnership) -    return;    // Check for copy or retain on non-object types.    if ((Attributes & (ObjCDeclSpec::DQ_PR_weak | ObjCDeclSpec::DQ_PR_copy | @@ -2295,13 +2387,6 @@ void Sema::CheckObjCPropertyAttributes(Decl *PDecl,        if (*nullability == NullabilityKind::NonNull)          Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)            << "nonnull" << "weak"; -    } else { -        PropertyTy = -          Context.getAttributedType( -            AttributedType::getNullabilityAttrKind(NullabilityKind::Nullable), -            PropertyTy, PropertyTy); -        TypeSourceInfo *TSInfo = PropertyDecl->getTypeSourceInfo(); -        PropertyDecl->setType(PropertyTy, TSInfo);      }    } @@ -2314,16 +2399,14 @@ void Sema::CheckObjCPropertyAttributes(Decl *PDecl,    // Warn if user supplied no assignment attribute, property is    // readwrite, and this is an object type. -  if (!(Attributes & (ObjCDeclSpec::DQ_PR_assign | ObjCDeclSpec::DQ_PR_copy | -                      ObjCDeclSpec::DQ_PR_unsafe_unretained | -                      ObjCDeclSpec::DQ_PR_retain | ObjCDeclSpec::DQ_PR_strong | -                      ObjCDeclSpec::DQ_PR_weak)) && -      PropertyTy->isObjCObjectPointerType()) { -      if (getLangOpts().ObjCAutoRefCount) -        // With arc,  @property definitions should default to (strong) when  -        // not specified; including when property is 'readonly'. -        PropertyDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_strong); -      else if (!(Attributes & ObjCDeclSpec::DQ_PR_readonly)) { +  if (!getOwnershipRule(Attributes) && PropertyTy->isObjCRetainableType()) { +    if (Attributes & ObjCDeclSpec::DQ_PR_readonly) { +      // do nothing +    } else if (getLangOpts().ObjCAutoRefCount) { +      // With arc, @property definitions should default to strong when  +      // not specified. +      PropertyDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_strong); +    } else if (PropertyTy->isObjCObjectPointerType()) {          bool isAnyClassTy =             (PropertyTy->isObjCClassType() ||              PropertyTy->isObjCQualifiedClassType()); @@ -2342,7 +2425,7 @@ void Sema::CheckObjCPropertyAttributes(Decl *PDecl,            if (getLangOpts().getGC() == LangOptions::NonGC)              Diag(Loc, diag::warn_objc_property_default_assign_on_object);          } -      } +    }      // FIXME: Implement warning dependent on NSCopying being      // implemented. See also:  | 
