]> granicus.if.org Git - clang/commitdiff
Add an ns_bridged attribute, used to specify that a
authorJohn McCall <rjmccall@apple.com>
Thu, 29 Sep 2011 07:17:38 +0000 (07:17 +0000)
committerJohn McCall <rjmccall@apple.com>
Thu, 29 Sep 2011 07:17:38 +0000 (07:17 +0000)
pointer to the annotated struct type can be used as an
Objective-C object pointer.  If an argument is given, the
type is actually "toll-free bridged" to the specific type
named there, rather than just to 'id'.

For now, we cannot rely on all types being so annotated,
and we'll always have to have exceptions for things like
CFTypeRef (aka const void*), but this is clearly a good
foundation for improving toolage in this area.

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

include/clang/Basic/Attr.td
include/clang/Basic/DiagnosticSemaKinds.td
include/clang/Sema/AttributeList.h
lib/Sema/AttributeList.cpp
lib/Sema/SemaDeclAttr.cpp
test/SemaObjC/attr-ns-bridged.m [new file with mode: 0644]

index 4d9aa5b9a3b274ea953caf72c99130fb2a01cfc3..be43bca9fdd489cef9f664ec08229732439d58dc 100644 (file)
@@ -362,6 +362,12 @@ def NoThrow : InheritableAttr {
   let Spellings = ["nothrow"];
 }
 
+def NSBridged : InheritableAttr {
+  let Spellings = ["ns_bridged"];
+  let Subjects = [Record];
+  let Args = [IdentifierArgument<"BridgedType">];
+}
+
 def NSReturnsRetained : InheritableAttr {
   let Spellings = ["ns_returns_retained"];
   let Subjects = [ObjCMethod, Function];
index 6ef027441b5317284d0fb28a6df7ee3f0367cd53..cbae5be61ff3981888360dc5f5c800ccd0d417d8 100644 (file)
@@ -1331,7 +1331,7 @@ def err_attribute_wrong_decl_type : Error<
   "variables and functions|functions and methods|parameters|"
   "parameters and methods|functions, methods and blocks|"
   "classes and virtual methods|functions, methods, and parameters|"
-  "classes|virtual methods|class members|variables|methods}1">;
+  "classes|virtual methods|class members|variables|methods|structs}1">;
 def warn_function_attribute_wrong_type : Warning<
   "'%0' only applies to function types; type here is %1">;
 def warn_pointer_attribute_wrong_type : Warning<
@@ -1573,6 +1573,8 @@ def warn_ns_attribute_wrong_return_type : Warning<
 def warn_ns_attribute_wrong_parameter_type : Warning<
   "%0 attribute only applies to %select{Objective-C object|pointer}1 "
   "parameters">;
+def err_ns_bridged_not_interface : Error<
+  "parameter of 'ns_bridged' attribute does not name an Objective-C class">;
 
 // Function Parameter Semantic Analysis.
 def err_param_with_void_type : Error<"argument may not have 'void' type">;
index a44f6fae3324a80a11a1e4d73ec302e1973b30c7..b0012e7c933f7a9e34d3ed8c67754df486591448 100644 (file)
@@ -215,6 +215,7 @@ public:
     AT_nonnull,
     AT_noreturn,
     AT_nothrow,
+    AT_ns_bridged,              // Clang-specific.
     AT_ns_consumed,             // Clang-specific.
     AT_ns_consumes_self,        // Clang-specific.
     AT_ns_returns_autoreleased, // Clang-specific.
index d9f17b42da4b40f1fe7ceb7fdd0b7b7a2519380b..5cd21a645d2afd9ee58b062ce938517e7e961c5a 100644 (file)
@@ -171,6 +171,7 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) {
     .Case("analyzer_noreturn", AT_analyzer_noreturn)
     .Case("warn_unused_result", AT_warn_unused_result)
     .Case("carries_dependency", AT_carries_dependency)
+    .Case("ns_bridged", AT_ns_bridged)
     .Case("ns_consumed", AT_ns_consumed)
     .Case("ns_consumes_self", AT_ns_consumes_self)
     .Case("ns_returns_autoreleased", AT_ns_returns_autoreleased)
index 435507f9d78f944bd4ace759f4c9c54423384a94..eca6874b3679bf56f3c3e6b162bec0cb5a428507 100644 (file)
@@ -22,6 +22,7 @@
 #include "clang/Basic/TargetInfo.h"
 #include "clang/Sema/DeclSpec.h"
 #include "clang/Sema/DelayedDiagnostic.h"
+#include "clang/Sema/Lookup.h"
 #include "llvm/ADT/StringExtras.h"
 using namespace clang;
 using namespace sema;
@@ -3262,6 +3263,36 @@ static void handleObjCReturnsInnerPointerAttr(Sema &S, Decl *D,
     ::new (S.Context) ObjCReturnsInnerPointerAttr(attr.getRange(), S.Context));
 }
 
