On 10/22/24 1:54 PM, 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.

OK.

-- >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);
+}

Reply via email to