r195061 - ObjectiveC ARC. Adopt objc_bridge attribute

Jean-Daniel Dupas devlists at shadowlab.org
Mon Nov 18 17:22:11 PST 2013


Le 19 nov. 2013 à 01:27, Douglas Gregor <dgregor at apple.com> a écrit :

> 
> On Nov 18, 2013, at 4:09 PM, Fariborz Jahanian <fjahanian at apple.com> wrote:
> 
>> Author: fjahanian
>> Date: Mon Nov 18 18:09:48 2013
>> New Revision: 195061
>> 
>> URL: http://llvm.org/viewvc/llvm-project?rev=195061&view=rev
>> Log:
>> ObjectiveC ARC. Adopt objc_bridge attribute
>> on struct/union/class instead of typedef of
>> such types. // rdar://15454846
>> 
>> Modified:
>>   cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
>>   cfe/trunk/lib/Sema/SemaDecl.cpp
>>   cfe/trunk/lib/Sema/SemaDeclAttr.cpp
>>   cfe/trunk/lib/Sema/SemaExprObjC.cpp
>>   cfe/trunk/test/SemaObjC/objcbridge-attribute.m
>> 
>> Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=195061&r1=195060&r2=195061&view=diff
>> ==============================================================================
>> --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
>> +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Mon Nov 18 18:09:48 2013
>> @@ -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”>;
> 
> Nit: could you %select{|, C++ class}0 based on getLangOpts().CPlusPlus, so that we don’t say “C++ class” in non-C++ code?
> 
>> 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<
>> 
>> Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=195061&r1=195060&r2=195061&view=diff
>> ==============================================================================
>> --- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
>> +++ cfe/trunk/lib/Sema/SemaDecl.cpp Mon Nov 18 18:09:48 2013
>> @@ -10072,6 +10072,31 @@ void Sema::AddKnownFunctionAttributes(Fu
>>  }
>> }
>> 
>> +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"));
>> +}
> 
> We shouldn’t be performing the name check here. Some CF-like types might not be named CF*Ref, and this attribute is specific enough that we can trust the user to only put it on structs where it makes sense.

You're right, for instance AddressBook Framework provides such types:

ABAddressBookRef -> ABAddressBook, 
…


>> +/// 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(Scop
>>    return NewTD;
>>  }
>> 
>> +  CheckObjCBridgeAttribute(*this, NewTD);
>> +  
>>  if (D.getDeclSpec().isModulePrivateSpecified()) {
>>    if (CurContext->isFunctionOrMethod())
>>      Diag(NewTD->getLocation(), diag::err_module_private_local)
>> 
>> Modified: cfe/trunk/lib/Sema/SemaDeclAttr.cpp
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclAttr.cpp?rev=195061&r1=195060&r2=195061&view=diff
>> ==============================================================================
>> --- cfe/trunk/lib/Sema/SemaDeclAttr.cpp (original)
>> +++ cfe/trunk/lib/Sema/SemaDeclAttr.cpp Mon Nov 18 18:09:48 2013
>> @@ -207,11 +207,6 @@ static inline bool isCFStringType(QualTy
>>  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,
>> 
>> 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;
>>  }
>> 
>> Modified: cfe/trunk/lib/Sema/SemaExprObjC.cpp
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprObjC.cpp?rev=195061&r1=195060&r2=195061&view=diff
>> ==============================================================================
>> --- cfe/trunk/lib/Sema/SemaExprObjC.cpp (original)
>> +++ cfe/trunk/lib/Sema/SemaExprObjC.cpp Mon Nov 18 18:09:48 2013
>> @@ -3165,15 +3165,26 @@ diagnoseObjCARCConversion(Sema &S, Sourc
>>    << 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())
> 
> How about
> 
> 	if (const RecordType *RT = QT->getAs<RecordType>())
> 
> ?
> 
> 
>> +      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 &
>>  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);
>> 
>> Modified: cfe/trunk/test/SemaObjC/objcbridge-attribute.m
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/objcbridge-attribute.m?rev=195061&r1=195060&r2=195061&view=diff
>> ==============================================================================
>> --- cfe/trunk/test/SemaObjC/objcbridge-attribute.m (original)
>> +++ cfe/trunk/test/SemaObjC/objcbridge-attribute.m Mon Nov 18 18:09:48 2013
>> @@ -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
>> 
>> + at 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'}}
>> }
>> 
>> 
>> _______________________________________________
>> cfe-commits mailing list
>> cfe-commits at cs.uiuc.edu
>> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
> 
> 
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

-- Jean-Daniel








More information about the cfe-commits mailing list