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/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.
+}