https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47877
Richard Biener <rguenth at gcc dot gnu.org> changed: What |Removed |Added ---------------------------------------------------------------------------- Keywords| |documentation Status|UNCONFIRMED |NEW Last reconfirmed| |2016-11-21 CC|rguenther at suse dot de |jason at gcc dot gnu.org, | |rguenth at gcc dot gnu.org Ever confirmed|0 |1 --- Comment #2 from Richard Biener <rguenth at gcc dot gnu.org> --- Confirmed. It looks like template instantiation somehow ends up using the explicitely specified visibility from the class. When determine_visibility_from_class is called for the template determine_hidden_inline () is false because of the processing_template_decl check. So the behavior is clearly on purpose and thus a documentation issue(?): /* Returns true iff DECL is an inline that should get hidden visibility because of -fvisibility-inlines-hidden. */ static bool determine_hidden_inline (tree decl) { return (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 && TREE_CODE (decl) == FUNCTION_DECL && DECL_DECLARED_INLINE_P (decl) && (! DECL_LANG_SPECIFIC (decl) || ! DECL_EXPLICIT_INSTANTIATION (decl))); } so the reason is along non-inline specializations (not sure why we'd want to avoid mixed visibility here).