This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: Preview: PATCH to overhaul C++ visibility handling


Jason Merrill wrote:
This patch reimplements large chunks of the visibility handling in GCC to improve handling of type visibility. Notable changes:

Visibility restrictions are propagated from class to members (26905), and from template arguments to instantiations (26612).

We now give an error if a declaration has higher visibility than its type, or if a class has higher visibility than one of its non-static data member types.

Declarations in the anonymous namespace, or declarations which use types from the anonymous namespace, etc. are now local to the file (21581, 25915).

An explicit visibility attribute on a class must come between the class-key and the name, not after the closing brace.

Fixes 26905.


Attributes are now allowed on elaborated-type-specifiers that only declare the type (21675), and after the 'enum' keyword in enum definitons.

More fixes in the current patch:


Implicit template instantiations are not affected by #pragma visibility (27000), nor are type_info nodes (26984).

The visibility attribute is respected on explicit template instantiations (17470).

Non-inline specializations of inline functions are not affected by -fvisibility-inlines-hidden (19134).

I'm planning to look at 20218 and 23756 soon; they have to do with the backend's use of visibility, this patch deals with setting the visibility properly. Any other visibility bug reports I'm missing?

Tested on x86_64-pc-linux-gnu. I'd like to apply this patch for 4.2, since it fixes the various issues that make visibility support useless for C++. Perhaps leaving out the bits to make the anonymous namespace imply TREE_PUBLIC = 0 for now; that code seems the most risky, and orthogonal to the actual visibility support. Mark?

Jason
2006-06-25  Jason Merrill  <jason@redhat.com>

	PR c++/26905
	PR c++/26612
	PR c++/27000
	PR c++/26984
	PR c++/19134
	* tree.c (build_decl_stat): Don't hande #pragma visibility here.
	* c-common.c (c_determine_visibility): Handle it here.
	* c-decl.c (finish_decl): Call c_determine_visibility for 
	functions, too.
	* flags.h (enum symbol_visibility): Sort from most to least visibility.
	* tree.h: Likewise.
	* varasm.c (default_assemble_visibility): Likewise.
	* c-common.c (handle_visibility_attribute): Complain about trying
	to give visibility to an already defined class, or trying to change
	declared visibility. Always attach the attribute.
	* cp/decl2.c (determine_visibility): Overhaul.
	(determine_visibility_from_class): Likewise.
	(min_vis_r, type_visibility, constrain_visibility): New fns.
	(constrain_visibility_for_template): Likewise.
	(constrain_class_visibility): Likewise.
	* cp/decl.c (cp_finish_decl): Call determine_visibility for function
	decls, too.
	* cp/name-lookup.c (pushtag): Call determine_visibility.
	* cp/decl.c (duplicate_decls): Don't copy visibility from template to
	specialization.
	* cp/pt.c (check_explicit_specialization): Likewise.
	(lookup_template_class, tsubst_decl): Call determine_visibility.
	* cp/class.c (finish_struct_1): Call constrain_class_visibility.

	PR c++/26905
	PR c++/21675
	PR c++/17470
	* cp/parser.c (cp_parser_explicit_instantiation): Pass the attributes
	to grokdeclarator.
	(cp_parser_type_specifier): Allow 'enum __attribute ((...)) E'.
	(cp_parser_enum_specifier): Likewise.
	(cp_parser_elaborated_type_specifier): Apply attributes if this
	declares only the class.
	(cp_parser_class_specifier): Apply leading attributes immediately.
	* cp/semantics.c (begin_class_definition): Add attributes parameter,
	apply them to the type.

	PR c++/21581
	PR c++/25915
	* cp/tree.c (decl_anon_ns_mem_p): New function.
	* cp/cp-tree.h: Declare it.
	* cp/decl2.c (determine_visibility): Make anonymous namespace
	members static.
	(min_vis_r, constrain_visibility): Likewise.
	* cp/rtti.c (create_pseudo_type_info): Set TREE_PUBLIC on
	pseudo-types.
	* cp/decl.c (cxx_init_decl_processing): Set TREE_PUBLIC on
	global_namespace.
	* cp/name-lookup.c (push_namespace_with_attribs): Don't set TREE_PUBLIC
	on anonymous namespaces.

Index: doc/extend.texi
===================================================================
*** doc/extend.texi	(revision 114895)
--- doc/extend.texi	(working copy)
*************** consistently, so that the same entity sh
*** 2409,2418 ****
  different settings of the attribute.
  
  In C++, the visibility attribute applies to types as well as functions
! and objects, because in C++ types have linkage.  There are some bugs
! in the C++ support for this flag, for example a template which has a
! hidden type as a parameter is not properly hidden.
! @c bugzilla 26612
  
  In C++, you can mark member functions and static member variables of a
  class with the visibility attribute.  This is useful if if you know a
--- 2409,2418 ----
  different settings of the attribute.
  
  In C++, the visibility attribute applies to types as well as functions
! and objects, because in C++ types have linkage.  A class must not have
! greater visibility than its non-static data member types and bases, and
! class members must not have greater visibility than their class.
! Also, a declaration must not have greater visibility than its type.
  
  In C++, you can mark member functions and static member variables of a
  class with the visibility attribute.  This is useful if if you know a
*************** the One Definition Rule; for example, it
*** 2423,2428 ****
--- 2423,2438 ----
  method which is defined inside a class definition as hidden without
  marking the whole class as hidden.
  
