Substantially revise how clang computes the visibility of a declaration to
more closely parallel the computation of linkage.  This gets us to a state
much closer to what gcc emits, modulo bugs, which will undoubtedly arise in
abundance.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@117147 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index 5a1edbd..fc5b57f 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -32,35 +32,53 @@
 // NamedDecl Implementation
 //===----------------------------------------------------------------------===//
 
+static Visibility GetVisibilityFromAttr(const VisibilityAttr *A) {
+  switch (A->getVisibility()) {
+  case VisibilityAttr::Default:
+    return DefaultVisibility;
+  case VisibilityAttr::Hidden:
+    return HiddenVisibility;
+  case VisibilityAttr::Protected:
+    return ProtectedVisibility;
+  }
+  return DefaultVisibility;
+}
+
+typedef std::pair<Linkage,Visibility> LVPair;
+static LVPair merge(LVPair L, LVPair R) {
+  return LVPair(minLinkage(L.first, R.first),
+                minVisibility(L.second, R.second));
+}
+
 /// \brief Get the most restrictive linkage for the types in the given
 /// template parameter list.
-static Linkage 
-getLinkageForTemplateParameterList(const TemplateParameterList *Params) {
-  Linkage L = ExternalLinkage;
+static LVPair 
+getLVForTemplateParameterList(const TemplateParameterList *Params) {
+  LVPair LV(ExternalLinkage, DefaultVisibility);
   for (TemplateParameterList::const_iterator P = Params->begin(),
                                           PEnd = Params->end();
        P != PEnd; ++P) {
     if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(*P))
       if (!NTTP->getType()->isDependentType()) {
-        L = minLinkage(L, NTTP->getType()->getLinkage());
+        LV = merge(LV, NTTP->getType()->getLinkageAndVisibility());
         continue;
       }
 
     if (TemplateTemplateParmDecl *TTP
                                    = dyn_cast<TemplateTemplateParmDecl>(*P)) {
-      L = minLinkage(L, 
-            getLinkageForTemplateParameterList(TTP->getTemplateParameters()));
+      LV =
+        merge(LV, getLVForTemplateParameterList(TTP->getTemplateParameters()));
     }
   }
 
-  return L;
+  return LV;
 }
 
 /// \brief Get the most restrictive linkage for the types and
 /// declarations in the given template argument list.
