I spent a while tweaking the visibility code while I was working on the lambdas in templates overhaul, but ended up putting that aside. This PR led me to pull that out again, but I hadn't realized that some of the code I was messing with was only a year old, from Nathan's fix for c++/79296. Specifically, the code to look at template arguments from an enclosing function, which I had been thinking looked unnecessary.
Looking at 79296 again, it turns out that the reason the old code wasn't working properly was my change to vague_linkage_p to handle thunked 'tor variants by looking at the flags on one of the thunks rather than the maybe-in-charge variant. This code is correct for the state after maybe_{clone,thunk}_body, but wrong before then, as the linkage isn't copied to the variants until that point. So this patch adds a check of DECL_ABSTRACT_P so that we only look at a thunk once we've decided it's a thunk. With that fixed, I can revert the part of Nathan's patch, as modified by me later for lambda issues, that looks at template arguments from the enclosing function. Tested x86_64-pc-linux-gnu, applying to trunk and 8.
commit 41895340ffee90823ff6c191d3518385337e2378 Author: Jason Merrill <ja...@redhat.com> Date: Mon May 7 16:58:08 2018 -0400 PR c++/85646 - lambda visibility. * decl2.c (determine_visibility): Don't mess with template arguments from the containing scope. (vague_linkage_p): Check DECL_ABSTRACT_P before looking at a 'tor thunk. diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index b0bf8241f71..9aae34a814c 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -1939,10 +1939,13 @@ vague_linkage_p (tree decl) { if (!TREE_PUBLIC (decl)) { - /* maybe_thunk_body clears TREE_PUBLIC on the maybe-in-charge 'tor - variants, check one of the "clones" for the real linkage. */ + /* maybe_thunk_body clears TREE_PUBLIC and DECL_ABSTRACT_P on the + maybe-in-charge 'tor variants; in that case we need to check one of + the "clones" for the real linkage. But only in that case; before + maybe_clone_body we haven't yet copied the linkage to the clones. */ if ((DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (decl) || DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (decl)) + && !DECL_ABSTRACT_P (decl) && DECL_CHAIN (decl) && DECL_CLONED_FUNCTION_P (DECL_CHAIN (decl))) return vague_linkage_p (DECL_CHAIN (decl)); @@ -2422,21 +2425,8 @@ determine_visibility (tree decl) } /* Local classes in templates have CLASSTYPE_USE_TEMPLATE set, - but have no TEMPLATE_INFO. Their containing template - function does, and the local class could be constrained - by that. */ - if (DECL_LANG_SPECIFIC (fn) && DECL_USE_TEMPLATE (fn)) - template_decl = fn; - else if (template_decl) - { - /* FN must be a regenerated lambda function, since they don't - have template arguments. Find a containing non-lambda - template instantiation. */ - tree ctx = fn; - while (ctx && !get_template_info (ctx)) - ctx = get_containing_scope (ctx); - template_decl = ctx; - } + but have no TEMPLATE_INFO, so don't try to check it. */ + template_decl = NULL_TREE; } else if (VAR_P (decl) && DECL_TINFO_P (decl) && flag_visibility_ms_compat) diff --git a/gcc/testsuite/g++.dg/ext/visibility/lambda1.C b/gcc/testsuite/g++.dg/ext/visibility/lambda1.C new file mode 100644 index 00000000000..359f8e4af5a --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/visibility/lambda1.C @@ -0,0 +1,14 @@ +// PR c++/85646 +// { dg-do compile { target c++11 } } +// { dg-additional-options -fvisibility=hidden } + +template<typename T> +void foo() { + struct inner { + inner() { + (void)([this] { }); + } + }; +} + +int main() { foo<int>(); }