diff mbox series

[2/4] c++: Preparatory type canonicalization fixes

Message ID 20210208190352.1475602-2-ppalka@redhat.com
State New
Headers show
Series [1/4] c++: Avoid building garbage trees from tsubst_requires_expr | expand

Commit Message

Patrick Palka Feb. 8, 2021, 7:03 p.m. UTC
The subsequent patches revealed some latent type canonicalization
issues during normalization and satisfaction:

1. In tsubst_parameter_mapping, we're canonicalizing the arguments of a
   TYPE_ARGUMENT_PACK only if 'arg' wasn't a TYPE_ARGUMENT_PACK to begin
   with.

2. We currently set DECL_CONTEXT and CONSTRAINT_VAR_P on each of the
   parameters introduced in a requires-expression _after_ we're done
   processing the requirements.  But meanwhile we may have already
   computed the canonical form of a type that depends on one of these
   PARM_DECLs, which depends on the result of cp_tree_equal, which
   depends on CONSTRAINT_VAR_P and DECL_CONTEXT.  So we must set these
   fields earlier, before processing the requirements.

3. In do_auto_deduction, we use the result of finish_decltype_type later
   as a template argument, so we should canonicalize the result too.
   (While we're here, we should pass 'complain' to finish_decltype_type,
   which fixes the testcase auto1.C below.)

gcc/cp/ChangeLog:

	* constraint.cc (tsubst_parameter_mapping): Canonicalize the
	arguments of a TYPE_ARGUMENT_PACK even if we've started with a
	TYPE_ARGUMENT_PACK.
	(finish_requires_expr): Don't set DECL_CONTEXT and
	CONSTRAINT_VAR_P on each of the introduced parameters here.
	* parser.c (cp_parser_requirement_parameter_list): Instead set
	these fields earlier, here.

gcc/testsuite/ChangeLog:

	* g++.dg/cpp1z/auto1.C: New test.
---
 gcc/cp/constraint.cc               | 25 ++++++++-----------------
 gcc/cp/parser.c                    | 12 ++++++++++++
 gcc/cp/pt.c                        |  8 ++++++--
 gcc/testsuite/g++.dg/cpp1z/auto1.C | 13 +++++++++++++
 4 files changed, 39 insertions(+), 19 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp1z/auto1.C

Comments

