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