aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFariborz Jahanian <fjahanian@apple.com>2011-06-21 17:38:29 +0000
committerFariborz Jahanian <fjahanian@apple.com>2011-06-21 17:38:29 +0000
commitaf9751747b098d77052cb71f1e648f29cfbadcc1 (patch)
treeb0d391080be0a9d8962d361160daaffd6958ddbd
parent14d251cd62942bf7d56bb87a267ba2ca2f7fae3e (diff)
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
-rw-r--r--include/clang/Sema/Sema.h4
-rw-r--r--lib/Sema/SemaCXXCast.cpp9
-rw-r--r--lib/Sema/SemaExprObjC.cpp46
-rw-r--r--test/CodeGenObjC/arc-unbridged-cast.m27
4 files changed, 76 insertions, 10 deletions
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<ObjCMessageExpr>(Exp) || isa<ObjCPropertyRefExpr>(Exp);
+Sema::ValidObjCARCNoBridgeCastExpr(Expr *&Exp, QualType castType) {
+ Expr *NewExp = Exp->IgnoreParenImpCasts();
+
+ if (!isa<ObjCMessageExpr>(NewExp) && !isa<ObjCPropertyRefExpr>(NewExp))
+ return false;
+ ObjCMethodDecl *method = 0;
+ if (ObjCPropertyRefExpr *PRE = dyn_cast<ObjCPropertyRefExpr>(NewExp)) {
+ method = PRE->getExplicitProperty()->getGetterMethodDecl();
+ }
+ else {
+ ObjCMessageExpr *ME = cast<ObjCMessageExpr>(NewExp);
+ method = ME->getMethodDecl();
+ }
+ if (!method)
+ return false;
+ if (method->hasAttr<CFReturnsNotRetainedAttr>())
+ return true;
+ bool MethodReturnsPlusOne = method->hasAttr<CFReturnsRetainedAttr>();
+ 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