ObjectiveC. Implement attribute 'objc_bridge_mutable'

whose semantic is currently identical to objc_bridge,
but their differences may manifest down the road with
further enhancements. // rdar://15498044

llvm-svn: 195376
This commit is contained in:
Fariborz Jahanian 2013-11-21 20:50:32 +00:00
parent c680226fbf
commit 87c7791bb7
4 changed files with 72 additions and 11 deletions

View File

@ -551,6 +551,12 @@ def ObjCBridge : InheritableAttr {
let Args = [IdentifierArgument<"BridgedType", 1>];
}
def ObjCBridgeMutable : InheritableAttr {
let Spellings = [GNU<"objc_bridge_mutable">];
let Subjects = [Record];
let Args = [IdentifierArgument<"BridgedType", 1>];
}
def NSReturnsRetained : InheritableAttr {
let Spellings = [GNU<"ns_returns_retained">];
let Subjects = [ObjCMethod, Function];

View File

@ -4362,6 +4362,30 @@ static void handleObjCBridgeAttr(Sema &S, Scope *Sc, Decl *D,
Attr.getAttributeSpellingListIndex()));
}
static void handleObjCBridgeMutableAttr(Sema &S, Scope *Sc, Decl *D,
const AttributeList &Attr) {
if (!isa<RecordDecl>(D)) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type)
<< Attr.getName()
<< (S.getLangOpts().CPlusPlus ? ExpectedStructOrUnionOrClass
: ExpectedStructOrUnion);
return;
}
IdentifierLoc *Parm = 0;
if (Attr.getNumArgs() == 1)
Parm = Attr.isArgIdent(0) ? Attr.getArgAsIdent(0) : 0;
if (!Parm) {
S.Diag(D->getLocStart(), diag::err_objc_attr_not_id) << Attr.getName() << 0;
return;
}
D->addAttr(::new (S.Context)
ObjCBridgeMutableAttr(Attr.getRange(), S.Context, Parm->Ident,
Attr.getAttributeSpellingListIndex()));
}
static void handleObjCOwnershipAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
if (hasDeclarator(D)) return;
@ -4651,6 +4675,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
case AttributeList::AT_ObjCBridge:
handleObjCBridgeAttr(S, scope, D, Attr); break;
case AttributeList::AT_ObjCBridgeMutable:
handleObjCBridgeMutableAttr(S, scope, D, Attr); break;
case AttributeList::AT_CFAuditedTransfer:
case AttributeList::AT_CFUnknownTransfer:

View File

