]> granicus.if.org Git - clang/commitdiff
ObjectiveC. Implement attribute 'objc_bridge_mutable'
authorFariborz Jahanian <fjahanian@apple.com>
Thu, 21 Nov 2013 20:50:32 +0000 (20:50 +0000)
committerFariborz Jahanian <fjahanian@apple.com>
Thu, 21 Nov 2013 20:50:32 +0000 (20:50 +0000)
whose semantic is currently identical to objc_bridge,
but their differences may manifest down the road with
further enhancements. // rdar://15498044

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

include/clang/Basic/Attr.td
lib/Sema/SemaDeclAttr.cpp
lib/Sema/SemaExprObjC.cpp
test/SemaObjC/objcbridgemutable-attribute.m [new file with mode: 0644]

index bcca1d25ef78caabce6e0a4884cade92c98aac77..416da743623de9f84152cd547564d2714f685ca8 100644 (file)
@@ -551,6 +551,12 @@ def ObjCBridge : InheritableAttr {
   let Args = [IdentifierArgument<"BridgedType", 1>];
 }
 
+def ObjCBridgeMutable : InheritableAttr {
+  let Spellings = [GNU<"objc_bridge_mutable">];
+  let Subjects = [Record];
+  let Args = [IdentifierArgument<"BridgedType", 1>];
+}
+
 def NSReturnsRetained : InheritableAttr {
   let Spellings = [GNU<"ns_returns_retained">];
   let Subjects = [ObjCMethod, Function];
index 38bffa2f99e46b89a9f3e6acf5ffa52338b4b592..8b3d738c60b95285a57a1f085bc71364b3577db2 100644 (file)
@@ -4362,6 +4362,30 @@ static void handleObjCBridgeAttr(Sema &S, Scope *Sc, Decl *D,
                            Attr.getAttributeSpellingListIndex()));
 }
 
