On Tue, 22 Oct 2024, Patrick Palka wrote:
> On Tue, 9 Jan 2024, Jason Merrill wrote:
>
> > On 1/5/24 15:01, Patrick Palka wrote:
> > > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this
> > > look OK for trunk?
> > >
> > > -- >8 --
> > >
> > > Here during default template argument substitution we wrongly consider
> > > the (substituted) default arguments v and vt<int> as value-dependent[1]
> > > which ultimately leads to deduction failure for the calls.
> > >
> > > The bogus value_dependent_expression_p result aside, I noticed
> > > type_unification_real during default targ substitution keeps track of
> > > whether all previous targs are known and non-dependent, as is the case
> > > for these calls. And in such cases it should be safe to avoid checking
> > > dependence of the substituted default targ and just assume it's not.
> > > This patch implements this optimization, which lets us accept both
> > > testcases by sidestepping the value_dependent_expression_p issue
> > > altogether.
> >
> > Hmm, maybe instead of substituting and asking if it's dependent, we should
> > specifically look for undeduced parameters.
>
> We took this approach with r15-3038-g5348e3cb9bc99d for GCC 15, but it
> might be too risky to backport. The original approach of avoiding the
> dependence check when we know all previous arguments are non-dependent
> seems safer, and we can simplify it a bit even.
>
> What do you think about backporting the following in order to fix 101463
> on the release branches? Bootstrappped and regtested on
> x86_64-pc-linux-gnu on the 14 branch.
Ping.
>
> -- >8 --
>
> Subject: [PATCH] c++: reference variable as default targ [PR101463]
>
> Here during default template argument substitution we wrongly consider
> the (substituted) default arguments v and vt<int> as value-dependent[1]
> which ultimately leads to deduction failure for the calls.
>
> The bogus value_dependent_expression_p result aside, I noticed
> type_unification_real during default targ substitution keeps track of
> whether all previous targs are known and non-dependent, as is the case
> for these calls. And in such cases it should be safe to avoid checking
> dependence of the substituted default targ and just assume it's not.
> This patch implements this optimization, which lets us accept both
> testcases by sidestepping the value_dependent_expression_p issue
> altogether.
>
> Note that for GCC 15 we fixed this differently, see
> r15-3038-g5348e3cb9bc99d.
>
> PR c++/101463
>
> gcc/cp/ChangeLog:
>
> * pt.cc (type_unification_real): Avoid checking dependence of
> a substituted default template argument if we can assume it's
> non-dependent.
>
> gcc/testsuite/ChangeLog:
>
> * g++.dg/cpp1z/nontype6.C: New test.
> * g++.dg/cpp1z/nontype6a.C: New test.
> ---
> gcc/cp/pt.cc | 4 +++-
> gcc/testsuite/g++.dg/cpp1z/nontype6.C | 24 ++++++++++++++++++++++++
> gcc/testsuite/g++.dg/cpp1z/nontype6a.C | 25 +++++++++++++++++++++++++
> 3 files changed, 52 insertions(+), 1 deletion(-)
> create mode 100644 gcc/testsuite/g++.dg/cpp1z/nontype6.C
> create mode 100644 gcc/testsuite/g++.dg/cpp1z/nontype6a.C
>
> diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> index 818d5b65edc..4f83426fb56 100644
> --- a/gcc/cp/pt.cc
> +++ b/gcc/cp/pt.cc
> @@ -23651,12 +23651,14 @@ type_unification_real (tree tparms,
> /* We replaced all the tparms, substitute again out of
> template context. */
> substed = NULL_TREE;
> + else
> + processing_template_decl = 1;
> }
> if (!substed)
> substed = tsubst_template_arg (arg, full_targs, complain,
> NULL_TREE);
>
> - if (!uses_template_parms (substed))
> + if (!processing_template_decl || !uses_template_parms (substed))
> arg = convert_template_argument (parm, substed, full_targs,
> complain, i, NULL_TREE);
> else if (saw_undeduced == 1)
> diff --git a/gcc/testsuite/g++.dg/cpp1z/nontype6.C
> b/gcc/testsuite/g++.dg/cpp1z/nontype6.C
> new file mode 100644
> index 00000000000..06cd234cc61
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp1z/nontype6.C
> @@ -0,0 +1,24 @@
> +// PR c++/101463
> +// { dg-do compile { target c++17 } }
> +
> +int a;
> +
> +int& v = a;
> +
> +template<const int& = v>
> +void f(int) { }
> +
> +template<class T, int& = v>
> +void g(T) { }
> +
> +template<class T>
> +int& vt = a;
> +
> +template<class T, int& = vt<T>>
> +void h(T) { }
> +
> +int main() {
> + f(0);
> + g(0);
> + h(0);
> +}
> diff --git a/gcc/testsuite/g++.dg/cpp1z/nontype6a.C
> b/gcc/testsuite/g++.dg/cpp1z/nontype6a.C
> new file mode 100644
> index 00000000000..8bc40a0505c
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp1z/nontype6a.C
> @@ -0,0 +1,25 @@
> +// PR c++/101463
> +// A version of nontype6.C where v and vt are constexpr.
> +// { dg-do compile { target c++17 } }
> +
> +int a;
> +
> +constexpr int& v = a;
> +
> +template<const int& = v>
> +void f(int) { }
> +
> +template<class T, const int& = v>
> +void g(T) { }
> +
> +template<class T>
> +constexpr int& vt = a;
> +
> +template<class T, const int& = vt<T>>
> +void h(T) { }
> +
> +int main() {
> + f(0);
> + g(0);
> + h(0);
> +}
> --
> 2.47.0.107.g34b6ce9b30
>
>