@ -3165,24 +3165,26 @@ diagnoseObjCARCConversion(Sema &S, SourceRange castRange,
<< castRange << castExpr->getSourceRange();
}
static inline ObjCBridgeAttr *getObjCBridgeAttr(const TypedefType *TD) {
template <typename T>
static inline T *getObjCBridgeAttr(const TypedefType *TD) {
TypedefNameDecl *TDNDecl = TD->getDecl();
QualType QT = TDNDecl->getUnderlyingType();
if (QT->isPointerType()) {
QT = QT->getPointeeType();
if (const RecordType *RT = QT->getAs<RecordType>())
if (RecordDecl *RD = RT->getDecl())
if (RD->hasAttr<ObjCBridgeAttr>())
return RD->getAttr<ObjCBridgeAttr>();
if (RD->hasAttr<T>())
return RD->getAttr<T>();
}
return 0;
}
template <typename TB>
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 (ObjCBridgeAttr *ObjCBAttr = getObjCBridgeAttr(TD)) {
if (TB *ObjCBAttr = getObjCBridgeAttr<TB>(TD)) {
if (IdentifierInfo *Parm = ObjCBAttr->getBridgedType()) {
NamedDecl *Target = 0;
// Check for an existing type with this name.
@ -3231,11 +3233,12 @@ static bool CheckObjCBridgeNSCast(Sema &S, QualType castType, Expr *castExpr) {
return false;
}
template <typename TB>
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 (ObjCBridgeAttr *ObjCBAttr = getObjCBridgeAttr(TD)) {
if (TB *ObjCBAttr = getObjCBridgeAttr<TB>(TD)) {
if (IdentifierInfo *Parm = ObjCBAttr->getBridgedType()) {
NamedDecl *Target = 0;
// Check for an existing type with this name.
@ -3289,10 +3292,14 @@ void Sema::CheckTollFreeBridgeCast(QualType castType, Expr *castExpr) {
// warn in presense of __bridge casting to or from a toll free bridge cast.
ARCConversionTypeClass exprACTC = classifyTypeForARCConversion(castExpr->getType());
ARCConversionTypeClass castACTC = classifyTypeForARCConversion(castType);
if (castACTC == ACTC_retainable && exprACTC == ACTC_coreFoundation)
(void)CheckObjCBridgeNSCast(*this, castType, castExpr);
else if (castACTC == ACTC_coreFoundation && exprACTC == ACTC_retainable)
(void)CheckObjCBridgeCFCast(*this, castType, castExpr);
if (castACTC == ACTC_retainable && exprACTC == ACTC_coreFoundation) {
(void)CheckObjCBridgeNSCast<ObjCBridgeAttr>(*this, castType, castExpr);
(void)CheckObjCBridgeNSCast<ObjCBridgeMutableAttr>(*this, castType, castExpr);
}
else if (castACTC == ACTC_coreFoundation && exprACTC == ACTC_retainable) {
(void)CheckObjCBridgeCFCast<ObjCBridgeAttr>(*this, castType, castExpr);
(void)CheckObjCBridgeCFCast<ObjCBridgeMutableAttr>(*this, castType, castExpr);
}
}
Sema::ARCConversionResult
@ -3355,12 +3362,14 @@ Sema::CheckObjCARCConversion(SourceRange castRange, QualType castType,
if (castACTC == ACTC_retainable && exprACTC == ACTC_coreFoundation &&
(CCK == CCK_CStyleCast || CCK == CCK_FunctionalCast))
if (CheckObjCBridgeNSCast(*this, castType, castExpr))
if (CheckObjCBridgeNSCast<ObjCBridgeAttr>(*this, castType, castExpr) ||
CheckObjCBridgeNSCast<ObjCBridgeMutableAttr>(*this, castType, castExpr))
return ACR_okay;
if (castACTC == ACTC_coreFoundation && exprACTC == ACTC_retainable &&
(CCK == CCK_CStyleCast || CCK == CCK_FunctionalCast))
if (CheckObjCBridgeCFCast(*this, castType, castExpr))
if (CheckObjCBridgeCFCast<ObjCBridgeAttr>(*this, castType, castExpr) ||
CheckObjCBridgeCFCast<ObjCBridgeMutableAttr>(*this, castType, castExpr))
return ACR_okay;

View File

@ -0,0 +1,19 @@
// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
// rdar://15498044
typedef struct __attribute__((objc_bridge_mutable(NSMutableDictionary))) __CFDictionary * CFMutableDictionaryRef; // expected-note {{declared here}}
@interface NSDictionary
@end
@interface NSMutableDictionary : NSDictionary
@end
void Test(NSMutableDictionary *md, NSDictionary *nd, CFMutableDictionaryRef mcf) {
(void) (CFMutableDictionaryRef)md;
(void) (CFMutableDictionaryRef)nd; // expected-warning {{'NSDictionary' cannot bridge to 'CFMutableDictionaryRef' (aka 'struct __CFDictionary *')}}
(void) (NSDictionary *)mcf; // expected-warning {{'CFMutableDictionaryRef' (aka 'struct __CFDictionary *') bridges to NSMutableDictionary, not 'NSDictionary'}}
(void) (NSMutableDictionary *)mcf; // ok;
}