[ARC] Complain about property without storage attribute when @synthesizing it, not at its declaration.

For this sample:

@interface Foo
@property id x;
@end

we get:

t.m:2:1: error: ARC forbids properties of Objective-C objects with unspecified storage attribute
@property  id x;
^
1 error generated.

The error should be imposed on the implementor of the interface, not the user. If the user uses
a header of a non-ARC library whose source code he does not have, we are basically asking him to
go change the header of the library (bad in general), possible overriding how the property is
implemented if he gets confused and says "Oh I'll just add 'copy' then" (even worse).

Second issue is that we don't emit any error for 'readonly' properties, e.g:

@interface Foo
@property (readonly) id x; // no error  here
@end

@implementation Foo
@synthesize x; // no error here too
@end

We should give an error when the implementor is @synthesizing a property which doesn't have
any storage specifier; this is when the explicit specifier is important, because we are
going to create an ivar and we want its ownership to be explicit.

Related improvements:
-OBJC_PR_unsafe_unretained turned out to not fit in ObjCPropertyDecl's bitfields, fix it.
-For properties of extension classes don't drop PropertyAttributesAsWritten values.
-Have PropertyAttributesAsWritten actually only reflect what the user wrote

rdar://9756610.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@134960 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaObjCProperty.cpp b/lib/Sema/SemaObjCProperty.cpp
index b47d627..c830c3e 100644
--- a/lib/Sema/SemaObjCProperty.cpp
+++ b/lib/Sema/SemaObjCProperty.cpp
@@ -200,10 +200,6 @@
       CreatePropertyDecl(S, CCPrimary, AtLoc,
                          FD, GetterSel, SetterSel, isAssign, isReadWrite,
                          Attributes, T, MethodImplKind, DC);
-    // Mark written attribute as having no attribute because
-    // this is not a user-written property declaration in primary
-    // class.
-    PDecl->setPropertyAttributesAsWritten(ObjCPropertyDecl::OBJC_PR_noattr);
 
     // 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.
@@ -336,6 +332,35 @@
   PDecl->setGetterName(GetterSel);
   PDecl->setSetterName(SetterSel);
 
+  unsigned attributesAsWritten = 0;
+  if (Attributes & ObjCDeclSpec::DQ_PR_readonly)
+    attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_readonly;
+  if (Attributes & ObjCDeclSpec::DQ_PR_readwrite)
+    attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_readwrite;
+  if (Attributes & ObjCDeclSpec::DQ_PR_getter)
+    attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_getter;
+  if (Attributes & ObjCDeclSpec::DQ_PR_setter)
+    attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_setter;
+  if (Attributes & ObjCDeclSpec::DQ_PR_assign)
+    attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_assign;
+  if (Attributes & ObjCDeclSpec::DQ_PR_retain)
+    attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_retain;
+  if (Attributes & ObjCDeclSpec::DQ_PR_strong)
+    attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_strong;
+  if (Attributes & ObjCDeclSpec::DQ_PR_weak)
+    attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_weak;
+  if (Attributes & ObjCDeclSpec::DQ_PR_copy)
+    attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_copy;
+  if (Attributes & ObjCDeclSpec::DQ_PR_unsafe_unretained)
+    attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_unsafe_unretained;
+  if (Attributes & ObjCDeclSpec::DQ_PR_nonatomic)
+    attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_nonatomic;
+  if (Attributes & ObjCDeclSpec::DQ_PR_atomic)
+    attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_atomic;
+
+  PDecl->setPropertyAttributesAsWritten(
+                  (ObjCPropertyDecl::PropertyAttributeKind)attributesAsWritten);
+
   if (Attributes & ObjCDeclSpec::DQ_PR_readonly)
     PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_readonly);
 
@@ -371,11 +396,6 @@
   else if (Attributes & ObjCDeclSpec::DQ_PR_atomic)
     PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_atomic);
 
-  // FIXME: Why do PropertyAttributesAsWritten get set from PropertyAttributes,
-  // shouldn't PropertyAttributesAsWritten get set *only* through the attributes
-  // of the ObjCDeclSpec ?
-  PDecl->setPropertyAttributesAsWritten(PDecl->getPropertyAttributes());
-
   // 'unsafe_unretained' is alias for 'assign'.
   if (Attributes & ObjCDeclSpec::DQ_PR_unsafe_unretained)
     PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_assign);
@@ -565,6 +585,13 @@
   ObjCIvarDecl *Ivar = 0;
   // Check that we have a valid, previously declared ivar for @synthesize
   if (Synthesize) {
+    if (getLangOptions().ObjCAutoRefCount &&
+        !property->hasWrittenStorageAttribute() &&
+        property->getType()->isObjCRetainableType()) {
+      Diag(PropertyLoc, diag::err_arc_objc_property_default_assign_on_object);
+      Diag(property->getLocation(), diag::note_property_declare);
+    }
+
     // @synthesize
     if (!PropertyIvar)
       PropertyIvar = PropertyId;
@@ -1672,17 +1699,13 @@
                       ObjCDeclSpec::DQ_PR_weak)) &&
       !(Attributes & ObjCDeclSpec::DQ_PR_readonly) &&
       PropertyTy->isObjCObjectPointerType()) {
-    if (getLangOptions().ObjCAutoRefCount)
-      Diag(Loc, diag::err_arc_objc_property_default_assign_on_object);
-    else {
-      // Skip this warning in gc-only mode.
-      if (getLangOptions().getGCMode() != LangOptions::GCOnly)
-        Diag(Loc, diag::warn_objc_property_no_assignment_attribute);
+    // 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);
-    }
+    // 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: