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