A couple of tweaks to the visibility rules: 
  - tags with C linkage should ignore visibility=hidden
  - functions and variables with explicit visibility attributes should
    ignore the linkage of their types
Either of these should be sufficient to fix PR8457.

Also, FileCheck-ize a test case.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@117351 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index 42e762d..5cc745d 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -212,9 +212,13 @@
     //   given variable or function shall be identical...
     // C does not have an equivalent rule.
     //
+    // Ignore this if we've got an explicit attribute;  the user
+    // probably knows what they're doing.
+    //
     // Note that we don't want to make the variable non-external
     // because of this, but unique-external linkage suits us.
-    if (Context.getLangOptions().CPlusPlus && !Var->isExternC()) {
+    if (Context.getLangOptions().CPlusPlus && !Var->isExternC() &&
+        !Var->hasAttr<VisibilityAttr>()) {
       LVPair TypeLV = Var->getType()->getLinkageAndVisibility();
       if (TypeLV.first != ExternalLinkage)
         return LVPair(UniqueExternalLinkage, DefaultVisibility);
@@ -247,7 +251,8 @@
   } else if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) {
     // Modify the function's LV by the LV of its type unless this is
     // C or extern "C".  See the comment above about variables.
-    if (Context.getLangOptions().CPlusPlus && !Function->isExternC()) {
+    if (Context.getLangOptions().CPlusPlus && !Function->isExternC() &&
+        !Function->hasAttr<VisibilityAttr>()) {
       LVPair TypeLV = Function->getType()->getLinkageAndVisibility();
       if (TypeLV.first != ExternalLinkage)
         return LVPair(UniqueExternalLinkage, DefaultVisibility);
@@ -321,8 +326,11 @@
         ConsiderDashFVisibility = false;
     }
 
+    // Consider -fvisibility unless the type has C linkage.
     if (ConsiderDashFVisibility)
-      ConsiderDashFVisibility = Tag->isDefinition();
+      ConsiderDashFVisibility =
+        (Context.getLangOptions().CPlusPlus &&
+         !Tag->getDeclContext()->isExternCContext());
 
   //     - an enumerator belonging to an enumeration with external linkage;
   } else if (isa<EnumConstantDecl>(D)) {
diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp
index 483352f..5606d54 100644
--- a/lib/AST/DeclBase.cpp
+++ b/lib/AST/DeclBase.cpp
@@ -529,6 +529,17 @@
   return false;
 }
 
+bool DeclContext::isExternCContext() const {
+  const DeclContext *DC = this;
+  while (DC->DeclKind != Decl::TranslationUnit) {
+    if (DC->DeclKind == Decl::LinkageSpec)
+      return cast<LinkageSpecDecl>(DC)->getLanguage()
+        == LinkageSpecDecl::lang_c;
+    DC = DC->getParent();
+  }
+  return false;
+}
+
 bool DeclContext::Encloses(const DeclContext *DC) const {
   if (getPrimaryContext() != this)
     return getPrimaryContext()->Encloses(DC);