From 0a0a39708c6a879db82562f094259906b3587a93 Mon Sep 17 00:00:00 2001 From: Fariborz Jahanian Date: Wed, 13 Nov 2013 23:59:17 +0000 Subject: [PATCH] ObjectiveC ARC. Introduce a new attribute, 'objc_bridge' that teaches the compiler about a subset of toll-free bridging semantics. This is wip. // rdar://15454846 llvm-svn: 194633 --- clang/include/clang/Basic/Attr.td | 6 +++ .../clang/Basic/DiagnosticSemaKinds.td | 10 ++++ clang/lib/Sema/SemaDeclAttr.cpp | 53 +++++++++++++++++++ clang/test/SemaObjC/objcbridge-attribute.m | 29 ++++++++++ 4 files changed, 98 insertions(+) create mode 100644 clang/test/SemaObjC/objcbridge-attribute.m diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 8ff725b77a80..a149a6a908f5 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -542,6 +542,12 @@ def NSBridged : InheritableAttr { let Args = [IdentifierArgument<"BridgedType", 1>]; } +def ObjCBridge : InheritableAttr { + let Spellings = [GNU<"objc_bridge">]; + let Subjects = [Record]; + let Args = [IdentifierArgument<"BridgedType", 1>]; +} + def NSReturnsRetained : InheritableAttr { let Spellings = [GNU<"ns_returns_retained">]; let Subjects = [ObjCMethod, Function]; diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 4d89a4d55c77..aae9df7ac4a1 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -2435,8 +2435,18 @@ def warn_objc_requires_super_protocol : Warning< def note_protocol_decl : Note< "protocol is declared here">; +// objc_bridge attribute diagnostics. def err_ns_bridged_not_interface : Error< "parameter of 'ns_bridged' attribute does not name an Objective-C class">; +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">; +def err_objc_bridge_not_cftype : Error< + "'objc_bridge' attribute must be applied to definition of CF types">; + +def err_objc_bridge_not_pointertype : Error< + "'objc_bridge' attribute must be applied to a pointer type">; // Function Parameter Semantic Analysis. def err_param_with_void_type : Error<"argument may not have 'void' type">; diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 09cc8becca1a..46a85c59b521 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -207,6 +207,12 @@ static inline bool isCFStringType(QualType T, ASTContext &Ctx) { return RD->getIdentifier() == &Ctx.Idents.get("__CFString"); } +static inline bool isCFRefType(TypedefNameDecl *TD, ASTContext &Ctx) { + StringRef TDName = TD->getIdentifier()->getName(); + return ((TDName.startswith("CF") || TDName.startswith("CG")) && + (TDName.rfind("Ref") != StringRef::npos)); +} + static unsigned getNumAttributeArgs(const AttributeList &Attr) { // FIXME: Include the type in the argument list. return Attr.getNumArgs() + Attr.hasParsedType(); @@ -4389,6 +4395,50 @@ static void handleNSBridgedAttr(Sema &S, Scope *Sc, Decl *D, Attr.getAttributeSpellingListIndex())); } +static void handleObjCBridgeAttr(Sema &S, Scope *Sc, Decl *D, + const AttributeList &Attr) { + if (TypedefNameDecl *TD = dyn_cast(D)) { + QualType T = TD->getUnderlyingType(); + if (T->isPointerType()) { + T = T->getPointeeType(); + if (T->isRecordType()) { + RecordDecl *RD = T->getAs()->getDecl(); + if (!RD || RD->isUnion()) { + S.Diag(D->getLocStart(), diag::err_attribute_wrong_decl_type) + << Attr.getRange() << Attr.getName() << ExpectedStruct; + return; + } + } + } else { + S.Diag(TD->getLocStart(), diag::err_objc_bridge_not_pointertype); + return; + } + // Check for T being a CFType goes here. + if (!isCFRefType(TD, S.Context)) { + S.Diag(TD->getLocStart(), diag::err_objc_bridge_not_cftype); + return; + } + } + else { + S.Diag(D->getLocStart(), diag::err_objc_bridge_attribute); + return; + } + + if (Attr.getNumArgs() != 1) { + S.Diag(D->getLocStart(), diag::err_objc_bridge_not_id); + return; + } + IdentifierLoc *Parm = Attr.isArgIdent(0) ? Attr.getArgAsIdent(0) : 0; + if (!Parm) { + S.Diag(D->getLocStart(), diag::err_objc_bridge_not_id); + return; + } + + D->addAttr(::new (S.Context) + ObjCBridgeAttr(Attr.getRange(), S.Context, Parm ? Parm->Ident : 0, + Attr.getAttributeSpellingListIndex())); +} + static void handleObjCOwnershipAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (hasDeclarator(D)) return; @@ -4675,6 +4725,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case AttributeList::AT_NSBridged: handleNSBridgedAttr(S, scope, D, Attr); break; + + case AttributeList::AT_ObjCBridge: + handleObjCBridgeAttr(S, scope, D, Attr); break; case AttributeList::AT_CFAuditedTransfer: case AttributeList::AT_CFUnknownTransfer: diff --git a/clang/test/SemaObjC/objcbridge-attribute.m b/clang/test/SemaObjC/objcbridge-attribute.m new file mode 100644 index 000000000000..797f00be546f --- /dev/null +++ b/clang/test/SemaObjC/objcbridge-attribute.m @@ -0,0 +1,29 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s +// rdar://15454846 + +typedef struct CGColor * __attribute__ ((objc_bridge(NSError))) CGColorRef; + +typedef struct CGColor * __attribute__((objc_bridge(12))) CFMyColorRef; // expected-error {{parameter of 'objc_bridge' attribute must be a single name of an Objective-C class}} + +typedef struct S1 * __attribute__ ((objc_bridge)) CGColorRef1; // expected-error {{parameter of 'objc_bridge' attribute must be a single name of an Objective-C class}} + +typedef void * __attribute__ ((objc_bridge(NSString))) CGColorRef2; + +typedef void * CFTypeRef __attribute__ ((objc_bridge(NSError))); + +typedef struct CGColor * __attribute__((objc_bridge(NSString, NSError))) CGColorRefNoNSObject;// expected-error {{use of undeclared identifier 'NSError'}} + +typedef struct CGColor __attribute__((objc_bridge(NSError))) CGColorRefNoNSObject2; // expected-error {{'objc_bridge' attribute must be applied to a pointer type}} + +typedef struct __attribute__((objc_bridge(NSError))) CFColor * CFColorRefNoNSObject; // expected-error {{'objc_bridge' attribute must be put on a typedef only}} + +typedef struct __attribute__((objc_bridge(NSError))) CFColor * CFColorRefNoNSObject1; + +typedef union CFUColor * __attribute__((objc_bridge(NSError))) CFColorRefNoNSObject2; // expected-error {{'objc_bridge' attribute only applies to structs}} + +@interface I +{ + __attribute__((objc_bridge(NSError))) void * color; // expected-error {{'objc_bridge' attribute must be put on a typedef only}} + +} +@end