+static void handleNSBridgedAttr(Sema &S, Scope *Sc, Decl *D,
+                                const AttributeList &Attr) {
+  RecordDecl *RD = dyn_cast<RecordDecl>(D);
+  if (!RD || RD->isUnion()) {
+    S.Diag(D->getLocStart(), diag::err_attribute_wrong_decl_type)
+      << Attr.getRange() << Attr.getName() << 14 /*struct */;
+  }
+
+  IdentifierInfo *ParmName = Attr.getParameterName();
+
+  // In Objective-C, verify that the type names an Objective-C type.
+  // We don't want to check this outside of ObjC because people sometimes
+  // do crazy C declarations of Objective-C types.
+  if (ParmName && S.getLangOptions().ObjC1) {
+    // Check for an existing type with this name.
+    LookupResult R(S, DeclarationName(ParmName), Attr.getParameterLoc(),
+                   Sema::LookupOrdinaryName);
+    if (S.LookupName(R, Sc)) {
+      NamedDecl *Target = R.getFoundDecl();
+      if (Target && !isa<ObjCInterfaceDecl>(Target)) {
+        S.Diag(D->getLocStart(), diag::err_ns_bridged_not_interface);
+        S.Diag(Target->getLocStart(), diag::note_declared_at);
+      }
+    }
+  }
+
+  D->addAttr(::new (S.Context) NSBridgedAttr(Attr.getRange(), S.Context,
+                                             ParmName));
+}
+
 static void handleObjCOwnershipAttr(Sema &S, Decl *D,
                                     const AttributeList &Attr) {
   if (hasDeclarator(D)) return;
@@ -3465,6 +3496,9 @@ static void ProcessInheritableDeclAttr(Sema &S, Scope *scope, Decl *D,
   case AttributeList::AT_objc_returns_inner_pointer:
     handleObjCReturnsInnerPointerAttr(S, D, Attr); break;
 
+  case AttributeList::AT_ns_bridged:
+    handleNSBridgedAttr(S, scope, D, Attr); break;
+
   // Checker-specific.
   case AttributeList::AT_cf_consumed:
   case AttributeList::AT_ns_consumed: handleNSConsumedAttr  (S, D, Attr); break;
diff --git a/test/SemaObjC/attr-ns-bridged.m b/test/SemaObjC/attr-ns-bridged.m
new file mode 100644 (file)
index 0000000..1ab60a2
--- /dev/null
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+typedef struct __attribute__((ns_bridged)) test0s *test0ref;
+
+void test0func(void) __attribute__((ns_bridged)); // expected-error {{'ns_bridged' attribute only applies to structs}}
+
+union __attribute__((ns_bridged)) test0u; // expected-error {{'ns_bridged' attribute only applies to structs}}
+
+struct __attribute__((ns_bridged(Test1))) test1s;
+
+@class Test2;
+struct __attribute__((ns_bridged(Test2))) test2s;
+
+void Test3(void); // expected-note {{declared here}}
+struct __attribute__((ns_bridged(Test3))) test3s; // expected-error {{parameter of 'ns_bridged' attribute does not name an Objective-C class}}