r255309 - Objective-C properties: merge attributes when redeclaring 'readonly' as 'readwrite' in an extension.

Douglas Gregor via cfe-commits cfe-commits at lists.llvm.org
Thu Dec 10 15:02:10 PST 2015


Author: dgregor
Date: Thu Dec 10 17:02:09 2015
New Revision: 255309

URL: http://llvm.org/viewvc/llvm-project?rev=255309&view=rev
Log:
Objective-C properties: merge attributes when redeclaring 'readonly' as 'readwrite' in an extension.

r251874 stopped back-patching the AST when an Objective-C 'readonly'
property is redeclared in a class extension as 'readwrite'. However,
it did not properly handle merging of Objective-C property attributes
(e.g., getter name, ownership, atomicity) to the redeclaration,
leading to bad metadata. Merge (and check!) those property attributes
so we get the right metadata and reasonable ASTs. Fixes
rdar://problem/23823989.

Modified:
    cfe/trunk/include/clang/AST/DeclObjC.h
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/lib/Parse/ParseObjc.cpp
    cfe/trunk/lib/Sema/SemaObjCProperty.cpp
    cfe/trunk/test/CodeGenObjC/property-list-in-extension.m
    cfe/trunk/test/SemaObjC/property-3.m
    cfe/trunk/test/SemaObjC/property-atomic-redecl.m

Modified: cfe/trunk/include/clang/AST/DeclObjC.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclObjC.h?rev=255309&r1=255308&r2=255309&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclObjC.h (original)
+++ cfe/trunk/include/clang/AST/DeclObjC.h Thu Dec 10 17:02:09 2015
@@ -2509,17 +2509,14 @@ public:
   void setPropertyAttributes(PropertyAttributeKind PRVal) {
     PropertyAttributes |= PRVal;
   }
+  void overwritePropertyAttributes(unsigned PRVal) {
+    PropertyAttributes = PRVal;
+  }
 
   PropertyAttributeKind getPropertyAttributesAsWritten() const {
     return PropertyAttributeKind(PropertyAttributesAsWritten);
   }
 
-  bool hasWrittenStorageAttribute() const {
-    return PropertyAttributesAsWritten & (OBJC_PR_assign | OBJC_PR_copy |
-        OBJC_PR_unsafe_unretained | OBJC_PR_retain | OBJC_PR_strong |
-        OBJC_PR_weak);
-  }
-
   void setPropertyAttributesAsWritten(PropertyAttributeKind PRVal) {
     PropertyAttributesAsWritten = PRVal;
   }

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=255309&r1=255308&r2=255309&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Thu Dec 10 17:02:09 2015
@@ -930,6 +930,9 @@ def warn_missing_explicit_synthesis : Wa
 def warn_property_getter_owning_mismatch : Warning<
   "property declared as returning non-retained objects"
   "; getter returning retained objects">;
+def warn_property_redecl_getter_mismatch : Warning<
+  "getter name mismatch between property redeclaration (%1) and its original "
+  "declaration (%0)">, InGroup<PropertyAttr>;
 def error_property_setter_ambiguous_use : Error<
   "synthesized properties %0 and %1 both claim setter %2 -"
   " use of this setter will cause unexpected behavior">;

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=255309&r1=255308&r2=255309&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Thu Dec 10 17:02:09 2015
@@ -3057,11 +3057,9 @@ public:
                       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);
@@ -3075,7 +3073,6 @@ public:
                                        FieldDeclarator &FD,
                                        Selector GetterSel,
                                        Selector SetterSel,
-                                       const bool isAssign,
                                        const bool isReadWrite,
                                        const unsigned Attributes,
                                        const unsigned AttributesAsWritten,
@@ -7333,7 +7330,6 @@ public:
                       SourceLocation LParenLoc,
                       FieldDeclarator &FD, ObjCDeclSpec &ODS,
                       Selector GetterSel, Selector SetterSel,
-                      bool *OverridingProperty,
                       tok::ObjCKeywordKind MethodImplKind,
                       DeclContext *lexicalDC = nullptr);
 

