From 9003af0a2442571f26f2b53a8d19ee25450212ed Mon Sep 17 00:00:00 2001
From: Akira Hatanaka <ahatanaka@apple.com>
Date: Tue, 11 Apr 2017 22:01:33 +0000
Subject: [PATCH] [Sema][ObjC] Check whether a variable has a definition,
 rather than checking its storage class, when determining whether casting a C
 pointer to an ObjC pointer is allowed.

This change allows casting variables whose declarations are directly
contained in a linkage specification to an ObjC pointer type. Those
variables are treated as if they contain the extern specifier for the
purpose of determining whether they are definitions or not.

rdar://problem/29249853

Differential Revision: https://reviews.llvm.org/D31673

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@299992 91177308-0d34-0410-b5e6-96231b3b80d8
---
 lib/Sema/SemaExprObjC.cpp           |  2 +-
 test/SemaObjCXX/arc-bridged-cast.mm | 16 ++++++++++++++++
 2 files changed, 17 insertions(+), 1 deletion(-)

diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp
index c883f2e2fe7..9cc443ed4fd 100644
--- a/lib/Sema/SemaExprObjC.cpp
+++ b/lib/Sema/SemaExprObjC.cpp
@@ -3355,7 +3355,7 @@ namespace {
       if (isAnyRetainable(TargetClass) &&
           isAnyRetainable(SourceClass) &&
           var &&
-          var->getStorageClass() == SC_Extern &&
+          !var->hasDefinition(Context) &&
           var->getType().isConstQualified()) {
 
         // In system headers, they can also be assumed to be immune to retains.
diff --git a/test/SemaObjCXX/arc-bridged-cast.mm b/test/SemaObjCXX/arc-bridged-cast.mm
index 55cdd3f2c48..b5d57740eec 100644
--- a/test/SemaObjCXX/arc-bridged-cast.mm
+++ b/test/SemaObjCXX/arc-bridged-cast.mm
@@ -52,3 +52,19 @@ void testObjCBridgeId() {
   ref = (__bridge_retained CFAnnotatedObjectRef) CreateSomething();
   ref = (__bridge_retained CFAnnotatedObjectRef) CreateNSString();
 }
+
+struct __CFAnnotatedObject {
+} cf0;
+
+extern const CFAnnotatedObjectRef r0;
+extern const CFAnnotatedObjectRef r1 = &cf0;
+extern "C" const CFAnnotatedObjectRef r2;
+extern "C" const CFAnnotatedObjectRef r3 = &cf0;
+
+void testExternC() {
+  id obj;
+  obj = (id)r0;
+  obj = (id)r1; // expected-error{{cast of C pointer type 'CFAnnotatedObjectRef' (aka 'const __CFAnnotatedObject *') to Objective-C pointer type 'id' requires a bridged cast}} expected-note{{use __bridge to convert directly}} expected-note{{use __bridge_transfer to transfer ownership of a +1 'CFAnnotatedObjectRef'}}
+  obj = (id)r2;
+  obj = (id)r3; // expected-error{{cast of C pointer type 'CFAnnotatedObjectRef' (aka 'const __CFAnnotatedObject *') to Objective-C pointer type 'id' requires a bridged cast}} expected-note{{use __bridge to convert directly}} expected-note{{use __bridge_transfer to transfer ownership of a +1 'CFAnnotatedObjectRef'}}
+}
-- 
GitLab