c++: Some preparatory type canonicalization fixes
authorPatrick Palka <ppalka@redhat.com>
Tue, 2 Mar 2021 12:38:37 +0000 (07:38 -0500)
committerPatrick Palka <ppalka@redhat.com>
Tue, 2 Mar 2021 12:38:37 +0000 (07:38 -0500)
The patches that follow revealed some latent type canonicalization
issues during normalization/satisfaction, due to normalization of
some constraint-expressions now being performed in different contexts
and more frequently (since the normalization caches get frequently
emptied in a checking compiler).  The issues are:

1. In tsubst_parameter_mapping, we canonicalize the arguments of a
   substituted TYPE_ARGUMENT_PACK only if the argument we started with
   wasn't a TYPE_ARGUMENT_PACK.  We should canonicalize a substituted
   TYPE_ARGUMENT_PACK regardless of what we started 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
   built and computed the canonical form of a type that uses one of
   these PARM_DECLs (as say an operand to decltype).  But the canonical
   form depends on the result of cp_tree_equal, which in turn depends on
   the value of CONSTRAINT_VAR_P and DECL_CONTEXT.  So we must set these
   fields earlier, before processing 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 substituted 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.
* pt.c (do_auto_deduction): Canonicalize the result of
do_auto_deduction.  Pass 'complain' to finish_decltype_type.

gcc/testsuite/ChangeLog:

* g++.dg/cpp1z/auto1.C: New test.

gcc/cp/constraint.cc
gcc/cp/parser.c
gcc/cp/pt.c
gcc/testsuite/g++.dg/cpp1z/auto1.C [new file with mode: 0644]

index 3e599fe..39c9798 100644 (file)
@@ -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;
index bb1499a..92de144 100644 (file)
@@ -28817,6 +28817,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;
 }
 
index 6a2c4f3..f324f6a 100644 (file)
@@ -29517,9 +29517,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 (file)
index 0000000..5cc762a
--- /dev/null
@@ -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();
+}