]> granicus.if.org Git - clang/commitdiff
Implement #pragma GCC visibility.
authorEli Friedman <eli.friedman@gmail.com>
Thu, 5 Aug 2010 06:57:20 +0000 (06:57 +0000)
committerEli Friedman <eli.friedman@gmail.com>
Thu, 5 Aug 2010 06:57:20 +0000 (06:57 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@110315 91177308-0d34-0410-b5e6-96231b3b80d8

17 files changed:
include/clang/AST/Attr.h
include/clang/Basic/DiagnosticSemaKinds.td
include/clang/Parse/Action.h
include/clang/Parse/Parser.h
lib/AST/AttrImpl.cpp
lib/CodeGen/CodeGenModule.cpp
lib/Frontend/PCHReaderDecl.cpp
lib/Frontend/PCHWriter.cpp
lib/Parse/ParsePragma.cpp
lib/Parse/ParsePragma.h
lib/Parse/Parser.cpp
lib/Sema/Sema.cpp
lib/Sema/Sema.h
lib/Sema/SemaAttr.cpp
lib/Sema/SemaDecl.cpp
lib/Sema/SemaDeclAttr.cpp
lib/Sema/SemaDeclCXX.cpp

index 5775b2be4781b86322c09645983ffc206eecbf0b..3e9c45ad4a9a58856582ed2aa74f9a913e322ea0 100644 (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.
index 2ff8de310e328af96a8669527ac135e233533611..bebc333f6d1a0537f9fac3ca73736031f2a722f5 100644 (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<
index d5cbd0cde3389126877e05cf6c2d99b0e6f200e9..e1a8ffbb7a405af4019059c1b92ae213f4f0b1ae 100644 (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,
index 234752decb8d2c5e49ab290cfc46e53ad7dc5452..9a166a1e98ef4b297f31bfc8af730ef706b11081 100644 (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;
index 4146248fb039a6cf7b438451b47fb7ac59f83830..8992e4823d524dac39431204abc79be462c452ff 100644 (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 {
index d2be5af14a4ad924c0fafa6ae56577e1dac78894..6338402579934a40025a623e02f8ef27b8ca518f 100644 (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();
 }
index 21beb42e93e5c653b2fe93a5c52f4add92137356..7557950e66d94a1e1ad8b8c63dea3000f87afd15 100644 (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);
index d5750a1f5049af6270592ee73e424e8386d2399f..b2fd984766653aad4410cc9fe6e91ad7d1743fc9 100644 (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:
index e414e4fc5ae17030691098598afbb8c8bd5434cc..c53b2e4d27ccbbf31a466d5e67cd85d13e824499 100644 (file)
 #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 1d66277d33e5ae2b0e93bc5e960c1f2aeab315e6..8aef4009689c814f9c929dd2d37f4808810087ad 100644 (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:
index 63aa2bf47d206cf26806ab5c536e4e110af631dc..b32c1f8a1799fcfe5307b93c3eb4723427e68877 100644 (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());
index a42c6e804cf880dd1b7855d47a9636c85866fed8..2c834f434928daceafd817ca96a1a1f238ab17d2 100644 (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();
index 59a628aad2225cafbb9c9cdbb0a2e90dc4c72276..967d4757da4b60448d68ebed4a1f02ff25317052 100644 (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);
 
index 13a0c59bbdb598cbf997161c01582f85780a63c2..d1e5fe64dfb3f66c690e5061c9b02feabee5cd97 100644 (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.
+}
index e166e9cc2dc6c9be2942fb0a8bc51318d1787fde..a1580f14dc521e0c3e71382502bf4d25136d2ac3 100644 (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
index cebe6e7850a1541e2a462b89b8dc5815306578b0..2af3102ad759c64911bbdc1e2cd4bd4f48bb093a 100644 (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,
index 9a1a4cceced0b0b2ca2e013306696b4a59cf9503..bd7c47683efdd65ed3c5acffcf5628363c3d235c 100644 (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