Bug 17470 - Visibility attribute ignored for explicit template instantiation
Summary: Visibility attribute ignored for explicit template instantiation
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 4.0.0
: P2 normal
Target Milestone: 4.2.0
Assignee: Jason Merrill
URL:
Keywords: visibility
: 21243 (view as bug list)
Depends on:
Blocks: 21243
  Show dependency treegraph
 
Reported: 2004-09-13 21:37 UTC by Matt Austern
Modified: 2006-06-30 15:28 UTC (History)
7 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2006-03-21 03:29:23


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Matt Austern 2004-09-13 21:37:50 UTC
[isolde:tmp]$ cat foo.cc
template <class T> T identity(T t) { return t; }
template int identity(int);
template  __attribute__((visibility("default"))) double identity(double);
[isolde:tmp]$ /work/root.u/bin/g++ -fvisibility=hidden -c foo.cc
[isolde:tmp]$ nm -m foo.o
00000024 (__TEXT,__text) private external __Z8identityIdET_S0_
00000000 (absolute) private external __Z8identityIdET_S0_.eh
00000000 (__TEXT,__text) private external __Z8identityIiET_S0_
00000000 (absolute) private external __Z8identityIiET_S0_.eh
[isolde:tmp]$
Comment 1 Wolfgang Bangerth 2004-09-13 23:40:03 UTC
May I remark that I would find it quite odd to have attributes 
for functions on a template _instantiations_? I would think that 
the attribute should be at either the declaration or the definition. 
I understand that this precludes giving different instantiations 
different visibility, but it would make the system somewhat less 
odd... 
 
W. 
Comment 2 Matt Austern 2004-09-14 02:20:02 UTC
Tastes differ, I suppose!  My own feeling is that it's unnatural, when declaring an unbounded set of 
functions, to have to say that either all of them or none of them get exported.  I find it more likely that 
a dynamic library author would decide that a selected few specializations are the library's interface.

However, I don't insist on that point.  What I do insist on: it's wrong for the compiler to silently ignore 
the visibility attribute on explicit instantiations.  Either it should be honored, or else it should be 
documented and diagnosed as an error.  Silently ignoring it is a nasty trap for users.
Comment 3 Wolfgang Bangerth 2004-09-14 03:48:08 UTC
That latter point is most certainly uncontested! :-) 
W. 
Comment 4 Eric Frias 2004-12-13 20:46:55 UTC
I just ran into this quirk too.  It looks like you can work around by using
"#pragma GCC visibility push(default)" before the explicit instantiation and
then popping afterwards.  I'd greatly prefer the __attribute__ syntax because
that would permit me to use one macro for porting __declspec(dllexport)
constructs from windows code.  Even displaying a warning or error for the
ignored __attribute__ would've saved me some grief.
Comment 5 Simon Perreault 2004-12-22 20:54:31 UTC
I just got hit with that bug and spent too much time figuring out what was
wrong. Here's my code, just to show an example of real-life usage:

//////////////////////////////////////////////////////////////////////////
/**
 * Returns the unsigned version of \a number.
 */
template< class T >
T abs( T number )
{
    // This is the default implementation, using comparison to zero and unary
    // negation operator.
    if ( number < 0 ) {
        return -number;
    }
    return number;
}

// Here are some specific implementations.

template<> bool             WRAP_API abs( bool           number );
template<> char             WRAP_API abs( char           number );
template<> unsigned char    WRAP_API abs( unsigned char  number );
template<> short            WRAP_API abs( short          number );
template<> unsigned short   WRAP_API abs( unsigned short number );
template<> int              WRAP_API abs( int            number );
template<> unsigned int     WRAP_API abs( unsigned int   number );
template<> long             WRAP_API abs( long           number );
template<> unsigned long    WRAP_API abs( unsigned long  number );
template<> float            WRAP_API abs( float          number );
template<> double           WRAP_API abs( double         number );
//////////////////////////////////////////////////////////////////////////

Please fix this bug!
Comment 6 Andrew Pinski 2004-12-28 23:52:56 UTC
Confirmed.
Comment 7 James Megquier 2005-09-02 00:16:51 UTC
Regarding macros -- I just found out about the _Pragma directive from C99, so at
least you can do something like this (paraphrasing some ACE code):

#define EXPORT_SINGLETON_DECLARE (SINGLETON_TYPE, CLASS, LOCK) \
        _Pragma ("GCC visibility push(default)")               \
        template class SINGLETON_TYPE <CLASS, LOCK>;           \
        _Pragma ("GCC visibility pop")

#define IMPORT_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) extern template
class SINGLETON_TYPE <CLASS, LOCK>;

Then define SINGLETON_DECLARE to depending on whether you're building the lib or
not.

