]> granicus.if.org Git - clang/commitdiff
ObjectiveC ARC. Adopt objc_bridge attribute
authorFariborz Jahanian <fjahanian@apple.com>
Tue, 19 Nov 2013 00:09:48 +0000 (00:09 +0000)
committerFariborz Jahanian <fjahanian@apple.com>
Tue, 19 Nov 2013 00:09:48 +0000 (00:09 +0000)
on struct/union/class instead of typedef of
such types. // rdar://15454846

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

include/clang/Basic/DiagnosticSemaKinds.td
lib/Sema/SemaDecl.cpp
lib/Sema/SemaDeclAttr.cpp
lib/Sema/SemaExprObjC.cpp
test/SemaObjC/objcbridge-attribute.m

index 22db61dde4264eb679d6482697ddec7fac6d72b6..3b80df844a59a902bb4a9a2e57f363f250aa58c2 100644 (file)
@@ -2442,11 +2442,9 @@ def err_ns_bridged_not_interface : Error<
 def err_objc_bridge_not_id : Error<
   "parameter of 'objc_bridge' attribute must be a single name of an Objective-C class">;
 def err_objc_bridge_attribute : Error<
-  "'objc_bridge' attribute must be put on a typedef only">;
+  "'objc_bridge' attribute must be applied to a struct, C++ class, or union">;
 def err_objc_bridge_not_cftype : Error<
   "'objc_bridge' attribute must be applied to definition of CF types">;
-def err_objc_bridge_not_pointert_to_struct : Error<
-  "'objc_bridge' attribute must be applied to a pointer to struct type">;
 def err_objc_cf_bridged_not_interface : Error<
   "CF object of type %0 is bridged to '%1', which is not an Objective-C class">;
 def err_objc_ns_bridged_invalid_cfobject : Error<
index 3cdb72714f46256354a90aede99deb10eb02f914..6a5d608c7b2e87d493267f3a8d89079f28c2f703 100644 (file)
@@ -10072,6 +10072,31 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) {
   }
 }
 
