This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
C++ PATCH for c++/32470 (namespace visibility bug)
- From: Jason Merrill <jason at redhat dot com>
- To: gcc-patches List <gcc-patches at gcc dot gnu dot org>
- Date: Wed, 03 Oct 2007 22:47:51 -1000
- Subject: C++ PATCH for c++/32470 (namespace visibility bug)
My earlier implementation of namespace visibility assumed that only the
parser would be calling push_namespace_with_attrs, which of course is
not actually the case. So this patch fixes the bug by moving the
visibility handling out of push_namespace into the parser.
Tested x86_64-pc-linux-gnu, applied to trunk. Will apply to 4.2 when it
unfreezes.
2007-10-03 Jason Merrill <jason@redhat.com>
PR c++/32470
* name-lookup.c (push_namespace_with_attrs): Fold back into...
(push_namespace): Here.
(handle_namespace_attrs): New fn for the attr code.
(leave_scope): Don't pop_visibility.
* name-lookup.h (struct cp_binding_level): Remove has_visibility.
* parser.c (cp_parser_namespace_definition): Call
handle_namespace_attrs and pop_visibility as appropriate.
Index: cp/name-lookup.c
===================================================================
*** cp/name-lookup.c (revision 128889)
--- cp/name-lookup.c (working copy)
*************** leave_scope (void)
*** 1364,1374 ****
is_class_level = 0;
}
- #ifdef HANDLE_PRAGMA_VISIBILITY
- if (scope->has_visibility)
- pop_visibility ();
- #endif
-
/* Move one nesting level up. */
current_binding_level = scope->level_chain;
--- 1364,1369 ----
*************** current_decl_namespace (void)
*** 3027,3046 ****
return result;
}
! /* Push into the scope of the NAME namespace. If NAME is NULL_TREE, then we
! select a name that is unique to this compilation unit. */
! void
! push_namespace (tree name)
{
! push_namespace_with_attribs (name, NULL_TREE);
! }
! /* Same, but specify attributes to apply to the namespace. The attributes
! only apply to the current namespace-body, not to any later extensions. */
void
! push_namespace_with_attribs (tree name, tree attributes)
{
tree d = NULL_TREE;
int need_new = 1;
--- 3022,3080 ----
return result;
}
! /* Process any ATTRIBUTES on a namespace definition. Currently only
! attribute visibility is meaningful, which is a property of the syntactic
! block rather than the namespace as a whole, so we don't touch the
! NAMESPACE_DECL at all. Returns true if attribute visibility is seen. */
! bool
! handle_namespace_attrs (tree ns, tree attributes)
{
! tree d;
! bool saw_vis = false;
!
! for (d = attributes; d; d = TREE_CHAIN (d))
! {
! tree name = TREE_PURPOSE (d);
! tree args = TREE_VALUE (d);
!
! #ifdef HANDLE_PRAGMA_VISIBILITY
! if (is_attribute_p ("visibility", name))
! {
! tree x = args ? TREE_VALUE (args) : NULL_TREE;
! if (x == NULL_TREE || TREE_CODE (x) != STRING_CST || TREE_CHAIN (args))
! {
! warning (OPT_Wattributes,
! "%qD attribute requires a single NTBS argument",
! name);
! continue;
! }
!
! if (!TREE_PUBLIC (ns))
! warning (OPT_Wattributes,
! "%qD attribute is meaningless since members of the "
! "anonymous namespace get local symbols", name);
!
! push_visibility (TREE_STRING_POINTER (x));
! saw_vis = true;
! }
! else
! #endif
! {
! warning (OPT_Wattributes, "%qD attribute directive ignored",
! name);
! continue;
! }
! }
! return saw_vis;
! }
!
! /* Push into the scope of the NAME namespace. If NAME is NULL_TREE, then we
! select a name that is unique to this compilation unit. */
void
! push_namespace (tree name)
{
tree d = NULL_TREE;
int need_new = 1;
*************** push_namespace_with_attribs (tree name,
*** 3107,3144 ****
/* Enter the name space. */
current_namespace = d;
- #ifdef HANDLE_PRAGMA_VISIBILITY
- /* Clear has_visibility in case a previous namespace-definition had a
- visibility attribute and this one doesn't. */
- current_binding_level->has_visibility = 0;
- for (d = attributes; d; d = TREE_CHAIN (d))
- {
- tree name = TREE_PURPOSE (d);
- tree args = TREE_VALUE (d);
- tree x;
-
- if (! is_attribute_p ("visibility", name))
- {
- warning (OPT_Wattributes, "%qs attribute directive ignored",
- IDENTIFIER_POINTER (name));
- continue;
- }
-
- x = args ? TREE_VALUE (args) : NULL_TREE;
- if (x == NULL_TREE || TREE_CODE (x) != STRING_CST || TREE_CHAIN (args))
- {
- warning (OPT_Wattributes, "%qs attribute requires a single NTBS argument",
- IDENTIFIER_POINTER (name));
- continue;
- }
-
- current_binding_level->has_visibility = 1;
- push_visibility (TREE_STRING_POINTER (x));
- goto found;
- }
- found:
- #endif
-
timevar_pop (TV_NAME_LOOKUP);
}
--- 3141,3146 ----
Index: cp/name-lookup.h
===================================================================
*** cp/name-lookup.h (revision 128889)
--- cp/name-lookup.h (working copy)
*************** struct cp_binding_level GTY(())
*** 255,265 ****
unsigned more_cleanups_ok : 1;
unsigned have_cleanups : 1;
! /* Nonzero if this level has associated visibility which we should pop
! when leaving the scope. */
! unsigned has_visibility : 1;
!
! /* 23 bits left to fill a 32-bit word. */
};
/* The binding level currently in effect. */
--- 255,261 ----
unsigned more_cleanups_ok : 1;
unsigned have_cleanups : 1;
! /* 24 bits left to fill a 32-bit word. */
};
/* The binding level currently in effect. */
*************** extern void pop_inner_scope (tree, tree)
*** 307,316 ****
extern void push_binding_level (struct cp_binding_level *);
extern void push_namespace (tree);
- extern void push_namespace_with_attribs (tree, tree);
extern void pop_namespace (void);
extern void push_nested_namespace (tree);
extern void pop_nested_namespace (tree);
extern void pushlevel_class (void);
extern void poplevel_class (void);
extern tree pushdecl_with_scope (tree, cxx_scope *, bool);
--- 303,312 ----
extern void push_binding_level (struct cp_binding_level *);
extern void push_namespace (tree);
extern void pop_namespace (void);
extern void push_nested_namespace (tree);
extern void pop_nested_namespace (tree);
+ extern bool handle_namespace_attrs (tree, tree);
extern void pushlevel_class (void);
extern void poplevel_class (void);
extern tree pushdecl_with_scope (tree, cxx_scope *, bool);
Index: cp/parser.c
===================================================================
*** cp/parser.c (revision 128889)
--- cp/parser.c (working copy)
*************** static void
*** 11475,11480 ****
--- 11475,11481 ----
cp_parser_namespace_definition (cp_parser* parser)
{
tree identifier, attribs;
+ bool has_visibility;
/* Look for the `namespace' keyword. */
cp_parser_require_keyword (parser, RID_NAMESPACE, "`namespace'");
*************** cp_parser_namespace_definition (cp_parse
*** 11494,11502 ****
/* Look for the `{' to start the namespace. */
cp_parser_require (parser, CPP_OPEN_BRACE, "`{'");
/* Start the namespace. */
! push_namespace_with_attribs (identifier, attribs);
/* Parse the body of the namespace. */
cp_parser_namespace_body (parser);
/* Finish the namespace. */
pop_namespace ();
/* Look for the final `}'. */
--- 11495,11512 ----
/* Look for the `{' to start the namespace. */
cp_parser_require (parser, CPP_OPEN_BRACE, "`{'");
/* Start the namespace. */
! push_namespace (identifier);
!
! has_visibility = handle_namespace_attrs (current_namespace, attribs);
!
/* Parse the body of the namespace. */
cp_parser_namespace_body (parser);
+
+ #ifdef HANDLE_PRAGMA_VISIBILITY
+ if (has_visibility)
+ pop_visibility ();
+ #endif
+
/* Finish the namespace. */
pop_namespace ();
/* Look for the final `}'. */
Index: testsuite/g++.dg/ext/visibility/namespace2.C
===================================================================
*** testsuite/g++.dg/ext/visibility/namespace2.C (revision 0)
--- testsuite/g++.dg/ext/visibility/namespace2.C (revision 0)
***************
*** 0 ****
--- 1,20 ----
+ // PR c++/32470
+
+ // { dg-require-visibility }
+ // { dg-options "-fvisibility=hidden" }
+ // { dg-final { scan-hidden "_ZN4Test4testEv" } }
+
+ namespace std __attribute__((__visibility__("default"))) {
+ template<typename _CharT>
+ class basic_streambuf
+ {
+ friend void getline();
+ };
+ extern template class basic_streambuf<char>;
+ }
+
+ class Test
+ {
+ void test();
+ };
+ void Test::test() { }