https://gcc.gnu.org/g:5b14c8d1d65c178407234c86dbad41496b264a0c
commit r16-6924-g5b14c8d1d65c178407234c86dbad41496b264a0c Author: Marek Polacek <[email protected]> Date: Fri Jan 16 13:00:35 2026 -0500 c++: adjust visibility of _DECLs with no linkage This came up during Reflection review: <https://gcc.gnu.org/pipermail/gcc-patches/2026-January/705175.html> Certain entities, e.g. vars in public inline functions or template functions should be exported. But entities defined within TU-local should not be exported. This patch adjusts min_vis_expr_r to that effect as per the Reflection discussion. gcc/cp/ChangeLog: * decl2.cc (min_vis_expr_r): For _DECLs with no linkage refer to the linkage of the containing entity that does have a name with linkage. gcc/testsuite/ChangeLog: * g++.dg/reflect/visibility1.C: Adjust dg-final. Reviewed-by: Jason Merrill <[email protected]> Diff: --- gcc/cp/decl2.cc | 13 ++++++------- gcc/testsuite/g++.dg/reflect/visibility1.C | 18 +++++++++--------- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/gcc/cp/decl2.cc b/gcc/cp/decl2.cc index 6dbfdeada205..f29f56f65841 100644 --- a/gcc/cp/decl2.cc +++ b/gcc/cp/decl2.cc @@ -3114,8 +3114,10 @@ min_vis_expr_r (tree *tp, int *walk_subtrees, void *data) break; } addressable: + /* For _DECLs with no linkage refer to the linkage of the containing + entity that does have a name with linkage. */ if (decl_linkage (t) == lk_none) - tpvis = type_visibility (TREE_TYPE (t)); + tpvis = expr_visibility (DECL_CONTEXT (t)); /* Decls that have had their visibility constrained will report as external linkage, but we still want to transitively constrain if we refer to them, so just check TREE_PUBLIC instead. */ @@ -3170,13 +3172,10 @@ min_vis_expr_r (tree *tp, int *walk_subtrees, void *data) *walk_subtrees = 0; break; } - if ((VAR_P (r) && decl_function_context (r)) - || TREE_CODE (r) == PARM_DECL) + if (VAR_P (r) || TREE_CODE (r) == PARM_DECL) { - /* Block scope variables are local to the TU. */ - tpvis = VISIBILITY_ANON; - *walk_subtrees = 0; - break; + t = r; + goto addressable; } break; } diff --git a/gcc/testsuite/g++.dg/reflect/visibility1.C b/gcc/testsuite/g++.dg/reflect/visibility1.C index c47817b9b4ef..e2858c2d4fe2 100644 --- a/gcc/testsuite/g++.dg/reflect/visibility1.C +++ b/gcc/testsuite/g++.dg/reflect/visibility1.C @@ -49,8 +49,8 @@ inline void qux (int x) { int v = 42; - foo <106, ^^x> (); // { dg-final { scan-assembler-not "\t.weak\t_Z3fooILi106EL" } } - var in inline fn - TODO, shall this be exported? - foo <107, ^^v> (); // { dg-final { scan-assembler-not "\t.weak\t_Z3fooILi107EL" } } - var in inline fn - TODO, shall this be exported? + foo <106, ^^x> (); // { dg-final { scan-assembler "\t.weak\t_Z3fooILi106EL" } } - var in inline fn + foo <107, ^^v> (); // { dg-final { scan-assembler "\t.weak\t_Z3fooILi107EL" } } - var in inline fn } template <int N> @@ -58,8 +58,8 @@ void plugh (int x) { int v = 42; - foo <132, ^^x> (); // { dg-final { scan-assembler-not "\t.weak\t_Z3fooILi132EL" } } - var in public fn template instantiation - TODO, shall this be exported? - foo <133, ^^v> (); // { dg-final { scan-assembler-not "\t.weak\t_Z3fooILi133EL" } } - var in public fn template instantiation - TODO, shall this be exported? + foo <132, ^^x> (); // { dg-final { scan-assembler "\t.weak\t_Z3fooILi132EL" } } - var in public fn template instantiation + foo <133, ^^v> (); // { dg-final { scan-assembler "\t.weak\t_Z3fooILi133EL" } } - var in public fn template instantiation foo <134, parameters_of (parent_of (^^v))[0]> (); // { dg-final { scan-assembler "\t.weak\t_Z3fooILi134EL" { target *-*-linux* } } } - fn parm of public fn template instantiation } @@ -80,9 +80,9 @@ void fred (int x) { int v = 42; - foo <138, ^^x> (); // { dg-final { scan-assembler-not "\t.weak\t_Z3fooILi138EL" } } - var in TU-local fn template instantiation - foo <139, ^^v> (); // { dg-final { scan-assembler-not "\t.weak\t_Z3fooILi139EL" } } - var in Tu-local fn template instantiation - foo <140, parameters_of (parent_of (^^v))[0]> (); // { dg-final { scan-assembler-not "\t.weak\t_Z3fooILi140EL" { xfail *-*-* } } } - fn parm of TU-local fn template instantiation - TODO, I think this shouldn't be exported and the mangling of these 3 doesn't include the template parameter + foo <138, ^^x> (); // { dg-final { scan-assembler "\t.weak\t_Z3fooILi138EL" } } - var in fn template instantiation + foo <139, ^^v> (); // { dg-final { scan-assembler "\t.weak\t_Z3fooILi139EL" } } - var in fn template instantiation + foo <140, parameters_of (parent_of (^^v))[0]> (); // { dg-final { scan-assembler "\t.weak\t_Z3fooILi140EL" } } - fn parm of fn template instantiation } [[=1]] void @@ -108,8 +108,8 @@ xyzzy (int x) foo <122, ^^G <int>> (); // { dg-final { scan-assembler-not "\t.weak\t_Z3fooILi122EL" } } - specialization of TU-local template foo <123, ^^G <A>> (); // { dg-final { scan-assembler-not "\t.weak\t_Z3fooILi123EL" } } - specialization of TU-local template foo <124, ^^G <B>> (); // { dg-final { scan-assembler-not "\t.weak\t_Z3fooILi124EL" } } - specialization of TU-local template - foo <125, ^^x> (); // { dg-final { scan-assembler-not "\t.weak\t_Z3fooILi125EL" } } - var in public fn but non-comdat - TODO, shall this be exported? - foo <126, ^^v> (); // { dg-final { scan-assembler-not "\t.weak\t_Z3fooILi126EL" } } - var in public fn but non-comdat - TODO, shall this be exported? + foo <125, ^^x> (); // { dg-final { scan-assembler "\t.weak\t_Z3fooILi125EL" } } - var in public fn but non-comdat + foo <126, ^^v> (); // { dg-final { scan-assembler "\t.weak\t_Z3fooILi126EL" } } - var in public fn but non-comdat foo <127, std::meta::info {}> (); // { dg-final { scan-assembler "\t.weak\t_Z3fooILi127EL" { target *-*-linux* } } } - null reflection foo <128, ^^b> (); // { dg-final { scan-assembler "\t.weak\t_Z3fooILi128EL" { target *-*-linux* } } } - public variable foo <129, ^^c> (); // { dg-final { scan-assembler-not "\t.weak\t_Z3fooILi129EL" } } - TU-local variable