+static void handleObjCBridgeMutableAttr(Sema &S, Scope *Sc, Decl *D,
+                                        const AttributeList &Attr) {
+  if (!isa<RecordDecl>(D)) {
+    S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type)
+    << Attr.getName()
+    << (S.getLangOpts().CPlusPlus ? ExpectedStructOrUnionOrClass
+        : ExpectedStructOrUnion);
+    return;
+  }
+  
+  IdentifierLoc *Parm = 0;
+  if (Attr.getNumArgs() == 1)
+    Parm = Attr.isArgIdent(0) ? Attr.getArgAsIdent(0) : 0;
+  
+  if (!Parm) {
+    S.Diag(D->getLocStart(), diag::err_objc_attr_not_id) << Attr.getName() << 0;
+    return;
+  }
+  
+  D->addAttr(::new (S.Context)
+             ObjCBridgeMutableAttr(Attr.getRange(), S.Context, Parm->Ident,
+                            Attr.getAttributeSpellingListIndex()));
+}
+
 static void handleObjCOwnershipAttr(Sema &S, Decl *D,
                                     const AttributeList &Attr) {
   if (hasDeclarator(D)) return;
@@ -4651,6 +4675,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
       
   case AttributeList::AT_ObjCBridge:
     handleObjCBridgeAttr(S, scope, D, Attr); break;
+      
+  case AttributeList::AT_ObjCBridgeMutable:
+    handleObjCBridgeMutableAttr(S, scope, D, Attr); break;
 
   case AttributeList::AT_CFAuditedTransfer:
   case AttributeList::AT_CFUnknownTransfer:
index a906e2e9f920175a0ddfb390bad675a41d0ebc64..a60749b0224f4c1347776e8e73b0cf24e4165eb2 100644 (file)
@@ -3165,24 +3165,26 @@ diagnoseObjCARCConversion(Sema &S, SourceRange castRange,
     << castRange << castExpr->getSourceRange();
 }
 
-static inline ObjCBridgeAttr *getObjCBridgeAttr(const TypedefType *TD) {
+template <typename T>
+static inline T *getObjCBridgeAttr(const TypedefType *TD) {
   TypedefNameDecl *TDNDecl = TD->getDecl();
   QualType QT = TDNDecl->getUnderlyingType();
   if (QT->isPointerType()) {
     QT = QT->getPointeeType();
     if (const RecordType *RT = QT->getAs<RecordType>())
       if (RecordDecl *RD = RT->getDecl())
-        if (RD->hasAttr<ObjCBridgeAttr>())
-          return RD->getAttr<ObjCBridgeAttr>();
+        if (RD->hasAttr<T>())
+          return RD->getAttr<T>();
   }
   return 0;
 }
 
+template <typename TB>
 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 (ObjCBridgeAttr *ObjCBAttr = getObjCBridgeAttr(TD)) {
+    if (TB *ObjCBAttr = getObjCBridgeAttr<TB>(TD)) {
       if (IdentifierInfo *Parm = ObjCBAttr->getBridgedType()) {
         NamedDecl *Target = 0;
         // Check for an existing type with this name.
@@ -3231,11 +3233,12 @@ static bool CheckObjCBridgeNSCast(Sema &S, QualType castType, Expr *castExpr) {
   return false;
 }
 
+template <typename TB>
 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 (ObjCBridgeAttr *ObjCBAttr = getObjCBridgeAttr(TD)) {
+    if (TB *ObjCBAttr = getObjCBridgeAttr<TB>(TD)) {
       if (IdentifierInfo *Parm = ObjCBAttr->getBridgedType()) {
         NamedDecl *Target = 0;
         // Check for an existing type with this name.
@@ -3289,10 +3292,14 @@ void Sema::CheckTollFreeBridgeCast(QualType castType, Expr *castExpr) {
   // warn in presense of __bridge casting to or from a toll free bridge cast.
   ARCConversionTypeClass exprACTC = classifyTypeForARCConversion(castExpr->getType());
   ARCConversionTypeClass castACTC = classifyTypeForARCConversion(castType);
-  if (castACTC == ACTC_retainable && exprACTC == ACTC_coreFoundation)
-    (void)CheckObjCBridgeNSCast(*this, castType, castExpr);
-  else if (castACTC == ACTC_coreFoundation && exprACTC == ACTC_retainable)
-    (void)CheckObjCBridgeCFCast(*this, castType, castExpr);
+  if (castACTC == ACTC_retainable && exprACTC == ACTC_coreFoundation) {
+    (void)CheckObjCBridgeNSCast<ObjCBridgeAttr>(*this, castType, castExpr);
+    (void)CheckObjCBridgeNSCast<ObjCBridgeMutableAttr>(*this, castType, castExpr);
+  }
+  else if (castACTC == ACTC_coreFoundation && exprACTC == ACTC_retainable) {
+    (void)CheckObjCBridgeCFCast<ObjCBridgeAttr>(*this, castType, castExpr);
+    (void)CheckObjCBridgeCFCast<ObjCBridgeMutableAttr>(*this, castType, castExpr);
+  }
 }
 
 Sema::ARCConversionResult
@@ -3355,12 +3362,14 @@ Sema::CheckObjCARCConversion(SourceRange castRange, QualType castType,
   
   if (castACTC == ACTC_retainable && exprACTC == ACTC_coreFoundation &&
       (CCK == CCK_CStyleCast || CCK == CCK_FunctionalCast))
-    if (CheckObjCBridgeNSCast(*this, castType, castExpr))
+    if (CheckObjCBridgeNSCast<ObjCBridgeAttr>(*this, castType, castExpr) ||
+        CheckObjCBridgeNSCast<ObjCBridgeMutableAttr>(*this, castType, castExpr))
       return ACR_okay;
     
   if (castACTC == ACTC_coreFoundation && exprACTC == ACTC_retainable &&
       (CCK == CCK_CStyleCast || CCK == CCK_FunctionalCast))
-    if (CheckObjCBridgeCFCast(*this, castType, castExpr))
+    if (CheckObjCBridgeCFCast<ObjCBridgeAttr>(*this, castType, castExpr) ||
+        CheckObjCBridgeCFCast<ObjCBridgeMutableAttr>(*this, castType, castExpr))
       return ACR_okay;
     
 
diff --git a/test/SemaObjC/objcbridgemutable-attribute.m b/test/SemaObjC/objcbridgemutable-attribute.m
new file mode 100644 (file)
index 0000000..52989f9
--- /dev/null
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
+// rdar://15498044
+
+typedef struct __attribute__((objc_bridge_mutable(NSMutableDictionary))) __CFDictionary * CFMutableDictionaryRef; // expected-note {{declared here}}
+
+@interface NSDictionary
+@end
+
+@interface NSMutableDictionary : NSDictionary
+@end
+
+void Test(NSMutableDictionary *md, NSDictionary *nd, CFMutableDictionaryRef mcf) {
+
+  (void) (CFMutableDictionaryRef)md;
+  (void) (CFMutableDictionaryRef)nd; // expected-warning {{'NSDictionary' cannot bridge to 'CFMutableDictionaryRef' (aka 'struct __CFDictionary *')}}
+  (void) (NSDictionary *)mcf;  // expected-warning {{'CFMutableDictionaryRef' (aka 'struct __CFDictionary *') bridges to NSMutableDictionary, not 'NSDictionary'}}
+  (void) (NSMutableDictionary *)mcf; // ok;
+}
+