+ A C++ namespace declaration can also have the visibility attribute.
+ This attribute applies only to the particular namespace body, not to
+ other definitions of the same namespace; it is equivalent to using
+ @samp{#pragma GCC visibility} before and after the namespace
+ definition.
+ 
+ In C++, if a type given as a template argument has limited visibility,
+ this restriction is implicitly propagated to the template
+ instantiation.
+ 
  @item warn_unused_result
  @cindex @code{warn_unused_result} attribute
  The @code{warn_unused_result} attribute causes a warning to be emitted
*************** does not arise there.
*** 2604,2613 ****
  An attribute specifier list may appear as part of a @code{struct},
  @code{union} or @code{enum} specifier.  It may go either immediately
  after the @code{struct}, @code{union} or @code{enum} keyword, or after
! the closing brace.  It is ignored if the content of the structure, union
! or enumerated type is not defined in the specifier in which the
! attribute specifier list is used---that is, in usages such as
! @code{struct __attribute__((foo)) bar} with no following opening brace.
  Where attribute specifiers follow the closing brace, they are considered
  to relate to the structure, union or enumerated type defined, not to any
  enclosing declaration the type specifier appears in, and the type
--- 2614,2620 ----
  An attribute specifier list may appear as part of a @code{struct},
  @code{union} or @code{enum} specifier.  It may go either immediately
  after the @code{struct}, @code{union} or @code{enum} keyword, or after
! the closing brace.  The former syntax is preferred.
  Where attribute specifiers follow the closing brace, they are considered
  to relate to the structure, union or enumerated type defined, not to any
  enclosing declaration the type specifier appears in, and the type
*************** placed in either the @code{.bss_below100
*** 3382,3394 ****
  @cindex type attributes
  
  The keyword @code{__attribute__} allows you to specify special
! attributes of @code{struct} and @code{union} types when you define such
! types.  This keyword is followed by an attribute specification inside
! double parentheses.  Six attributes are currently defined for types:
! @code{aligned}, @code{packed}, @code{transparent_union}, @code{unused},
! @code{deprecated} and @code{may_alias}.  Other attributes are defined for
! functions (@pxref{Function Attributes}) and for variables
! (@pxref{Variable Attributes}).
  
  You may also specify any one of these attributes with @samp{__}
  preceding and following its keyword.  This allows you to use these
--- 3389,3402 ----
  @cindex type attributes
  
  The keyword @code{__attribute__} allows you to specify special
! attributes of @code{struct} and @code{union} types when you define
! such types.  This keyword is followed by an attribute specification
! inside double parentheses.  Seven attributes are currently defined for
! types: @code{aligned}, @code{packed}, @code{transparent_union},
! @code{unused}, @code{deprecated}, @code{visibility}, and
! @code{may_alias}.  Other attributes are defined for functions
! (@pxref{Function Attributes}) and for variables (@pxref{Variable
! Attributes}).
  
  You may also specify any one of these attributes with @samp{__}
  preceding and following its keyword.  This allows you to use these
*************** attributes in header files without being
*** 3396,3409 ****
  macro of the same name.  For example, you may use @code{__aligned__}
  instead of @code{aligned}.
  
! You may specify the @code{aligned} and @code{transparent_union}
! attributes either in a @code{typedef} declaration or just past the
! closing curly brace of a complete enum, struct or union type
! @emph{definition} and the @code{packed} attribute only past the closing
! brace of a definition.
  
! You may also specify attributes between the enum, struct or union
! tag and the name of the type rather than after the closing brace.
  
  @xref{Attribute Syntax}, for details of the exact syntax for using
  attributes.
--- 3404,3416 ----
  macro of the same name.  For example, you may use @code{__aligned__}
  instead of @code{aligned}.
  
! You may specify type attributes either in a @code{typedef} declaration
! or in an enum, struct or union type declaration or definition.
  
! For an enum, struct or union type, you may specify attributes either
! between the enum, struct or union tag and the name of the type, or
! just past the closing curly brace of the @emph{definition}.  The
! former syntax is preferred.
  
  @xref{Attribute Syntax}, for details of the exact syntax for using
  attributes.
*************** declaration, the above program would abo
*** 3652,3657 ****
--- 3659,3671 ----
  @option{-fstrict-aliasing}, which is on by default at @option{-O2} or
  above in recent GCC versions.
  
+ @item visibility
+ 
+ In C++, attribute visibility (@pxref{Function Attributes}) can also be
+ applied to class, struct, union and enum types.  Unlike other type
+ attributes, the attribute must appear between the initial keyword and
+ the name of the type; it cannot appear after the body of the type.
+ 
  @subsection ARM Type Attributes
  
  On those ARM targets that support @code{dllimport} (such as Symbian
Index: doc/invoke.texi
===================================================================
*** doc/invoke.texi	(revision 114895)
--- doc/invoke.texi	(working copy)
*************** when used within the DSO@.  Enabling thi
*** 1619,1634 ****
  on load and link times of a DSO as it massively reduces the size of the
  dynamic export table when the library makes heavy use of templates.
  
- The behavior of this switch is not quite the same as marking the
- methods as hidden directly.  Normally if there is a class with default
- visibility which has a hidden method, the effect of this is that the
- method must be defined in only one shared object.  This switch does
- not have this restriction.
- 
  You may mark a method as having a visibility explicitly to negate the
  effect of the switch for that method.  For example, if you do want to
! compare pointers to a particular inline method, you might mark it as
! having default visibility.
  
  @item -fno-weak
  @opindex fno-weak
--- 1619,1628 ----
  on load and link times of a DSO as it massively reduces the size of the
  dynamic export table when the library makes heavy use of templates.
  
  You may mark a method as having a visibility explicitly to negate the
  effect of the switch for that method.  For example, if you do want to
! compare pointers to a particular inline method, or the method has
! local static data, you might mark it as having default visibility.
  
  @item -fno-weak
  @opindex fno-weak
*************** expecting to be compiled with visibility
*** 13506,13511 ****
--- 13500,13519 ----
  may need to explicitly say @samp{#pragma GCC visibility push(default)}
  before including any such headers.
  
+ @samp{extern} declarations are not affected by @samp{-fvisibility}, so
+ a lot of code can be recompiled with @samp{-fvisibility=hidden} with
+ no modifications.  However, this means that calls to @samp{extern}
+ functions with no explicit visibility will use the PLT, so it is more
+ effective to use @samp{__attribute ((visibility))} and/or
+ @samp{#pragma GCC visibility} to tell the compiler which @samp{extern}
+ declarations should be treated as hidden.
+ 
+ Note that @samp{-fvisibility} does affect C++ vague linkage
+ entities. This means that, for instance, an exception class that will
+ be thrown between DSOs must be explicitly marked with default
+ visibility so that the @samp{type_info} nodes will be unified between
+ the DSOs.
+ 
  An overview of these techniques, their benefits and how to use them
  is at @w{@uref{http://gcc.gnu.org/wiki/Visibility}}.
  
Index: flags.h
===================================================================
*** flags.h	(revision 114895)
--- flags.h	(working copy)
*************** extern enum debug_info_level debug_info_
*** 58,72 ****
     debugging information.  */
  extern bool use_gnu_debug_info_extensions;
  
! /* Enumerate visibility settings.  */
  #ifndef SYMBOL_VISIBILITY_DEFINED
  #define SYMBOL_VISIBILITY_DEFINED
  enum symbol_visibility
  {
    VISIBILITY_DEFAULT,
!   VISIBILITY_INTERNAL,
    VISIBILITY_HIDDEN,
!   VISIBILITY_PROTECTED
  };
  #endif
  
--- 58,73 ----
     debugging information.  */
  extern bool use_gnu_debug_info_extensions;
  
! /* Enumerate visibility settings.  This is deliberately ordered from most
!    to least visibility.  */
  #ifndef SYMBOL_VISIBILITY_DEFINED
  #define SYMBOL_VISIBILITY_DEFINED
  enum symbol_visibility
  {
    VISIBILITY_DEFAULT,
!   VISIBILITY_PROTECTED,
    VISIBILITY_HIDDEN,
!   VISIBILITY_INTERNAL
  };
  #endif
  
Index: tree.c
===================================================================
*** tree.c	(revision 114895)
--- tree.c	(working copy)
*************** build_decl_stat (enum tree_code code, tr
*** 3099,3112 ****
    else if (code == FUNCTION_DECL)
      DECL_MODE (t) = FUNCTION_MODE;
  
-   if (CODE_CONTAINS_STRUCT (code, TS_DECL_WITH_VIS))
-     {
-       /* Set default visibility to whatever the user supplied with
- 	 visibility_specified depending on #pragma GCC visibility.  */
-       DECL_VISIBILITY (t) = default_visibility;
-       DECL_VISIBILITY_SPECIFIED (t) = visibility_options.inpragma;
-     }
- 
    return t;
  }
  
--- 3099,3104 ----
Index: tree.h
===================================================================
*** tree.h	(revision 114895)
--- tree.h	(working copy)
*************** extern void omp_clause_range_check_faile
*** 1062,1068 ****
  
  #define TREE_OVERFLOW(NODE) (CST_CHECK (NODE)->common.public_flag)
  
! /* In a VAR_DECL or FUNCTION_DECL,
     nonzero means name is to be accessible from outside this module.
     In an IDENTIFIER_NODE, nonzero means an external declaration
     accessible from outside this module was previously seen
--- 1062,1068 ----
  
  #define TREE_OVERFLOW(NODE) (CST_CHECK (NODE)->common.public_flag)
  
! /* In a VAR_DECL, FUNCTION_DECL, NAMESPACE_DECL or TYPE_DECL,
     nonzero means name is to be accessible from outside this module.
     In an IDENTIFIER_NODE, nonzero means an external declaration
     accessible from outside this module was previously seen
*************** struct tree_binfo GTY (())
*** 2259,2267 ****
  enum symbol_visibility
  {
    VISIBILITY_DEFAULT,
!   VISIBILITY_INTERNAL,
    VISIBILITY_HIDDEN,
!   VISIBILITY_PROTECTED
  };
  #endif
  
--- 2259,2267 ----
  enum symbol_visibility
  {
    VISIBILITY_DEFAULT,
!   VISIBILITY_PROTECTED,
    VISIBILITY_HIDDEN,
!   VISIBILITY_INTERNAL
  };
  #endif
  
Index: testsuite/g++.old-deja/g++.pt/enum5.C
===================================================================
*** testsuite/g++.old-deja/g++.pt/enum5.C	(revision 114895)
--- testsuite/g++.old-deja/g++.pt/enum5.C	(working copy)
***************
*** 1,4 ****
  // { dg-do assemble  }
  
! template <> // { dg-error "" } template declaration of enum
! enum E {e};
--- 1,4 ----
  // { dg-do assemble  }
  
! template <>
! enum E {e}; // { dg-error "" } template declaration of enum
Index: testsuite/g++.dg/ext/attrib9.C
===================================================================
*** testsuite/g++.dg/ext/attrib9.C	(revision 114913)
--- testsuite/g++.dg/ext/attrib9.C	(working copy)
***************
*** 1,5 ****
! class __attribute__((unused)) C;	//  { dg-warning "type attributes" }
! struct __attribute__((unused)) S;	//  { dg-warning "type attributes" }
! union __attribute__((unused)) U;	//  { dg-warning "type attributes" }
  enum e {};
! enum __attribute__((unused)) e;		//  { dg-warning "type attributes" }
--- 1,10 ----
! class __attribute__((unused)) C;
! struct __attribute__((unused)) S;
! union __attribute__((unused)) U;
  enum e {};
! enum __attribute__((unused)) e;
! 
! struct __attribute((unused)) B *p;	//  { dg-warning "attributes" }
! 
! template <class T> struct A { };
! struct __attribute((unused)) A<int>;	//  { dg-warning "attributes" }
Index: testsuite/g++.dg/ext/attrib14.C
===================================================================
*** testsuite/g++.dg/ext/attrib14.C	(revision 114913)
--- testsuite/g++.dg/ext/attrib14.C	(working copy)
***************
*** 3,13 ****
  // parsing of the class, causing some variants to have it and some not.
  
  struct __attribute__((bogus)) A
! {
      virtual ~A();
      void foo(const A&);
      void bar(const A&);
! };				// { dg-warning "ignored" "" }
  
  void A::foo(const A&)   {}
  void A::bar(const A& a) { foo(a); }
--- 3,13 ----
  // parsing of the class, causing some variants to have it and some not.
  
  struct __attribute__((bogus)) A
! {				// { dg-warning "ignored" "" }
      virtual ~A();
      void foo(const A&);
      void bar(const A&);
! };
  
  void A::foo(const A&)   {}
  void A::bar(const A& a) { foo(a); }
Index: testsuite/g++.dg/ext/visibility/anon1.C
===================================================================
*** testsuite/g++.dg/ext/visibility/anon1.C	(revision 114913)
--- testsuite/g++.dg/ext/visibility/anon1.C	(working copy)
***************
*** 1,8 ****
  // PR c++/21581
! // Test for anonymous namespace default hidden visibility
  
! // { dg-require-visibility "" }
! // { dg-final-NOT { scan-hidden "_ZN.*1fEv" } }
  
  namespace
  {
--- 1,8 ----
  // PR c++/21581
! // Test for anonymous namespace internal linkage
  
! // { dg-do compile }
! // { dg-final { scan-assembler-not "globl.*_ZN.*1fEv" } }
  
  namespace
  {
Index: testsuite/g++.dg/ext/visibility/anon2.C
===================================================================
*** testsuite/g++.dg/ext/visibility/anon2.C	(revision 0)
--- testsuite/g++.dg/ext/visibility/anon2.C	(revision 0)
***************
*** 0 ****
--- 1,11 ----
+ // Test for propagation of anonymous namespace internal linkage
+ 
+ // { dg-do compile }
+ // { dg-final { scan-assembler-not "globl.*_Z1fv" } }
+ 
+ namespace
+ {
+   struct A { };
+ }
+ 
+ A f () { }
Index: testsuite/g++.dg/ext/visibility/redecl1.C
===================================================================
*** testsuite/g++.dg/ext/visibility/redecl1.C	(revision 0)
--- testsuite/g++.dg/ext/visibility/redecl1.C	(revision 0)
***************
*** 0 ****
--- 1,7 ----
+ // Test that we complain about redeclaration with different visibility
+ 
+ struct __attribute((visibility("hidden"))) B;
+ struct __attribute((visibility("default"))) B;	// { dg-warning "visibility" }
+ 
+ __attribute ((visibility ("hidden"))) void f();	// { dg-warning "previous" }
+ __attribute ((visibility ("default"))) void f(); // { dg-warning "visibility" }
Index: testsuite/g++.dg/ext/visibility/class1.C
===================================================================
*** testsuite/g++.dg/ext/visibility/class1.C	(revision 0)
--- testsuite/g++.dg/ext/visibility/class1.C	(revision 0)
***************
*** 0 ****
--- 1,20 ----
+ // PR c++/26905
+ // Init should not be hidden, so calling it should use the PLT.
+ 
+ // { dg-require-visibility "" }
+ // { dg-options "-fpic" }
+ // { dg-do compile { target i?86-*-* x86_64-*-* } }
+ // { dg-final { scan-assembler "InitEv@PLT" } }
+ 
+ #pragma GCC visibility push(hidden)
+ struct __attribute__ ((visibility ("default"))) nsINIParser
+ {
+     static void Init();
+ };
+ 
+ __attribute__ ((visibility ("default")))
+ void
+ CheckCompatibility(void)
+ {
+   nsINIParser::Init();
+ }
Index: testsuite/g++.dg/ext/visibility/fvisibility-override2.C
===================================================================
*** testsuite/g++.dg/ext/visibility/fvisibility-override2.C	(revision 114913)
--- testsuite/g++.dg/ext/visibility/fvisibility-override2.C	(working copy)
***************
*** 6,12 ****
  
  class Foo
  {
!   __attribute__ ((visibility ("default"))) void method();
  };
  
  void Foo::method() { }
--- 6,12 ----
  
  class Foo
  {
!   __attribute__ ((visibility ("internal"))) void method();
  };
  
  void Foo::method() { }
Index: testsuite/g++.dg/ext/visibility/template1.C
===================================================================
*** testsuite/g++.dg/ext/visibility/template1.C	(revision 0)
--- testsuite/g++.dg/ext/visibility/template1.C	(revision 0)
***************
*** 0 ****
--- 1,35 ----
+ // PR c++/19134
+ // -fvisibility-inlines-hidden doesn't apply to non-inline specializations
+ 
+ // { dg-require-visibility "" }
+ // { dg-options "-fvisibility-inlines-hidden" }
+ // { dg-final { scan-not-hidden "_ZN1AIiE3fooEv" } }
+ // { dg-final { scan-not-hidden "_ZN1AIiE3barEv" } }
+ // { dg-final { scan-hidden "_ZN1AIlE3fooEv" } }
+ // { dg-final { scan-hidden "_ZN1AIlE3barEv" } }
+ // { dg-final { scan-hidden "_ZN1AIcE3barEv" } }
+ 
+ template<class T>
+ struct A {
+   void foo() {};
+   __attribute ((visibility ("hidden"))) void bar();
+ };
+ 
+ // This has default visibility.
+ template<> void A<int>::foo() {}
+ 
+ // This has hidden visibility because of -fvisibility-inlines-hidden.
+ template<> inline void A<long>::foo() {}
+ // Force the inline out.
+ void f () { A<long> a; a.foo(); }
+ 
+ // This has default visibility.
+ template<> __attribute ((visibility ("default"))) void A<int>::bar() {}
+ 
+ // This inherits hidden visibility from its template.
+ template<> void A<long>::bar() { }
+ 
+ // This also has hidden visibility; #pragma vis doesn't affect class members.
+ #pragma GCC visibility push(default)
+ template<> void A<char>::bar() { }
+ #pragma GCC visibility pop
Index: testsuite/g++.dg/ext/visibility/template2.C
===================================================================
*** testsuite/g++.dg/ext/visibility/template2.C	(revision 0)
--- testsuite/g++.dg/ext/visibility/template2.C	(revision 0)
***************
*** 0 ****
--- 1,35 ----
+ // PR c++/27000
+ // Implicitly instantiated templates should not be affected by
+ // #pragma visibility.
+ 
+ /* { dg-do compile } */
+ /* { dg-require-visibility "" } */
+ /* { dg-final { scan-not-hidden "_ZN1SIiED1Ev" } } */
+ /* { dg-final { scan-not-hidden "_ZN1SIiEC1ERKi" } } */
+ 
+ template <class T>
+ struct S
+ {
+   S (const T &);
+   ~S ();
+   T t;
+ };
+ 
+ template <class T>
+ S<T>::S (const T &x)
+ {
+   t = x;
+ }
+ 
+ template <class T>
+ S<T>::~S ()
+ {
+ }
+ 
+ #pragma GCC visibility push(hidden)
+ struct U
+ {
+   S<int> s;
+   U () : s (6) { }
+ } u;
+ #pragma GCC visibility pop
Index: testsuite/g++.dg/ext/visibility/template3.C
===================================================================
*** testsuite/g++.dg/ext/visibility/template3.C	(revision 0)
--- testsuite/g++.dg/ext/visibility/template3.C	(revision 0)
***************
*** 0 ****
--- 1,22 ----
+ // PR c++/17470
+ // Test that we can give visibility to explicit template instantiations
+ 
+ // { dg-require-visibility "" }
+ // { dg-final { scan-hidden "_ZN1AIlE1fEl" } }
+ // { dg-final { scan-hidden "_ZN1AIiE1fEi" } }
+ // { dg-final { scan-not-hidden "_ZN1AIcE1fEc" } }
+ // { dg-final { scan-hidden "_Z8identityIdET_S0_" } }
+ // { dg-final { scan-not-hidden "_Z8identityIiET_S0_" } }
+ 
+ template <class T> T identity(T t) { return t; }
+ template  __attribute__((visibility("hidden"))) double identity(double);
+ template int identity(int);
+ 
+ 
+ template <class T> struct A { void f (T); };
+ template <class T> void A<T>::f (T) { }
+ template struct __attribute ((visibility ("hidden"))) A<int>;
+ template<> struct  __attribute ((visibility ("hidden"))) A<long> { void f(long); };
+ // inherits hidden visibility from its class
+ void A<long>::f (long) { }
+ template struct A<char>;
Index: testsuite/g++.dg/ext/visibility/template4.C
===================================================================
*** testsuite/g++.dg/ext/visibility/template4.C	(revision 0)
--- testsuite/g++.dg/ext/visibility/template4.C	(revision 0)
***************
*** 0 ****
--- 1,39 ----
+ // Test for explicit visibility on template vs. #pragma vis at explicit
+ // instantiation/specialization point for plain function templates.
+ 
+ // { dg-require-visibility "" }
+ // { dg-final { scan-hidden "_Z3fooIdEvT_" } }
+ // { dg-final { scan-hidden "_Z3fooIlEvT_" } }
+ // { dg-final { scan-not-hidden "_Z3fooIfEVT_" } }
+ // { dg-final { scan-not-hidden "_Z3fooIcEVT_" } }
+ // { dg-final { scan-not-hidden "_Z3fooIsEVT_" } }
+ // { dg-final { scan-not-hidden "_Z3fooIiEVT_" } }
+ 
+ // { dg-final { scan-hidden "_Z3barIdEvT_" } }
+ // { dg-final { scan-hidden "_Z3barIlEvT_" } }
+ // { dg-final { scan-not-hidden "_Z3barIfEVT_" } }
+ // { dg-final { scan-not-hidden "_Z3barIcEVT_" } }
+ // { dg-final { scan-not-hidden "_Z3barIsEVT_" } }
+ // { dg-final { scan-not-hidden "_Z3barIiEVT_" } }
+ 
+ #pragma GCC visibility push(hidden)
+ template <class T> void bar(T) { }
+ #pragma GCC visibility pop
+ template void bar (long);
+ template<> void bar (double) { }
+ template __attribute ((visibility ("default"))) void bar (short);
+ template<> __attribute ((visibility ("default"))) void bar (float) { }
+ #pragma GCC visibility push(default)
+ template<> void bar(char) { }
+ template void bar(int);
+ #pragma GCC visibility pop
+ 
+ template <class T> __attribute ((visibility ("hidden"))) void foo(T) { }
+ template void foo (long);
+ template<> void foo (double) { }
+ template __attribute ((visibility ("default"))) void foo (short);
+ template<> __attribute ((visibility ("default"))) void foo (float) { }
+ #pragma GCC visibility push(default)
+ template<> void foo(char) { }
+ template void foo(int);
+ #pragma GCC visibility pop
Index: testsuite/g++.dg/ext/visibility/prop1.C
===================================================================
*** testsuite/g++.dg/ext/visibility/prop1.C	(revision 0)
--- testsuite/g++.dg/ext/visibility/prop1.C	(revision 0)
***************
*** 0 ****
--- 1,23 ----
+ // Test for propagation of visibility through template arguments
+ 
+ // { dg-do compile }
+ // { dg-require-visibility "" }
+ // { dg-final { scan-hidden "_Z1fIN1N1AEEvT_" } }
+ // { dg-final { scan-hidden "_Z1hIXadL_ZN1N1iEEEEvv" } }
+ 
+ namespace N __attribute ((__visibility__ ("hidden")))
+ {
+   struct A { };
+   int i;
+ }
+ 
+ template <class T> void f (T) { }
+ template <int *I> void h() { }
+ 
+ void g()
+ {
+   N::A a;
+   f(a);
+   h<&N::i>();
+ }
+ 
Index: testsuite/g++.dg/ext/visibility/assign1.C
===================================================================
*** testsuite/g++.dg/ext/visibility/assign1.C	(revision 114913)
--- testsuite/g++.dg/ext/visibility/assign1.C	(working copy)
*************** struct B {
*** 6,16 ****
    B& operator=(const B&);
  };
  
! struct D : public B {
    // The implicit assignment operator should be hidden.
! } __attribute__((visibility("hidden")));
  
! D d1, d2;
  
  void f() {
    d1 = d2;
--- 6,17 ----
    B& operator=(const B&);
  };
  
! struct __attribute__((visibility("hidden"))) D : public B {
    // The implicit assignment operator should be hidden.
! };
  
! __attribute__((visibility("hidden"))) D d1;
! __attribute__((visibility("hidden"))) D d2;
  
  void f() {
    d1 = d2;
Index: testsuite/g++.dg/ext/visibility/typeinfo1.C
===================================================================
*** testsuite/g++.dg/ext/visibility/typeinfo1.C	(revision 0)
--- testsuite/g++.dg/ext/visibility/typeinfo1.C	(revision 0)
***************
*** 0 ****
--- 1,19 ----
+ // PR c++/26984
+ // lazily generated typeinfos should not be affected by #pragma vis, but
+ // they should be affected by the visibility of the type they describe.
+ 
+ // { dg-require-visibility "" }
+ // { dg-options "-fvisibility-inlines-hidden" }
+ // { dg-final { scan-not-hidden "_ZTIPPi" } }
+ // { dg-final { scan-not-hidden "_ZTSPPi" } }
+ // { dg-final { scan-hidden "_ZTIP1A" } }
+ // { dg-final { scan-hidden "_ZTSP1A" } }
+ 
+ #include <typeinfo>
+ 
+ #pragma GCC visibility push(hidden)
+ const std::type_info* t = &(typeid(int **));
+ struct A { };
+ #pragma GCC visibility pop
+ 
+ const std::type_info* t2 = &(typeid(A *));
Index: testsuite/g++.dg/ext/visibility/virtual.C
===================================================================
*** testsuite/g++.dg/ext/visibility/virtual.C	(revision 114913)
--- testsuite/g++.dg/ext/visibility/virtual.C	(working copy)
***************
*** 1,9 ****
! /* Test that setting visibility for class affects virtual table. */
  /* { dg-do compile } */
  /* { dg-require-visibility "" } */
  /* { dg-final { scan-hidden "ZTV3Foo" } } */
  
! class __attribute__ ((visibility ("hidden"))) Foo
  {
    virtual void method();
  };
--- 1,15 ----
! /* Test that setting visibility for class affects virtual table, VTT and
!    type_info name and node. */
  /* { dg-do compile } */
  /* { dg-require-visibility "" } */
  /* { dg-final { scan-hidden "ZTV3Foo" } } */
+ /* { dg-final { scan-hidden "ZTT3Foo" } } */
+ /* { dg-final { scan-hidden "ZTS3Foo" } } */
+ /* { dg-final { scan-hidden "ZTI3Foo" } } */
  
! struct A { };
! 
! class __attribute__ ((visibility ("hidden"))) Foo: virtual public A
  {
    virtual void method();
  };
Index: testsuite/g++.dg/ext/visibility/warn1.C
===================================================================
*** testsuite/g++.dg/ext/visibility/warn1.C	(revision 0)
--- testsuite/g++.dg/ext/visibility/warn1.C	(revision 0)
***************
*** 0 ****
--- 1,13 ----
+ // Warn when a declaration is specified with greater visibility than that
+ // of its type.
+ 
+ // { dg-do compile }
+ // { dg-require-visibility "" }
+ // { dg-final { scan-hidden "_Z1fv" } }
+ 
+ namespace N __attribute ((__visibility__ ("hidden")))
+ {
+   struct A { };
+ }
+ 
+ N::A f() { } // { dg-warning "visibility" "" }
Index: testsuite/g++.dg/ext/visibility/warn2.C
===================================================================
*** testsuite/g++.dg/ext/visibility/warn2.C	(revision 0)
--- testsuite/g++.dg/ext/visibility/warn2.C	(revision 0)
***************
*** 0 ****
--- 1,19 ----
+ // Complain when a class is specified with greater visibility than one of
+ // its members' types or bases, and when a declaration has greater
+ // visibility than its type.
+ 
+ // { dg-require-visibility "" }
+ 
+ namespace N __attribute ((__visibility__ ("hidden")))
+ {
+   struct A { };
+ }
+ 
+ struct B
+ {				// { dg-warning "visibility" }
+   N::A a;
+ };
+ 
+ B f () { }			// { dg-warning "visibility" }
+ 
+ struct C: public N::A { };	// { dg-warning "visibility" }
Index: testsuite/g++.dg/ext/visibility/warn3.C
===================================================================
*** testsuite/g++.dg/ext/visibility/warn3.C	(revision 0)
--- testsuite/g++.dg/ext/visibility/warn3.C	(revision 0)
***************
*** 0 ****
--- 1,11 ----
+ // Warn when a class member is specified to have greater visibility than
+ // its class.
+ 
+ // { dg-require-visibility "" }
+ 
+ struct __attribute ((visibility ("hidden"))) A
+ {
+   __attribute ((visibility ("default"))) void f (); // { dg-warning "visibility" }
+ };
+ 
+ void A::f() { }
Index: testsuite/g++.dg/ext/visibility/warn4.C
===================================================================
*** testsuite/g++.dg/ext/visibility/warn4.C	(revision 0)
--- testsuite/g++.dg/ext/visibility/warn4.C	(revision 0)
***************
*** 0 ****
--- 1,10 ----
+ // Error if we try to give an instantiation visibility after it's already
+ // been instantiated.
+ 
+ // { dg-require-visibility "" }
+ 
+ template <class T> struct A { void f (T); };
+ template <class T> void A<T>::f (T) { }
+ 
+ A<double> ad;
+ template struct __attribute ((visibility ("hidden"))) A<double>; // { dg-error "already defined" }
Index: cp/class.c
===================================================================
*** cp/class.c	(revision 114895)
--- cp/class.c	(working copy)
*************** finish_struct_1 (tree t)
*** 5084,5089 ****
--- 5084,5092 ----
        DECL_SORTED_FIELDS (TYPE_MAIN_DECL (t)) = field_vec;
      }
  
+   /* Complain if one of the field types requires lower visibility.  */
+   constrain_class_visibility (t);
+ 
    /* Make the rtl for any new vtables we have created, and unmark
       the base types we marked.  */
    finish_vtbls (t);
Index: cp/decl.c
===================================================================
*** cp/decl.c	(revision 114895)
--- cp/decl.c	(working copy)
*************** duplicate_decls (tree newdecl, tree oldd
*** 1857,1862 ****
--- 1857,1867 ----
  
  	  SET_DECL_TEMPLATE_SPECIALIZATION (olddecl);
  
+ 	  /* Don't propagate visibility from the template to the
+ 	     specialization here.  We'll do that in determine_visibility if
+ 	     appropriate.  */
+ 	  DECL_VISIBILITY_SPECIFIED (olddecl) = 0;
+ 
  	  /* [temp.expl.spec/14] We don't inline explicit specialization
  	     just because the primary template says so.  */
  	}
*************** cxx_init_decl_processing (void)
*** 3119,3124 ****
--- 3124,3130 ----
    gcc_assert (global_namespace == NULL_TREE);
    global_namespace = build_lang_decl (NAMESPACE_DECL, global_scope_name,
  				      void_type_node);
+   TREE_PUBLIC (global_namespace) = 1;
    begin_scope (sk_namespace, global_namespace);
  
    current_lang_name = NULL_TREE;
*************** cp_finish_decl (tree decl, tree init, bo
*** 5230,5235 ****
--- 5236,5244 ----
        else
  	abstract_virtuals_error (decl, type);
  
+       /* This needs to happen after the linkage is set. */
+       determine_visibility (decl);
+ 
        if (TREE_CODE (decl) == FUNCTION_DECL
  	  || TREE_TYPE (decl) == error_mark_node)
  	/* No initialization required.  */
*************** cp_finish_decl (tree decl, tree init, bo
*** 5253,5262 ****
  		initialize_local_var (decl, init);
  	    }
  
- 	  /* The variable is being defined, so determine its visibility.
- 	     This needs to happen after the linkage is set. */
- 	  determine_visibility (decl);
- 
  	  /* If a variable is defined, and then a subsequent
  	     definition with external linkage is encountered, we will
  	     get here twice for the same variable.  We want to avoid
--- 5262,5267 ----
Index: cp/rtti.c
===================================================================
*** cp/rtti.c	(revision 114895)
--- cp/rtti.c	(working copy)
*************** create_pseudo_type_info (int tk, const c
*** 1156,1161 ****
--- 1156,1165 ----
    ti->name = get_identifier (real_name);
    ti->vtable = NULL_TREE;
  
+   /* Pretend this is public so determine_visibility doesn't give vtables
+      internal linkage.  */
+   TREE_PUBLIC (TYPE_MAIN_DECL (ti->type)) = 1;
+ 
    va_end (ap);
  }
  
Index: cp/tree.c
===================================================================
*** cp/tree.c	(revision 114895)
--- cp/tree.c	(working copy)
*************** decl_namespace_context (tree decl)
*** 1385,1390 ****
--- 1385,1414 ----
      }
  }
  
+ /* Returns true if decl is within an anonymous namespace, however deeply
+    nested, or false otherwise.  */
+ 
+ bool
+ decl_anon_ns_mem_p (tree decl)
+ {
+   while (1)
+     {
+       if (decl == NULL_TREE)
+ 	return false;
+       if (TREE_CODE (decl) == NAMESPACE_DECL
+ 	  && DECL_NAME (decl) == NULL_TREE)
+ 	return true;
+       /* Classes and namespaces inside anonymous namespaces have
+          TREE_PUBLIC == 0, so we can shortcut the search.  */
+       else if (TYPE_P (decl))
+ 	return (TREE_PUBLIC (TYPE_NAME (decl)) == 0);
+       else if (TREE_CODE (decl) == NAMESPACE_DECL)
+ 	return (TREE_PUBLIC (decl) == 0);
+       else
+ 	decl = DECL_CONTEXT (decl);
+     }
+ }
+ 
  /* Return truthvalue of whether T1 is the same tree structure as T2.
     Return 1 if they are the same. Return 0 if they are different.  */
  
*************** decl_linkage (tree decl)
*** 2181,2187 ****
       template instantiations have internal linkage (in the object
       file), but the symbols should still be treated as having external
       linkage from the point of view of the language.  */
!   if (TREE_CODE (decl) != TYPE_DECL && DECL_LANG_SPECIFIC (decl) && DECL_COMDAT (decl))
      return lk_external;
  
    /* Things in local scope do not have linkage, if they don't have
--- 2205,2212 ----
       template instantiations have internal linkage (in the object
       file), but the symbols should still be treated as having external
       linkage from the point of view of the language.  */
!   if (TREE_CODE (decl) != TYPE_DECL && DECL_LANG_SPECIFIC (decl)
!       && DECL_COMDAT (decl))
      return lk_external;
  
    /* Things in local scope do not have linkage, if they don't have
Index: cp/cp-tree.h
===================================================================
*** cp/cp-tree.h	(revision 114895)
--- cp/cp-tree.h	(working copy)
*************** extern tree coerce_new_type			(tree);
*** 3965,3970 ****
--- 3965,3972 ----
  extern tree coerce_delete_type			(tree);
  extern void comdat_linkage			(tree);
  extern void determine_visibility		(tree);
+ extern void constrain_class_visibility		(tree);
+ extern void update_member_visibility		(tree);
  extern void import_export_decl			(tree);
  extern tree build_cleanup			(tree);
  extern tree build_offset_ref_call_from_tree	(tree, tree);
*************** extern tree finish_fname			(tree);
*** 4271,4277 ****
  extern void finish_translation_unit		(void);
  extern tree finish_template_type_parm		(tree, tree);
  extern tree finish_template_template_parm       (tree, tree);
! extern tree begin_class_definition		(tree);
  extern void finish_template_decl		(tree);
  extern tree finish_template_type		(tree, tree, int);
  extern tree finish_base_specifier		(tree, tree, bool);
--- 4273,4279 ----
  extern void finish_translation_unit		(void);
  extern tree finish_template_type_parm		(tree, tree);
  extern tree finish_template_template_parm       (tree, tree);
! extern tree begin_class_definition		(tree, tree);
  extern void finish_template_decl		(tree);
  extern tree finish_template_type		(tree, tree, int);
  extern tree finish_base_specifier		(tree, tree, bool);
*************** extern tree array_type_nelts_top		(tree)
*** 4353,4358 ****
--- 4355,4361 ----
  extern tree break_out_target_exprs		(tree);
  extern tree get_type_decl			(tree);
  extern tree decl_namespace_context		(tree);
+ extern bool decl_anon_ns_mem_p			(tree);
  extern tree lvalue_type				(tree);
  extern tree error_type				(tree);
  extern int varargs_function_p			(tree);
Index: cp/pt.c
===================================================================
*** cp/pt.c	(revision 114895)
--- cp/pt.c	(working copy)
*************** check_explicit_specialization (tree decl
*** 2140,2152 ****
  	     template it specializes.  */
  	  TREE_PRIVATE (decl) = TREE_PRIVATE (gen_tmpl);
  	  TREE_PROTECTED (decl) = TREE_PROTECTED (gen_tmpl);
! 	  /* The specialization has the same visibility as the
! 	     template it specializes.  */
! 	  if (DECL_VISIBILITY_SPECIFIED (gen_tmpl))
! 	    {
! 	      DECL_VISIBILITY_SPECIFIED (decl) = 1;
! 	      DECL_VISIBILITY (decl) = DECL_VISIBILITY (gen_tmpl);
! 	    }
  	  /* If DECL is a friend declaration, declared using an
  	     unqualified name, the namespace associated with DECL may
  	     have been set incorrectly.  For example, in:
--- 2140,2146 ----
  	     template it specializes.  */
  	  TREE_PRIVATE (decl) = TREE_PRIVATE (gen_tmpl);
  	  TREE_PROTECTED (decl) = TREE_PROTECTED (gen_tmpl);
! 
  	  /* If DECL is a friend declaration, declared using an
  	     unqualified name, the namespace associated with DECL may
  	     have been set incorrectly.  For example, in:
*************** convert_nontype_argument (tree type, tre
*** 3592,3600 ****
  
        if (!constant_address_p)
  	{
! 	    error ("%qE is not a valid template argument for type %qT "
! 		  "because it is not a constant pointer", expr, type);
! 	    return NULL_TREE;
  	}
      }
    /* [temp.arg.nontype]/5, bullet 3
--- 3586,3594 ----
  
        if (!constant_address_p)
  	{
! 	  error ("%qE is not a valid template argument for type %qT "
! 		 "because it is not a constant pointer", expr, type);
! 	  return NULL_TREE;
  	}
      }
    /* [temp.arg.nontype]/5, bullet 3
*************** lookup_template_class (tree d1,
*** 4785,4790 ****
--- 4779,4788 ----
  	   code that generates debugging information will crash.  */
  	DECL_IGNORED_P (TYPE_STUB_DECL (t)) = 1;
  
+       /* Possibly limit visibility based on template args.  */
+       TREE_PUBLIC (type_decl) = 1;
+       determine_visibility (type_decl);
+ 
        POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, t);
      }
    timevar_pop (TV_NAME_LOOKUP);
*************** tsubst_decl (tree t, tree args, tsubst_f
*** 6591,6596 ****
--- 6589,6599 ----
  	  SET_DECL_FRIEND_CONTEXT (r,
  				   tsubst (DECL_FRIEND_CONTEXT (t),
  					    args, complain, in_decl));
+ 
+ 	/* Possibly limit visibility based on template args.  */
+ 	DECL_VISIBILITY (r) = VISIBILITY_DEFAULT;
+ 	DECL_VISIBILITY_SPECIFIED (r) = 0;
+ 	determine_visibility (r);
        }
        break;
  
*************** tsubst_decl (tree t, tree args, tsubst_f
*** 6763,6768 ****
--- 6766,6778 ----
  	if (CODE_CONTAINS_STRUCT (TREE_CODE (t), TS_DECL_WRTL))
  	  SET_DECL_RTL (r, NULL_RTX);
  	DECL_SIZE (r) = DECL_SIZE_UNIT (r) = 0;
+ 	if (TREE_CODE (r) == VAR_DECL)
+ 	  {
+ 	    /* Possibly limit visibility based on template args.  */
+ 	    DECL_VISIBILITY (r) = VISIBILITY_DEFAULT;
+ 	    DECL_VISIBILITY_SPECIFIED (r) = 0;
+ 	    determine_visibility (r);
+ 	  }
  
  	if (!local_p)
  	  {
Index: cp/semantics.c
===================================================================
*** cp/semantics.c	(revision 114895)
--- cp/semantics.c	(working copy)
*************** check_template_template_default_arg (tre
*** 2161,2167 ****
  /* Begin a class definition, as indicated by T.  */
  
  tree
! begin_class_definition (tree t)
  {
    if (t == error_mark_node)
      return error_mark_node;
--- 2161,2167 ----
  /* Begin a class definition, as indicated by T.  */
  
  tree
! begin_class_definition (tree t, tree attributes)
  {
    if (t == error_mark_node)
      return error_mark_node;
*************** begin_class_definition (tree t)
*** 2200,2205 ****
--- 2200,2208 ----
    maybe_process_partial_specialization (t);
    pushclass (t);
    TYPE_BEING_DEFINED (t) = 1;
+ 
+   cplus_decl_attributes (&t, attributes, (int) ATTR_FLAG_TYPE_IN_PLACE);
+ 
    if (flag_pack_struct)
      {
        tree v;
Index: cp/name-lookup.c
===================================================================
*** cp/name-lookup.c	(revision 114895)
--- cp/name-lookup.c	(working copy)
*************** push_namespace_with_attribs (tree name, 
*** 3033,3039 ****
        /* Make a new namespace, binding the name to it.  */
        d = build_lang_decl (NAMESPACE_DECL, name, void_type_node);
        DECL_CONTEXT (d) = FROB_CONTEXT (current_namespace);
!       TREE_PUBLIC (d) = 1;
        pushdecl (d);
        if (anon)
  	{
--- 3033,3044 ----
        /* Make a new namespace, binding the name to it.  */
        d = build_lang_decl (NAMESPACE_DECL, name, void_type_node);
        DECL_CONTEXT (d) = FROB_CONTEXT (current_namespace);
!       /* The name of this namespace is not visible to other translation
! 	 units if it is an anonymous namespace or member thereof.  */
!       if (anon || decl_anon_ns_mem_p (current_namespace))
! 	TREE_PUBLIC (d) = 0;
!       else
! 	TREE_PUBLIC (d) = 1;
        pushdecl (d);
        if (anon)
  	{
*************** push_namespace_with_attribs (tree name, 
*** 3080,3094 ****
        push_visibility (TREE_STRING_POINTER (x));
        goto found;
      }
- #if 0
-   if (anon)
-     {
-       /* Anonymous namespaces default to hidden visibility.  This might
- 	 change once we implement export.  */
-       current_binding_level->has_visibility = 1;
-       push_visibility ("hidden");
-     }
- #endif
   found:
  #endif
  
--- 3085,3090 ----
*************** pushtag (tree name, tree type, tag_scope
*** 4904,4909 ****
--- 4900,4909 ----
    gcc_assert (TREE_CODE (decl) == TYPE_DECL);
    TYPE_STUB_DECL (type) = decl;
  
+   /* Set type visibility now if this is a forward declaration.  */
+   TREE_PUBLIC (decl) = 1;
+   determine_visibility (decl);
+ 
    POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, type);
  }
  
Index: cp/decl2.c
===================================================================
*** cp/decl2.c	(revision 114895)
--- cp/decl2.c	(working copy)
*************** maybe_emit_vtables (tree ctype)
*** 1532,1537 ****
--- 1532,1641 ----
    return true;
  }
  
+ /* A special return value from type_visibility meaning internal
+    linkage.  */
+ 
+ enum { VISIBILITY_STATIC = VISIBILITY_INTERNAL+1 };
+ 
+ /* walk_tree helper function for type_visibility.  */
+ 
+ static tree
+ min_vis_r (tree *tp, int *walk_subtrees, void *data)
+ {
+   int *vis_p = (int *)data;
+   if (! TYPE_P (*tp))
+     {
+       *walk_subtrees = 0;
+     }
+   else if (CLASS_TYPE_P (*tp))
+     {
+       if (!TREE_PUBLIC (TYPE_MAIN_DECL (*tp)))
+ 	{
+ 	  *vis_p = VISIBILITY_STATIC;
+ 	  return *tp;
+ 	}
+       else if (CLASSTYPE_VISIBILITY (*tp) > *vis_p)
+ 	*vis_p = CLASSTYPE_VISIBILITY (*tp);
+     }
+   return NULL;
+ }
+ 
+ /* Returns the visibility of TYPE, which is the minimum visibility of its
+    component types.  */
+ 
+ static int
+ type_visibility (tree type)
+ {
+   int vis = VISIBILITY_DEFAULT;
+   walk_tree_without_duplicates (&type, min_vis_r, &vis);
+   return vis;
+ }
+ 
+ /* Limit the visibility of DECL to VISIBILITY.  SPECIFIED is true if the
+    constraint comes from an attribute or pragma; REASON is the source of
+    the constraint.  */
+ 
+ static bool
+ constrain_visibility (tree decl, int visibility, bool specified,
+ 		      const char *reason)
+ {
+   if (visibility == VISIBILITY_STATIC)
+     {
+       TREE_PUBLIC (decl) = 0;
+       DECL_INTERFACE_KNOWN (decl) = 1;
+       if (DECL_LANG_SPECIFIC (decl))
+ 	DECL_NOT_REALLY_EXTERN (decl) = 1;
+     }
+   else if (visibility > DECL_VISIBILITY (decl))
+     {
+       if (lookup_attribute ("visibility", DECL_ATTRIBUTES (decl)))
+ 	warning (OPT_Wattributes, "%q+D: visibility attribute requests "
+ 		 "greater visibility than its %s allows", decl, reason);
+       DECL_VISIBILITY (decl) = visibility;
+       if (!DECL_VISIBILITY_SPECIFIED (decl))
+ 	DECL_VISIBILITY_SPECIFIED (decl) = specified;
+       return true;
+     }
+   return false;
+ }
+ 
+ /* Constrain the visibility of DECL based on the visbility of its template
+    arguments.  */
+ 
+ static void
+ constrain_visibility_for_template (tree decl, tree targs)
+ {
+   /* If this is a template instantiation, check the innermost
+      template args for visibility constraints.  The outer template
+      args are covered by the class check.  */
+   tree args = INNERMOST_TEMPLATE_ARGS (targs);
+   int i;
+   for (i = TREE_VEC_LENGTH (args); i > 0; --i)
+     {
+       int vis = 0;
+ 
+       tree arg = TREE_VEC_ELT (args, i-1);
+       if (TYPE_P (arg))
+ 	vis = type_visibility (arg);
+       else if (TREE_TYPE (arg) && POINTER_TYPE_P (TREE_TYPE (arg)))
+ 	{
+ 	  STRIP_NOPS (arg);
+ 	  if (TREE_CODE (arg) == ADDR_EXPR)
+ 	    arg = TREE_OPERAND (arg, 0);
+ 	  if (TREE_CODE (arg) == VAR_DECL
+ 	      || TREE_CODE (arg) == FUNCTION_DECL)
+ 	    {
+ 	      if (! TREE_PUBLIC (arg))
+ 		vis = VISIBILITY_STATIC;
+ 	      else
+ 		vis = DECL_VISIBILITY (arg);
+ 	    }
+ 	}
+       if (vis)
+ 	constrain_visibility (decl, vis, false, "template parameter");
+     }
+ }
+ 
  /* Like c_determine_visibility, but with additional C++-specific
     behavior.
  
*************** maybe_emit_vtables (tree ctype)
*** 1543,1554 ****
  
     Note that because namespaces have multiple independent definitions,
     namespace visibility is handled elsewhere using the #pragma visibility
!    machinery rather than by decorating the namespace declaration.  */
  
  void
  determine_visibility (tree decl)
  {
!   tree class_type;
  
    /* Only relevant for names with external linkage.  */
    if (!TREE_PUBLIC (decl))
--- 1647,1664 ----
  
     Note that because namespaces have multiple independent definitions,
     namespace visibility is handled elsewhere using the #pragma visibility
!    machinery rather than by decorating the namespace declaration.
! 
!    The goal is for constraints from the type to give a diagnostic, and
!    other constraints to be applied silently.  */
  
  void
  determine_visibility (tree decl)
  {
!   tree class_type = NULL_TREE;
!   bool use_template;
! 
!   /* Remember that all decls get VISIBILITY_DEFAULT when built.  */
  
    /* Only relevant for names with external linkage.  */
    if (!TREE_PUBLIC (decl))
*************** determine_visibility (tree decl)
*** 1559,1567 ****
       maybe_clone_body.  */
    gcc_assert (!DECL_CLONED_FUNCTION_P (decl));
  
!   /* Give the common code a chance to make a determination.  */
!   if (c_determine_visibility (decl))
!     return;
  
    /* If DECL is a member of a class, visibility specifiers on the
       class can influence the visibility of the DECL.  */
--- 1669,1698 ----
       maybe_clone_body.  */
    gcc_assert (!DECL_CLONED_FUNCTION_P (decl));
  
!   if (TREE_CODE (decl) == TYPE_DECL)
!     {
!       if (CLASS_TYPE_P (TREE_TYPE (decl)))
! 	use_template = CLASSTYPE_USE_TEMPLATE (TREE_TYPE (decl));
!       else if (TYPE_TEMPLATE_INFO (TREE_TYPE (decl)))
! 	use_template = 1;
!       else
! 	use_template = 0;
!     }
!   else if (DECL_LANG_SPECIFIC (decl))
!     use_template = DECL_USE_TEMPLATE (decl);
!   else
!     use_template = 0;
! 
!   /* Anything that is exported must have default visibility.  */
!   if (TARGET_DLLIMPORT_DECL_ATTRIBUTES
!       && lookup_attribute ("dllexport",
! 			   TREE_CODE (decl) == TYPE_DECL
! 			   ? TYPE_ATTRIBUTES (TREE_TYPE (decl))
! 			   : DECL_ATTRIBUTES (decl)))
!     {
!       DECL_VISIBILITY (decl) = VISIBILITY_DEFAULT;
!       DECL_VISIBILITY_SPECIFIED (decl) = 1;
!     }
  
    /* If DECL is a member of a class, visibility specifiers on the
       class can influence the visibility of the DECL.  */
*************** determine_visibility (tree decl)
*** 1573,1578 ****
--- 1704,1711 ----
      class_type = TREE_TYPE (DECL_NAME (decl));
    else
      {
+       /* Not a class member.  */
+ 
        /* Virtual tables have DECL_CONTEXT set to their associated class,
  	 so they are automatically handled above.  */
        gcc_assert (TREE_CODE (decl) != VAR_DECL
*************** determine_visibility (tree decl)
*** 1580,1656 ****
  
        if (DECL_FUNCTION_SCOPE_P (decl))
  	{
  	  tree fn = DECL_CONTEXT (decl);
  	  DECL_VISIBILITY (decl) = DECL_VISIBILITY (fn);
  	  DECL_VISIBILITY_SPECIFIED (decl) = DECL_VISIBILITY_SPECIFIED (fn);
- 	}
  
!       /* Entities not associated with any class just get the
! 	 visibility specified by their attributes.  */
!       return;
      }
  
!   /* By default, static data members and function members receive
!      the visibility of their containing class.  */
!   if (class_type)
      {
!       determine_visibility_from_class (decl, class_type);
  
!       /* Give the target a chance to override the visibility associated
! 	 with DECL.  */
!       if (TREE_CODE (decl) == VAR_DECL
! 	  && (DECL_TINFO_P (decl)
! 	      || (DECL_VTABLE_OR_VTT_P (decl)
! 		  /* Construction virtual tables are not exported because
! 		     they cannot be referred to from other object files;
! 		     their name is not standardized by the ABI.  */
! 		  && !DECL_CONSTRUCTION_VTABLE_P (decl)))
! 	  && TREE_PUBLIC (decl)
! 	  && !DECL_REALLY_EXTERN (decl)
! 	  && DECL_VISIBILITY_SPECIFIED (decl)
! 	  && (!class_type || !CLASSTYPE_VISIBILITY_SPECIFIED (class_type)))
! 	targetm.cxx.determine_class_data_visibility (decl);
      }
  }
  
  static void
  determine_visibility_from_class (tree decl, tree class_type)
  {
!   if (TARGET_DLLIMPORT_DECL_ATTRIBUTES
!       && lookup_attribute ("dllexport", TYPE_ATTRIBUTES (class_type)))
!     {
!       DECL_VISIBILITY (decl) = VISIBILITY_DEFAULT;
!       DECL_VISIBILITY_SPECIFIED (decl) = 1;
!     }
!   else if (TREE_CODE (decl) == FUNCTION_DECL
! 	   && DECL_DECLARED_INLINE_P (decl)
! 	   && visibility_options.inlines_hidden)
!     {
!       /* Don't change it if it has been set explicitly by user.  */
!       if (!DECL_VISIBILITY_SPECIFIED (decl))
! 	{
! 	  DECL_VISIBILITY (decl) = VISIBILITY_HIDDEN;
! 	  DECL_VISIBILITY_SPECIFIED (decl) = 1;
! 	}
!     }
!   else if (CLASSTYPE_VISIBILITY_SPECIFIED (class_type))
!     {
!       DECL_VISIBILITY (decl) = CLASSTYPE_VISIBILITY (class_type);
!       DECL_VISIBILITY_SPECIFIED (decl) = 1;
!     }
!   else if (TYPE_CLASS_SCOPE_P (class_type))
!     determine_visibility_from_class (decl, TYPE_CONTEXT (class_type));
!   else if (TYPE_FUNCTION_SCOPE_P (class_type))
!     {
!       tree fn = TYPE_CONTEXT (class_type);
!       DECL_VISIBILITY (decl) = DECL_VISIBILITY (fn);
!       DECL_VISIBILITY_SPECIFIED (decl) = DECL_VISIBILITY_SPECIFIED (fn);
!     }
!   else if (!DECL_VISIBILITY_SPECIFIED (decl))
!     {
!       DECL_VISIBILITY (decl) = CLASSTYPE_VISIBILITY (class_type);
!       DECL_VISIBILITY_SPECIFIED (decl) = 0;
!     }
  }
  
  /* DECL is a FUNCTION_DECL or VAR_DECL.  If the object file linkage
--- 1713,1852 ----
  
        if (DECL_FUNCTION_SCOPE_P (decl))
  	{
+ 	  /* Local statics and classes get the visibility of their
+ 	     containing function.  */
  	  tree fn = DECL_CONTEXT (decl);
  	  DECL_VISIBILITY (decl) = DECL_VISIBILITY (fn);
  	  DECL_VISIBILITY_SPECIFIED (decl) = DECL_VISIBILITY_SPECIFIED (fn);
  
! 	  /* Local classes in templates have CLASSTYPE_USE_TEMPLATE set,
! 	     but have no TEMPLATE_INFO, so don't try to check it.  */
! 	  use_template = 0;
! 	}
!       else if (TREE_CODE (decl) == VAR_DECL && DECL_TINFO_P (decl))
! 	{
! 	  /* tinfo visibility is based on the type it's for.  */
! 	  constrain_visibility
! 	    (decl, type_visibility (TREE_TYPE (DECL_NAME (decl))),
! 	     false, "type");
! 	}
!       else if (use_template == 1 && !processing_explicit_instantiation)
! 	/* Visibility of implicit instantiations is based on their
! 	   template.  Note that explicit instantiations also have
! 	   use_template == 1 at this point, it isn't changed until
! 	   later.  */;
!       else if (! DECL_VISIBILITY_SPECIFIED (decl))
! 	{
! 	  /* Set default visibility to whatever the user supplied with
! 	     #pragma GCC visibility or a namespace visibility attribute.  */
! 	  DECL_VISIBILITY (decl) = default_visibility;
! 	  DECL_VISIBILITY_SPECIFIED (decl) = visibility_options.inpragma;
! 	}
      }
  
!   if (use_template)
      {
!       tree tinfo = (TREE_CODE (decl) == TYPE_DECL
! 		    ? TYPE_TEMPLATE_INFO (TREE_TYPE (decl))
! 		    : DECL_TEMPLATE_INFO (decl));
!       tree args = TI_ARGS (tinfo);
!       int depth = TMPL_ARGS_DEPTH (args);
  
!       /* If the template has explicit visibility and the specialization
! 	 doesn't, use the visibility from the template.  */
!       if (!DECL_VISIBILITY_SPECIFIED (decl))
! 	{
! 	  tree pattern = DECL_TEMPLATE_RESULT (TI_TEMPLATE (tinfo));
! 	  DECL_VISIBILITY (decl) = DECL_VISIBILITY (pattern);
! 	}
! 
!       /* FIXME should TMPL_ARGS_DEPTH really return 1 for null input? */
!       if (args && depth > template_class_depth (class_type))
! 	/* Don't let it have more visibility than its template type
! 	   arguments.  */
! 	constrain_visibility_for_template (decl, args);
      }
+   
+   if (class_type)
+     determine_visibility_from_class (decl, class_type);
+ 
+   /* Don't let it have more visibility than its type.  */
+   if (TREE_CODE (decl) != TYPE_DECL)
+     if (constrain_visibility (decl, type_visibility (TREE_TYPE (decl)),
+ 			      false, "type"))
+       warning (OPT_Wattributes, "\
+ %q+D declared with greater visibility than its type",
+ 	       decl);
+ 
+   if (decl_anon_ns_mem_p (decl))
+     /* Names in an anonymous namespace get internal linkage.
+        This might change once we implement export.  */
+     constrain_visibility (decl, VISIBILITY_STATIC,
+ 			  false, "namespace");
  }
  
+ /* By default, static data members and function members receive
+    the visibility of their containing class.  */
+ 
  static void
  determine_visibility_from_class (tree decl, tree class_type)
  {
!   if (visibility_options.inlines_hidden
!       /* Don't do this for inline templates; specializations might not be
! 	 inline, and we don't want them to inherit the hidden
! 	 visibility.  We'll set it here for all inline instantiations.  */
!       && !processing_template_decl
!       && ! DECL_VISIBILITY_SPECIFIED (decl)
!       && TREE_CODE (decl) == FUNCTION_DECL
!       && DECL_DECLARED_INLINE_P (decl))
!     DECL_VISIBILITY (decl) = VISIBILITY_HIDDEN;
! 
!   /* The decl can't have more visibility than its class.  */
!   constrain_visibility (decl, CLASSTYPE_VISIBILITY (class_type),
! 			CLASSTYPE_VISIBILITY_SPECIFIED (class_type),
! 			"class");
! 
!   /* Give the target a chance to override the visibility associated
!      with DECL.  */
!   if (TREE_CODE (decl) == VAR_DECL
!       && (DECL_TINFO_P (decl)
! 	  || (DECL_VTABLE_OR_VTT_P (decl)
! 	      /* Construction virtual tables are not exported because
! 		 they cannot be referred to from other object files;
! 		 their name is not standardized by the ABI.  */
! 	      && !DECL_CONSTRUCTION_VTABLE_P (decl)))
!       && TREE_PUBLIC (decl)
!       && !DECL_REALLY_EXTERN (decl)
!       && DECL_VISIBILITY_SPECIFIED (decl)
!       && (!class_type || !CLASSTYPE_VISIBILITY_SPECIFIED (class_type)))
!     targetm.cxx.determine_class_data_visibility (decl);
! }
! 
! /* Constrain the visibility of a class TYPE based on the visibility of its
!    field types.  Warn if any fields require lesser visibility.  */
! 
! void
! constrain_class_visibility (tree type)
! {
!   tree decl = TYPE_MAIN_DECL (type);
!   tree binfo = TYPE_BINFO (type);
!   tree t;
!   int i;
! 
!   for (t = TYPE_FIELDS (type); t; t = TREE_CHAIN (t))
!     if (TREE_CODE (t) == FIELD_DECL)
!       if (constrain_visibility (decl, type_visibility (TREE_TYPE (t)),
! 				false, "field type"))
! 	warning (OPT_Wattributes, "\
! %qT declared with greater visibility than the type of its field %qD",
! 		 type, t);
! 
!   for (i = 0; BINFO_BASE_ITERATE (binfo, i, t); ++i)
!     if (constrain_visibility (decl, type_visibility (TREE_TYPE (t)),
! 			      false, "base type"))
!       warning (OPT_Wattributes, "\
! %qT declared with greater visibility than its base %qT",
! 	       type, TREE_TYPE (t));
  }
  
  /* DECL is a FUNCTION_DECL or VAR_DECL.  If the object file linkage
Index: cp/parser.c
===================================================================
*** cp/parser.c	(revision 114895)
--- cp/parser.c	(working copy)
*************** cp_parser_explicit_instantiation (cp_par
*** 9412,9418 ****
        if (declarator != cp_error_declarator)
  	{
  	  decl = grokdeclarator (declarator, &decl_specifiers,
! 				 NORMAL, 0, NULL);
  	  /* Turn access control back on for names used during
  	     template instantiation.  */
  	  pop_deferring_access_checks ();
--- 9412,9418 ----
        if (declarator != cp_error_declarator)
  	{
  	  decl = grokdeclarator (declarator, &decl_specifiers,
! 				 NORMAL, 0, &decl_specifiers.attributes);
  	  /* Turn access control back on for names used during
  	     template instantiation.  */
  	  pop_deferring_access_checks ();
*************** cp_parser_type_specifier (cp_parser* par
*** 9561,9582 ****
    switch (keyword)
      {
      case RID_ENUM:
!       /* 'enum' [identifier] '{' introduces an enum-specifier;
! 	 'enum' <anything else> introduces an elaborated-type-specifier.  */
!       if (cp_lexer_peek_nth_token (parser->lexer, 2)->type == CPP_OPEN_BRACE
! 	  || (cp_lexer_peek_nth_token (parser->lexer, 2)->type == CPP_NAME
! 	      && cp_lexer_peek_nth_token (parser->lexer, 3)->type
! 		 == CPP_OPEN_BRACE))
  	{
- 	  if (parser->num_template_parameter_lists)
- 	    {
- 	      error ("template declaration of %qs", "enum");
- 	      cp_parser_skip_to_end_of_block_or_statement (parser);
- 	      type_spec = error_mark_node;
- 	    }
- 	  else
- 	    type_spec = cp_parser_enum_specifier (parser);
- 
  	  if (declares_class_or_enum)
  	    *declares_class_or_enum = 2;
  	  if (decl_specs)
--- 9561,9571 ----
    switch (keyword)
      {
      case RID_ENUM:
!       /* Look for the enum-specifier.  */
!       type_spec = cp_parser_enum_specifier (parser);
!       /* If that worked, we're done.  */
!       if (type_spec)
  	{
  	  if (declares_class_or_enum)
  	    *declares_class_or_enum = 2;
  	  if (decl_specs)
*************** cp_parser_elaborated_type_specifier (cp_
*** 10078,10083 ****
--- 10067,10073 ----
  					 /*type_p=*/true,
  					 is_declaration);
    /* For everything but enumeration types, consider a template-id.  */
+   /* For an enumeration type, consider only a plain identifier.  */
    if (tag_type != enum_type)
      {
        bool template_p = false;
*************** cp_parser_elaborated_type_specifier (cp_
*** 10109,10115 ****
  	type = TREE_TYPE (decl);
      }
  
-   /* For an enumeration type, consider only a plain identifier.  */
    if (!type)
      {
        identifier = cp_parser_identifier (parser);
--- 10099,10104 ----
*************** cp_parser_elaborated_type_specifier (cp_
*** 10237,10247 ****
  	  else
  	    ts = ts_global;
  
- 	  /* Warn about attributes. They are ignored.  */
- 	  if (attributes)
- 	    warning (OPT_Wattributes,
- 		     "type attributes are honored only at type definition");
- 
  	  template_p =
  	    (parser->num_template_parameter_lists
  	     && (cp_parser_next_token_starts_class_definition_p (parser)
--- 10226,10231 ----
*************** cp_parser_elaborated_type_specifier (cp_
*** 10254,10259 ****
--- 10238,10258 ----
  	  type = xref_tag (tag_type, identifier, ts, template_p);
  	}
      }
+ 
+   /* Allow attributes on forward declarations of classes.  */
+   if (attributes)
+     {
+       if (tag_type != enum_type && CLASSTYPE_TEMPLATE_INSTANTIATION (type)
+ 	  && ! processing_explicit_instantiation)
+ 	warning (OPT_Wattributes,
+ 		 "attributes ignored on template instantiation");
+       else if (is_declaration && cp_parser_declares_only_class_p (parser))
+ 	cplus_decl_attributes (&type, attributes, (int) ATTR_FLAG_TYPE_IN_PLACE);
+       else
+ 	warning (OPT_Wattributes,
+ 		 "attributes ignored on elaborated-type-specifier that is not a forward declaration");
+     }
+ 
    if (tag_type != enum_type)
      cp_parser_check_class_key (tag_type, type);
  
*************** cp_parser_elaborated_type_specifier (cp_
*** 10270,10284 ****
       enum identifier [opt] { enumerator-list [opt] }
  
     GNU Extensions:
!      enum identifier [opt] { enumerator-list [opt] } attributes
  
!    Returns an ENUM_TYPE representing the enumeration.  */
  
  static tree
  cp_parser_enum_specifier (cp_parser* parser)
  {
    tree identifier;
    tree type;
  
    /* Caller guarantees that the current token is 'enum', an identifier
       possibly follows, and the token after that is an opening brace.
--- 10269,10290 ----
       enum identifier [opt] { enumerator-list [opt] }
  
     GNU Extensions:
!      enum attributes[opt] identifier [opt] { enumerator-list [opt] }
!        attributes[opt]
  
!    Returns an ENUM_TYPE representing the enumeration, or NULL_TREE
!    if the token stream isn't an enum-specifier after all.  */
  
  static tree
  cp_parser_enum_specifier (cp_parser* parser)
  {
    tree identifier;
    tree type;
+   tree attributes;
+ 
+   /* Parse tentatively so that we can back up if we don't find a
+      enum-specifier.  */
+   cp_parser_parse_tentatively (parser);
  
    /* Caller guarantees that the current token is 'enum', an identifier
       possibly follows, and the token after that is an opening brace.
*************** cp_parser_enum_specifier (cp_parser* par
*** 10286,10296 ****
--- 10292,10311 ----
       the enumeration being defined.  */
    cp_lexer_consume_token (parser->lexer);
  
+   attributes = cp_parser_attributes_opt (parser);
+ 
    if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
      identifier = cp_parser_identifier (parser);
    else
      identifier = make_anon_name ();
  
+   /* Look for the `{' but don't consume it yet.  */
+   if (!cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE))
+     cp_parser_simulate_error (parser);
+ 
+   if (!cp_parser_parse_definitely (parser))
+     return NULL_TREE;
+ 
    /* Issue an error message if type-definitions are forbidden here.  */
    cp_parser_check_type_definition (parser);
  
*************** cp_parser_enum_specifier (cp_parser* par
*** 10302,10307 ****
--- 10317,10328 ----
    /* Consume the opening brace.  */
    cp_lexer_consume_token (parser->lexer);
  
+   if (type == error_mark_node)
+     {
+       cp_parser_skip_to_end_of_block_or_statement (parser);
+       return error_mark_node;
+     }
+ 
    /* If the next token is not '}', then there are some enumerators.  */
    if (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_BRACE))
      cp_parser_enumerator_list (parser, type);
*************** cp_parser_class_specifier (cp_parser* pa
*** 12917,12923 ****
        scope = CP_DECL_CONTEXT (TYPE_MAIN_DECL (type));
        old_scope = push_inner_scope (scope);
      }
!   type = begin_class_definition (type);
  
    if (type == error_mark_node)
      /* If the type is erroneous, skip the entire body of the class.  */
--- 12938,12944 ----
        scope = CP_DECL_CONTEXT (TYPE_MAIN_DECL (type));
        old_scope = push_inner_scope (scope);
      }
!   type = begin_class_definition (type, attributes);
  
    if (type == error_mark_node)
      /* If the type is erroneous, skip the entire body of the class.  */
*************** cp_parser_class_specifier (cp_parser* pa
*** 12934,12943 ****
    has_trailing_semicolon = (token->type == CPP_SEMICOLON);
    /* Look for trailing attributes to apply to this class.  */
    if (cp_parser_allow_gnu_extensions_p (parser))
!     {
!       tree sub_attr = cp_parser_attributes_opt (parser);
!       attributes = chainon (attributes, sub_attr);
!     }
    if (type != error_mark_node)
      type = finish_struct (type, attributes);
    if (nested_name_specifier_p)
--- 12955,12961 ----
    has_trailing_semicolon = (token->type == CPP_SEMICOLON);
    /* Look for trailing attributes to apply to this class.  */
    if (cp_parser_allow_gnu_extensions_p (parser))
!     attributes = cp_parser_attributes_opt (parser);
    if (type != error_mark_node)
      type = finish_struct (type, attributes);
    if (nested_name_specifier_p)
Index: c-decl.c
===================================================================
*** c-decl.c	(revision 114895)
--- c-decl.c	(working copy)
*************** finish_decl (tree decl, tree init, tree 
*** 3459,3476 ****
    /* If #pragma weak was used, mark the decl weak now.  */
    maybe_apply_pragma_weak (decl);
  
-   /* If this is a variable definition, determine its ELF visibility.  */
-   if (TREE_CODE (decl) == VAR_DECL
-       && TREE_STATIC (decl)
-       && !DECL_EXTERNAL (decl))
-     c_determine_visibility (decl);
- 
    /* Output the assembler code and/or RTL code for variables and functions,
       unless the type is an undefined structure or union.
       If not, it will get done when the type is completed.  */
  
    if (TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == FUNCTION_DECL)
      {
        /* This is a no-op in c-lang.c or something real in objc-act.c.  */
        if (c_dialect_objc ())
  	objc_check_decl (decl);
--- 3459,3474 ----
    /* If #pragma weak was used, mark the decl weak now.  */
    maybe_apply_pragma_weak (decl);
  
    /* Output the assembler code and/or RTL code for variables and functions,
       unless the type is an undefined structure or union.
       If not, it will get done when the type is completed.  */
  
    if (TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == FUNCTION_DECL)
      {
+       /* Determine the ELF visibility.  */
+       if (TREE_PUBLIC (decl))
+ 	c_determine_visibility (decl);
+ 
        /* This is a no-op in c-lang.c or something real in objc-act.c.  */
        if (c_dialect_objc ())
  	objc_check_decl (decl);
Index: varasm.c
===================================================================
*** varasm.c	(revision 114895)
--- varasm.c	(working copy)
*************** void
*** 5033,5039 ****
  default_assemble_visibility (tree decl, int vis)
  {
    static const char * const visibility_types[] = {
!     NULL, "internal", "hidden", "protected"
    };
  
    const char *name, *type;
--- 5033,5039 ----
  default_assemble_visibility (tree decl, int vis)
  {
    static const char * const visibility_types[] = {
!     NULL, "protected", "hidden", "internal"
    };
  
    const char *name, *type;
Index: c-common.c
===================================================================
*** c-common.c	(revision 114895)
--- c-common.c	(working copy)
*************** handle_weakref_attribute (tree *node, tr
*** 4876,4896 ****
  static tree
  handle_visibility_attribute (tree *node, tree name, tree args,
  			     int ARG_UNUSED (flags),
! 			     bool *no_add_attrs)
  {
    tree decl = *node;
    tree id = TREE_VALUE (args);
! 
!   *no_add_attrs = true;
  
    if (TYPE_P (*node))
      {
!       if (TREE_CODE (*node) != RECORD_TYPE && TREE_CODE (*node) != UNION_TYPE)
!        {
! 	 warning (OPT_Wattributes, "%qE attribute ignored on non-class types",
! 		  name);
! 	 return NULL_TREE;
!        }
      }
    else if (decl_function_context (decl) != 0 || !TREE_PUBLIC (decl))
      {
--- 4876,4903 ----
  static tree
  handle_visibility_attribute (tree *node, tree name, tree args,
  			     int ARG_UNUSED (flags),
! 			     bool *ARG_UNUSED (no_add_attrs))
  {
    tree decl = *node;
    tree id = TREE_VALUE (args);
!   enum symbol_visibility vis;
  
    if (TYPE_P (*node))
      {
!       if (TREE_CODE (*node) == ENUMERAL_TYPE)
! 	/* OK */;
!       else if (TREE_CODE (*node) != RECORD_TYPE && TREE_CODE (*node) != UNION_TYPE)
! 	{
! 	  warning (OPT_Wattributes, "%qE attribute ignored on non-class types",
! 		   name);
! 	  return NULL_TREE;
! 	}
!       else if (TYPE_FIELDS (*node))
! 	{
! 	  error ("%qE attribute ignored because %qT is already defined",
! 		 name, *node);
! 	  return NULL_TREE;
! 	}
      }
    else if (decl_function_context (decl) != 0 || !TREE_PUBLIC (decl))
      {
*************** handle_visibility_attribute (tree *node,
*** 4919,4941 ****
      }
  
    if (strcmp (TREE_STRING_POINTER (id), "default") == 0)
!     DECL_VISIBILITY (decl) = VISIBILITY_DEFAULT;
    else if (strcmp (TREE_STRING_POINTER (id), "internal") == 0)
!     DECL_VISIBILITY (decl) = VISIBILITY_INTERNAL;
    else if (strcmp (TREE_STRING_POINTER (id), "hidden") == 0)
!     DECL_VISIBILITY (decl) = VISIBILITY_HIDDEN;
    else if (strcmp (TREE_STRING_POINTER (id), "protected") == 0)
!     DECL_VISIBILITY (decl) = VISIBILITY_PROTECTED;
    else
!     error ("visibility argument must be one of \"default\", \"hidden\", \"protected\" or \"internal\"");
    DECL_VISIBILITY_SPECIFIED (decl) = 1;
  
!   /* For decls only, go ahead and attach the attribute to the node as well.
!      This is needed so we can determine whether we have VISIBILITY_DEFAULT
!      because the visibility was not specified, or because it was explicitly
!      overridden from the class visibility.  */
!   if (DECL_P (*node))
!     *no_add_attrs = false;
  
    return NULL_TREE;
  }
--- 4926,4958 ----
      }
  
    if (strcmp (TREE_STRING_POINTER (id), "default") == 0)
!     vis = VISIBILITY_DEFAULT;
    else if (strcmp (TREE_STRING_POINTER (id), "internal") == 0)
!     vis = VISIBILITY_INTERNAL;
    else if (strcmp (TREE_STRING_POINTER (id), "hidden") == 0)
!     vis = VISIBILITY_HIDDEN;
    else if (strcmp (TREE_STRING_POINTER (id), "protected") == 0)
!     vis = VISIBILITY_PROTECTED;
    else
!     {
!       error ("visibility argument must be one of \"default\", \"hidden\", \"protected\" or \"internal\"");
!       vis = VISIBILITY_DEFAULT;
!     }
! 
!   if (DECL_VISIBILITY_SPECIFIED (decl)
!       && vis != DECL_VISIBILITY (decl)
!       && lookup_attribute ("visibility", (TYPE_P (*node)
! 					  ? TYPE_ATTRIBUTES (*node)
! 					  : DECL_ATTRIBUTES (decl))))
!     error ("%qD redeclared with different visibility", decl);
! 
!   DECL_VISIBILITY (decl) = vis;
    DECL_VISIBILITY_SPECIFIED (decl) = 1;
  
!   /* Go ahead and attach the attribute to the node as well.  This is needed
!      so we can determine whether we have VISIBILITY_DEFAULT because the
!      visibility was not specified, or because it was explicitly overridden
!      from the containing scope.  */
  
    return NULL_TREE;
  }
*************** c_determine_visibility (tree decl)
*** 4963,4969 ****
    if (lookup_attribute ("visibility", DECL_ATTRIBUTES (decl)))
      return true;
  
!   /* Anything that is exported must have default visibility.  */
    if (TARGET_DLLIMPORT_DECL_ATTRIBUTES
        && lookup_attribute ("dllexport", DECL_ATTRIBUTES (decl)))
      {
--- 4980,4986 ----
    if (lookup_attribute ("visibility", DECL_ATTRIBUTES (decl)))
      return true;
  
!  /* Anything that is exported must have default visibility.  */
    if (TARGET_DLLIMPORT_DECL_ATTRIBUTES
        && lookup_attribute ("dllexport", DECL_ATTRIBUTES (decl)))
      {
*************** c_determine_visibility (tree decl)
*** 4972,4977 ****
--- 4989,5001 ----
        return true;
      }
  
+   /* Set default visibility to whatever the user supplied with
+      visibility_specified depending on #pragma GCC visibility.  */
+   if (!DECL_VISIBILITY_SPECIFIED (decl))
+     {
+       DECL_VISIBILITY (decl) = default_visibility;
+       DECL_VISIBILITY_SPECIFIED (decl) = visibility_options.inpragma;
+     }
    return false;
  }
  

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]