Implemenent objective-c's NSObject attribute as a way of ddeclaraing c-type
objects as an objective-c object.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@62197 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index b548756..c64c101 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -2078,6 +2078,19 @@
 //                        Type Predicates.
 //===----------------------------------------------------------------------===//
 
+/// isObjCNSObjectType - Return true if this is an NSObject object using
+/// NSObject attribute on a c-style pointer type.
+/// FIXME - Make it work directly on types.
+///
+bool ASTContext::isObjCNSObjectType(QualType Ty) const {
+  if (TypedefType *TDT = dyn_cast<TypedefType>(Ty)) {
+    if (TypedefDecl *TD = TDT->getDecl())
+      if (TD->getAttr<ObjCNSObjectAttr>())
+        return true;
+  }
+  return false;  
+}
+
 /// isObjCObjectPointerType - Returns true if type is an Objective-C pointer
 /// to an object type.  This includes "id" and "Class" (two 'special' pointers
 /// to struct), Interface* (pointer to ObjCInterfaceType) and id<P> (qualified
@@ -2101,7 +2114,11 @@
     return true;
   
   // If this a pointer to an interface (e.g. NSString*), it is ok.
-  return Ty->getAsPointerType()->getPointeeType()->isObjCInterfaceType();
+  if (Ty->getAsPointerType()->getPointeeType()->isObjCInterfaceType())
+    return true;
+  
+  // If is has NSObject attribute, OK as well.
+  return isObjCNSObjectType(Ty);
 }
 
 //===----------------------------------------------------------------------===//
diff --git a/lib/Parse/AttributeList.cpp b/lib/Parse/AttributeList.cpp
index 0a418bb..6c1583a 100644
--- a/lib/Parse/AttributeList.cpp
+++ b/lib/Parse/AttributeList.cpp
@@ -81,6 +81,7 @@
     if (!memcmp(Str, "fastcall", 8)) return AT_fastcall;
     if (!memcmp(Str, "iboutlet", 8)) return AT_IBOutlet;
     if (!memcmp(Str, "sentinel", 8)) return AT_sentinel;
+    if (!memcmp(Str, "NSObject", 8)) return AT_nsobject;
     break;
   case 9:
     if (!memcmp(Str, "dllimport", 9)) return AT_dllimport;
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index 759ef09..f444c71 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -578,6 +578,22 @@
   d->addAttr(new ObjCGCAttr(type));
 }
 
+static void HandleObjCNSObject(Decl *d, const AttributeList &Attr, Sema &S) {
+  if (Attr.getNumArgs() != 0) {
+    S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
+    return;
+  }
+  if (TypedefDecl *TD = dyn_cast<TypedefDecl>(d)) {
+    QualType T = TD->getUnderlyingType();
+    if (!T->isPointerType() ||
+        !T->getAsPointerType()->getPointeeType()->isRecordType()) {
+      S.Diag(TD->getLocation(), diag::err_nsobject_attribute);
+      return;
+    }
+  }
+  d->addAttr(new ObjCNSObjectAttr);
+}
+
 static void HandleBlocksAttr(Decl *d, const AttributeList &Attr, Sema &S) {
   if (!Attr.getParameterName()) {    
     S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string)
@@ -1228,6 +1244,7 @@
     HandleTransparentUnionAttr(D, Attr, S);
     break;
   case AttributeList::AT_objc_gc:     HandleObjCGCAttr    (D, Attr, S); break;
+  case AttributeList::AT_nsobject:    HandleObjCNSObject  (D, Attr, S); break;
   case AttributeList::AT_blocks:      HandleBlocksAttr    (D, Attr, S); break;
   case AttributeList::AT_sentinel:    HandleSentinelAttr  (D, Attr, S); break;
   case AttributeList::AT_const:       HandleConstAttr     (D, Attr, S); break;
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index d7a041d..0c97611 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -3023,7 +3023,14 @@
   if (CompoundType.isNull()) {
     // Simple assignment "x = y".
     ConvTy = CheckSingleAssignmentConstraints(LHSType, RHS);
-    
+    // Special case of NSObject attributes on c-style pointer types.
+    if (ConvTy == IncompatiblePointer &&
+        ((Context.isObjCNSObjectType(LHSType) &&
+          Context.isObjCObjectPointerType(RHSType)) ||
+         (Context.isObjCNSObjectType(RHSType) &&
+          Context.isObjCObjectPointerType(LHSType))))
+      ConvTy = Compatible;
+  
     // If the RHS is a unary plus or minus, check to see if they = and + are
     // right next to each other.  If so, the user may have typo'd "x =+ 4"
     // instead of "x += 4".