Implement #pragma GCC visibility.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@110315 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
index a42c6e8..2c834f4 100644
--- a/lib/Sema/Sema.cpp
+++ b/lib/Sema/Sema.cpp
@@ -126,7 +126,7 @@
     LangOpts(pp.getLangOptions()), PP(pp), Context(ctxt), Consumer(consumer),
     Diags(PP.getDiagnostics()), SourceMgr(PP.getSourceManager()),
     ExternalSource(0), CodeCompleter(CodeCompleter), CurContext(0), 
-    PackContext(0), TopFunctionScope(0), ParsingDeclDepth(0),
+    PackContext(0), VisContext(0), TopFunctionScope(0), ParsingDeclDepth(0),
     IdResolver(pp.getLangOptions()), GlobalNewDeleteDeclared(false), 
     CompleteTranslationUnit(CompleteTranslationUnit),
     NumSFINAEErrors(0), SuppressAccessChecking(false),
@@ -147,6 +147,7 @@
 
 Sema::~Sema() {
   if (PackContext) FreePackedContext();
+  if (VisContext) FreeVisContext();
   delete TheTargetAttributesSema;
   while (!FunctionScopes.empty())
     PopFunctionOrBlockScope();
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 59a628a..967d475 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -285,6 +285,9 @@
   /// of 0 indicates default alignment.
   void *PackContext; // Really a "PragmaPackStack*"
 
+  /// VisContext - Manages the stack for #pragma GCC visibility.
+  void *VisContext; // Really a "PragmaVisStack*"
+
   /// \brief Stack containing information about each of the nested function,
   /// block, and method scopes that are currently active.
   llvm::SmallVector<FunctionScopeInfo *, 4> FunctionScopes;
@@ -4199,6 +4202,10 @@
                                  SourceLocation LParenLoc,
                                  SourceLocation RParenLoc);
 
+  /// ActOnPragmaVisibility - Called on well formed #pragma GCC visibility... .
+  virtual void ActOnPragmaVisibility(bool IsPush, const IdentifierInfo* VisType,
+                                     SourceLocation PragmaLoc);
+
   NamedDecl *DeclClonePragmaWeak(NamedDecl *ND, IdentifierInfo *II);
   void DeclApplyPragmaWeak(Scope *S, NamedDecl *ND, WeakInfo &W);
 
@@ -4221,6 +4228,21 @@
   /// FreePackedContext - Deallocate and null out PackContext.
   void FreePackedContext();
 
+  /// AddPushedVisibilityAttribute - If '#pragma GCC visibility' was used,
+  /// add an appropriate visibility attribute.
+  void AddPushedVisibilityAttribute(Decl *RD);
+
+  /// PushPragmaVisibility - Push the top element of the visibility stack; used
+  ///  for '#pragma GCC visibility' and visibility attributes on namespaces.
+  void PushPragmaVisibility(VisibilityAttr::VisibilityTypes type);
+
+  /// PopPragmaVisibility - Pop the top element of the visibility stack; used
+  /// for '#pragma GCC visibility' and visibility attributes on namespaces.
+  void PopPragmaVisibility();
+
+  /// FreeVisContext - Deallocate and null out VisContext.
+  void FreeVisContext();
+
   /// AddAlignedAttr - Adds an aligned attribute to a particular declaration.
   void AddAlignedAttr(SourceLocation AttrLoc, Decl *D, Expr *E);
 
diff --git a/lib/Sema/SemaAttr.cpp b/lib/Sema/SemaAttr.cpp
index 13a0c59..d1e5fe6 100644
--- a/lib/Sema/SemaAttr.cpp
+++ b/lib/Sema/SemaAttr.cpp
@@ -288,3 +288,70 @@
     VD->addAttr(::new (Context) UnusedAttr());
   }
 }
