]> granicus.if.org Git - clang/commitdiff
Objective-C properties: loosen 'atomic' checking for readonly properties.
authorDouglas Gregor <dgregor@apple.com>
Wed, 9 Dec 2015 22:57:32 +0000 (22:57 +0000)
committerDouglas Gregor <dgregor@apple.com>
Wed, 9 Dec 2015 22:57:32 +0000 (22:57 +0000)
r251874 reworked the way we handle properties declared within
Objective-C class extensions, which had the effective of tightening up
property checking in a number of places. In this particular class of
cases, we end up complaining about "atomic" mismatches between an
implicitly-atomic, readonly property and a nonatomic, readwrite
property, which doesn't make sense because "atomic" is essentially
irrelevant to readonly properties.

Therefore, suppress this diagnostic when the readonly property is
implicitly atomic. Fixes rdar://problem/23803109.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@255174 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Sema/SemaObjCProperty.cpp
test/SemaObjC/property-3.m
test/SemaObjC/property-atomic-redecl.m [new file with mode: 0644]
test/SemaObjC/property-in-class-extension-1.m

index e204936b500721c2de721cffb8268d611985f27b..0beb336092665d7b1d86988f9a72835e4e0f20f3 100644 (file)
@@ -339,6 +339,54 @@ static bool LocPropertyAttribute( ASTContext &Context, const char *attrName,
   
 }
 
+/// Check for a mismatch in the atomicity of the given properties.
+static void checkAtomicPropertyMismatch(Sema &S,
+                                        ObjCPropertyDecl *OldProperty,
+                                        ObjCPropertyDecl *NewProperty) {
+  // If the atomicity of both matches, we're done.
+  bool OldIsAtomic =
+    (OldProperty->getPropertyAttributes() & ObjCDeclSpec::DQ_PR_nonatomic) == 0;
+  bool NewIsAtomic =
+    (NewProperty->getPropertyAttributes() & ObjCDeclSpec::DQ_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 & ObjCDeclSpec::DQ_PR_readonly) == 0) return false;
+
+    // Is it nonatomic?
+    if (Attrs & ObjCDeclSpec::DQ_PR_nonatomic) return false;
+
+    // Was 'atomic' specified directly?
+    if (Property->getPropertyAttributesAsWritten() & ObjCDeclSpec::DQ_PR_atomic)
+      return false;
+
+    return true;
+  };
+
+  // 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 *
 Sema::HandlePropertyInClassExtension(Scope *S,
                                      SourceLocation AtLoc,
@@ -464,20 +512,7 @@ Sema::HandlePropertyInClassExtension(Scope *S,
   
   // Check that atomicity of property in class extension matches the previous
   // declaration.
-  unsigned PDeclAtomicity =
-    PDecl->getPropertyAttributes() & (ObjCDeclSpec::DQ_PR_atomic | ObjCDeclSpec::DQ_PR_nonatomic);
-  unsigned PIDeclAtomicity =
-    PIDecl->getPropertyAttributes() & (ObjCDeclSpec::DQ_PR_atomic | ObjCDeclSpec::DQ_PR_nonatomic);
-  if (PDeclAtomicity != PIDeclAtomicity) {
-    bool PDeclAtomic = (!PDeclAtomicity || PDeclAtomicity & ObjCDeclSpec::DQ_PR_atomic);
-    bool PIDeclAtomic = (!PIDeclAtomicity || PIDeclAtomicity & ObjCDeclSpec::DQ_PR_atomic);
-    if (PDeclAtomic != PIDeclAtomic) {
-      Diag(PDecl->getLocation(), diag::warn_property_attribute)
-        << PDecl->getDeclName() << "atomic"
-        << cast<ObjCContainerDecl>(PIDecl->getDeclContext())->getName();
-      Diag(PIDecl->getLocation(), diag::note_property_declare);
-    }
-  }
+  checkAtomicPropertyMismatch(*this, PIDecl, PDecl);
 
   *isOverridingProperty = true;
 
@@ -1326,12 +1361,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);
   if (Property->getSetterName() != SuperProperty->getSetterName()) {
     Diag(Property->getLocation(), diag::warn_property_attribute)
       << Property->getDeclName() << "setter" << inheritedName;
index 7c0ba579ee487b9f586b650a963fc6eb62e80afc..3f82bcc3b7cd5e94960ecb5eee9f49969f4a3bb7 100644 (file)
@@ -29,5 +29,5 @@ typedef signed char BOOL;
 
 @interface EKCalendar ()  <EKProtocolMutableCalendar>
 @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}}
