From: John McCall Date: Thu, 29 Sep 2011 07:17:38 +0000 (+0000) Subject: Add an ns_bridged attribute, used to specify that a X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=fe98da0fa352462c02db037360788748f95466f7;p=clang Add an ns_bridged attribute, used to specify that a 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 --- diff --git a/include/clang/Basic/Attr.td b/include/clang/Basic/Attr.td index 4d9aa5b9a3..be43bca9fd 100644 --- a/include/clang/Basic/Attr.td +++ b/include/clang/Basic/Attr.td @@ -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]; diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 6ef027441b..cbae5be61f 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -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">; diff --git a/include/clang/Sema/AttributeList.h b/include/clang/Sema/AttributeList.h index a44f6fae33..b0012e7c93 100644 --- a/include/clang/Sema/AttributeList.h +++ b/include/clang/Sema/AttributeList.h @@ -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. diff --git a/lib/Sema/AttributeList.cpp b/lib/Sema/AttributeList.cpp index d9f17b42da..5cd21a645d 100644 --- a/lib/Sema/AttributeList.cpp +++ b/lib/Sema/AttributeList.cpp @@ -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) diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index 435507f9d7..eca6874b36 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -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(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(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 index 0000000000..1ab60a2b0d --- /dev/null +++ b/test/SemaObjC/attr-ns-bridged.m @@ -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}}