Modified: cfe/trunk/lib/Parse/ParseObjc.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseObjc.cpp?rev=255309&r1=255308&r2=255309&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseObjc.cpp (original)
+++ cfe/trunk/lib/Parse/ParseObjc.cpp Thu Dec 10 17:02:09 2015
@@ -633,7 +633,6 @@ ObjCTypeParamList *Parser::parseObjCType
 void Parser::ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey, 
                                         Decl *CDecl) {
   SmallVector<Decl *, 32> allMethods;
-  SmallVector<Decl *, 16> allProperties;
   SmallVector<DeclGroupPtrTy, 8> allTUVariables;
   tok::ObjCKeywordKind MethodImplKind = tok::objc_not_keyword;
 
@@ -789,12 +788,9 @@ void Parser::ParseObjCInterfaceDeclList(
           SetterSel = SelectorTable::constructSetterSelector(
               PP.getIdentifierTable(), PP.getSelectorTable(),
               FD.D.getIdentifier());
-        bool isOverridingProperty = false;
         Decl *Property = Actions.ActOnProperty(
             getCurScope(), AtLoc, LParenLoc, FD, OCDS, GetterSel, SetterSel,
-            &isOverridingProperty, MethodImplKind);
-        if (!isOverridingProperty)
-          allProperties.push_back(Property);
+            MethodImplKind);
 
         FD.complete(Property);
       };

Modified: cfe/trunk/lib/Sema/SemaObjCProperty.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaObjCProperty.cpp?rev=255309&r1=255308&r2=255309&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaObjCProperty.cpp (original)
+++ cfe/trunk/lib/Sema/SemaObjCProperty.cpp Thu Dec 10 17:02:09 2015
@@ -153,13 +153,26 @@ static unsigned deducePropertyOwnershipF
   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) {
-  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);
+  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,
@@ -168,7 +181,6 @@ Decl *Sema::ActOnProperty(Scope *S, Sour
                           ObjCDeclSpec &ODS,
                           Selector GetterSel,
                           Selector SetterSel,
-                          bool *isOverridingProperty,
                           tok::ObjCKeywordKind MethodImplKind,
                           DeclContext *lexicalDC) {
   unsigned Attributes = ODS.getPropertyAttributes();
@@ -182,19 +194,6 @@ Decl *Sema::ActOnProperty(Scope *S, Sour
                       // default is readwrite!
                       !(Attributes & ObjCDeclSpec::DQ_PR_readonly));
 
-  // 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());
-  }
-
   // Proceed with constructing the ObjCPropertyDecls.
   ObjCContainerDecl *ClassDecl = cast<ObjCContainerDecl>(CurContext);
   ObjCPropertyDecl *Res = nullptr;
@@ -202,11 +201,10 @@ Decl *Sema::ActOnProperty(Scope *S, Sour
     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;
     }