A possible issue with this is that it must come before, say, a typedef of the
template type.  The example below works on VS but not g++ (not that VS matters,
but I'm using code that does this):

typedef Singleton_T<Foo, Mutex> FOO_SINGLETON;

SINGLETON_DECLARE(Singleton_T, Foo, Mutex)

Instead, the SINGLETON_DECLARE needs to come before the typedef or it will get
hidden visibility on g++.  I'm curious as to why the typedef causes the symbols
to get hidden visibility -- is that in spec, or is a bug?
Comment 8 Jason Merrill 2006-06-23 01:11:39 UTC
*** Bug 21243 has been marked as a duplicate of this bug. ***
Comment 9 Jason Merrill 2006-06-30 01:16:31 UTC
Subject: Bug 17470

Author: jason
Date: Fri Jun 30 01:15:56 2006
New Revision: 115086

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=115086
Log:
        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.
        * attribs.c (decl_attributes): Ignore type-in-place attributes
        once the type has been defined.

        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.

Added:
    trunk/gcc/testsuite/g++.dg/ext/visibility/anon2.C
    trunk/gcc/testsuite/g++.dg/ext/visibility/class1.C
    trunk/gcc/testsuite/g++.dg/ext/visibility/prop1.C
    trunk/gcc/testsuite/g++.dg/ext/visibility/redecl1.C
    trunk/gcc/testsuite/g++.dg/ext/visibility/template1.C
    trunk/gcc/testsuite/g++.dg/ext/visibility/template2.C
    trunk/gcc/testsuite/g++.dg/ext/visibility/template3.C
    trunk/gcc/testsuite/g++.dg/ext/visibility/template4.C
    trunk/gcc/testsuite/g++.dg/ext/visibility/typeinfo1.C
    trunk/gcc/testsuite/g++.dg/ext/visibility/warn1.C
    trunk/gcc/testsuite/g++.dg/ext/visibility/warn2.C
    trunk/gcc/testsuite/g++.dg/ext/visibility/warn3.C
    trunk/gcc/testsuite/g++.dg/ext/visibility/warn4.C
Modified:
    trunk/gcc/ChangeLog
    trunk/gcc/attribs.c
    trunk/gcc/c-common.c
    trunk/gcc/c-decl.c
    trunk/gcc/cp/ChangeLog
    trunk/gcc/cp/class.c
    trunk/gcc/cp/cp-tree.h
    trunk/gcc/cp/decl.c
    trunk/gcc/cp/decl2.c
    trunk/gcc/cp/name-lookup.c
    trunk/gcc/cp/parser.c
    trunk/gcc/cp/pt.c
    trunk/gcc/cp/rtti.c
    trunk/gcc/cp/semantics.c
    trunk/gcc/cp/tree.c
    trunk/gcc/doc/extend.texi
    trunk/gcc/doc/invoke.texi
    trunk/gcc/flags.h
    trunk/gcc/testsuite/g++.dg/ext/attrib14.C
    trunk/gcc/testsuite/g++.dg/ext/attrib9.C
    trunk/gcc/testsuite/g++.dg/ext/visibility/anon1.C
    trunk/gcc/testsuite/g++.dg/ext/visibility/assign1.C
    trunk/gcc/testsuite/g++.dg/ext/visibility/fvisibility-override2.C
    trunk/gcc/testsuite/g++.dg/ext/visibility/virtual.C
    trunk/gcc/testsuite/g++.old-deja/g++.pt/enum5.C
    trunk/gcc/tree.c
    trunk/gcc/tree.h
    trunk/gcc/varasm.c

Comment 10 Andrew Pinski 2006-06-30 15:28:33 UTC
Fixed.
Comment 11 Jakub Jelinek 2006-08-28 12:27:13 UTC
Subject: Bug 17470

Author: jakub
Date: Mon Aug 28 12:26:41 2006
New Revision: 116505

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=116505
Log:
2006-07-06  Jason Merrill  <jason@redhat.com>

cp/
	PR c++/28279
	* decl2.c (finish_static_data_member_decl): Don't assert
	TREE_PUBLIC.

2006-07-01  Jason Merrill  <jason@redhat.com>

cp/
	PR c++/28215
	* method.c (make_thunk): Unset DECL_USE_TEMPLATE and 
	DECL_TEMPLATE_INFO.

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

objcp/
	* objcp-decl.c (objcp_start_struct): Pass null attributes argument
	to begin_class_definition.

2006-06-29  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.

	PR c++/26905
	PR c++/21675
	PR c++/17470
	* attribs.c (decl_attributes): Ignore type-in-place attributes
	once the type has been defined.
cp/
	PR c++/26905
	PR c++/26612
	PR c++/27000
	PR c++/26984
	PR c++/19134
	* 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.
	* decl.c (cp_finish_decl): Call determine_visibility for function
	decls, too.
	* name-lookup.c (pushtag): Call determine_visibility.
	* decl.c (duplicate_decls): Don't copy visibility from template to
	specialization.
	* pt.c (check_explicit_specialization): Likewise.
	(lookup_template_class, tsubst_decl): Call determine_visibility.
	* class.c (finish_struct_1): Call constrain_class_visibility.

	PR c++/26905
	PR c++/21675
	PR c++/17470
	* 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.
	* semantics.c (begin_class_definition): Add attributes parameter,
	apply them to the type.

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

Added:
    branches/redhat/gcc-4_1-branch/gcc/testsuite/g++.dg/ext/visibility/anon1.C
    branches/redhat/gcc-4_1-branch/gcc/testsuite/g++.dg/ext/visibility/anon2.C
    branches/redhat/gcc-4_1-branch/gcc/testsuite/g++.dg/ext/visibility/class1.C
    branches/redhat/gcc-4_1-branch/gcc/testsuite/g++.dg/ext/visibility/prop1.C
    branches/redhat/gcc-4_1-branch/gcc/testsuite/g++.dg/ext/visibility/redecl1.C
    branches/redhat/gcc-4_1-branch/gcc/testsuite/g++.dg/ext/visibility/template1.C
    branches/redhat/gcc-4_1-branch/gcc/testsuite/g++.dg/ext/visibility/template2.C
    branches/redhat/gcc-4_1-branch/gcc/testsuite/g++.dg/ext/visibility/template3.C
    branches/redhat/gcc-4_1-branch/gcc/testsuite/g++.dg/ext/visibility/template4.C
    branches/redhat/gcc-4_1-branch/gcc/testsuite/g++.dg/ext/visibility/typeinfo1.C
    branches/redhat/gcc-4_1-branch/gcc/testsuite/g++.dg/ext/visibility/warn1.C
    branches/redhat/gcc-4_1-branch/gcc/testsuite/g++.dg/ext/visibility/warn2.C
    branches/redhat/gcc-4_1-branch/gcc/testsuite/g++.dg/ext/visibility/warn3.C
    branches/redhat/gcc-4_1-branch/gcc/testsuite/g++.dg/ext/visibility/warn4.C
    branches/redhat/gcc-4_1-branch/gcc/testsuite/g++.dg/template/anon2.C
Modified:
    branches/redhat/gcc-4_1-branch/gcc/ChangeLog
    branches/redhat/gcc-4_1-branch/gcc/attribs.c
    branches/redhat/gcc-4_1-branch/gcc/c-common.c
    branches/redhat/gcc-4_1-branch/gcc/c-decl.c
    branches/redhat/gcc-4_1-branch/gcc/cp/ChangeLog
    branches/redhat/gcc-4_1-branch/gcc/cp/class.c
    branches/redhat/gcc-4_1-branch/gcc/cp/cp-tree.h
    branches/redhat/gcc-4_1-branch/gcc/cp/decl.c
    branches/redhat/gcc-4_1-branch/gcc/cp/decl2.c
    branches/redhat/gcc-4_1-branch/gcc/cp/method.c
    branches/redhat/gcc-4_1-branch/gcc/cp/name-lookup.c
    branches/redhat/gcc-4_1-branch/gcc/cp/parser.c
    branches/redhat/gcc-4_1-branch/gcc/cp/pt.c
    branches/redhat/gcc-4_1-branch/gcc/cp/rtti.c
    branches/redhat/gcc-4_1-branch/gcc/cp/semantics.c
    branches/redhat/gcc-4_1-branch/gcc/cp/tree.c
    branches/redhat/gcc-4_1-branch/gcc/doc/extend.texi
    branches/redhat/gcc-4_1-branch/gcc/doc/invoke.texi
    branches/redhat/gcc-4_1-branch/gcc/flags.h
    branches/redhat/gcc-4_1-branch/gcc/objcp/ChangeLog
    branches/redhat/gcc-4_1-branch/gcc/objcp/objcp-decl.c
    branches/redhat/gcc-4_1-branch/gcc/testsuite/g++.dg/ext/attrib14.C
    branches/redhat/gcc-4_1-branch/gcc/testsuite/g++.dg/ext/attrib9.C
    branches/redhat/gcc-4_1-branch/gcc/testsuite/g++.dg/ext/visibility/assign1.C
    branches/redhat/gcc-4_1-branch/gcc/testsuite/g++.dg/ext/visibility/fvisibility-override2.C
    branches/redhat/gcc-4_1-branch/gcc/testsuite/g++.dg/ext/visibility/virtual.C
    branches/redhat/gcc-4_1-branch/gcc/testsuite/g++.old-deja/g++.pt/enum5.C
    branches/redhat/gcc-4_1-branch/gcc/tree.c
    branches/redhat/gcc-4_1-branch/gcc/tree.h
    branches/redhat/gcc-4_1-branch/gcc/varasm.c