+static inline bool isTollFreeBridgeCFRefType(TypedefDecl *TD) {
+  TypedefNameDecl * TDefNameDecl = TD;
+  const Type *TP = TDefNameDecl->getUnderlyingType().getTypePtr();
+  while (const TypedefType *TDef = dyn_cast<TypedefType>(TP)) {
+    TDefNameDecl = TDef->getDecl();
+    TP = TDefNameDecl->getUnderlyingType().getTypePtr();
+  }
+  
+  StringRef TDName = TDefNameDecl->getIdentifier()->getName();
+  return (TDName.startswith("CF") && TDName.endswith("Ref"));
+}
+
+/// CheckObjCBridgeAttribute - Checks that objc_bridge attribute is
+/// properly applied to a typedef of a pointer to struct/union/class
+static void CheckObjCBridgeAttribute(Sema &S, TypedefDecl *TD) {
+  QualType T = TD->getUnderlyingType();
+  if (!T->isPointerType())
+    return;
+  T = T->getPointeeType();
+  if (T->isStructureType() || T->isUnionType() || T->isClassType())
+    if (RecordDecl *RD = T->getAs<RecordType>()->getDecl())
+      if (RD->hasAttr<ObjCBridgeAttr>() && !isTollFreeBridgeCFRefType(TD))
+        S.Diag(TD->getLocStart(), diag::err_objc_bridge_not_cftype);
+}
+
 TypedefDecl *Sema::ParseTypedefDecl(Scope *S, Declarator &D, QualType T,
                                     TypeSourceInfo *TInfo) {
   assert(D.getIdentifier() && "Wrong callback for declspec without declarator");
@@ -10095,6 +10120,8 @@ TypedefDecl *Sema::ParseTypedefDecl(Scope *S, Declarator &D, QualType T,
     return NewTD;
   }
 
+  CheckObjCBridgeAttribute(*this, NewTD);
+  
   if (D.getDeclSpec().isModulePrivateSpecified()) {
     if (CurContext->isFunctionOrMethod())
       Diag(NewTD->getLocation(), diag::err_module_private_local)
index 7987a18f6105ab1a0377ac57a87bcf09675eb908..77f7905302d0568f7467d39e6a499c6b4ad08736 100644 (file)
@@ -207,11 +207,6 @@ static inline bool isCFStringType(QualType T, ASTContext &Ctx) {
   return RD->getIdentifier() == &Ctx.Idents.get("__CFString");
 }
 
-static inline bool isTollFreeBridgeCFRefType(TypedefNameDecl *TD, ASTContext &Ctx) {
-  StringRef TDName = TD->getIdentifier()->getName();
-  return (TDName.startswith("CF") && TDName.endswith("Ref"));
-}
-
 static unsigned getNumAttributeArgs(const AttributeList &Attr) {
   // FIXME: Include the type in the argument list.
   return Attr.getNumArgs() + Attr.hasParsedType();
@@ -4396,34 +4391,7 @@ static void handleNSBridgedAttr(Sema &S, Scope *Sc, Decl *D,
 
 static void handleObjCBridgeAttr(Sema &S, Scope *Sc, Decl *D,
                                 const AttributeList &Attr) {
-  if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D)) {
-    QualType T = TD->getUnderlyingType();
-    if (T->isPointerType()) {
-      T = T->getPointeeType();
-      if (T->isRecordType()) {
-        RecordDecl *RD = T->getAs<RecordType>()->getDecl();
-        if (!RD || RD->isUnion()) {
-          S.Diag(D->getLocStart(), diag::err_objc_bridge_not_pointert_to_struct)
-          << Attr.getRange();
-          return;
-        }
-      } else {
-        S.Diag(TD->getLocStart(), diag::err_objc_bridge_not_pointert_to_struct)
-        << Attr.getRange();
-        return;
-      }
-    } else {
-      S.Diag(TD->getLocStart(), diag::err_objc_bridge_not_pointert_to_struct)
-            << Attr.getRange();
-      return;
-    }
-    // Check for T being a CFType goes here.
-    if (!isTollFreeBridgeCFRefType(TD, S.Context)) {
-      S.Diag(TD->getLocStart(), diag::err_objc_bridge_not_cftype);
-      return;
-    }
-  }
-  else {
+  if (!isa<RecordDecl>(D)) {
     S.Diag(D->getLocStart(), diag::err_objc_bridge_attribute);
     return;
   }
index b59e0a62381c15ec02cca84609cda35665bf3813..69d7b9e07e9c5e93375a9e46aa7ac3a09083bd7e 100644 (file)
@@ -3165,15 +3165,26 @@ diagnoseObjCARCConversion(Sema &S, SourceRange castRange,
     << castRange << castExpr->getSourceRange();
 }
 
+static inline ObjCBridgeAttr *getObjCBridgeAttr(const TypedefType *TD) {
+  TypedefNameDecl *TDNDecl = TD->getDecl();
+  QualType QT = TDNDecl->getUnderlyingType();
+  if (QT->isPointerType()) {
+    QT = QT->getPointeeType();
+    if (QT->isStructureType() || QT->isUnionType() || QT->isClassType())
+      if (RecordDecl *RD = QT->getAs<RecordType>()->getDecl())
+        if (RD->hasAttr<ObjCBridgeAttr>())
+          return RD->getAttr<ObjCBridgeAttr>();
+  }
+  return 0;
+}
+
 static bool CheckObjCBridgeNSCast(Sema &S, QualType castType, Expr *castExpr) {
   QualType T = castExpr->getType();
   while (const TypedefType *TD = dyn_cast<TypedefType>(T.getTypePtr())) {
     TypedefNameDecl *TDNDecl = TD->getDecl();
-    if (TDNDecl->hasAttr<ObjCBridgeAttr>()) {
-      ObjCBridgeAttr *ObjCBAttr = TDNDecl->getAttr<ObjCBridgeAttr>();
-      IdentifierInfo *Parm = ObjCBAttr->getBridgedType();
-      NamedDecl *Target = 0;
-      if (Parm && S.getLangOpts().ObjC1) {
+    if (ObjCBridgeAttr *ObjCBAttr = getObjCBridgeAttr(TD)) {
+      if (IdentifierInfo *Parm = ObjCBAttr->getBridgedType()) {
+        NamedDecl *Target = 0;
         // Check for an existing type with this name.
         LookupResult R(S, DeclarationName(Parm), SourceLocation(),
                        Sema::LookupOrdinaryName);
@@ -3215,11 +3226,9 @@ static bool CheckObjCBridgeCFCast(Sema &S, QualType castType, Expr *castExpr) {
   QualType T = castType;
   while (const TypedefType *TD = dyn_cast<TypedefType>(T.getTypePtr())) {
     TypedefNameDecl *TDNDecl = TD->getDecl();
-    if (TDNDecl->hasAttr<ObjCBridgeAttr>()) {
-      ObjCBridgeAttr *ObjCBAttr = TDNDecl->getAttr<ObjCBridgeAttr>();
-      IdentifierInfo *Parm = ObjCBAttr->getBridgedType();
-      NamedDecl *Target = 0;
-      if (Parm && S.getLangOpts().ObjC1) {
+    if (ObjCBridgeAttr *ObjCBAttr = getObjCBridgeAttr(TD)) {
+      if (IdentifierInfo *Parm = ObjCBAttr->getBridgedType()) {
+        NamedDecl *Target = 0;
         // Check for an existing type with this name.
         LookupResult R(S, DeclarationName(Parm), SourceLocation(),
                        Sema::LookupOrdinaryName);
index d39861f0613239b729d75acff3a445310dca65c5..2ab21016cbf97b26fd8988c7558a0d0e70069506 100644 (file)
@@ -1,37 +1,41 @@
 // RUN: %clang_cc1 -fsyntax-only -fobjc-arc -verify -Wno-objc-root-class %s
 // rdar://15454846
 
-typedef struct __CFErrorRef * __attribute__ ((objc_bridge(NSError))) CFErrorRef; // expected-note 2 {{declared here}}
+typedef struct __attribute__ ((objc_bridge(NSError))) __CFErrorRef * CFErrorRef; // expected-note 2 {{declared here}}
 
-typedef struct __CFMyColor  * __attribute__((objc_bridge(12))) CFMyColorRef; // expected-error {{parameter of 'objc_bridge' attribute must be a single name of an Objective-C class}}
+typedef struct __attribute__((objc_bridge(12))) __CFMyColor  *CFMyColorRef; // expected-error {{parameter of 'objc_bridge' attribute must be a single name of an Objective-C class}}
 
-typedef struct __CFArray *  __attribute__ ((objc_bridge)) CFArrayRef; // expected-error {{parameter of 'objc_bridge' attribute must be a single name of an Objective-C class}}
+typedef struct __attribute__ ((objc_bridge)) __CFArray *CFArrayRef; // expected-error {{parameter of 'objc_bridge' attribute must be a single name of an Objective-C class}}
 
-typedef void *  __attribute__ ((objc_bridge(NSURL))) CFURLRef;  // expected-error {{'objc_bridge' attribute must be applied to a pointer to struct type}}
+typedef void *  __attribute__ ((objc_bridge(NSURL))) CFURLRef;  // expected-error {{'objc_bridge' attribute must be applied to a struct, C++ class, or union}}
 
-typedef void * CFStringRef __attribute__ ((objc_bridge(NSString))); // expected-error {{'objc_bridge' attribute must be applied to a pointer to struct type}}
+typedef void * CFStringRef __attribute__ ((objc_bridge(NSString))); // expected-error {{'objc_bridge' attribute must be applied to a struct, C++ class, or union}}
 
-typedef struct __CFLocale * __attribute__((objc_bridge(NSLocale, NSError))) CFLocaleRef;// expected-error {{use of undeclared identifier 'NSError'}}
+typedef struct __attribute__((objc_bridge(NSLocale, NSError))) __CFLocale *CFLocaleRef;// expected-error {{use of undeclared identifier 'NSError'}}
 
-typedef struct __CFData __attribute__((objc_bridge(NSData))) CFDataRef; // expected-error {{'objc_bridge' attribute must be applied to a pointer to struct type}}
+typedef struct __CFData __attribute__((objc_bridge(NSData))) CFDataRef; // expected-error {{'objc_bridge' attribute must be applied to a struct, C++ class, or union}}
 
-typedef struct __attribute__((objc_bridge(NSDictionary))) __CFDictionary * CFDictionaryRef; // expected-error {{'objc_bridge' attribute must be put on a typedef only}}
+typedef struct __attribute__((objc_bridge(NSDictionary))) __CFDictionary * CFDictionaryRef;
 
-typedef struct __CFSetRef * CFSetRef __attribute__((objc_bridge(NSSet)));
+typedef struct __CFSetRef * CFSetRef __attribute__((objc_bridge(NSSet))); // expected-error {{'objc_bridge' attribute must be applied to a struct, C++ class, or union}};
 
-typedef union __CFUColor * __attribute__((objc_bridge(NSUColor))) CFUColorRef; // expected-error {{'objc_bridge' attribute must be applied to a pointer to struct type}}
+typedef union __CFUColor __attribute__((objc_bridge(NSUColor))) * CFUColorRef; // expected-error {{'objc_bridge' attribute must be applied to a struct, C++ class, or union}};
+
+typedef union __CFUColor __attribute__((objc_bridge(NSUColor))) *CFUColor1Ref; // expected-error {{'objc_bridge' attribute must be applied to a struct, C++ class, or union}};
+
+typedef union __attribute__((objc_bridge(NSUColor))) __CFUPrimeColor XXX;
+typedef XXX *CFUColor2Ref;
 
 @interface I
 {
-   __attribute__((objc_bridge(NSError))) void * color; // expected-error {{'objc_bridge' attribute must be put on a typedef only}}
-
+   __attribute__((objc_bridge(NSError))) void * color; // expected-error {{'objc_bridge' attribute must be applied to a struct, C++ class, or union}};
 }
 @end
 
 @protocol NSTesting @end
 @class NSString;
 
-typedef struct __CFError * __attribute__((objc_bridge(NSTesting))) CFTestingRef; // expected-note {{declared here}}
+typedef struct __attribute__((objc_bridge(NSTesting))) __CFError *CFTestingRef; // expected-note {{declared here}}
 
 id Test1(CFTestingRef cf) {
   return (NSString *)cf; // expected-error {{CF object of type 'CFTestingRef' (aka 'struct __CFError *') is bridged to 'NSTesting', which is not an Objective-C class}}
@@ -46,14 +50,17 @@ typedef CFErrorRef1 CFErrorRef2;
 @interface MyError : NSError
 @end
 
+@interface NSUColor @end
+
 @class NSString;
 
-void Test2(CFErrorRef2 cf, NSError *ns, NSString *str, Class c) {
-  (void)(NSString *)cf; // expected-warning {{CFErrorRef bridges to NSError, not NSString}}
+void Test2(CFErrorRef2 cf, NSError *ns, NSString *str, Class c, CFUColor2Ref cf2) {
+  (void)(NSString *)cf; // expected-warning {{CFErrorRef2 bridges to NSError, not NSString}}
   (void)(NSError *)cf; // okay
   (void)(MyError*)cf; // okay,
+  (void)(NSUColor *)cf2; // okay
   (void)(CFErrorRef)ns; // okay
   (void)(CFErrorRef)str;  // expected-warning {{NSString cannot bridge to CFErrorRef}}
-  (void)(Class)cf; // expected-warning {{CFErrorRef bridges to NSError, not 'Class'}}
+  (void)(Class)cf; // expected-warning {{CFErrorRef2 bridges to NSError, not 'Class'}}
   (void)(CFErrorRef)c; // expected-warning {{'Class' cannot bridge to 'CFErrorRef'}}
 }