From: Fariborz Jahanian Date: Tue, 21 Jun 2011 17:38:29 +0000 (+0000) Subject: objc-arc: CodeGen part of unbridged cast of CF types. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=af9751747b098d77052cb71f1e648f29cfbadcc1;p=clang objc-arc: CodeGen part of unbridged cast of CF types. // rdar://9474349 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@133525 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index f43ff934ff..0339a2941b 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -5616,12 +5616,12 @@ public: /// \brief Checks for valid expressions which can be cast to an ObjC /// pointer without needing a bridge cast. - bool ValidObjCARCNoBridgeCastExpr(const Expr *Exp); + bool ValidObjCARCNoBridgeCastExpr(Expr *&Exp, QualType castType); /// \brief Checks for invalid conversions and casts between /// retainable pointers and other pointer kinds. void CheckObjCARCConversion(SourceRange castRange, QualType castType, - Expr *op, CheckedConversionKind CCK); + Expr *&op, CheckedConversionKind CCK); /// checkRetainCycles - Check whether an Objective-C message send /// might create an obvious retain cycle. diff --git a/lib/Sema/SemaCXXCast.cpp b/lib/Sema/SemaCXXCast.cpp index 0b3083aaa6..5f1a355c8a 100644 --- a/lib/Sema/SemaCXXCast.cpp +++ b/lib/Sema/SemaCXXCast.cpp @@ -641,8 +641,9 @@ CheckReinterpretCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, diagnoseBadCast(Self, msg, CT_Reinterpret, OpRange, SrcExpr.get(), DestType); } } else if (tcr == TC_Success && Self.getLangOptions().ObjCAutoRefCount) { + Expr *Exp = SrcExpr.get(); Self.CheckObjCARCConversion(OpRange, DestType, - SrcExpr.get(), Sema::CCK_OtherCast); + Exp, Sema::CCK_OtherCast); } } @@ -704,9 +705,11 @@ CheckStaticCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, } else if (tcr == TC_Success) { if (Kind == CK_BitCast) Self.CheckCastAlign(SrcExpr.get(), DestType, OpRange); - if (Self.getLangOptions().ObjCAutoRefCount) + if (Self.getLangOptions().ObjCAutoRefCount) { + Expr *Exp = SrcExpr.get(); Self.CheckObjCARCConversion(OpRange, DestType, - SrcExpr.get(), Sema::CCK_OtherCast); + Exp, Sema::CCK_OtherCast); + } } else if (Kind == CK_BitCast) Self.CheckCastAlign(SrcExpr.get(), DestType, OpRange); diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp index 02dd4a1a3e..ff3f837bac 100644 --- a/lib/Sema/SemaExprObjC.cpp +++ b/lib/Sema/SemaExprObjC.cpp @@ -1551,14 +1551,50 @@ namespace { } bool -Sema::ValidObjCARCNoBridgeCastExpr(const Expr *Exp) { - Exp = Exp->IgnoreParenImpCasts(); - return isa(Exp) || isa(Exp); +Sema::ValidObjCARCNoBridgeCastExpr(Expr *&Exp, QualType castType) { + Expr *NewExp = Exp->IgnoreParenImpCasts(); + + if (!isa(NewExp) && !isa(NewExp)) + return false; + ObjCMethodDecl *method = 0; + if (ObjCPropertyRefExpr *PRE = dyn_cast(NewExp)) { + method = PRE->getExplicitProperty()->getGetterMethodDecl(); + } + else { + ObjCMessageExpr *ME = cast(NewExp); + method = ME->getMethodDecl(); + } + if (!method) + return false; + if (method->hasAttr()) + return true; + bool MethodReturnsPlusOne = method->hasAttr(); + if (!MethodReturnsPlusOne) { + ObjCMethodFamily family = method->getSelector().getMethodFamily(); + switch (family) { + case OMF_alloc: + case OMF_copy: + case OMF_mutableCopy: + case OMF_new: + MethodReturnsPlusOne = true; + break; + default: + break; + } + } + if (MethodReturnsPlusOne) { + TypeSourceInfo *TSInfo = + Context.getTrivialTypeSourceInfo(castType, SourceLocation()); + ExprResult ExpRes = BuildObjCBridgedCast(SourceLocation(), OBC_BridgeTransfer, + SourceLocation(), TSInfo, Exp); + Exp = ExpRes.take(); + } + return true; } void Sema::CheckObjCARCConversion(SourceRange castRange, QualType castType, - Expr *castExpr, CheckedConversionKind CCK) { + Expr *&castExpr, CheckedConversionKind CCK) { QualType castExprType = castExpr->getType(); ARCConversionTypeClass exprACTC = classifyTypeForARCConversion(castExprType); @@ -1614,7 +1650,7 @@ Sema::CheckObjCARCConversion(SourceRange castRange, QualType castType, castExprType->isCARCBridgableType()) { // explicit unbridged casts are allowed if the source of the cast is a // message sent to an objc method (or property access) - if (ValidObjCARCNoBridgeCastExpr(castExpr)) + if (ValidObjCARCNoBridgeCastExpr(castExpr, castType)) return; Diag(loc, diag::err_arc_cast_requires_bridge) << 2 diff --git a/test/CodeGenObjC/arc-unbridged-cast.m b/test/CodeGenObjC/arc-unbridged-cast.m new file mode 100644 index 0000000000..5c560e94ab --- /dev/null +++ b/test/CodeGenObjC/arc-unbridged-cast.m @@ -0,0 +1,27 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -emit-llvm -fobjc-nonfragile-abi -fobjc-arc -o - %s | FileCheck %s +// rdar://9744349 + +typedef const struct __CFString * CFStringRef; + +@interface I +@property CFStringRef P; +- (CFStringRef) CFMeth __attribute__((cf_returns_retained)); +- (CFStringRef) newSomething; +- (CFStringRef) P __attribute__((cf_returns_retained)); +@end + +@implementation I +@synthesize P; +- (id) Meth { + I* p1 = (id)[p1 P]; + id p2 = (id)[p1 CFMeth]; + id p3 = (id)[p1 newSomething]; + return (id) p1.P; +} +- (CFStringRef) CFMeth { return 0; } +- (CFStringRef) newSomething { return 0; } +- (CFStringRef) P { return 0; } +- (void) setP : (CFStringRef)arg {} +@end + +// CHECK-NOT: call i8* @objc_retainAutoreleasedReturnValue