-static Linkage getLinkageForTemplateArgumentList(const TemplateArgument *Args,
-                                                 unsigned NumArgs) {
-  Linkage L = ExternalLinkage;
+static LVPair getLVForTemplateArgumentList(const TemplateArgument *Args,
+                                           unsigned NumArgs) {
+  LVPair LV(ExternalLinkage, DefaultVisibility);
 
   for (unsigned I = 0; I != NumArgs; ++I) {
     switch (Args[I].getKind()) {
@@ -70,40 +88,41 @@
       break;
       
     case TemplateArgument::Type:
-      L = minLinkage(L, Args[I].getAsType()->getLinkage());
+      LV = merge(LV, Args[I].getAsType()->getLinkageAndVisibility());
       break;
 
     case TemplateArgument::Declaration:
-      if (NamedDecl *ND = dyn_cast<NamedDecl>(Args[I].getAsDecl()))
-        L = minLinkage(L, ND->getLinkage());
-      if (ValueDecl *VD = dyn_cast<ValueDecl>(Args[I].getAsDecl()))
-        L = minLinkage(L, VD->getType()->getLinkage());
+      // The decl can validly be null as the representation of nullptr
+      // arguments, valid only in C++0x.
+      if (Decl *D = Args[I].getAsDecl()) {
+        if (NamedDecl *ND = dyn_cast<NamedDecl>(D))
+          LV = merge(LV, ND->getLinkageAndVisibility());
+        if (ValueDecl *VD = dyn_cast<ValueDecl>(D))
+          LV = merge(LV, VD->getType()->getLinkageAndVisibility());
+      }
       break;
 
     case TemplateArgument::Template:
-      if (TemplateDecl *Template
-                                = Args[I].getAsTemplate().getAsTemplateDecl())
-        L = minLinkage(L, Template->getLinkage());
+      if (TemplateDecl *Template = Args[I].getAsTemplate().getAsTemplateDecl())
+        LV = merge(LV, Template->getLinkageAndVisibility());
       break;
 
     case TemplateArgument::Pack:
-      L = minLinkage(L, 
-                     getLinkageForTemplateArgumentList(Args[I].pack_begin(),
-                                                       Args[I].pack_size()));
+      LV = merge(LV, getLVForTemplateArgumentList(Args[I].pack_begin(),
+                                                  Args[I].pack_size()));
       break;
     }
   }
 
-  return L;
+  return LV;
 }
 
-static Linkage
-getLinkageForTemplateArgumentList(const TemplateArgumentList &TArgs) {
-  return getLinkageForTemplateArgumentList(TArgs.getFlatArgumentList(), 
-                                           TArgs.flat_size());
+static LVPair getLVForTemplateArgumentList(const TemplateArgumentList &TArgs) {
+  return getLVForTemplateArgumentList(TArgs.getFlatArgumentList(), 
+                                      TArgs.flat_size());
 }
 
-static Linkage getLinkageForNamespaceScopeDecl(const NamedDecl *D) {
+static LVPair getLVForNamespaceScopeDecl(const NamedDecl *D) {
   assert(D->getDeclContext()->getRedeclContext()->isFileContext() &&
          "Not a name having namespace scope");
   ASTContext &Context = D->getASTContext();
@@ -117,7 +136,7 @@
   if (const VarDecl *Var = dyn_cast<VarDecl>(D)) {
     // Explicitly declared static.
     if (Var->getStorageClass() == SC_Static)
-      return InternalLinkage;
+      return LVPair(InternalLinkage, DefaultVisibility);
 
     // - an object or reference that is explicitly declared const
     //   and neither explicitly declared extern nor previously
@@ -135,7 +154,7 @@
           FoundExtern = true;
       
       if (!FoundExtern)
-        return InternalLinkage;
+        return LVPair(InternalLinkage, DefaultVisibility);
     }
   } else if (isa<FunctionDecl>(D) || isa<FunctionTemplateDecl>(D)) {
     // C++ [temp]p4:
@@ -150,23 +169,63 @@
 
     // Explicitly declared static.
     if (Function->getStorageClass() == SC_Static)
-      return InternalLinkage;
+      return LVPair(InternalLinkage, DefaultVisibility);
   } else if (const FieldDecl *Field = dyn_cast<FieldDecl>(D)) {
     //   - a data member of an anonymous union.
     if (cast<RecordDecl>(Field->getDeclContext())->isAnonymousStructOrUnion())
-      return InternalLinkage;
+      return LVPair(InternalLinkage, DefaultVisibility);
   }
 
+  if (D->isInAnonymousNamespace())
+    return LVPair(UniqueExternalLinkage, DefaultVisibility);
+
+  // Set up the defaults.
+
+  // C99 6.2.2p5:
+  //   If the declaration of an identifier for an object has file
+  //   scope and no storage-class specifier, its linkage is
+  //   external.
+  LVPair LV(ExternalLinkage, DefaultVisibility);
+
+  // We ignore -fvisibility on non-definitions and explicit
+  // instantiation declarations.
+  bool ConsiderDashFVisibility = true;
+
   // C++ [basic.link]p4:
-  
+
   //   A name having namespace scope has external linkage if it is the
   //   name of
   //
   //     - an object or reference, unless it has internal linkage; or
   if (const VarDecl *Var = dyn_cast<VarDecl>(D)) {
+    // Modify the variable's LV by the LV of its type unless this is
+    // C or extern "C".  This follows from [basic.link]p9:
+    //   A type without linkage shall not be used as the type of a
+    //   variable or function with external linkage unless
+    //    - the entity has C language linkage, or
+    //    - the entity is declared within an unnamed namespace, or
+    //    - the entity is not used or is defined in the same
+    //      translation unit.
+    // and [basic.link]p10:
+    //   ...the types specified by all declarations referring to a
+    //   given variable or function shall be identical...
+    // C does not have an equivalent rule.
+    //
+    // 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()) {
+      LVPair TypeLV = Var->getType()->getLinkageAndVisibility();
+      if (TypeLV.first != ExternalLinkage)
+        return LVPair(UniqueExternalLinkage, DefaultVisibility);
+      LV.second = minVisibility(LV.second, TypeLV.second);
+    }
+
     if (!Context.getLangOptions().CPlusPlus &&
         (Var->getStorageClass() == SC_Extern ||
          Var->getStorageClass() == SC_PrivateExtern)) {
+      if (Var->getStorageClass() == SC_PrivateExtern)
+        LV.second = HiddenVisibility;
+
       // C99 6.2.2p4:
       //   For an identifier declared with the storage-class specifier
       //   extern in a scope in which a prior declaration of that
@@ -177,23 +236,23 @@
       //   is visible, or if the prior declaration specifies no
       //   linkage, then the identifier has external linkage.
       if (const VarDecl *PrevVar = Var->getPreviousDeclaration()) {
-        if (Linkage L = PrevVar->getLinkage())
-          return L;
+        LVPair PrevLV = PrevVar->getLinkageAndVisibility();
+        if (PrevLV.first) LV.first = PrevLV.first;
+        LV.second = minVisibility(LV.second, PrevLV.second);
       }
     }
 
-    // C99 6.2.2p5:
-    //   If the declaration of an identifier for an object has file
-    //   scope and no storage-class specifier, its linkage is
-    //   external.
-    if (Var->isInAnonymousNamespace())
-      return UniqueExternalLinkage;
-
-    return ExternalLinkage;
-  }
-
   //     - a function, unless it has internal linkage; or
-  if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) {
+  } 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()) {
+      LVPair TypeLV = Function->getType()->getLinkageAndVisibility();
+      if (TypeLV.first != ExternalLinkage)
+        return LVPair(UniqueExternalLinkage, DefaultVisibility);
+      LV.second = minVisibility(LV.second, TypeLV.second);
+    }
+
     // C99 6.2.2p5:
     //   If the declaration of an identifier for a function has no
     //   storage-class specifier, its linkage is determined exactly
@@ -213,24 +272,25 @@
       //   is visible, or if the prior declaration specifies no
       //   linkage, then the identifier has external linkage.
       if (const FunctionDecl *PrevFunc = Function->getPreviousDeclaration()) {
-        if (Linkage L = PrevFunc->getLinkage())
-          return L;
+        LVPair PrevLV = PrevFunc->getLinkageAndVisibility();
+        if (PrevLV.first) LV.first = PrevLV.first;
+        LV.second = minVisibility(LV.second, PrevLV.second);
       }
     }
 
-    if (Function->isInAnonymousNamespace())
-      return UniqueExternalLinkage;
-
     if (FunctionTemplateSpecializationInfo *SpecInfo
                                = Function->getTemplateSpecializationInfo()) {
-      Linkage L = SpecInfo->getTemplate()->getLinkage();
+      LV = merge(LV, SpecInfo->getTemplate()->getLinkageAndVisibility());
       const TemplateArgumentList &TemplateArgs = *SpecInfo->TemplateArguments;
-      L = minLinkage(L, getLinkageForTemplateArgumentList(TemplateArgs));
-      return L;
+      LV = merge(LV, getLVForTemplateArgumentList(TemplateArgs));
+
+      if (SpecInfo->getTemplateSpecializationKind()
+            == TSK_ExplicitInstantiationDeclaration)
+        ConsiderDashFVisibility = false;
     }
 
-    return ExternalLinkage;
-  }
+    if (ConsiderDashFVisibility)
+      ConsiderDashFVisibility = Function->hasBody();
 
   //     - a named class (Clause 9), or an unnamed class defined in a
   //       typedef declaration in which the class has the typedef name
