From af8ca37a7fa45bff84831706c6d85f9e5b4e1d15 Mon Sep 17 00:00:00 2001
From: John McCall <rjmccall@apple.com>
Date: Thu, 10 Feb 2011 06:50:24 +0000
Subject: [PATCH] Move the check that gives functions with unique-external
 types unique-external linkage into Decl.cpp.  Disable this logic for extern
 "C" functions, because the operative rule there is weaker.  Fixes
 rdar://problem/8898466

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@125268 91177308-0d34-0410-b5e6-96231b3b80d8
---
 lib/AST/ASTContext.cpp                  |  4 ----
 lib/AST/Decl.cpp                        | 13 +++++++++++++
 test/SemaCXX/linkage.cpp                | 11 +++++++++++
 test/SemaCXX/warn-unused-filescoped.cpp | 10 +++++++++-
 4 files changed, 33 insertions(+), 5 deletions(-)

diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index d6c89c947ce..6b267432586 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -5859,10 +5859,6 @@ GVALinkage ASTContext::GetGVALinkageForFunction(const FunctionDecl *FD) {
   GVALinkage External = GVA_StrongExternal;
 
   Linkage L = FD->getLinkage();
-  if (L == ExternalLinkage && getLangOptions().CPlusPlus &&
-      FD->getType()->getLinkage() == UniqueExternalLinkage)
-    L = UniqueExternalLinkage;
-  
   switch (L) {
   case NoLinkage:
   case InternalLinkage:
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index 11614df5003..9aeb04fa448 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -392,6 +392,14 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, LVFlags F) {
       }
     }
 
+    // In C++, then if the type of the function uses a type with
+    // unique-external linkage, it's not legally usable from outside
+    // this translation unit.  However, we should use the C linkage
+    // rules instead for extern "C" declarations.
+    if (Context.getLangOptions().CPlusPlus && !Function->isExternC() &&
+        Function->getType()->getLinkage() == UniqueExternalLinkage)
+      return LinkageInfo::uniqueExternal();
+
     if (FunctionTemplateSpecializationInfo *SpecInfo
                                = Function->getTemplateSpecializationInfo()) {
       LV.merge(getLVForDecl(SpecInfo->getTemplate(),
@@ -512,6 +520,11 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D, LVFlags F) {
     return LinkageInfo::uniqueExternal();
 
   if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) {
+    // If the type of the function uses a type with unique-external
+    // linkage, it's not legally usable from outside this translation unit.
+    if (MD->getType()->getLinkage() == UniqueExternalLinkage)
+      return LinkageInfo::uniqueExternal();
+
     TemplateSpecializationKind TSK = TSK_Undeclared;
 
     // If this is a method template specialization, use the linkage for
diff --git a/test/SemaCXX/linkage.cpp b/test/SemaCXX/linkage.cpp
index fb21f94e92e..ba56318fbd6 100644
--- a/test/SemaCXX/linkage.cpp
+++ b/test/SemaCXX/linkage.cpp
@@ -53,5 +53,16 @@ namespace test2 {
   }
 }
 
+namespace test3 {
+  namespace { struct A {}; }
+
+  // CHECK: define internal void @_ZN5test34testENS_12_GLOBAL__N_11AE(
+  void test(A a) {}
+  void force() { test(A()); }
+
+  // CHECK: define void @test3(
+  extern "C" void test3(A a) {}
+}
+
 // CHECK: define linkonce_odr i8* @_ZN5test21A1BILj0EE3fooEv(
 // CHECK: define linkonce_odr i8* @_ZN5test11A3fooILj0EEEPvv(
diff --git a/test/SemaCXX/warn-unused-filescoped.cpp b/test/SemaCXX/warn-unused-filescoped.cpp
index 628075ac04d..c32acb0b48b 100644
--- a/test/SemaCXX/warn-unused-filescoped.cpp
+++ b/test/SemaCXX/warn-unused-filescoped.cpp
@@ -66,7 +66,15 @@ namespace PR8841 {
   template <typename T> void template_test(X<T> x) {
     (void)(x == x);
   }
-  void test(X<int> x) {
+  void test() {
+    X<int> x;
     template_test(x);
   }
 }
+
+namespace test4 {
+  namespace { struct A {}; }
+
+  void test(A a); // expected-warning {{unused function}}
+  extern "C" void test4(A a);
+}
-- 
GitLab