Compare ARGUMENT_PACKS [pr93933]
authorNathan Sidwell <nathan@acm.org>
Thu, 27 Feb 2020 18:50:36 +0000 (10:50 -0800)
committerNathan Sidwell <nathan@acm.org>
Thu, 27 Feb 2020 18:50:36 +0000 (10:50 -0800)
This implements Jason's suggested approach: 'I'd think that the bug is
that we're treating them as types in the first place; they aren't
types, so they shouldn't reach comptypes.  I'd lean toward adding an
assert to that effect and fixing the caller to use
e.g. template_args_equal.'

PR c++/93933
* pt.c (template_args_equal): Pass ARGUMENT_PACKS through to
cp_tree_equal.
* tree.c (cp_tree_equal): Compare ARGUMENT_PACKS here,
* typeck.c (comptypes): Assert we don't get any argument packs.

gcc/cp/ChangeLog
gcc/cp/pt.c
gcc/cp/tree.c
gcc/cp/typeck.c
gcc/testsuite/g++.dg/concepts/pr93933.C [new file with mode: 0644]

index 5e9eeec..22fe803 100644 (file)
@@ -1,5 +1,11 @@
 2020-02-27  Nathan Sidwell  <nathan@acm.org>
 
+       PR c++/93933
+       * pt.c (template_args_equal): Pass ARGUMENT_PACKS through to
+       cp_tree_equal.
+       * tree.c (cp_tree_equal): Compare ARGUMENT_PACKS here,
+       * typeck.c (comptypes): Assert we don't get any argument packs.
+
        * class.c (adjust_clone_args): Correct arg-checking assert.
        * typeck.c (comptypes): Assert not nulls.
 
index 6c9abb8..622c70b 100644 (file)
@@ -8999,25 +8999,8 @@ template_args_equal (tree ot, tree nt, bool partial_order /* = false */)
                                    PACK_EXPANSION_PATTERN (nt))
            && template_args_equal (PACK_EXPANSION_EXTRA_ARGS (ot),
                                    PACK_EXPANSION_EXTRA_ARGS (nt)));
-  else if (ARGUMENT_PACK_P (ot))
-    {
-      int i, len;
-      tree opack, npack;
-
-      if (!ARGUMENT_PACK_P (nt))
-       return 0;
-
-      opack = ARGUMENT_PACK_ARGS (ot);
-      npack = ARGUMENT_PACK_ARGS (nt);
-      len = TREE_VEC_LENGTH (opack);
-      if (TREE_VEC_LENGTH (npack) != len)
-       return 0;
-      for (i = 0; i < len; ++i)
-       if (!template_args_equal (TREE_VEC_ELT (opack, i),
-                                 TREE_VEC_ELT (npack, i)))
-         return 0;
-      return 1;
-    }
+  else if (ARGUMENT_PACK_P (ot) || ARGUMENT_PACK_P (nt))
+    return cp_tree_equal (ot, nt);
   else if (ot && TREE_CODE (ot) == ARGUMENT_PACK_SELECT)
     gcc_unreachable ();
   else if (TYPE_P (nt))
index 72b3a72..3fc6287 100644 (file)
@@ -3857,12 +3857,27 @@ cp_tree_equal (tree t1, tree t2)
                             DEFERRED_NOEXCEPT_PATTERN (t2))
              && comp_template_args (DEFERRED_NOEXCEPT_ARGS (t1),
                                     DEFERRED_NOEXCEPT_ARGS (t2)));
-      break;
 
     case LAMBDA_EXPR:
       /* Two lambda-expressions are never considered equivalent.  */
       return false;
 
+    case TYPE_ARGUMENT_PACK:
+    case NONTYPE_ARGUMENT_PACK:
+      {
+       tree p1 = ARGUMENT_PACK_ARGS (t1);
+       tree p2 = ARGUMENT_PACK_ARGS (t2);
+       int len = TREE_VEC_LENGTH (p1);
+       if (TREE_VEC_LENGTH (p2) != len)
+         return false;
+
+       for (int ix = 0; ix != len; ix++)
+         if (!template_args_equal (TREE_VEC_ELT (p1, ix),
+                                   TREE_VEC_ELT (p2, ix)))
+           return false;
+       return true;
+      }
+
     default:
       break;
     }
index 42d0b47..2a3243f 100644 (file)
@@ -1485,6 +1485,10 @@ comptypes (tree t1, tree t2, int strict)
 {
   gcc_checking_assert (t1 && t2);
 
+  /* TYPE_ARGUMENT_PACKS are not really types.  */
+  gcc_checking_assert (TREE_CODE (t1) != TYPE_ARGUMENT_PACK
+                      && TREE_CODE (t2) != TYPE_ARGUMENT_PACK);
+
   if (strict == COMPARE_STRICT && comparing_specializations
       && (t1 != TYPE_CANONICAL (t1) || t2 != TYPE_CANONICAL (t2)))
     /* If comparing_specializations, treat dependent aliases as distinct.  */
diff --git a/gcc/testsuite/g++.dg/concepts/pr93933.C b/gcc/testsuite/g++.dg/concepts/pr93933.C
new file mode 100644 (file)
index 0000000..b4f2c36
--- /dev/null
@@ -0,0 +1,31 @@
+// { dg-do compile { target c++17 } }
+// { dg-options "-fconcepts" }
+
+// distilled from <concepts>, via header units
+
+template<typename _ArgTypes>
+struct is_invocable;
+
+template<typename... _Args>
+concept invocable = is_invocable<_Args...>::value;
+
+template<typename _Is>
+requires invocable<_Is>
+class BUG;
+
+template<typename _Is>
+requires invocable<_Is>
+class BUG {}; // { dg-bogus "different constraints" }
+
+template<int> struct is_invocable_NT;
+
+template<int... Ints>
+concept invocable_NT = is_invocable_NT<Ints...>::value;
+
+template<int _Is>
+requires invocable_NT<_Is>
+class BUG_NT;
+
+template<int _Is>
+requires invocable_NT<_Is>
+class BUG_NT {};