+@property (nonatomic, assign) BOOL allowNonatomicProperty; // expected-warning {{'atomic' attribute on property 'allowNonatomicProperty' does not match the property inherited from 'EKProtocolCalendar'}}
 @end
diff --git a/test/SemaObjC/property-atomic-redecl.m b/test/SemaObjC/property-atomic-redecl.m
new file mode 100644 (file)
index 0000000..8fd7780
--- /dev/null
@@ -0,0 +1,57 @@
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -fsyntax-only -verify %s
+
+@interface A
+@end
+
+// Readonly, atomic public redeclaration of property in subclass.
+@interface AtomicInheritanceSuper
+@property (readonly) A *property;
+@end
+
+@interface AtomicInheritanceSuper()
+@property (nonatomic,readwrite,retain) A *property;
+@end
+
+@interface AtomicInheritanceSub : AtomicInheritanceSuper
+@property (readonly) A *property;
+@end
+
+// Readonly, atomic public redeclaration of property in subclass.
+@interface AtomicInheritanceSuper2
+@property (readonly) A *property;
+@end
+
+@interface AtomicInheritanceSub2 : AtomicInheritanceSuper2
+@property (nonatomic, readwrite, retain) A *property; // FIXME: should be okay
+@end
+
+@interface ReadonlyAtomic
+@property (readonly, nonatomic) A *property; // expected-note{{property declared here}}
+@end
+
+@interface ReadonlyAtomic ()
+@property (readwrite) A *property; // expected-warning{{'atomic' attribute on property 'property' does not match the property inherited from 'ReadonlyAtomic'}}
+@end
+
+// Readonly, atomic public redeclaration of property in subclass.
+@interface AtomicInheritanceSuper3
+@property (readonly,atomic) A *property; // expected-note{{property declared here}}
+@end
+
+@interface AtomicInheritanceSuper3()
+@property (nonatomic,readwrite,retain) A *property; // expected-warning{{'atomic' attribute on property 'property' does not match the property inherited from 'AtomicInheritanceSuper3'}}
+@end
+
+@interface AtomicInheritanceSub3 : AtomicInheritanceSuper3
+@property (readonly) A *property;
+@end
+
+// Readonly, atomic public redeclaration of property in subclass.
+@interface AtomicInheritanceSuper4
+@property (readonly, atomic) A *property; // expected-note{{property declared here}}
+@end
+
+@interface AtomicInheritanceSub4 : AtomicInheritanceSuper4
+@property (nonatomic, readwrite, retain) A *property; // expected-warning{{atomic' attribute on property 'property' does not match the property inherited from 'AtomicInheritanceSuper4'}}
+@end
+
index b25639cf06247f987bdc99c6d73f59b81f85282d..67b57e5faec5b1925fc1686dd1ec474d0bc39e35 100644 (file)
@@ -58,6 +58,6 @@
 @property (atomic, nonatomic, readonly, readwrite) float propertyName; // expected-error {{property attributes 'readonly' and 'readwrite' are mutually exclusive}} \
                // expected-error {{property attributes 'atomic' and 'nonatomic' are mutually exclusive}}
 
-@property (atomic, readwrite) float propertyName2; // expected-warning {{'atomic' attribute on property 'propertyName2' does not match the property inherited from radar12214070}}
+@property (atomic, readwrite) float propertyName2; // expected-warning {{'atomic' attribute on property 'propertyName2' does not match the property inherited from 'radar12214070'}}
 @end