@@ -238,116 +298,180 @@
   //     - a named enumeration (7.2), or an unnamed enumeration
   //       defined in a typedef declaration in which the enumeration
   //       has the typedef name for linkage purposes (7.1.3); or
-  if (const TagDecl *Tag = dyn_cast<TagDecl>(D))
-    if (Tag->getDeclName() || Tag->getTypedefForAnonDecl()) {
-      if (Tag->isInAnonymousNamespace())
-        return UniqueExternalLinkage;
+  } else if (const TagDecl *Tag = dyn_cast<TagDecl>(D)) {
+    // Unnamed tags have no linkage.
+    if (!Tag->getDeclName() && !Tag->getTypedefForAnonDecl())
+      return LVPair(NoLinkage, DefaultVisibility);
 
-      // If this is a class template specialization, consider the
-      // linkage of the template and template arguments.
-      if (const ClassTemplateSpecializationDecl *Spec
-            = dyn_cast<ClassTemplateSpecializationDecl>(Tag)) {
-        const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs();
-        Linkage L = getLinkageForTemplateArgumentList(TemplateArgs);
-        return minLinkage(L, Spec->getSpecializedTemplate()->getLinkage());
-      }
+    // If this is a class template specialization, consider the
+    // linkage of the template and template arguments.
+    if (const ClassTemplateSpecializationDecl *Spec
+          = dyn_cast<ClassTemplateSpecializationDecl>(Tag)) {
+      // From the template.  Note below the restrictions on how we
+      // compute template visibility.
+      LV = merge(LV, Spec->getSpecializedTemplate()->getLinkageAndVisibility());
 
-      return ExternalLinkage;
+      // The arguments at which the template was instantiated.
+      const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs();
+      LV = merge(LV, getLVForTemplateArgumentList(TemplateArgs));
+
+      if (Spec->getTemplateSpecializationKind()
+            == TSK_ExplicitInstantiationDeclaration)
+        ConsiderDashFVisibility = false;
     }
 
+    if (ConsiderDashFVisibility)
+      ConsiderDashFVisibility = Tag->isDefinition();
+
   //     - an enumerator belonging to an enumeration with external linkage;
-  if (isa<EnumConstantDecl>(D)) {
-    Linkage L = cast<NamedDecl>(D->getDeclContext())->getLinkage();
-    if (isExternalLinkage(L))
-      return L;
-  }
+  } else if (isa<EnumConstantDecl>(D)) {
+    LVPair EnumLV =
+      cast<NamedDecl>(D->getDeclContext())->getLinkageAndVisibility();
+    if (!isExternalLinkage(EnumLV.first))
+      return LVPair(NoLinkage, DefaultVisibility);
+    LV = merge(LV, EnumLV);
 
   //     - a template, unless it is a function template that has
   //       internal linkage (Clause 14);
-  if (const TemplateDecl *Template = dyn_cast<TemplateDecl>(D)) {
-    if (D->isInAnonymousNamespace())
-      return UniqueExternalLinkage;
+  } else if (const TemplateDecl *Template = dyn_cast<TemplateDecl>(D)) {
+    LV = merge(LV, getLVForTemplateParameterList(
+                                         Template->getTemplateParameters()));
 
-    return getLinkageForTemplateParameterList(
-                                         Template->getTemplateParameters());
-  }
+    // We do not want to consider attributes or global settings when
+    // computing template visibility.
+    return LV;
 
   //     - a namespace (7.3), unless it is declared within an unnamed
   //       namespace.
-  if (isa<NamespaceDecl>(D) && !D->isInAnonymousNamespace())
-    return ExternalLinkage;
+  } else if (isa<NamespaceDecl>(D) && !D->isInAnonymousNamespace()) {
+    return LV;
 
-  return NoLinkage;
+  // By extension, we assign external linkage to Objective-C
+  // interfaces.
+  } else if (isa<ObjCInterfaceDecl>(D)) {
+    // fallout
+
+  // Everything not covered here has no linkage.
+  } else {
+    return LVPair(NoLinkage, DefaultVisibility);
+  }
+
+  // If we ended up with non-external linkage, visibility should
+  // always be default.
+  if (LV.first != ExternalLinkage)
+    return LVPair(LV.first, DefaultVisibility);
+
+  // If we didn't end up with hidden visibility, consider attributes
+  // and -fvisibility.
+  if (LV.second != HiddenVisibility) {
+    Visibility StandardV;
+
+    // If we have an explicit visibility attribute, merge that in.
+    const VisibilityAttr *VA = D->getAttr<VisibilityAttr>();
+    if (VA)
+      StandardV = GetVisibilityFromAttr(VA);
+    else if (ConsiderDashFVisibility)
+      StandardV = Context.getLangOptions().getVisibilityMode();
+    else
+      StandardV = DefaultVisibility; // no-op
+
+    LV.second = minVisibility(LV.second, StandardV);  
+  }
+
+  return LV;
 }
 
