On 10/28/25 4:53 AM, Patrick Palka wrote:
On Sat, 18 Oct 2025, Patrick Palka wrote:

On Sat, 18 Oct 2025, Jason Merrill wrote:

On 10/18/25 6:13 PM, Jason Merrill wrote:
On 10/18/25 5:52 PM, Patrick Palka wrote:
On Sun, 19 Oct 2025, Nathaniel Shead wrote:

On Sat, Oct 18, 2025 at 06:38:57PM +1100, Nathaniel Shead wrote:
On Sat, Oct 18, 2025 at 10:35:15AM +0300, Jason Merrill wrote:
On 10/17/25 7:15 PM, Patrick Palka wrote:
On Fri, 17 Oct 2025, Patrick Palka wrote:

On Fri, 17 Oct 2025, Jason Merrill wrote:

On 10/16/25 2:58 PM, Nathaniel Shead wrote:
I'm not 100% sure this is the correct approach, or whether
I've picked
the right sense of "dependent" to check here; any thoughts?

I think it makes sense to return early in expr_visibility if
the argument is
value-dependent.

I believe that'll break g++.dg/abi/no-linkage-expr1.C, the
value-dependent ((P)0, N) needs to be walked so that the anon
type P
within forces specializations of f and g to have internal
linkage.

This seems similar to PR110323 / r14-9596-g081f8937cb82da except
for
local variables instead of constexpr variables. So maybe the
decl_constant_var_p code path should be used for local vars too?

.. the decl_constant_var_p code path added by r14-9596, to be
precise.

Like with constexpr variables, a (non-constexpr) local variable
within a template argument shouldn't affect linkage because
presumably
it's only used for its value.

Ah, indeed, the distinction is also between dependent expressions in
the
template signature vs those in a template argument.

Maybe it would be better to check for dependent template arguments
in
constrain_visibility_for_template?


That had actually been my first attempt, to check
'dependent_template_arg_p' in 'constrain_visibility_for_template', but
that also caused abi/no-linkage-expr1.C to fail, which is why I
went with the approach I did.

Hmm, right, we want the visibility of g to be affected by the template
arguments to A in the argument type, but determine_visibility for g relies
on the CLASSTYPE_VISIBILITY of that dependent A specialization, and that
change breaks that dependency.

To avoid that I guess we'd need to recurse into the template arguments.

I'll try just ignoring local variables instead and see how that goes.

diff --git a/gcc/cp/decl2.cc b/gcc/cp/decl2.cc
index 0073f83a10c..5efab46ef91 100644
--- a/gcc/cp/decl2.cc
+++ b/gcc/cp/decl2.cc
@@ -2885,7 +2885,12 @@ min_vis_expr_r (tree *tp, int */
*walk_subtrees*/, void *data)
         break;
       }
       addressable:
-      if (! TREE_PUBLIC (t))
+      if (local_variable_p (t))
+    /* Likewise, local variables being used as a template argument are
+       presumably only used for their value, so shouldn't constrain its
+       visibility.  */
+    tpvis = type_visibility (TREE_TYPE (t));

This local_variable_p check needs to be moved up before the
'addressable' label so that for a local_variable_p decl whose address
_is_ needed (in a contrived way e.g. ic<&s != nullptr>), we still
constrain the containing thing's visibility, I think?

That still works out to ic<true> at instantiation time, which should not
have constrained visibility.

Note local_variable_p also includes DECL_LOCAL_DECL_P decls (i.e.
block-scope externs), not sure what the linkage of those is but their
address could in theory be needed in a less contrived way inside a
template argument where it doesn't get folded at instantiation time.

Ah, good point, block-scope externs have linkage, so we don't want to include them.

But perhaps local_variable_p itself is the problem; most uses of the term in the standard have changed to "variables with automatic storage duration". The primary use for a diagnostic in a default argument has now been changed in the standard to refer to whether a local *entity* is odr-usable, which does not apply to block-scope externs. The other uses of "local variable" in the standard are talking about cleanup of automatic variables.

I think the only current use of local_variable_p where it would make sense to include local externs is in tsubst_expr, but that function handles DECL_LOCAL_DECL_P in the previous clause, so it's not needed there either.

So I'd be inclined to change local_variable_p to exclude block-scope externs.

Local statics are another question; they can have "vague linkage" and visibility even if they don't have linkage in the standard. And are also not included in "local entity". But tsubst_expr seems to rely on them being included in local_variable_p.

We might check decl_storage_duration == dk_auto instead of local_variable_p?

And if we're considering backporting the change moving up the check to
before the 'addressable' case should be strictly safer and still fix the
issue.  Or we could change it to directly check VAR/PARM_P &&
DECL_FUNCTION_SCOPE_P (excluding DECL_LOCAL_DECL_P) and keep the check
in the same spot.  Just some ideas, I don't have a strong preference.

So shall we go with Nathaniel's v2 patch, or a variant of it where say
the added local_variable_p handling is combined with the existing
decl_constant_var_p handling (occurring before the 'addressable' label),
or something else?



I think this further illustrates the distinction between a dependent
expression in the template signature vs. on e in a use of a template in
another context.

...or perhaps that's wrong and the problem is really all about local
variables, and min_vis_expr_r treating them as having internal linkage when
really they have no linkage, and this fix is exactly right.

Reply via email to