On 1/20/26 5:01 AM, Marek Polacek wrote:
On Sat, Jan 17, 2026 at 04:34:11PM +0800, Jason Merrill wrote:
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?
Ah, presumably we want Z3fooILi140EL to be exported here, so the xfail
can be removed. Done in this version. No other change.
Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?
OK.
-- >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 6dbfdeada20..f29f56f6584 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..e2858c2d4fe 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
base-commit: 832de2f102fb988ebe4a304635a796854978d880