diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 71af797f77b..450d469b4e1 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,10 @@ 2012-03-05 Jason Merrill + PR c++/51930 + * decl2.c (determine_visibility): Correct calculation of class + args depth. + * decl.c (check_tag_decl): Adjust warning. + * method.c (synthesized_method_walk): Cleanups don't affect the EH spec either. diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index c47f87c3032..a18b312841d 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -4216,17 +4216,20 @@ check_tag_decl (cp_decl_specifier_seq *declspecs) error ("% cannot be used for type declarations"); } - if (declspecs->attributes) + if (declspecs->attributes && warn_attributes) { - location_t loc = input_location; + location_t loc; if (!CLASSTYPE_TEMPLATE_INSTANTIATION (declared_type)) - /* For a non-template class, use the name location; for a template - class (an explicit instantiation), use the current location. */ - input_location = location_of (declared_type); - warning (0, "attribute ignored in declaration of %q#T", declared_type); - warning (0, "attribute for %q#T must follow the %qs keyword", - declared_type, class_key_or_enum_as_string (declared_type)); - input_location = loc; + /* For a non-template class, use the name location. */ + loc = location_of (declared_type); + else + /* For a template class (an explicit instantiation), use the + current location. */ + loc = input_location; + warning_at (loc, OPT_Wattributes, "attribute ignored in declaration " + "of %q#T", declared_type); + inform (loc, "attribute for %q#T must follow the %qs keyword", + declared_type, class_key_or_enum_as_string (declared_type)); } return declared_type; diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index bdc962abcf9..7eccf672546 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -2181,12 +2181,8 @@ determine_visibility (tree decl) ? TYPE_ATTRIBUTES (TREE_TYPE (decl)) : DECL_ATTRIBUTES (decl)); - if (args != error_mark_node - /* Template argument visibility outweighs #pragma or namespace - visibility, but not an explicit attribute. */ - && !lookup_attribute ("visibility", attribs)) + if (args != error_mark_node) { - int depth = TMPL_ARGS_DEPTH (args); tree pattern = DECL_TEMPLATE_RESULT (TI_TEMPLATE (tinfo)); if (!DECL_VISIBILITY_SPECIFIED (decl)) @@ -2202,10 +2198,31 @@ determine_visibility (tree decl) } } - /* FIXME should TMPL_ARGS_DEPTH really return 1 for null input? */ - if (args && depth > template_class_depth (class_type)) - /* Limit visibility based on its template arguments. */ - constrain_visibility_for_template (decl, args); + if (args + /* Template argument visibility outweighs #pragma or namespace + visibility, but not an explicit attribute. */ + && !lookup_attribute ("visibility", attribs)) + { + int depth = TMPL_ARGS_DEPTH (args); + int class_depth = 0; + if (class_type && CLASSTYPE_TEMPLATE_INFO (class_type)) + class_depth = TMPL_ARGS_DEPTH (CLASSTYPE_TI_ARGS (class_type)); + if (DECL_VISIBILITY_SPECIFIED (decl)) + { + /* A class template member with explicit visibility + overrides the class visibility, so we need to apply + all the levels of template args directly. */ + int i; + for (i = 1; i <= depth; ++i) + { + tree lev = TMPL_ARGS_LEVEL (args, i); + constrain_visibility_for_template (decl, lev); + } + } + else if (depth > class_depth) + /* Limit visibility based on its template arguments. */ + constrain_visibility_for_template (decl, args); + } } } diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 5fbd14fcc8c..5ea082ee293 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,5 +1,8 @@ 2012-03-05 Jason Merrill + PR c++/51930 + * g++.dg/ext/visibility/template11.C: New. + * g++.dg/cpp0x/implicit13.C: New. 2012-03-05 Jakub Jelinek diff --git a/gcc/testsuite/g++.dg/ext/visibility/template11.C b/gcc/testsuite/g++.dg/ext/visibility/template11.C new file mode 100644 index 00000000000..fb47fe2aff2 --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/visibility/template11.C @@ -0,0 +1,20 @@ +// PR c++/51930 +// { dg-require-visibility "" } +// { dg-options "-fvisibility=hidden" } +// { dg-final { scan-not-hidden "_ZN13template_testI4testE8functionEv" } } + +struct test { }; + +template +struct template_test +{ + __attribute__((visibility("default"))) + void function(); +}; + +template +void template_test::function() { } + +template +struct __attribute__((visibility("default"))) +template_test;