On 20/01/12 12:40 AM, Richard Smith wrote:
> Perhaps it's time to review the handling of #pragma visibility. The existing
> mechanism is very flaky -- this is the second subtle bug we've had with it in
> recent months (the previous bug, which probably can still be observed in some
> cases, is that lookahead / tentative parsing which looks past such a #pragma
> applies its effects immediately).

The attached patch implements your suggestion. It also fixes some old
FIXMEs in pragma-visibility.cpp.

Cheers,
Rafael
diff --git a/include/clang/Basic/TokenKinds.def 
b/include/clang/Basic/TokenKinds.def
index cac0733..5c9708b 100644
--- a/include/clang/Basic/TokenKinds.def
+++ b/include/clang/Basic/TokenKinds.def
@@ -568,6 +568,11 @@ ANNOTATION(decltype)     // annotation for a decltype 
expression,
 // one 'pragma_unused' annotation token followed by the argument token.
 ANNOTATION(pragma_unused)
 
+// Annotation for #pragma GCC visibility...
+// The lexer produces these so that they only take effect when the parser
+// handles them.
+ANNOTATION(pragma_vis)
+
 #undef ANNOTATION
 #undef TESTING_KEYWORD
 #undef OBJC2_AT_KEYWORD
diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h
index ea79b98..590c355 100644
--- a/include/clang/Parse/Parser.h
+++ b/include/clang/Parse/Parser.h
@@ -410,6 +410,10 @@ private:
   /// \brief Handle the annotation token produced for #pragma unused(...)
   void HandlePragmaUnused();
 
+  /// \brief Handle the annotation token produced for
+  /// #pragma GCC visibility...
+  void HandlePragmaVisibility();
+
   /// GetLookAheadToken - This peeks ahead N tokens and returns that token
   /// without consuming any tokens.  LookAhead(0) returns 'Tok', LookAhead(1)
   /// returns the token after Tok, etc.
diff --git a/lib/Parse/ParsePragma.cpp b/lib/Parse/ParsePragma.cpp
index 2fe2f3b..f47b32f 100644
--- a/lib/Parse/ParsePragma.cpp
+++ b/lib/Parse/ParsePragma.cpp
@@ -29,6 +29,14 @@ void Parser::HandlePragmaUnused() {
   ConsumeToken(); // The argument token.
 }
 
+void Parser::HandlePragmaVisibility() {
+  assert(Tok.is(tok::annot_pragma_vis));
+  const IdentifierInfo *VisType =
+    static_cast<IdentifierInfo *>(Tok.getAnnotationValue());
+  SourceLocation VisLoc = ConsumeToken();
+  Actions.ActOnPragmaVisibility(VisType, VisLoc);
+}
+
 // #pragma GCC visibility comes in two variants:
 //   'push' '(' [visibility] ')'
 //   'pop'
@@ -77,7 +85,14 @@ void PragmaGCCVisibilityHandler::HandlePragma(Preprocessor 
&PP,
     return;
   }
 
-  Actions.ActOnPragmaVisibility(VisType, VisLoc);
+  Token *Toks = new Token[1];
+  Toks[0].startToken();
+  Toks[0].setKind(tok::annot_pragma_vis);
+  Toks[0].setLocation(VisLoc);
+  Toks[0].setAnnotationValue(
+                          const_cast<void*>(static_cast<const 
void*>(VisType)));
+  PP.EnterTokenStream(Toks, 1, /*DisableMacroExpansion=*/true,
+                      /*OwnsTokens=*/true);
 }
 
 // #pragma pack(...) comes in the following delicious flavors:
diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp
index 45b4a74..7f7fdf7 100644
--- a/lib/Parse/Parser.cpp
+++ b/lib/Parse/Parser.cpp
@@ -543,6 +543,9 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange 
&attrs,
 
   Decl *SingleDecl = 0;
   switch (Tok.getKind()) {
+  case tok::annot_pragma_vis:
+    HandlePragmaVisibility();
+    return DeclGroupPtrTy();
   case tok::semi:
     Diag(Tok, getLang().CPlusPlus0x ?
          diag::warn_cxx98_compat_top_level_semi : diag::ext_top_level_semi)
diff --git a/test/CodeGenCXX/pr11797.cpp b/test/CodeGenCXX/pr11797.cpp
new file mode 100644
index 0000000..05221ac
--- /dev/null
+++ b/test/CodeGenCXX/pr11797.cpp
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 %s -fvisibility hidden -emit-llvm -o - | FileCheck %s
+
+namespace std __attribute__ ((__visibility__ ("default"))) {}
+#pragma GCC visibility push(default)
+void foo() {
+}
+#pragma GCC visibility pop
+// CHECK: define void @_Z3foov()
diff --git a/test/CodeGenCXX/pragma-visibility.cpp 
b/test/CodeGenCXX/pragma-visibility.cpp
index 2dc8bcc..97f8cc8 100644
--- a/test/CodeGenCXX/pragma-visibility.cpp
+++ b/test/CodeGenCXX/pragma-visibility.cpp
@@ -55,8 +55,6 @@ namespace n __attribute((visibility("default"))) {
 #pragma GCC visibility pop
 
 namespace n __attribute((visibility("default")))  {
-  extern int foofoo; // FIXME: Shouldn't be necessary, but otherwise the pragma
-                     //        gets to Sema before the namespace!
 #pragma GCC visibility push(hidden)
   void g() {}
   // CHECK: define hidden void @_ZN1n1gEv
@@ -66,8 +64,6 @@ namespace n __attribute((visibility("default")))  {
 // We used to test this, but it's insane, so unless it happens in
 // headers, we should not support it.
 namespace n __attribute((visibility("hidden"))) {
-  extern int foofoo; // FIXME: Shouldn't be necessary, but otherwise the pragma
-                     //        gets to Sema before the namespace!
   #pragma GCC visibility pop
   void h() {}
   // CHECK disabled: define void @_ZN1n1hEv
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to