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?

-- >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
-- 
2.52.0

Reply via email to