@@ -214,7 +212,7 @@ Decl *Sema::ActOnProperty(Scope *S, Sour
 
   if (!Res) {
     Res = CreatePropertyDecl(S, ClassDecl, AtLoc, LParenLoc, FD,
-                             GetterSel, SetterSel, isAssign, isReadWrite,
+                             GetterSel, SetterSel, isReadWrite,
                              Attributes, ODS.getPropertyAttributes(),
                              T, TSI, MethodImplKind);
     if (lexicalDC)
@@ -342,12 +340,15 @@ static bool LocPropertyAttribute( ASTCon
 /// Check for a mismatch in the atomicity of the given properties.
 static void checkAtomicPropertyMismatch(Sema &S,
                                         ObjCPropertyDecl *OldProperty,
-                                        ObjCPropertyDecl *NewProperty) {
+                                        ObjCPropertyDecl *NewProperty,
+                                        bool PropagateAtomicity) {
   // If the atomicity of both matches, we're done.
   bool OldIsAtomic =
-    (OldProperty->getPropertyAttributes() & ObjCDeclSpec::DQ_PR_nonatomic) == 0;
+    (OldProperty->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_nonatomic)
+      == 0;
   bool NewIsAtomic =
-    (NewProperty->getPropertyAttributes() & ObjCDeclSpec::DQ_PR_nonatomic) == 0;
+    (NewProperty->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_nonatomic)
+      == 0;
   if (OldIsAtomic == NewIsAtomic) return;
 
   // Determine whether the given property is readonly and implicitly
@@ -355,18 +356,36 @@ static void checkAtomicPropertyMismatch(
   auto isImplicitlyReadonlyAtomic = [](ObjCPropertyDecl *Property) -> bool {
     // Is it readonly?
     auto Attrs = Property->getPropertyAttributes();
-    if ((Attrs & ObjCDeclSpec::DQ_PR_readonly) == 0) return false;
+    if ((Attrs & ObjCPropertyDecl::OBJC_PR_readonly) == 0) return false;
 
     // Is it nonatomic?
-    if (Attrs & ObjCDeclSpec::DQ_PR_nonatomic) return false;
+    if (Attrs & ObjCPropertyDecl::OBJC_PR_nonatomic) return false;
 
     // Was 'atomic' specified directly?
-    if (Property->getPropertyAttributesAsWritten() & ObjCDeclSpec::DQ_PR_atomic)
+    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)) ||
@@ -393,11 +412,9 @@ Sema::HandlePropertyInClassExtension(Sco
                                      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) {
@@ -411,7 +428,6 @@ Sema::HandlePropertyInClassExtension(Sco
   // already declared.
   if (!CCPrimary) {
     Diag(CDecl->getLocation(), diag::err_continuation_class);
-    *isOverridingProperty = true;
     return nullptr;
   }
 
@@ -427,11 +443,73 @@ Sema::HandlePropertyInClassExtension(Sco
     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,
-                                               isAssign, isReadWrite,
+                                               isReadWrite,
                                                Attributes, AttributesAsWritten,
                                                T, TSI, MethodImplKind, DC);
 
@@ -464,57 +542,10 @@ Sema::HandlePropertyInClassExtension(Sco
       return nullptr;
     }
   }
-
-  // A readonly property declared in the primary class can be refined
-  // by adding a readwrite property within an extension.
-  // Anything else is an error.
-  unsigned PIkind = PIDecl->getPropertyAttributesAsWritten();
-  if (!(isReadWrite && (PIkind & ObjCPropertyDecl::OBJC_PR_readonly))) {
-    // 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;
-  }
-
-  PIkind &= ~ObjCPropertyDecl::OBJC_PR_readonly;
-  PIkind |= ObjCPropertyDecl::OBJC_PR_readwrite;
-  PIkind |= deducePropertyOwnershipFromType(*this, 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);
-          }
-      }
-  }
   
   // Check that atomicity of property in class extension matches the previous
   // declaration.
-  checkAtomicPropertyMismatch(*this, PIDecl, PDecl);
-
-  *isOverridingProperty = true;
+  checkAtomicPropertyMismatch(*this, PIDecl, PDecl, true);
 
   // Make sure getter/setter are appropriately synthesized.
   ProcessPropertyDecl(PDecl);
@@ -528,7 +559,6 @@ ObjCPropertyDecl *Sema::CreatePropertyDe
                                            FieldDeclarator &FD,
                                            Selector GetterSel,
                                            Selector SetterSel,
-                                           const bool isAssign,
                                            const bool isReadWrite,
                                            const unsigned Attributes,
                                            const unsigned AttributesAsWritten,
@@ -538,10 +568,23 @@ ObjCPropertyDecl *Sema::CreatePropertyDe
                                            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();
@@ -551,6 +594,7 @@ ObjCPropertyDecl *Sema::CreatePropertyDe
           if (IDecl->ClassImplementsProtocol(PNSCopying, true))
             Diag(AtLoc, diag::warn_implements_nscopying) << PropertyId;
     }
+  }
 
   if (T->isObjCObjectType()) {
     SourceLocation StarLoc = TInfo->getTypeLoc().getLocEnd();
@@ -802,6 +846,31 @@ DiagnosePropertyMismatchDeclInProtocols(
     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;
+  }
+
+  return false;
+}
+
 /// ActOnPropertyImplDecl - This routine performs semantic checks and
 /// builds the AST node for a property implementation declaration; declared
 /// as \@synthesize or \@dynamic.
