diff mbox series

c++: default targ eligibility refinement [PR101463]

Message ID 20240816160001.1826916-1-ppalka@redhat.com
State New
Headers show
Series c++: default targ eligibility refinement [PR101463] | expand

Commit Message

Patrick Palka Aug. 16, 2024, 4 p.m. UTC
> > 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.

	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

Comments

Jason Merrill Aug. 19, 2024, 5:08 p.m. UTC | #1
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 mbox series

Patch

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