[cfe-commits] [PATCH] Implement '#pragma GCC visibility' (WIP)
Eli Friedman
eli.friedman at gmail.com
Sat Jul 17 21:09:39 PDT 2010
Attached. Review comments welcome. This doesn't interact quite
correctly with classes and namespaces; any guidance on how to
implement the correct rules there would be appreciated.
-Eli
-------------- next part --------------
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td (revision 108632)
+++ include/clang/Basic/DiagnosticSemaKinds.td (working copy)
@@ -977,7 +977,7 @@
"transparent_union attribute ignored">;
def warn_attribute_type_not_supported : Warning<
"'%0' attribute argument not supported: %1">;
-def warn_attribute_unknown_visibility : Warning<"unknown visibility '%1'">;
+def warn_attribute_unknown_visibility : Warning<"unknown visibility '%0'">;
def err_unknown_machine_mode : Error<"unknown machine mode %0">;
def err_unsupported_machine_mode : Error<"unsupported machine mode %0">;
def err_mode_not_primitive : Error<
Index: include/clang/Parse/Parser.h
===================================================================
--- include/clang/Parse/Parser.h (revision 108632)
+++ include/clang/Parse/Parser.h (working copy)
@@ -110,6 +110,7 @@
IdentifierInfo *Ident_vector;
IdentifierInfo *Ident_pixel;
+ llvm::OwningPtr<PragmaHandler> GCCVisibilityHandler;
llvm::OwningPtr<PragmaHandler> OptionsHandler;
llvm::OwningPtr<PragmaHandler> PackHandler;
llvm::OwningPtr<PragmaHandler> UnusedHandler;
Index: include/clang/Parse/Action.h
===================================================================
--- include/clang/Parse/Action.h (revision 108632)
+++ include/clang/Parse/Action.h (working copy)
@@ -2738,6 +2738,14 @@
return;
}
+
+ /// ActOnPragmaVisibility - Called on well formed #pragma GCC visibility... .
+ virtual void ActOnPragmaVisibility(bool IsPush, const IdentifierInfo* VisType,
+ SourceLocation PragmaLoc) {
+ return;
+ }
+
+
/// ActOnPragmaWeakID - Called on well formed #pragma weak ident.
virtual void ActOnPragmaWeakID(IdentifierInfo* WeakName,
SourceLocation PragmaLoc,
Index: lib/Sema/SemaDeclAttr.cpp
===================================================================
--- lib/Sema/SemaDeclAttr.cpp (revision 108632)
+++ lib/Sema/SemaDeclAttr.cpp (working copy)
@@ -678,7 +678,7 @@
else if (TypeStr == "protected")
type = VisibilityAttr::ProtectedVisibility;
else {
- S.Diag(Attr.getLoc(), diag::warn_attribute_unknown_visibility) << TypeStr;
+ S.Diag(Attr.getLoc(), diag::warn_attribute_unknown_visibility) << Str;
return;
}
@@ -2172,6 +2172,9 @@
// Finally, apply any attributes on the decl itself.
if (const AttributeList *Attrs = PD.getAttributes())
ProcessDeclAttributeList(S, D, Attrs);
+
+ // Tack on a visibility attribute from '#pragma GCC visibility', if necessary.
+ AddPushedVisibilityAttribute(D);
}
/// PushParsingDeclaration - Enter a new "scope" of deprecation
Index: lib/Sema/Sema.h
===================================================================
--- lib/Sema/Sema.h (revision 108632)
+++ lib/Sema/Sema.h (working copy)
@@ -273,6 +273,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;
@@ -4128,6 +4131,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);
@@ -4150,6 +4157,13 @@
/// FreePackedContext - Deallocate and null out PackContext.
void FreePackedContext();
+ /// AddPushedVisibilityAttribute - If '#pragma GCC visibility' was used,
+ /// add an appropriate visibility attribute.
+ void AddPushedVisibilityAttribute(Decl *RD);
+
+ /// 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);
Index: lib/Sema/SemaAttr.cpp
===================================================================
--- lib/Sema/SemaAttr.cpp (revision 108632)
+++ lib/Sema/SemaAttr.cpp (working copy)
@@ -289,3 +289,62 @@
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));
+}
+
+/// 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;
+ }
+
+ // Put visibility on stack.
+ if (!VisContext)
+ VisContext = new VisStack;
+ VisStack *Stack = static_cast<VisStack*>(VisContext);
+ Stack->push_back(type);
+ } else { // !IsPush
+ // 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.
+ }
+}
Index: lib/Sema/Sema.cpp
===================================================================
--- lib/Sema/Sema.cpp (revision 108632)
+++ lib/Sema/Sema.cpp (working copy)
@@ -123,7 +123,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()), StdNamespace(0), StdBadAlloc(0),
GlobalNewDeleteDeclared(false),
CompleteTranslationUnit(CompleteTranslationUnit),
@@ -145,6 +145,7 @@
Sema::~Sema() {
if (PackContext) FreePackedContext();
+ if (VisContext) FreeVisContext();
delete TheTargetAttributesSema;
while (!FunctionScopes.empty())
PopFunctionOrBlockScope();
Index: lib/Parse/ParsePragma.cpp
===================================================================
--- lib/Parse/ParsePragma.cpp (revision 108632)
+++ lib/Parse/ParsePragma.cpp (working copy)
@@ -18,6 +18,59 @@
#include "clang/Parse/Parser.h"
using namespace clang;
+
+// #pragma GCC visibility comes in two variants:
+// 'push' '(' [visibility] ')'
+// 'pop'
+void PragmaGCCVisibilityHandler::HandlePragma(Preprocessor &PP, Token &VisTok) {
+ SourceLocation VisLoc = VisTok.getLocation();
+
+ Token Tok;
+ PP.Lex(Tok);
+
+ const IdentifierInfo *PushPop = Tok.getIdentifierInfo();
+
+ bool IsPush;
+ const IdentifierInfo *VisType;
+ if (PushPop && PushPop->isStr("pop")) {
+ IsPush = false;
+ VisType = 0;
+ } else if (PushPop && PushPop->isStr("push")) {
+ IsPush = true;
+ PP.Lex(Tok);
+ if (Tok.isNot(tok::l_paren)) {
+ PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_lparen)
+ << "visibility";
+ return;
+ }
+ PP.Lex(Tok);
+ VisType = Tok.getIdentifierInfo();
+ if (!VisType) {
+ PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier)
+ << "visibility";
+ return;
+ }
+ PP.Lex(Tok);
+ if (Tok.isNot(tok::r_paren)) {
+ PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_rparen)
+ << "visibility";
+ return;
+ }
+ } else {
+ PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier)
+ << "visibility";
+ return;
+ }
+ PP.Lex(Tok);
+ if (Tok.isNot(tok::eom)) {
+ PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol)
+ << "visibility";
+ return;
+ }
+
+ Actions.ActOnPragmaVisibility(IsPush, VisType, VisLoc);
+}
+
// #pragma pack(...) comes in the following delicious flavors:
// pack '(' [integer] ')'
// pack '(' 'show' ')'
Index: lib/Parse/ParsePragma.h
===================================================================
--- lib/Parse/ParsePragma.h (revision 108632)
+++ lib/Parse/ParsePragma.h (working copy)
@@ -20,6 +20,15 @@
class Action;
class Parser;
+class PragmaGCCVisibilityHandler : public PragmaHandler {
+ Action &Actions;
+public:
+ explicit PragmaGCCVisibilityHandler(Action &A) : PragmaHandler("visibility"),
+ Actions(A) {}
+
+ virtual void HandlePragma(Preprocessor &PP, Token &FirstToken);
+};
+
class PragmaOptionsHandler : public PragmaHandler {
Action &Actions;
public:
Index: lib/Parse/Parser.cpp
===================================================================
--- lib/Parse/Parser.cpp (revision 108632)
+++ lib/Parse/Parser.cpp (working copy)
@@ -33,6 +33,9 @@
// Add #pragma handlers. These are removed and destroyed in the
// destructor.
+ GCCVisibilityHandler.reset(new PragmaGCCVisibilityHandler(actions));
+ PP.AddPragmaHandler("GCC", GCCVisibilityHandler.get());
+
OptionsHandler.reset(new PragmaOptionsHandler(actions));
PP.AddPragmaHandler(OptionsHandler.get());
@@ -298,6 +301,8 @@
delete ScopeCache[i];
// Remove the pragma handlers we installed.
+ PP.RemovePragmaHandler("GCC", GCCVisibilityHandler.get());
+ GCCVisibilityHandler.reset();
PP.RemovePragmaHandler(OptionsHandler.get());
OptionsHandler.reset();
PP.RemovePragmaHandler(PackHandler.get());
More information about the cfe-commits
mailing list