@@ -1029,7 +1098,7 @@ Decl *Sema::ActOnPropertyImplDecl(Scope
 
         // 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);
@@ -1364,7 +1433,7 @@ Sema::DiagnosePropertyMismatch(ObjCPrope
   // 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);
+  checkAtomicPropertyMismatch(*this, SuperProperty, Property, false);
   if (Property->getSetterName() != SuperProperty->getSetterName()) {
     Diag(Property->getLocation(), diag::warn_property_attribute)
       << Property->getDeclName() << "setter" << inheritedName;

Modified: cfe/trunk/test/CodeGenObjC/property-list-in-extension.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjC/property-list-in-extension.m?rev=255309&r1=255308&r2=255309&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenObjC/property-list-in-extension.m (original)
+++ cfe/trunk/test/CodeGenObjC/property-list-in-extension.m Thu Dec 10 17:02:09 2015
@@ -1,9 +1,10 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-weak -fobjc-runtime-has-weak -emit-llvm %s -o - | FileCheck %s
 
 // Checks metadata for properties in a few cases.
 
 
 // Property from a class extension:
+__attribute__((objc_root_class))
 @interface Foo
 @end
 
@@ -20,12 +21,17 @@
 // CHECK: @"\01l_OBJC_$_PROP_LIST_Foo" = private global { i32, i32, [1 x %struct._prop_t] }
 
 // Readonly property in interface made readwrite in a category:
+__attribute__((objc_root_class))
 @interface FooRO
 @property (readonly) int evolvingprop;
+ at property (nonatomic,readonly,getter=isBooleanProp) int booleanProp;
+ at property (nonatomic,readonly,weak) Foo *weakProp;
 @end
 
 @interface FooRO ()
 @property int evolvingprop;
+ at property int booleanProp;
+ at property Foo *weakProp;
 @end
 
 @implementation FooRO
@@ -34,6 +40,8 @@
 // Metadata for _evolvingprop should be present, and PROP_LIST for FooRO should
 // still have only one entry, and the one entry should point to the version of
 // the property with a getter and setter.
-// CHECK: [[getter:@OBJC_PROP_NAME_ATTR[^ ]+]] = private global [13 x i8] c"evolvingprop\00"
-// CHECK: [[setter:@OBJC_PROP_NAME_ATTR[^ ]+]] = private global [18 x i8] c"Ti,V_evolvingprop\00",
-// CHECK: @"\01l_OBJC_$_PROP_LIST_FooRO" = private global { i32, i32, [1 x %struct._prop_t] }{{.*}}[[getter]]{{.*}}[[setter]]
+// CHECK: [[evolvinggetter:@OBJC_PROP_NAME_ATTR[^ ]+]] = private global [13 x i8] c"evolvingprop\00"
+// CHECK: [[evolvingsetter:@OBJC_PROP_NAME_ATTR[^ ]+]] = private global [18 x i8] c"Ti,V_evolvingprop\00",
+// CHECK: [[booleanmetadata:@OBJC_PROP_NAME_ATTR[^ ]+]] = private global [34 x i8] c"Ti,N,GisBooleanProp,V_booleanProp\00"
+// CHECK: [[weakmetadata:@OBJC_PROP_NAME_ATTR[^ ]+]] = private global [23 x i8] c"T@\22Foo\22,W,N,V_weakProp\00"
+// CHECK: @"\01l_OBJC_$_PROP_LIST_FooRO" = private global { i32, i32, [3 x %struct._prop_t] }{{.*}}[[evolvinggetter]]{{.*}}[[evolvingsetter]]{{.*}}[[booleanmetadata]]

Modified: cfe/trunk/test/SemaObjC/property-3.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/property-3.m?rev=255309&r1=255308&r2=255309&view=diff
==============================================================================
--- cfe/trunk/test/SemaObjC/property-3.m (original)
+++ cfe/trunk/test/SemaObjC/property-3.m Thu Dec 10 17:02:09 2015
@@ -31,3 +31,12 @@ typedef signed char BOOL;
 @property (nonatomic, assign) BOOL allowReminders;
 @property (nonatomic, assign) BOOL allowNonatomicProperty; // expected-warning {{'atomic' attribute on property 'allowNonatomicProperty' does not match the property inherited from 'EKProtocolCalendar'}}
 @end
+
+__attribute__((objc_root_class))
+ at interface A
+ at property (nonatomic, readonly, getter=isAvailable) int available; // expected-note{{property declared here}}
+ at end
+
+ at interface A ()
+ at property (nonatomic, assign, getter=wasAvailable) int available; // expected-warning{{getter name mismatch between property redeclaration ('wasAvailable') and its original declaration ('isAvailable')}}
+ at end

Modified: cfe/trunk/test/SemaObjC/property-atomic-redecl.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/property-atomic-redecl.m?rev=255309&r1=255308&r2=255309&view=diff
==============================================================================
--- cfe/trunk/test/SemaObjC/property-atomic-redecl.m (original)
+++ cfe/trunk/test/SemaObjC/property-atomic-redecl.m Thu Dec 10 17:02:09 2015
@@ -22,15 +22,15 @@
 @end
 
 @interface AtomicInheritanceSub2 : AtomicInheritanceSuper2
- at property (nonatomic, readwrite, retain) A *property; // FIXME: should be okay
+ at property (nonatomic, readwrite, retain) A *property;
 @end
 
 @interface ReadonlyAtomic
- at property (readonly, nonatomic) A *property; // expected-note{{property declared here}}
+ at property (readonly, nonatomic) A *property;
 @end
 
 @interface ReadonlyAtomic ()
- at property (readwrite) A *property; // expected-warning{{'atomic' attribute on property 'property' does not match the property inherited from 'ReadonlyAtomic'}}
+ at property (readwrite) A *property;
 @end
 
 // Readonly, atomic public redeclaration of property in subclass.




More information about the cfe-commits mailing list