-static Linkage getLinkageForClassMember(const NamedDecl *D) {
+static LVPair getLVForClassMember(const NamedDecl *D) {
+  // Only certain class members have linkage.  Note that fields don't
+  // really have linkage, but it's convenient to say they do for the
+  // purposes of calculating linkage of pointer-to-data-member
+  // template arguments.
   if (!(isa<CXXMethodDecl>(D) ||
         isa<VarDecl>(D) ||
+        isa<FieldDecl>(D) ||
         (isa<TagDecl>(D) &&
          (D->getDeclName() || cast<TagDecl>(D)->getTypedefForAnonDecl()))))
-    return NoLinkage;
+    return LVPair(NoLinkage, DefaultVisibility);
 
   // Class members only have linkage if their class has external linkage.
-  Linkage L = cast<RecordDecl>(D->getDeclContext())->getLinkage();
-  if (!isExternalLinkage(L)) return NoLinkage;
+  LVPair ClassLV =
+    cast<RecordDecl>(D->getDeclContext())->getLinkageAndVisibility();
+  if (!isExternalLinkage(ClassLV.first))
+    return LVPair(NoLinkage, DefaultVisibility);
 
   // If the class already has unique-external linkage, we can't improve.
-  if (L == UniqueExternalLinkage) return UniqueExternalLinkage;
+  if (ClassLV.first == UniqueExternalLinkage)
+    return LVPair(UniqueExternalLinkage, DefaultVisibility);
 
-  // If this is a method template specialization, use the linkage for
-  // the template parameters and arguments.
+  // Start with the class's linkage and visibility.
+  LVPair LV = ClassLV;
+
+  // If we have an explicit visibility attribute, merge that in.
+  const VisibilityAttr *VA = D->getAttr<VisibilityAttr>();
+  if (VA) LV.second = minVisibility(LV.second, GetVisibilityFromAttr(VA));
+
+  // If it's a value declaration, apply the LV from its type.
+  // See the comment about namespace-scope variable decls above.
+  if (isa<ValueDecl>(D)) {
+    LVPair TypeLV = cast<ValueDecl>(D)->getType()->getLinkageAndVisibility();
+    if (TypeLV.first != ExternalLinkage)
+      LV.first = minLinkage(LV.first, UniqueExternalLinkage);
+    LV.second = minVisibility(LV.second, TypeLV.second);
+  }
+
   if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) {
-    if (FunctionTemplateSpecializationInfo *SpecInfo
+    // If this is a method template specialization, use the linkage for
+    // the template parameters and arguments.
+    if (FunctionTemplateSpecializationInfo *Spec
            = MD->getTemplateSpecializationInfo()) {
-      Linkage ArgLinkage =
-        getLinkageForTemplateArgumentList(*SpecInfo->TemplateArguments);
-      Linkage ParamLinkage =
-        getLinkageForTemplateParameterList(
-                           SpecInfo->getTemplate()->getTemplateParameters());
-      return minLinkage(ArgLinkage, ParamLinkage);
+      LV = merge(LV, getLVForTemplateArgumentList(*Spec->TemplateArguments));
+      LV = merge(LV, getLVForTemplateParameterList(
+                              Spec->getTemplate()->getTemplateParameters()));
     }
 
+    // If -fvisibility-inlines-hidden was provided, then inline C++
+    // member functions get "hidden" visibility if they don't have an
+    // explicit visibility attribute.
+    if (!VA && MD->isInlined() && LV.second > HiddenVisibility &&
+        D->getASTContext().getLangOptions().InlineVisibilityHidden)
+      LV.second = HiddenVisibility;
+
   // Similarly for member class template specializations.
   } else if (const ClassTemplateSpecializationDecl *Spec
                = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
-    Linkage ArgLinkage =
-      getLinkageForTemplateArgumentList(Spec->getTemplateArgs());
-    Linkage ParamLinkage =
-      getLinkageForTemplateParameterList(
-                    Spec->getSpecializedTemplate()->getTemplateParameters());
-    return minLinkage(ArgLinkage, ParamLinkage);
+    LV = merge(LV, getLVForTemplateArgumentList(Spec->getTemplateArgs()));
+    LV = merge(LV, getLVForTemplateParameterList(
+                    Spec->getSpecializedTemplate()->getTemplateParameters()));
   }
 
-  return ExternalLinkage;
+  return LV;
 }
 
-Linkage NamedDecl::getLinkage() const {
+LVPair NamedDecl::getLinkageAndVisibility() const {
 
   // Objective-C: treat all Objective-C declarations as having external
   // linkage.
   switch (getKind()) {
     default:
       break;
+    case Decl::TemplateTemplateParm: // count these as external
+    case Decl::NonTypeTemplateParm:
     case Decl::ObjCAtDefsField:
     case Decl::ObjCCategory:
     case Decl::ObjCCategoryImpl:
-    case Decl::ObjCClass:
     case Decl::ObjCCompatibleAlias:
     case Decl::ObjCForwardProtocol:
     case Decl::ObjCImplementation:
-    case Decl::ObjCInterface:
-    case Decl::ObjCIvar:
     case Decl::ObjCMethod:
     case Decl::ObjCProperty:
     case Decl::ObjCPropertyImpl:
     case Decl::ObjCProtocol:
-      return ExternalLinkage;
+      return LVPair(ExternalLinkage, DefaultVisibility);
   }
 
   // Handle linkage for namespace-scope names.
   if (getDeclContext()->getRedeclContext()->isFileContext())
-    if (Linkage L = getLinkageForNamespaceScopeDecl(this))
-      return L;
+    return getLVForNamespaceScopeDecl(this);
   
   // C++ [basic.link]p5:
   //   In addition, a member function, static data member, a named
@@ -357,7 +481,7 @@
   //   purposes (7.1.3), has external linkage if the name of the class
   //   has external linkage.
   if (getDeclContext()->isRecord())
-    return getLinkageForClassMember(this);
+    return getLVForClassMember(this);
 
   // C++ [basic.link]p6:
   //   The name of a function declared in block scope and the name of
@@ -372,34 +496,48 @@
   //   external linkage.
   if (getLexicalDeclContext()->isFunctionOrMethod()) {
     if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(this)) {
-      if (Function->getPreviousDeclaration())
-        if (Linkage L = Function->getPreviousDeclaration()->getLinkage())
-          return L;
-
       if (Function->isInAnonymousNamespace())
-        return UniqueExternalLinkage;
+        return LVPair(UniqueExternalLinkage, DefaultVisibility);
 
-      return ExternalLinkage;
+      LVPair LV(ExternalLinkage, DefaultVisibility);
+      if (const VisibilityAttr *VA = Function->getAttr<VisibilityAttr>())
+        LV.second = GetVisibilityFromAttr(VA);
+
+      if (const FunctionDecl *Prev = Function->getPreviousDeclaration()) {
+        LVPair PrevLV = Prev->getLinkageAndVisibility();
+        if (PrevLV.first) LV.first = PrevLV.first;
+        LV.second = minVisibility(LV.second, PrevLV.second);
+      }
+
+      return LV;
     }
 
     if (const VarDecl *Var = dyn_cast<VarDecl>(this))
       if (Var->getStorageClass() == SC_Extern ||
           Var->getStorageClass() == SC_PrivateExtern) {
-        if (Var->getPreviousDeclaration())
-          if (Linkage L = Var->getPreviousDeclaration()->getLinkage())
-            return L;
-
         if (Var->isInAnonymousNamespace())
-          return UniqueExternalLinkage;
+          return LVPair(UniqueExternalLinkage, DefaultVisibility);
 
-        return ExternalLinkage;
+        LVPair LV(ExternalLinkage, DefaultVisibility);
+        if (Var->getStorageClass() == SC_PrivateExtern)
+          LV.second = HiddenVisibility;
+        else if (const VisibilityAttr *VA = Var->getAttr<VisibilityAttr>())
+          LV.second = GetVisibilityFromAttr(VA);
+
+        if (const VarDecl *Prev = Var->getPreviousDeclaration()) {
+          LVPair PrevLV = Prev->getLinkageAndVisibility();
+          if (PrevLV.first) LV.first = PrevLV.first;
+          LV.second = minVisibility(LV.second, PrevLV.second);
+        }
+
+        return LV;
       }
   }
 
   // C++ [basic.link]p6:
   //   Names not covered by these rules have no linkage.
-  return NoLinkage;
-  }
+  return LVPair(NoLinkage, DefaultVisibility);
+}
 
 std::string NamedDecl::getQualifiedNameAsString() const {
   return getQualifiedNameAsString(getASTContext().getLangOptions());
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index 1452507..33aac12 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -1268,129 +1268,154 @@
   Profile(ID, getBaseType(), qual_begin(), getNumProtocols());
 }
 
