Message ID | 20240816160001.1826916-1-ppalka@redhat.com |
---|---|
State | New |
Headers | show |
Series | c++: default targ eligibility refinement [PR101463] | expand |
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); > +}
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); +}