[PATCH] c++: adjust visibility of _DECLs with no linkage

Jason Merrill jason@redhat.com
Sat Jan 17 08:34:11 GMT 2026


On 1/17/26 8:46 AM, Marek Polacek wrote:
> Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?
> 
> -- >8 --
> 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.
> ---
>   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 4de6345135f..3a2326b4a1d 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 c47817b9b4e..738edce5fa8 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-not "\t.weak\t_Z3fooILi140EL" { xfail *-*-* } } } - fn parm of fn template instantiation - TODO, I think this shouldn't be exported and the mangling of these 3 doesn't include the template parameter

Why isn't this line changed with the others?

>   }
>   
>   [[=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
> 
> base-commit: f0c9201c1f3003f35fa764fa9ebe864f6e123859



More information about the Gcc-patches mailing list