}
+/// 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,
// 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;
}
}
- 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;
--- /dev/null
+// 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
+