+
+typedef std::vector<VisibilityAttr::VisibilityTypes> VisStack;
+
+void Sema::AddPushedVisibilityAttribute(Decl *D) {
+  if (!VisContext)
+    return;
+
+  if (D->hasAttr<VisibilityAttr>())
+    return;
+
+  VisStack *Stack = static_cast<VisStack*>(VisContext);
+  VisibilityAttr::VisibilityTypes type = Stack->back();
+
+  D->addAttr(::new (Context) VisibilityAttr(type, true));
+}
+
+/// FreeVisContext - Deallocate and null out VisContext.
+void Sema::FreeVisContext() {
+  delete static_cast<VisStack*>(VisContext);
+  VisContext = 0;
+}
+
+void Sema::ActOnPragmaVisibility(bool IsPush, const IdentifierInfo* VisType,
+                                 SourceLocation PragmaLoc) {
+  if (IsPush) {
+    // Compute visibility to use.
+    VisibilityAttr::VisibilityTypes type;
+    if (VisType->isStr("default"))
+      type = VisibilityAttr::DefaultVisibility;
+    else if (VisType->isStr("hidden"))
+      type = VisibilityAttr::HiddenVisibility;
+    else if (VisType->isStr("internal"))
+      type = VisibilityAttr::HiddenVisibility; // FIXME
+    else if (VisType->isStr("protected"))
+      type = VisibilityAttr::ProtectedVisibility;
+    else {
+      Diag(PragmaLoc, diag::warn_attribute_unknown_visibility) <<
+        VisType->getName();
+      return;
+    }
+    PushPragmaVisibility(type);
+  } else {
+    PopPragmaVisibility();
+  }
+}
+
+void Sema::PushPragmaVisibility(VisibilityAttr::VisibilityTypes type) {
+  // Put visibility on stack.
+  if (!VisContext)
+    VisContext = new VisStack;
+
+  VisStack *Stack = static_cast<VisStack*>(VisContext);
+  Stack->push_back(type);
+}
+
+void Sema::PopPragmaVisibility() {
+  // Pop visibility from stack, if there is one on the stack.
+  if (VisContext) {
+    VisStack *Stack = static_cast<VisStack*>(VisContext);
+
+    Stack->pop_back();
+    // To simplify the implementation, never keep around an empty stack.
+    if (Stack->empty())
+      FreeVisContext();
+  }
+  // FIXME: Add diag for pop without push.
+}
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index e166e9c..a1580f1 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -2680,6 +2680,11 @@
       !NewVD->isInvalidDecl())
     RegisterLocallyScopedExternCDecl(NewVD, Previous, S);
 
+  // If there's a #pragma GCC visibility in scope, and this isn't a class
+  // member, set the visibility of this variable.
+  if (NewVD->getLinkage() == ExternalLinkage && !DC->isRecord())
+    AddPushedVisibilityAttribute(NewVD);
+
   return NewVD;
 }
 
@@ -3529,6 +3534,11 @@
     NewFD->addAttr(::new (Context) OverloadableAttr());
   }
 
+  // If there's a #pragma GCC visibility in scope, and this isn't a class
+  // member, set the visibility of this function.
+  if (NewFD->getLinkage() == ExternalLinkage && !DC->isRecord())
+    AddPushedVisibilityAttribute(NewFD);
+
   // If this is a locally-scoped extern C function, update the
   // map of such names.
   if (CurContext->isFunctionOrMethod() && NewFD->isExternC()
@@ -6367,6 +6377,11 @@
 
   if (Attr)
     ProcessDeclAttributeList(S, Record, Attr);
+
+  // If there's a #pragma GCC visibility in scope, and this isn't a subclass,
+  // set the visibility of this record.
+  if (Record && !Record->getDeclContext()->isRecord())
+    AddPushedVisibilityAttribute(Record);
 }
 
 /// \brief Determine whether the given integral value is representable within
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index cebe6e7..2af3102 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -847,7 +847,7 @@
     return;
   }
 
-  d->addAttr(::new (S.Context) VisibilityAttr(type));
+  d->addAttr(::new (S.Context) VisibilityAttr(type, false));
 }
 
 static void HandleObjCExceptionAttr(Decl *D, const AttributeList &Attr,
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 9a1a4cc..bd7c476 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -3179,6 +3179,9 @@
 
   ProcessDeclAttributeList(DeclRegionScope, Namespc, AttrList);
 
+  if (const VisibilityAttr *attr = Namespc->getAttr<VisibilityAttr>())
+    PushPragmaVisibility(attr->getVisibility());
+
   if (II) {
     // C++ [namespace.def]p2:
     // The identifier in an original-namespace-definition shall not have been
@@ -3310,6 +3313,8 @@
   assert(Namespc && "Invalid parameter, expected NamespaceDecl");
   Namespc->setRBracLoc(RBrace);
   PopDeclContext();
+  if (Namespc->hasAttr<VisibilityAttr>())
+    PopPragmaVisibility();
 }
 
 /// \brief Retrieve the special "std" namespace, which may require us to