Implement #pragma GCC visibility.

llvm-svn: 110315
This commit is contained in:
Eli Friedman 2010-08-05 06:57:20 +00:00
parent ef7c0ffe40
commit 570024a8d9
17 changed files with 202 additions and 9 deletions

View File

@ -540,12 +540,15 @@ public:
};
private:
VisibilityTypes VisibilityType;
bool FromPragma;
public:
VisibilityAttr(VisibilityTypes v) : Attr(attr::Visibility),
VisibilityType(v) {}
VisibilityAttr(VisibilityTypes v, bool fp) : Attr(attr::Visibility),
VisibilityType(v), FromPragma(fp) {}
VisibilityTypes getVisibility() const { return VisibilityType; }
bool isFromPragma() const { return FromPragma; }
virtual Attr *clone(ASTContext &C) const;
// Implement isa/cast/dyncast/etc.

View File

@ -988,7 +988,7 @@ def warn_transparent_union_attribute_zero_fields : Warning<
"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<

View File

@ -2734,6 +2734,14 @@ public:
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,

View File

@ -110,6 +110,7 @@ class Parser {
IdentifierInfo *Ident_pixel;
llvm::OwningPtr<PragmaHandler> AlignHandler;
llvm::OwningPtr<PragmaHandler> GCCVisibilityHandler;
llvm::OwningPtr<PragmaHandler> OptionsHandler;
llvm::OwningPtr<PragmaHandler> PackHandler;
llvm::OwningPtr<PragmaHandler> UnusedHandler;

View File

@ -213,7 +213,7 @@ Attr *SentinelAttr::clone(ASTContext &C) const {
}
Attr *VisibilityAttr::clone(ASTContext &C) const {
return ::new (C) VisibilityAttr(VisibilityType);
return ::new (C) VisibilityAttr(VisibilityType, FromPragma);
}
Attr *OverloadableAttr::clone(ASTContext &C) const {

View File

@ -190,9 +190,11 @@ CodeGenModule::getDeclVisibilityMode(const Decl *D) const {
return LangOptions::Hidden;
}
// This decl should have the same visibility as its parent.
// If this decl is contained in a class, it should have the same visibility
// as the parent class.
if (const DeclContext *DC = D->getDeclContext())
return getDeclVisibilityMode(cast<Decl>(DC));
if (DC->isRecord())
return getDeclVisibilityMode(cast<Decl>(DC));
return getLangOptions().getVisibilityMode();
}

View File

@ -1292,7 +1292,8 @@ Attr *PCHReader::ReadAttributes(llvm::BitstreamCursor &DeclsCursor) {
case attr::Visibility:
New = ::new (*Context) VisibilityAttr(
(VisibilityAttr::VisibilityTypes)Record[Idx++]);
(VisibilityAttr::VisibilityTypes)Record[Idx++],
(bool)Record[Idx++]);
break;
SIMPLE_ATTR(WarnUnusedResult);

View File

@ -2106,6 +2106,7 @@ void PCHWriter::WriteAttributeRecord(const Attr *Attr) {
case attr::Visibility:
// FIXME: stable encoding
Record.push_back(cast<VisibilityAttr>(Attr)->getVisibility());
Record.push_back(cast<VisibilityAttr>(Attr)->isFromPragma());
break;
case attr::WarnUnusedResult:

View File

@ -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' ')'

View File

@ -28,6 +28,15 @@ public:
virtual void HandlePragma(Preprocessor &PP, Token &FirstToken);
};
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:

View File

@ -36,6 +36,9 @@ Parser::Parser(Preprocessor &pp, Action &actions)
AlignHandler.reset(new PragmaAlignHandler(actions));
PP.AddPragmaHandler(AlignHandler.get());
GCCVisibilityHandler.reset(new PragmaGCCVisibilityHandler(actions));
PP.AddPragmaHandler("GCC", GCCVisibilityHandler.get());
OptionsHandler.reset(new PragmaOptionsHandler(actions));
PP.AddPragmaHandler(OptionsHandler.get());
@ -303,6 +306,8 @@ Parser::~Parser() {
// Remove the pragma handlers we installed.
PP.RemovePragmaHandler(AlignHandler.get());
AlignHandler.reset();
PP.RemovePragmaHandler("GCC", GCCVisibilityHandler.get());
GCCVisibilityHandler.reset();
PP.RemovePragmaHandler(OptionsHandler.get());
OptionsHandler.reset();
PP.RemovePragmaHandler(PackHandler.get());

View File

@ -126,7 +126,7 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
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(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
Sema::~Sema() {
if (PackContext) FreePackedContext();
if (VisContext) FreeVisContext();
delete TheTargetAttributesSema;
while (!FunctionScopes.empty())
PopFunctionOrBlockScope();

View File

@ -285,6 +285,9 @@ public:
/// 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 @@ public:
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 @@ public:
/// 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);

View File

@ -288,3 +288,70 @@ void Sema::ActOnPragmaUnused(const Token *Identifiers, unsigned NumIdentifiers,
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.
}

View File

@ -2680,6 +2680,11 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC,
!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 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
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 @@ void Sema::ActOnFields(Scope* S,
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

View File

@ -847,7 +847,7 @@ static void HandleVisibilityAttr(Decl *d, const AttributeList &Attr, Sema &S) {
return;
}
d->addAttr(::new (S.Context) VisibilityAttr(type));
d->addAttr(::new (S.Context) VisibilityAttr(type, false));
}
static void HandleObjCExceptionAttr(Decl *D, const AttributeList &Attr,

View File

@ -3179,6 +3179,9 @@ Sema::DeclPtrTy Sema::ActOnStartNamespaceDef(Scope *NamespcScope,
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 @@ void Sema::ActOnFinishNamespaceDef(DeclPtrTy D, SourceLocation RBrace) {
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