From 0f3bb9eb07a0cfd49929ca0d70bbe13b0aa74aff Mon Sep 17 00:00:00 2001 From: Fariborz Jahanian Date: Tue, 19 Nov 2013 00:09:48 +0000 Subject: [PATCH] ObjectiveC ARC. Adopt objc_bridge attribute on struct/union/class instead of typedef of such types. // rdar://15454846 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@195061 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/DiagnosticSemaKinds.td | 4 +-- lib/Sema/SemaDecl.cpp | 27 +++++++++++++++ lib/Sema/SemaDeclAttr.cpp | 34 +------------------ lib/Sema/SemaExprObjC.cpp | 29 ++++++++++------ test/SemaObjC/objcbridge-attribute.m | 39 +++++++++++++--------- 5 files changed, 71 insertions(+), 62 deletions(-) diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 22db61dde4..3b80df844a 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -2442,11 +2442,9 @@ def err_ns_bridged_not_interface : Error< 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">; + "'objc_bridge' attribute must be applied to a struct, C++ class, or union">; def err_objc_bridge_not_cftype : Error< "'objc_bridge' attribute must be applied to definition of CF types">; -def err_objc_bridge_not_pointert_to_struct : Error< - "'objc_bridge' attribute must be applied to a pointer to struct type">; def err_objc_cf_bridged_not_interface : Error< "CF object of type %0 is bridged to '%1', which is not an Objective-C class">; def err_objc_ns_bridged_invalid_cfobject : Error< diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 3cdb72714f..6a5d608c7b 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -10072,6 +10072,31 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) { } } +static inline bool isTollFreeBridgeCFRefType(TypedefDecl *TD) { + TypedefNameDecl * TDefNameDecl = TD; + const Type *TP = TDefNameDecl->getUnderlyingType().getTypePtr(); + while (const TypedefType *TDef = dyn_cast(TP)) { + TDefNameDecl = TDef->getDecl(); + TP = TDefNameDecl->getUnderlyingType().getTypePtr(); + } + + StringRef TDName = TDefNameDecl->getIdentifier()->getName(); + return (TDName.startswith("CF") && TDName.endswith("Ref")); +} + +/// CheckObjCBridgeAttribute - Checks that objc_bridge attribute is +/// properly applied to a typedef of a pointer to struct/union/class +static void CheckObjCBridgeAttribute(Sema &S, TypedefDecl *TD) { + QualType T = TD->getUnderlyingType(); + if (!T->isPointerType()) + return; + T = T->getPointeeType(); + if (T->isStructureType() || T->isUnionType() || T->isClassType()) + if (RecordDecl *RD = T->getAs()->getDecl()) + if (RD->hasAttr() && !isTollFreeBridgeCFRefType(TD)) + S.Diag(TD->getLocStart(), diag::err_objc_bridge_not_cftype); +} + TypedefDecl *Sema::ParseTypedefDecl(Scope *S, Declarator &D, QualType T, TypeSourceInfo *TInfo) { assert(D.getIdentifier() && "Wrong callback for declspec without declarator"); @@ -10095,6 +10120,8 @@ TypedefDecl *Sema::ParseTypedefDecl(Scope *S, Declarator &D, QualType T, return NewTD; } + CheckObjCBridgeAttribute(*this, NewTD); + if (D.getDeclSpec().isModulePrivateSpecified()) { if (CurContext->isFunctionOrMethod()) Diag(NewTD->getLocation(), diag::err_module_private_local) diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index 7987a18f61..77f7905302 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -207,11 +207,6 @@ static inline bool isCFStringType(QualType T, ASTContext &Ctx) { return RD->getIdentifier() == &Ctx.Idents.get("__CFString"); } -static inline bool isTollFreeBridgeCFRefType(TypedefNameDecl *TD, ASTContext &Ctx) { - StringRef TDName = TD->getIdentifier()->getName(); - return (TDName.startswith("CF") && TDName.endswith("Ref")); -} - static unsigned getNumAttributeArgs(const AttributeList &Attr) { // FIXME: Include the type in the argument list. return Attr.getNumArgs() + Attr.hasParsedType(); @@ -4396,34 +4391,7 @@ static void handleNSBridgedAttr(Sema &S, Scope *Sc, Decl *D, 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_objc_bridge_not_pointert_to_struct) - << Attr.getRange(); - return; - } - } else { - S.Diag(TD->getLocStart(), diag::err_objc_bridge_not_pointert_to_struct) - << Attr.getRange(); - return; - } - } else { - S.Diag(TD->getLocStart(), diag::err_objc_bridge_not_pointert_to_struct) - << Attr.getRange(); - return; - } - // Check for T being a CFType goes here. - if (!isTollFreeBridgeCFRefType(TD, S.Context)) { - S.Diag(TD->getLocStart(), diag::err_objc_bridge_not_cftype); - return; - } - } - else { + if (!isa(D)) { S.Diag(D->getLocStart(), diag::err_objc_bridge_attribute); return; } diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp index b59e0a6238..69d7b9e07e 100644 --- a/lib/Sema/SemaExprObjC.cpp +++ b/lib/Sema/SemaExprObjC.cpp @@ -3165,15 +3165,26 @@ diagnoseObjCARCConversion(Sema &S, SourceRange castRange, << castRange << castExpr->getSourceRange(); } +static inline ObjCBridgeAttr *getObjCBridgeAttr(const TypedefType *TD) { + TypedefNameDecl *TDNDecl = TD->getDecl(); + QualType QT = TDNDecl->getUnderlyingType(); + if (QT->isPointerType()) { + QT = QT->getPointeeType(); + if (QT->isStructureType() || QT->isUnionType() || QT->isClassType()) + if (RecordDecl *RD = QT->getAs()->getDecl()) + if (RD->hasAttr()) + return RD->getAttr(); + } + return 0; +} + static bool CheckObjCBridgeNSCast(Sema &S, QualType castType, Expr *castExpr) { QualType T = castExpr->getType(); while (const TypedefType *TD = dyn_cast(T.getTypePtr())) { TypedefNameDecl *TDNDecl = TD->getDecl(); - if (TDNDecl->hasAttr()) { - ObjCBridgeAttr *ObjCBAttr = TDNDecl->getAttr(); - IdentifierInfo *Parm = ObjCBAttr->getBridgedType(); - NamedDecl *Target = 0; - if (Parm && S.getLangOpts().ObjC1) { + if (ObjCBridgeAttr *ObjCBAttr = getObjCBridgeAttr(TD)) { + if (IdentifierInfo *Parm = ObjCBAttr->getBridgedType()) { + NamedDecl *Target = 0; // Check for an existing type with this name. LookupResult R(S, DeclarationName(Parm), SourceLocation(), Sema::LookupOrdinaryName); @@ -3215,11 +3226,9 @@ static bool CheckObjCBridgeCFCast(Sema &S, QualType castType, Expr *castExpr) { QualType T = castType; while (const TypedefType *TD = dyn_cast(T.getTypePtr())) { TypedefNameDecl *TDNDecl = TD->getDecl(); - if (TDNDecl->hasAttr()) { - ObjCBridgeAttr *ObjCBAttr = TDNDecl->getAttr(); - IdentifierInfo *Parm = ObjCBAttr->getBridgedType(); - NamedDecl *Target = 0; - if (Parm && S.getLangOpts().ObjC1) { + if (ObjCBridgeAttr *ObjCBAttr = getObjCBridgeAttr(TD)) { + if (IdentifierInfo *Parm = ObjCBAttr->getBridgedType()) { + NamedDecl *Target = 0; // Check for an existing type with this name. LookupResult R(S, DeclarationName(Parm), SourceLocation(), Sema::LookupOrdinaryName); diff --git a/test/SemaObjC/objcbridge-attribute.m b/test/SemaObjC/objcbridge-attribute.m index d39861f061..2ab21016cb 100644 --- a/test/SemaObjC/objcbridge-attribute.m +++ b/test/SemaObjC/objcbridge-attribute.m @@ -1,37 +1,41 @@ // RUN: %clang_cc1 -fsyntax-only -fobjc-arc -verify -Wno-objc-root-class %s // rdar://15454846 -typedef struct __CFErrorRef * __attribute__ ((objc_bridge(NSError))) CFErrorRef; // expected-note 2 {{declared here}} +typedef struct __attribute__ ((objc_bridge(NSError))) __CFErrorRef * CFErrorRef; // expected-note 2 {{declared here}} -typedef struct __CFMyColor * __attribute__((objc_bridge(12))) CFMyColorRef; // expected-error {{parameter of 'objc_bridge' attribute must be a single name of an Objective-C class}} +typedef struct __attribute__((objc_bridge(12))) __CFMyColor *CFMyColorRef; // expected-error {{parameter of 'objc_bridge' attribute must be a single name of an Objective-C class}} -typedef struct __CFArray * __attribute__ ((objc_bridge)) CFArrayRef; // expected-error {{parameter of 'objc_bridge' attribute must be a single name of an Objective-C class}} +typedef struct __attribute__ ((objc_bridge)) __CFArray *CFArrayRef; // expected-error {{parameter of 'objc_bridge' attribute must be a single name of an Objective-C class}} -typedef void * __attribute__ ((objc_bridge(NSURL))) CFURLRef; // expected-error {{'objc_bridge' attribute must be applied to a pointer to struct type}} +typedef void * __attribute__ ((objc_bridge(NSURL))) CFURLRef; // expected-error {{'objc_bridge' attribute must be applied to a struct, C++ class, or union}} -typedef void * CFStringRef __attribute__ ((objc_bridge(NSString))); // expected-error {{'objc_bridge' attribute must be applied to a pointer to struct type}} +typedef void * CFStringRef __attribute__ ((objc_bridge(NSString))); // expected-error {{'objc_bridge' attribute must be applied to a struct, C++ class, or union}} -typedef struct __CFLocale * __attribute__((objc_bridge(NSLocale, NSError))) CFLocaleRef;// expected-error {{use of undeclared identifier 'NSError'}} +typedef struct __attribute__((objc_bridge(NSLocale, NSError))) __CFLocale *CFLocaleRef;// expected-error {{use of undeclared identifier 'NSError'}} -typedef struct __CFData __attribute__((objc_bridge(NSData))) CFDataRef; // expected-error {{'objc_bridge' attribute must be applied to a pointer to struct type}} +typedef struct __CFData __attribute__((objc_bridge(NSData))) CFDataRef; // expected-error {{'objc_bridge' attribute must be applied to a struct, C++ class, or union}} -typedef struct __attribute__((objc_bridge(NSDictionary))) __CFDictionary * CFDictionaryRef; // expected-error {{'objc_bridge' attribute must be put on a typedef only}} +typedef struct __attribute__((objc_bridge(NSDictionary))) __CFDictionary * CFDictionaryRef; -typedef struct __CFSetRef * CFSetRef __attribute__((objc_bridge(NSSet))); +typedef struct __CFSetRef * CFSetRef __attribute__((objc_bridge(NSSet))); // expected-error {{'objc_bridge' attribute must be applied to a struct, C++ class, or union}}; -typedef union __CFUColor * __attribute__((objc_bridge(NSUColor))) CFUColorRef; // expected-error {{'objc_bridge' attribute must be applied to a pointer to struct type}} +typedef union __CFUColor __attribute__((objc_bridge(NSUColor))) * CFUColorRef; // expected-error {{'objc_bridge' attribute must be applied to a struct, C++ class, or union}}; + +typedef union __CFUColor __attribute__((objc_bridge(NSUColor))) *CFUColor1Ref; // expected-error {{'objc_bridge' attribute must be applied to a struct, C++ class, or union}}; + +typedef union __attribute__((objc_bridge(NSUColor))) __CFUPrimeColor XXX; +typedef XXX *CFUColor2Ref; @interface I { - __attribute__((objc_bridge(NSError))) void * color; // expected-error {{'objc_bridge' attribute must be put on a typedef only}} - + __attribute__((objc_bridge(NSError))) void * color; // expected-error {{'objc_bridge' attribute must be applied to a struct, C++ class, or union}}; } @end @protocol NSTesting @end @class NSString; -typedef struct __CFError * __attribute__((objc_bridge(NSTesting))) CFTestingRef; // expected-note {{declared here}} +typedef struct __attribute__((objc_bridge(NSTesting))) __CFError *CFTestingRef; // expected-note {{declared here}} id Test1(CFTestingRef cf) { return (NSString *)cf; // expected-error {{CF object of type 'CFTestingRef' (aka 'struct __CFError *') is bridged to 'NSTesting', which is not an Objective-C class}} @@ -46,14 +50,17 @@ typedef CFErrorRef1 CFErrorRef2; @interface MyError : NSError @end +@interface NSUColor @end + @class NSString; -void Test2(CFErrorRef2 cf, NSError *ns, NSString *str, Class c) { - (void)(NSString *)cf; // expected-warning {{CFErrorRef bridges to NSError, not NSString}} +void Test2(CFErrorRef2 cf, NSError *ns, NSString *str, Class c, CFUColor2Ref cf2) { + (void)(NSString *)cf; // expected-warning {{CFErrorRef2 bridges to NSError, not NSString}} (void)(NSError *)cf; // okay (void)(MyError*)cf; // okay, + (void)(NSUColor *)cf2; // okay (void)(CFErrorRef)ns; // okay (void)(CFErrorRef)str; // expected-warning {{NSString cannot bridge to CFErrorRef}} - (void)(Class)cf; // expected-warning {{CFErrorRef bridges to NSError, not 'Class'}} + (void)(Class)cf; // expected-warning {{CFErrorRef2 bridges to NSError, not 'Class'}} (void)(CFErrorRef)c; // expected-warning {{'Class' cannot bridge to 'CFErrorRef'}} } -- 2.40.0