Jason Merrill Feb. 9, 2021, 5:11 a.m. UTC | #1
On 2/8/21 2:03 PM, Patrick Palka wrote:
> The subsequent patches revealed some latent type canonicalization
> issues during normalization and satisfaction:
> 
> 1. In tsubst_parameter_mapping, we're canonicalizing the arguments of a
>     TYPE_ARGUMENT_PACK only if 'arg' wasn't a TYPE_ARGUMENT_PACK to begin
>     with.
> 
> 2. We currently set DECL_CONTEXT and CONSTRAINT_VAR_P on each of the
>     parameters introduced in a requires-expression _after_ we're done
>     processing the requirements.  But meanwhile we may have already
>     computed the canonical form of a type that depends on one of these
>     PARM_DECLs, which depends on the result of cp_tree_equal, which
>     depends on CONSTRAINT_VAR_P and DECL_CONTEXT.  So we must set these
>     fields earlier, before processing the requirements.
> 
> 3. In do_auto_deduction, we use the result of finish_decltype_type later
>     as a template argument, so we should canonicalize the result too.
>     (While we're here, we should pass 'complain' to finish_decltype_type,
>     which fixes the testcase auto1.C below.)
> 
> gcc/cp/ChangeLog:
> 
> 	* constraint.cc (tsubst_parameter_mapping): Canonicalize the
> 	arguments of a TYPE_ARGUMENT_PACK even if we've started with a
> 	TYPE_ARGUMENT_PACK.
> 	(finish_requires_expr): Don't set DECL_CONTEXT and
> 	CONSTRAINT_VAR_P on each of the introduced parameters here.
> 	* parser.c (cp_parser_requirement_parameter_list): Instead set
> 	these fields earlier, here.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* g++.dg/cpp1z/auto1.C: New test.
> ---
>   gcc/cp/constraint.cc               | 25 ++++++++-----------------
>   gcc/cp/parser.c                    | 12 ++++++++++++
>   gcc/cp/pt.c                        |  8 ++++++--
>   gcc/testsuite/g++.dg/cpp1z/auto1.C | 13 +++++++++++++
>   4 files changed, 39 insertions(+), 19 deletions(-)
>   create mode 100644 gcc/testsuite/g++.dg/cpp1z/auto1.C
> 
> diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
> index 3e599fe8c47..39c97986082 100644
> --- a/gcc/cp/constraint.cc
> +++ b/gcc/cp/constraint.cc
> @@ -2319,15 +2319,15 @@ tsubst_parameter_mapping (tree map, tree args, subst_info info)
>   	  new_arg = tsubst_template_arg (arg, args, complain, in_decl);
>   	  if (TYPE_P (new_arg))
>   	    new_arg = canonicalize_type_argument (new_arg, complain);
> -	  if (TREE_CODE (new_arg) == TYPE_ARGUMENT_PACK)
> +	}
> +      if (TREE_CODE (new_arg) == TYPE_ARGUMENT_PACK)
> +	{
> +	  tree pack_args = ARGUMENT_PACK_ARGS (new_arg);
> +	  for (int i = 0; i < TREE_VEC_LENGTH (pack_args); i++)
>   	    {
> -	      tree pack_args = ARGUMENT_PACK_ARGS (new_arg);
> -	      for (int i = 0; i < TREE_VEC_LENGTH (pack_args); i++)
> -		{
> -		  tree& pack_arg = TREE_VEC_ELT (pack_args, i);
> -		  if (TYPE_P (pack_arg))
> -		    pack_arg = canonicalize_type_argument (pack_arg, complain);
> -		}
> +	      tree& pack_arg = TREE_VEC_ELT (pack_args, i);
> +	      if (TYPE_P (pack_arg))
> +		pack_arg = canonicalize_type_argument (pack_arg, complain);
>   	    }
>   	}
>         if (new_arg == error_mark_node)
> @@ -3253,15 +3253,6 @@ evaluate_concept_check (tree check, tsubst_flags_t complain)
>   tree
>   finish_requires_expr (location_t loc, tree parms, tree reqs)
>   {
> -  /* Modify the declared parameters by removing their context
> -     so they don't refer to the enclosing scope and explicitly
> -     indicating that they are constraint variables. */
> -  for (tree parm = parms; parm; parm = DECL_CHAIN (parm))
> -    {
> -      DECL_CONTEXT (parm) = NULL_TREE;
> -      CONSTRAINT_VAR_P (parm) = true;
> -    }
> -
>     /* Build the node. */
>     tree r = build_min (REQUIRES_EXPR, boolean_type_node, parms, reqs, NULL_TREE);
>     TREE_SIDE_EFFECTS (r) = false;
> diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
> index 5da8670f0e2..fef10b9661d 100644
> --- a/gcc/cp/parser.c
> +++ b/gcc/cp/parser.c
> @@ -28779,6 +28779,18 @@ cp_parser_requirement_parameter_list (cp_parser *parser)
>     if (!parens.require_close (parser))
>       return error_mark_node;
>   
> +  /* Modify the declared parameters by removing their context
> +     so they don't refer to the enclosing scope and explicitly
> +     indicating that they are constraint variables. */
> +  for (tree parm = parms; parm; parm = TREE_CHAIN (parm))
> +    {
> +      if (parm == void_list_node || parm == explicit_void_list_node)
> +	break;
> +      tree decl = TREE_VALUE (parm);
> +      DECL_CONTEXT (decl) = NULL_TREE;
> +      CONSTRAINT_VAR_P (decl) = true;
> +    }
> +
>     return parms;
>   }
>   
> diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
> index 3605b67e424..bceb942e79a 100644
> --- a/gcc/cp/pt.c
> +++ b/gcc/cp/pt.c
> @@ -29478,9 +29478,13 @@ do_auto_deduction (tree type, tree init, tree auto_node,
>   		 || ((TREE_CODE (init) == COMPONENT_REF
>   		      || TREE_CODE (init) == SCOPE_REF)
>   		     && !REF_PARENTHESIZED_P (init)));
> +      tree deduced = finish_decltype_type (init, id, complain);
> +      deduced = canonicalize_type_argument (deduced, complain);
> +      if (deduced == error_mark_node)
> +	return error_mark_node;
>         targs = make_tree_vec (1);
> -      TREE_VEC_ELT (targs, 0)
> -	= finish_decltype_type (init, id, tf_warning_or_error);
> +      TREE_VEC_ELT (targs, 0) = deduced;
> +      /* FIXME: These errors ought to be diagnosed at parse time. */

Perhaps in grokdeclarator.

The patch is OK.

