ObjectiveC ARC. Adopt objc_bridge attribute

on struct/union/class instead of typedef of
such types. // rdar://15454846

llvm-svn: 195061
This commit is contained in:
Fariborz Jahanian 2013-11-19 00:09:48 +00:00
parent e26a3774c6
commit db3d8554be
5 changed files with 71 additions and 62 deletions

View File

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

View File

@ -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<TypedefType>(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<RecordType>()->getDecl())
if (RD->hasAttr<ObjCBridgeAttr>() && !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)

View File

@ -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<TypedefNameDecl>(D)) {
QualType T = TD->getUnderlyingType();
if (T->isPointerType()) {
T = T->getPointeeType();
if (T->isRecordType()) {
RecordDecl *RD = T->getAs<RecordType>()->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<RecordDecl>(D)) {
S.Diag(D->getLocStart(), diag::err_objc_bridge_attribute);
return;
}

View File

@ -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<RecordType>()->getDecl())
if (RD->hasAttr<ObjCBridgeAttr>())
return RD->getAttr<ObjCBridgeAttr>();
}
return 0;
}
static bool CheckObjCBridgeNSCast(Sema &S, QualType castType, Expr *castExpr) {
QualType T = castExpr->getType();
while (const TypedefType *TD = dyn_cast<TypedefType>(T.getTypePtr())) {
TypedefNameDecl *TDNDecl = TD->getDecl();
if (TDNDecl->hasAttr<ObjCBridgeAttr>()) {
ObjCBridgeAttr *ObjCBAttr = TDNDecl->getAttr<ObjCBridgeAttr>();
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<TypedefType>(T.getTypePtr())) {
TypedefNameDecl *TDNDecl = TD->getDecl();
if (TDNDecl->hasAttr<ObjCBridgeAttr>()) {
ObjCBridgeAttr *ObjCBAttr = TDNDecl->getAttr<ObjCBridgeAttr>();
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);

View File

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