+void Type::ensureCachedProperties() const {
+  if (!TypeBits.isCacheValid()) {
+    CachedProperties Result = getCachedProperties();
+    TypeBits.CacheValidAndVisibility = Result.getVisibility() + 1U;
+    assert(TypeBits.isCacheValid() &&
+           TypeBits.getVisibility() == Result.getVisibility());
+    TypeBits.CachedLinkage = Result.getLinkage();
+    TypeBits.CachedLocalOrUnnamed = Result.hasLocalOrUnnamedType();
+  }  
+}
+
 /// \brief Determine the linkage of this type.
 Linkage Type::getLinkage() const {
   if (this != CanonicalType.getTypePtr())
     return CanonicalType->getLinkage();
-  
-  if (!TypeBits.LinkageKnown) {
-    std::pair<Linkage, bool> Result = getLinkageUnnamedLocalImpl();
-    TypeBits.CachedLinkage = Result.first;
-    TypeBits.CachedLocalOrUnnamed = Result.second;
-    TypeBits.LinkageKnown = true;
-  }
-  
-  return static_cast<clang::Linkage>(TypeBits.CachedLinkage);
+
+  ensureCachedProperties();
+  return TypeBits.getLinkage();
+}
+
+/// \brief Determine the linkage of this type.
+Visibility Type::getVisibility() const {
+  if (this != CanonicalType.getTypePtr())
+    return CanonicalType->getVisibility();
+
+  ensureCachedProperties();
+  return TypeBits.getVisibility();
 }
 
 bool Type::hasUnnamedOrLocalType() const {
   if (this != CanonicalType.getTypePtr())
     return CanonicalType->hasUnnamedOrLocalType();
-  
-  if (!TypeBits.LinkageKnown) {
-    std::pair<Linkage, bool> Result = getLinkageUnnamedLocalImpl();
-    TypeBits.CachedLinkage = Result.first;
-    TypeBits.CachedLocalOrUnnamed = Result.second;
-    TypeBits.LinkageKnown = true;
-  }
-  
-  return TypeBits.CachedLocalOrUnnamed;
+
+  ensureCachedProperties();
+  return TypeBits.hasLocalOrUnnamedType();
 }
 
