On 8/16/24 12:00 PM, Patrick Palka wrote:
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.
Makes sense, like so? Bootstrapped and regtested on x86_64-pc-linux-gnu.
OK.
PR c++/101463
gcc/cp/ChangeLog:
* pt.cc (type_unification_real): Directly look for undeduced
parameters in the default argument instead of substituting
and asking if it's dependent.
gcc/testsuite/ChangeLog:
* g++.dg/cpp1z/nontype6.C: New test.
* g++.dg/cpp1z/nontype6a.C: New test.
---
gcc/cp/pt.cc | 41 ++++++++++++++------------
gcc/testsuite/g++.dg/cpp1z/nontype6.C | 24 +++++++++++++++
gcc/testsuite/g++.dg/cpp1z/nontype6a.C | 25 ++++++++++++++++
3 files changed, 71 insertions(+), 19 deletions(-)
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 8725a5eeb3f..ad0f73c2f43 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -23607,28 +23607,31 @@ type_unification_real (tree tparms,
is important if the default argument contains something that
might be instantiation-dependent like access (87480). */
processing_template_decl_sentinel s (!any_dependent_targs);
- tree substed = NULL_TREE;
- if (saw_undeduced == 1 && !any_dependent_targs)
+
+ tree used_tparms = NULL_TREE;
+ if (saw_undeduced == 1)
{
- /* First instatiate in template context, in case we still
- depend on undeduced template parameters. */
- ++processing_template_decl;
- substed = tsubst_template_arg (arg, full_targs, complain,
- NULL_TREE);
- --processing_template_decl;
- if (substed != error_mark_node
- && !uses_template_parms (substed))
- /* We replaced all the tparms, substitute again out of
- template context. */
- substed = NULL_TREE;
+ tree tparms_list = build_tree_list (size_int (1), tparms);
+ used_tparms = find_template_parameters (arg, tparms_list);
+ for (; used_tparms; used_tparms = TREE_CHAIN (used_tparms))
+ {
+ int level, index;
+ template_parm_level_and_index (TREE_VALUE (used_tparms),
+ &level, &index);
+ if (TREE_VEC_ELT (targs, index) == NULL_TREE)
+ break;
+ }
}
- if (!substed)
- substed = tsubst_template_arg (arg, full_targs, complain,
- NULL_TREE);
- if (!uses_template_parms (substed))
- arg = convert_template_argument (parm, substed, full_targs,
- complain, i, NULL_TREE);
+ if (!used_tparms)
+ {
+ /* All template parameters used within this default argument
+ are deduced, so we can use it. */
+ arg = tsubst_template_arg (arg, full_targs, complain,
+ NULL_TREE);
+ arg = convert_template_argument (parm, arg, full_targs,
+ complain, i, NULL_TREE);
+ }
else if (saw_undeduced == 1)
arg = NULL_TREE;
else if (!any_dependent_targs)
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);
+}