aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/Sema/Sema.h6
-rw-r--r--lib/Sema/SemaDeclObjC.cpp85
2 files changed, 82 insertions, 9 deletions
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 4fbd735113..ef5954b629 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -723,6 +723,12 @@ public:
unsigned NumProtocols,
llvm::SmallVectorImpl<DeclTy *> &Protocols);
+ /// Ensure attributes are consistent with type.
+ /// \param [in, out] Attributes The attributes to check; they will
+ /// be modified to be consistent with \arg PropertyTy.
+ void CheckObjCPropertyAttributes(QualType PropertyTy,
+ SourceLocation Loc,
+ unsigned &Attributes);
void DiagnosePropertyMismatch(ObjCPropertyDecl *Property,
ObjCPropertyDecl *SuperProperty,
const char *Name);
diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp
index 240d760b75..dbb3cf22ad 100644
--- a/lib/Sema/SemaDeclObjC.cpp
+++ b/lib/Sema/SemaDeclObjC.cpp
@@ -1038,6 +1038,68 @@ Sema::DeclTy *Sema::ActOnMethodDeclaration(
return ObjCMethod;
}
+void Sema::CheckObjCPropertyAttributes(QualType PropertyTy,
+ SourceLocation Loc,
+ unsigned &Attributes) {
+ // FIXME: Improve the reported location.
+
+ // readonly and readwrite conflict.
+ if ((Attributes & ObjCDeclSpec::DQ_PR_readonly) &&
+ (Attributes & ObjCDeclSpec::DQ_PR_readwrite)) {
+ Diag(Loc, diag::err_objc_property_attr_mutually_exclusive,
+ "readonly", "readwrite");
+ Attributes ^= ObjCDeclSpec::DQ_PR_readonly;
+ }
+
+ // Check for copy or retain on non-object types.
+ if ((Attributes & (ObjCDeclSpec::DQ_PR_copy | ObjCDeclSpec::DQ_PR_retain)) &&
+ !Context.isObjCObjectPointerType(PropertyTy)) {
+ Diag(Loc, diag::err_objc_property_requires_object,
+ Attributes & ObjCDeclSpec::DQ_PR_copy ? "copy" : "retain");
+ Attributes &= ~(ObjCDeclSpec::DQ_PR_copy | ObjCDeclSpec::DQ_PR_retain);
+ }
+
+ // Check for more than one of { assign, copy, retain }.
+ if (Attributes & ObjCDeclSpec::DQ_PR_assign) {
+ if (Attributes & ObjCDeclSpec::DQ_PR_copy) {
+ Diag(Loc, diag::err_objc_property_attr_mutually_exclusive,
+ "assign", "copy");
+ Attributes ^= ObjCDeclSpec::DQ_PR_copy;
+ }
+ if (Attributes & ObjCDeclSpec::DQ_PR_retain) {
+ Diag(Loc, diag::err_objc_property_attr_mutually_exclusive,
+ "assign", "retain");
+ Attributes ^= ObjCDeclSpec::DQ_PR_retain;
+ }
+ } else if (Attributes & ObjCDeclSpec::DQ_PR_copy) {
+ if (Attributes & ObjCDeclSpec::DQ_PR_retain) {
+ Diag(Loc, diag::err_objc_property_attr_mutually_exclusive,
+ "copy", "retain");
+ Attributes ^= ObjCDeclSpec::DQ_PR_retain;
+ }
+ }
+
+ // 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_retain)) &&
+ !(Attributes & ObjCDeclSpec::DQ_PR_readonly) &&
+ Context.isObjCObjectPointerType(PropertyTy)) {
+ // Skip this warning in gc-only mode.
+ if (getLangOptions().getGCMode() != LangOptions::GCOnly)
+ Diag(Loc, diag::warn_objc_property_no_assignment_attribute);
+
+ // If non-gc code warn that this is likely inappropriate.
+ if (getLangOptions().getGCMode() == LangOptions::NonGC)
+ Diag(Loc, diag::warn_objc_property_default_assign_on_object);
+
+ // FIXME: Implement warning dependent on NSCopying being
+ // implemented. See also:
+ // <rdar://5168496&4855821&5607453&5096644&4947311&5698469&4947014&5168496>
+ // (please trim this list while you are at it).
+ }
+}
+
Sema::DeclTy *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
FieldDeclarator &FD,
ObjCDeclSpec &ODS,
@@ -1045,6 +1107,11 @@ Sema::DeclTy *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
Selector SetterSel,
tok::ObjCKeywordKind MethodImplKind) {
QualType T = GetTypeForDeclarator(FD.D, S);
+ unsigned Attributes = ODS.getPropertyAttributes();
+
+ // May modify Attributes.
+ CheckObjCPropertyAttributes(T, AtLoc, Attributes);
+
ObjCPropertyDecl *PDecl = ObjCPropertyDecl::Create(Context, AtLoc,
FD.D.getIdentifier(), T);
// Regardless of setter/getter attribute, we save the default getter/setter
@@ -1052,28 +1119,28 @@ Sema::DeclTy *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
PDecl->setGetterName(GetterSel);
PDecl->setSetterName(SetterSel);
- if (ODS.getPropertyAttributes() & ObjCDeclSpec::DQ_PR_readonly)
+ if (Attributes & ObjCDeclSpec::DQ_PR_readonly)
PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_readonly);
- if (ODS.getPropertyAttributes() & ObjCDeclSpec::DQ_PR_getter)
+ if (Attributes & ObjCDeclSpec::DQ_PR_getter)
PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_getter);
- if (ODS.getPropertyAttributes() & ObjCDeclSpec::DQ_PR_setter)
+ if (Attributes & ObjCDeclSpec::DQ_PR_setter)
PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_setter);
- if (ODS.getPropertyAttributes() & ObjCDeclSpec::DQ_PR_assign)
+ if (Attributes & ObjCDeclSpec::DQ_PR_assign)
PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_assign);
- if (ODS.getPropertyAttributes() & ObjCDeclSpec::DQ_PR_readwrite)
+ if (Attributes & ObjCDeclSpec::DQ_PR_readwrite)
PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_readwrite);
- if (ODS.getPropertyAttributes() & ObjCDeclSpec::DQ_PR_retain)
+ if (Attributes & ObjCDeclSpec::DQ_PR_retain)
PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_retain);
- if (ODS.getPropertyAttributes() & ObjCDeclSpec::DQ_PR_copy)
+ if (Attributes & ObjCDeclSpec::DQ_PR_copy)
PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_copy);
- if (ODS.getPropertyAttributes() & ObjCDeclSpec::DQ_PR_nonatomic)
+ if (Attributes & ObjCDeclSpec::DQ_PR_nonatomic)
PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_nonatomic);
if (MethodImplKind == tok::objc_required)
@@ -1116,7 +1183,7 @@ Sema::DeclTy *Sema::ActOnPropertyImplDecl(SourceLocation AtLoc,
// Look for this property declaration in the @implementation's @interface
property = IDecl->FindPropertyDeclaration(PropertyId);
if (!property) {
- Diag(PropertyLoc, diag::error_bad_property_decl, IDecl->getName());
+ Diag(PropertyLoc, diag::error_bad_property_decl, IDecl->getName());
return 0;
}
}