>         if (type != auto_node)
>   	{
>             if (complain & tf_error)
> diff --git a/gcc/testsuite/g++.dg/cpp1z/auto1.C b/gcc/testsuite/g++.dg/cpp1z/auto1.C
> new file mode 100644
> index 00000000000..5cc762a386e
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp1z/auto1.C
> @@ -0,0 +1,13 @@
> +// Verify that deduction failure of the decltype(auto) template parameter is
> +// a SFINAE error.
> +// { dg-do compile { target c++17 } }
> +
> +template <class> void f();
> +template <class> void f(int);
> +
> +template <class T = int, decltype(auto) = &f<T>> void g();
> +template <class = int> void g();
> +
> +int main() {
> +  g();
> +}
>
diff mbox series

Patch

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 3e599fe8c47..39c97986082 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -2319,15 +2319,15 @@  tsubst_parameter_mapping (tree map, tree args, subst_info info)
 	  new_arg = tsubst_template_arg (arg, args, complain, in_decl);
 	  if (TYPE_P (new_arg))
 	    new_arg = canonicalize_type_argument (new_arg, complain);
-	  if (TREE_CODE (new_arg) == TYPE_ARGUMENT_PACK)
+	}
+      if (TREE_CODE (new_arg) == TYPE_ARGUMENT_PACK)
+	{
+	  tree pack_args = ARGUMENT_PACK_ARGS (new_arg);
+	  for (int i = 0; i < TREE_VEC_LENGTH (pack_args); i++)
 	    {
-	      tree pack_args = ARGUMENT_PACK_ARGS (new_arg);
-	      for (int i = 0; i < TREE_VEC_LENGTH (pack_args); i++)
-		{
-		  tree& pack_arg = TREE_VEC_ELT (pack_args, i);
-		  if (TYPE_P (pack_arg))
-		    pack_arg = canonicalize_type_argument (pack_arg, complain);
-		}
+	      tree& pack_arg = TREE_VEC_ELT (pack_args, i);
+	      if (TYPE_P (pack_arg))
+		pack_arg = canonicalize_type_argument (pack_arg, complain);
 	    }
 	}
       if (new_arg == error_mark_node)
@@ -3253,15 +3253,6 @@  evaluate_concept_check (tree check, tsubst_flags_t complain)
 tree
 finish_requires_expr (location_t loc, tree parms, tree reqs)
 {
-  /* Modify the declared parameters by removing their context
-     so they don't refer to the enclosing scope and explicitly
-     indicating that they are constraint variables. */
-  for (tree parm = parms; parm; parm = DECL_CHAIN (parm))
-    {
-      DECL_CONTEXT (parm) = NULL_TREE;
-      CONSTRAINT_VAR_P (parm) = true;
-    }
-
   /* Build the node. */
   tree r = build_min (REQUIRES_EXPR, boolean_type_node, parms, reqs, NULL_TREE);
   TREE_SIDE_EFFECTS (r) = false;
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 5da8670f0e2..fef10b9661d 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -28779,6 +28779,18 @@  cp_parser_requirement_parameter_list (cp_parser *parser)
   if (!parens.require_close (parser))
     return error_mark_node;
 
+  /* Modify the declared parameters by removing their context
+     so they don't refer to the enclosing scope and explicitly
+     indicating that they are constraint variables. */
+  for (tree parm = parms; parm; parm = TREE_CHAIN (parm))
+    {
+      if (parm == void_list_node || parm == explicit_void_list_node)
+	break;
+      tree decl = TREE_VALUE (parm);
+      DECL_CONTEXT (decl) = NULL_TREE;
+      CONSTRAINT_VAR_P (decl) = true;
+    }
+
   return parms;
 }
 
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 3605b67e424..bceb942e79a 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -29478,9 +29478,13 @@  do_auto_deduction (tree type, tree init, tree auto_node,
 		 || ((TREE_CODE (init) == COMPONENT_REF
 		      || TREE_CODE (init) == SCOPE_REF)
 		     && !REF_PARENTHESIZED_P (init)));
+      tree deduced = finish_decltype_type (init, id, complain);
+      deduced = canonicalize_type_argument (deduced, complain);
+      if (deduced == error_mark_node)
+	return error_mark_node;
       targs = make_tree_vec (1);
-      TREE_VEC_ELT (targs, 0)
-	= finish_decltype_type (init, id, tf_warning_or_error);
+      TREE_VEC_ELT (targs, 0) = deduced;
+      /* FIXME: These errors ought to be diagnosed at parse time. */
       if (type != auto_node)
 	{
           if (complain & tf_error)
diff --git a/gcc/testsuite/g++.dg/cpp1z/auto1.C b/gcc/testsuite/g++.dg/cpp1z/auto1.C
new file mode 100644
index 00000000000..5cc762a386e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/auto1.C
@@ -0,0 +1,13 @@ 
+// Verify that deduction failure of the decltype(auto) template parameter is
+// a SFINAE error.
+// { dg-do compile { target c++17 } }
+
+template <class> void f();
+template <class> void f(int);
+
+template <class T = int, decltype(auto) = &f<T>> void g();
+template <class = int> void g();
+
+int main() {
+  g();
+}