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.

llvm-svn: 140779
This commit is contained in:
John McCall 2011-09-29 07:17:38 +00:00
parent 7fd1723619
commit f1e8b34f6c
6 changed files with 60 additions and 1 deletions

View 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];

View 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">;

View 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.

View 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)

View 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;

View File

@ -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}}