-std::pair<Linkage, bool> Type::getLinkageUnnamedLocalImpl() const { 
-  // C++ [basic.link]p8:
-  //   Names not covered by these rules have no linkage.
-  return std::make_pair(NoLinkage, false);
+std::pair<Linkage,Visibility> Type::getLinkageAndVisibility() const {
+  if (this != CanonicalType.getTypePtr())
+    return CanonicalType->getLinkageAndVisibility();
+
+  ensureCachedProperties();
+  return std::make_pair(TypeBits.getLinkage(), TypeBits.getVisibility());
+}
+
+
+Type::CachedProperties Type::getCachedProperties(const Type *T) {
+  T = T->CanonicalType.getTypePtr();
+  T->ensureCachedProperties();
+  return CachedProperties(T->TypeBits.getLinkage(),
+                          T->TypeBits.getVisibility(),
+                          T->TypeBits.hasLocalOrUnnamedType());
 }
 
 void Type::ClearLinkageCache() {
   if (this != CanonicalType.getTypePtr())
     CanonicalType->ClearLinkageCache();
   else
-    TypeBits.LinkageKnown = false;
+    TypeBits.CacheValidAndVisibility = 0;
 }
 
-std::pair<Linkage, bool> BuiltinType::getLinkageUnnamedLocalImpl() const {
+Type::CachedProperties Type::getCachedProperties() const { 
+  // Treat dependent types as external.
+  if (isDependentType())
+    return CachedProperties(ExternalLinkage, DefaultVisibility, false);
+
+  // C++ [basic.link]p8:
+  //   Names not covered by these rules have no linkage.
+  return CachedProperties(NoLinkage, DefaultVisibility, false);
+}
+
+Type::CachedProperties BuiltinType::getCachedProperties() const {
   // C++ [basic.link]p8:
   //   A type is said to have linkage if and only if:
   //     - it is a fundamental type (3.9.1); or
-  return std::make_pair(ExternalLinkage, false);
+  return CachedProperties(ExternalLinkage, DefaultVisibility, false);
 }
 
-std::pair<Linkage, bool> TagType::getLinkageUnnamedLocalImpl() const {
+Type::CachedProperties TagType::getCachedProperties() const {
   // C++ [basic.link]p8:
   //     - it is a class or enumeration type that is named (or has a name for
   //       linkage purposes (7.1.3)) and the name has linkage; or
   //     -  it is a specialization of a class template (14); or
-  return std::make_pair(getDecl()->getLinkage(),
-                        getDecl()->getDeclContext()->isFunctionOrMethod() ||
+
+  std::pair<Linkage,Visibility> LV = getDecl()->getLinkageAndVisibility();
+  bool IsLocalOrUnnamed =
+    getDecl()->getDeclContext()->isFunctionOrMethod() ||
                         (!getDecl()->getIdentifier() &&
-                         !getDecl()->getTypedefForAnonDecl()));
+                         !getDecl()->getTypedefForAnonDecl());
+  return CachedProperties(LV.first, LV.second, IsLocalOrUnnamed);
 }
 
 // C++ [basic.link]p8:
 //   - it is a compound type (3.9.2) other than a class or enumeration, 
 //     compounded exclusively from types that have linkage; or
-std::pair<Linkage, bool> ComplexType::getLinkageUnnamedLocalImpl() const {
-  return std::make_pair(ElementType->getLinkage(), 
-                        ElementType->hasUnnamedOrLocalType());
+Type::CachedProperties ComplexType::getCachedProperties() const {
+  return Type::getCachedProperties(ElementType);
 }
 
-std::pair<Linkage, bool> PointerType::getLinkageUnnamedLocalImpl() const {
-  return std::make_pair(PointeeType->getLinkage(), 
-                        PointeeType->hasUnnamedOrLocalType());
+Type::CachedProperties PointerType::getCachedProperties() const {
+  return Type::getCachedProperties(PointeeType);
 }
 
-std::pair<Linkage, bool> BlockPointerType::getLinkageUnnamedLocalImpl() const {
-  return std::make_pair(PointeeType->getLinkage(),
-                        PointeeType->hasUnnamedOrLocalType());
+Type::CachedProperties BlockPointerType::getCachedProperties() const {
+  return Type::getCachedProperties(PointeeType);
 }
 
-std::pair<Linkage, bool> ReferenceType::getLinkageUnnamedLocalImpl() const {
-  return std::make_pair(PointeeType->getLinkage(),
-                        PointeeType->hasUnnamedOrLocalType());
+Type::CachedProperties ReferenceType::getCachedProperties() const {
+  return Type::getCachedProperties(PointeeType);
 }
 
-std::pair<Linkage, bool> MemberPointerType::getLinkageUnnamedLocalImpl() const {
-  return std::make_pair(minLinkage(Class->getLinkage(),
-                                   PointeeType->getLinkage()),
-                        Class->hasUnnamedOrLocalType() ||
-                        PointeeType->hasUnnamedOrLocalType());
+Type::CachedProperties MemberPointerType::getCachedProperties() const {
+  return merge(Type::getCachedProperties(Class),
+               Type::getCachedProperties(PointeeType));
 }
 
-std::pair<Linkage, bool> ArrayType::getLinkageUnnamedLocalImpl() const {
-  return std::make_pair(ElementType->getLinkage(), 
-                        ElementType->hasUnnamedOrLocalType());
+Type::CachedProperties ArrayType::getCachedProperties() const {
+  return Type::getCachedProperties(ElementType);
 }
 
-std::pair<Linkage, bool> VectorType::getLinkageUnnamedLocalImpl() const {
-  return std::make_pair(ElementType->getLinkage(),
-                        ElementType->hasUnnamedOrLocalType());
+Type::CachedProperties VectorType::getCachedProperties() const {
+  return Type::getCachedProperties(ElementType);
 }
 
-std::pair<Linkage, bool> 
-FunctionNoProtoType::getLinkageUnnamedLocalImpl() const {
-  return std::make_pair(getResultType()->getLinkage(),
-                        getResultType()->hasUnnamedOrLocalType());
+Type::CachedProperties FunctionNoProtoType::getCachedProperties() const {
+  return Type::getCachedProperties(getResultType());
 }
 
-std::pair<Linkage, bool> FunctionProtoType::getLinkageUnnamedLocalImpl() const {
-  Linkage L = getResultType()->getLinkage();
-  bool UnnamedOrLocal = getResultType()->hasUnnamedOrLocalType();
+Type::CachedProperties FunctionProtoType::getCachedProperties() const {
+  CachedProperties Cached = Type::getCachedProperties(getResultType());
   for (arg_type_iterator A = arg_type_begin(), AEnd = arg_type_end();
        A != AEnd; ++A) {
-    L = minLinkage(L, (*A)->getLinkage());
-    UnnamedOrLocal = UnnamedOrLocal || (*A)->hasUnnamedOrLocalType();
+    Cached = merge(Cached, Type::getCachedProperties(*A));
   }
-  
-  return std::make_pair(L, UnnamedOrLocal);
+  return Cached;
 }
 
-std::pair<Linkage, bool> ObjCObjectType::getLinkageUnnamedLocalImpl() const {
-  return std::make_pair(ExternalLinkage, false);
+Type::CachedProperties ObjCInterfaceType::getCachedProperties() const {
+  std::pair<Linkage,Visibility> LV = getDecl()->getLinkageAndVisibility();
+  return CachedProperties(LV.first, LV.second, false);
 }
 
-std::pair<Linkage, bool> 
-ObjCObjectPointerType::getLinkageUnnamedLocalImpl() const {
-  return std::make_pair(ExternalLinkage, false);
+Type::CachedProperties ObjCObjectType::getCachedProperties() const {
+  if (const ObjCInterfaceType *T = getBaseType()->getAs<ObjCInterfaceType>())
+    return Type::getCachedProperties(T);
+  return CachedProperties(ExternalLinkage, DefaultVisibility, false);
+}
+
+Type::CachedProperties ObjCObjectPointerType::getCachedProperties() const {
+  return Type::getCachedProperties(PointeeType);
 }
diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp
index 961233a..02cd8f8 100644
--- a/lib/CodeGen/CGCXX.cpp
+++ b/lib/CodeGen/CGCXX.cpp
@@ -180,7 +180,7 @@
   }
 
   // Finally, set up the alias with its proper name and attributes.
-  SetCommonAttributes(AliasDecl.getDecl(), Alias);
+  SetCommonAttributes(cast<NamedDecl>(AliasDecl.getDecl()), Alias);
 
   return false;
 }
diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp
index 9ed3733..0981574 100644
--- a/lib/CodeGen/CGObjCMac.cpp
+++ b/lib/CodeGen/CGObjCMac.cpp
@@ -2197,7 +2197,7 @@
     CGM.getContext().getASTObjCImplementationLayout(ID).getSize() / 8;
 
   // FIXME: Set CXX-structors flag.
-  if (CGM.getDeclVisibilityMode(ID->getClassInterface()) == LangOptions::Hidden)
+  if (ID->getClassInterface()->getVisibility() == HiddenVisibility)
     Flags |= eClassFlags_Hidden;
 
   std::vector<llvm::Constant*> InstanceMethods, ClassMethods;
@@ -2282,7 +2282,7 @@
   unsigned Flags = eClassFlags_Meta;
   unsigned Size = CGM.getTargetData().getTypeAllocSize(ObjCTypes.ClassTy);
 
-  if (CGM.getDeclVisibilityMode(ID->getClassInterface()) == LangOptions::Hidden)
+  if (ID->getClassInterface()->getVisibility() == HiddenVisibility)
     Flags |= eClassFlags_Hidden;
 
   std::vector<llvm::Constant*> Values(12);
@@ -4968,7 +4968,7 @@
   llvm::GlobalVariable *SuperClassGV, *IsAGV;
 
   bool classIsHidden =
-    CGM.getDeclVisibilityMode(ID->getClassInterface()) == LangOptions::Hidden;
+    ID->getClassInterface()->getVisibility() == HiddenVisibility;
   if (classIsHidden)
     flags |= OBJC2_CLS_HIDDEN;
   if (ID->getNumIvarInitializers())
@@ -5263,7 +5263,7 @@
   // well (i.e., in ObjCIvarOffsetVariable).
   if (Ivar->getAccessControl() == ObjCIvarDecl::Private ||
       Ivar->getAccessControl() == ObjCIvarDecl::Package ||
-      CGM.getDeclVisibilityMode(ID) == LangOptions::Hidden)
+      ID->getVisibility() == HiddenVisibility)
     IvarOffsetGV->setVisibility(llvm::GlobalValue::HiddenVisibility);
   else
     IvarOffsetGV->setVisibility(llvm::GlobalValue::DefaultVisibility);
@@ -6237,7 +6237,7 @@
                                       ID->getIdentifier()->getName()));
   }
 
-  if (CGM.getLangOptions().getVisibilityMode() == LangOptions::Hidden)
+  if (CGM.getLangOptions().getVisibilityMode() == HiddenVisibility)
     Entry->setVisibility(llvm::GlobalValue::HiddenVisibility);
   Entry->setAlignment(CGM.getTargetData().getABITypeAlignment(
       ObjCTypes.EHTypeTy));
diff --git a/lib/CodeGen/CGRTTI.cpp b/lib/CodeGen/CGRTTI.cpp
index 2659bd0..6dad2a0 100644
--- a/lib/CodeGen/CGRTTI.cpp
+++ b/lib/CodeGen/CGRTTI.cpp
@@ -113,7 +113,7 @@
     }
     if (const RecordType *RT = Ty->getAs<RecordType>())
       if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl()))
-        return CGM.getDeclVisibilityMode(RD) == LangOptions::Hidden;
+        return RD->getVisibility() == HiddenVisibility;
     return false;
   }
   
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
index 9199f6c..d35965e 100644
--- a/lib/CodeGen/CodeGenModule.cpp
+++ b/lib/CodeGen/CodeGenModule.cpp
@@ -164,81 +164,23 @@
   getDiags().Report(Context.getFullLoc(D->getLocation()), DiagID) << Msg;
 }
 
-LangOptions::VisibilityMode
-CodeGenModule::getDeclVisibilityMode(const Decl *D) const {
-  if (const VarDecl *VD = dyn_cast<VarDecl>(D))
-    if (VD->getStorageClass() == SC_PrivateExtern)
-      return LangOptions::Hidden;
-
-  if (const VisibilityAttr *attr = D->getAttr<VisibilityAttr>()) {
-    switch (attr->getVisibility()) {
-    default: assert(0 && "Unknown visibility!");
-    case VisibilityAttr::Default:
-      return LangOptions::Default;
-    case VisibilityAttr::Hidden:
-      return LangOptions::Hidden;
-    case VisibilityAttr::Protected:
-      return LangOptions::Protected;
-    }
-  }
-  
-  if (getLangOptions().CPlusPlus) {
-    // Entities subject to an explicit instantiation declaration get default
-    // visibility.
-    if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) {
-      if (Function->getTemplateSpecializationKind()
-                                        == TSK_ExplicitInstantiationDeclaration)
-        return LangOptions::Default;
-    } else if (const ClassTemplateSpecializationDecl *ClassSpec
-                              = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
-      if (ClassSpec->getSpecializationKind()
-                                        == TSK_ExplicitInstantiationDeclaration)
-        return LangOptions::Default;
-    } else if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(D)) {
-      if (Record->getTemplateSpecializationKind()
-                                        == TSK_ExplicitInstantiationDeclaration)
-        return LangOptions::Default;
-    } else if (const VarDecl *Var = dyn_cast<VarDecl>(D)) {
-      if (Var->isStaticDataMember() &&
-          (Var->getTemplateSpecializationKind()
-                                      == TSK_ExplicitInstantiationDeclaration))
-        return LangOptions::Default;
-    }
-
-    // If -fvisibility-inlines-hidden was provided, then inline C++ member
-    // functions get "hidden" visibility by default.
-    if (getLangOptions().InlineVisibilityHidden)
-      if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D))
-        if (Method->isInlined())
-          return LangOptions::Hidden;
-  }
-           
-  // If this decl is contained in a class, it should have the same visibility
-  // as the parent class.
-  if (const DeclContext *DC = D->getDeclContext()) 
-    if (DC->isRecord())
-      return getDeclVisibilityMode(cast<Decl>(DC));
-
-  return getLangOptions().getVisibilityMode();
-}
-
 void CodeGenModule::setGlobalVisibility(llvm::GlobalValue *GV,
-                                        const Decl *D) const {
+                                        const NamedDecl *D) const {
   // Internal definitions always have default visibility.
   if (GV->hasLocalLinkage()) {
     GV->setVisibility(llvm::GlobalValue::DefaultVisibility);
     return;
   }
 
-  switch (getDeclVisibilityMode(D)) {
-  default: assert(0 && "Unknown visibility!");
-  case LangOptions::Default:
+  switch (D->getVisibility()) {
+  case DefaultVisibility:
     return GV->setVisibility(llvm::GlobalValue::DefaultVisibility);
-  case LangOptions::Hidden:
+  case HiddenVisibility:
     return GV->setVisibility(llvm::GlobalValue::HiddenVisibility);
-  case LangOptions::Protected:
+  case ProtectedVisibility:
     return GV->setVisibility(llvm::GlobalValue::ProtectedVisibility);
   }
+  llvm_unreachable("unknown visibility!");
 }
 
 /// Set the symbol visibility of type information (vtable and RTTI)
@@ -498,7 +440,10 @@
 
 void CodeGenModule::SetCommonAttributes(const Decl *D,
                                         llvm::GlobalValue *GV) {
-  setGlobalVisibility(GV, D);
+  if (isa<NamedDecl>(D))
+    setGlobalVisibility(GV, cast<NamedDecl>(D));
+  else
+    GV->setVisibility(llvm::GlobalValue::DefaultVisibility);
 
   if (D->hasAttr<UsedAttr>())
     AddUsedGlobal(GV);
diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h
index d050eea..68898cf 100644
--- a/lib/CodeGen/CodeGenModule.h
+++ b/lib/CodeGen/CodeGenModule.h
@@ -257,12 +257,9 @@
   static void DecorateInstruction(llvm::Instruction *Inst,
                                   llvm::MDNode *TBAAInfo);
 
-  /// getDeclVisibilityMode - Compute the visibility of the decl \arg D.
-  LangOptions::VisibilityMode getDeclVisibilityMode(const Decl *D) const;
-
   /// setGlobalVisibility - Set the visibility for the given LLVM
   /// GlobalValue.
-  void setGlobalVisibility(llvm::GlobalValue *GV, const Decl *D) const;
+  void setGlobalVisibility(llvm::GlobalValue *GV, const NamedDecl *D) const;
 
   /// setTypeVisibility - Set the visibility for the given global
   /// value which holds information about a type.
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index 3ed859a..561555a 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -624,12 +624,12 @@
       Res.push_back("-fobjc-gc-only");
     }
   }
