objc-arc: Add support for unbridged cast of
__builtin___CFStringMakeConstantString and CF typed function calls
with explicit cf_returns_retained/cf_returns_not_retained attributes.
// rdar://9544832
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@133535 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp
index ff3f837..83b01f2 100644
--- a/lib/Sema/SemaExprObjC.cpp
+++ b/lib/Sema/SemaExprObjC.cpp
@@ -1552,36 +1552,56 @@
bool
Sema::ValidObjCARCNoBridgeCastExpr(Expr *&Exp, QualType castType) {
- Expr *NewExp = Exp->IgnoreParenImpCasts();
+ Expr *NewExp = Exp->IgnoreParenCasts();
- if (!isa<ObjCMessageExpr>(NewExp) && !isa<ObjCPropertyRefExpr>(NewExp))
+ if (!isa<ObjCMessageExpr>(NewExp) && !isa<ObjCPropertyRefExpr>(NewExp)
+ && !isa<CallExpr>(NewExp))
return false;
ObjCMethodDecl *method = 0;
+ bool MethodReturnsPlusOne = false;
+
if (ObjCPropertyRefExpr *PRE = dyn_cast<ObjCPropertyRefExpr>(NewExp)) {
method = PRE->getExplicitProperty()->getGetterMethodDecl();
}
- else {
- ObjCMessageExpr *ME = cast<ObjCMessageExpr>(NewExp);
+ else if (ObjCMessageExpr *ME = dyn_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;
+ else {
+ CallExpr *CE = cast<CallExpr>(NewExp);
+ Decl *CallDecl = CE->getCalleeDecl();
+ if (!CallDecl)
+ return false;
+ if (CallDecl->hasAttr<CFReturnsNotRetainedAttr>())
+ return true;
+ MethodReturnsPlusOne = CallDecl->hasAttr<CFReturnsRetainedAttr>();
+ if (!MethodReturnsPlusOne) {
+ if (NamedDecl *ND = dyn_cast<NamedDecl>(CallDecl))
+ if (const IdentifierInfo *Id = ND->getIdentifier())
+ if (Id->isStr("__builtin___CFStringMakeConstantString"))
+ return true;
}
}
+
+ if (!MethodReturnsPlusOne) {
+ if (!method)
+ return false;
+ if (method->hasAttr<CFReturnsNotRetainedAttr>())
+ return true;
+ 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());
diff --git a/test/CodeGenObjC/arc-unbridged-cast.m b/test/CodeGenObjC/arc-unbridged-cast.m
index 5c560e9..0f3db09 100644
--- a/test/CodeGenObjC/arc-unbridged-cast.m
+++ b/test/CodeGenObjC/arc-unbridged-cast.m
@@ -24,4 +24,14 @@
- (void) setP : (CFStringRef)arg {}
@end
+// rdar://9544832
+CFStringRef SomeOtherFunc() __attribute__((cf_returns_retained));
+id MMM()
+{
+ id obj = (id)((CFStringRef) __builtin___CFStringMakeConstantString ("" "Some CF String" ""));
+ if (obj)
+ return (id) SomeOtherFunc();
+ return 0;
+}
+
// CHECK-NOT: call i8* @objc_retainAutoreleasedReturnValue