-  if (Opts.getVisibilityMode() != LangOptions::Default) {
+  if (Opts.getVisibilityMode() != DefaultVisibility) {
     Res.push_back("-fvisibility");
-    if (Opts.getVisibilityMode() == LangOptions::Hidden) {
+    if (Opts.getVisibilityMode() == HiddenVisibility) {
       Res.push_back("hidden");
     } else {
-      assert(Opts.getVisibilityMode() == LangOptions::Protected &&
+      assert(Opts.getVisibilityMode() == ProtectedVisibility &&
              "Invalid visibility!");
       Res.push_back("protected");
     }
@@ -1304,11 +1304,11 @@
 
   llvm::StringRef Vis = Args.getLastArgValue(OPT_fvisibility, "default");
   if (Vis == "default")
-    Opts.setVisibilityMode(LangOptions::Default);
+    Opts.setVisibilityMode(DefaultVisibility);
   else if (Vis == "hidden")
-    Opts.setVisibilityMode(LangOptions::Hidden);
+    Opts.setVisibilityMode(HiddenVisibility);
   else if (Vis == "protected")
-    Opts.setVisibilityMode(LangOptions::Protected);
+    Opts.setVisibilityMode(ProtectedVisibility);
   else
     Diags.Report(diag::err_drv_invalid_value)
       << Args.getLastArg(OPT_fvisibility)->getAsString(Args) << Vis;
diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp
index 4461703..9dd6f4a 100644
--- a/lib/Serialization/ASTReader.cpp
+++ b/lib/Serialization/ASTReader.cpp
@@ -2526,7 +2526,7 @@
     PARSE_LANGOPT(CharIsSigned);
     PARSE_LANGOPT(ShortWChar);
     LangOpts.setGCMode((LangOptions::GCMode)Record[Idx++]);
-    LangOpts.setVisibilityMode((LangOptions::VisibilityMode)Record[Idx++]);
+    LangOpts.setVisibilityMode((Visibility)Record[Idx++]);
     LangOpts.setStackProtectorMode((LangOptions::StackProtectorMode)
                                    Record[Idx++]);
     PARSE_LANGOPT(InstantiationDepth);