c++: Fix ICE with concepts and aliases [PR93907].
authorJason Merrill <jason@redhat.com>
Wed, 11 Mar 2020 04:53:01 +0000 (00:53 -0400)
committerJason Merrill <jason@redhat.com>
Wed, 11 Mar 2020 20:45:39 +0000 (16:45 -0400)
The problem here was that we were checking satisfaction once with 'e', a
typedef of 'void', and another time with 'void' directly, and treated them
as different for hashing based on the assumption that
canonicalize_type_argument would have already removed a typedef that wasn't
a complex dependent alias.  But that wasn't happening here, so let's add a
call.

gcc/cp/ChangeLog
2020-03-11  Jason Merrill  <jason@redhat.com>

PR c++/93907
* constraint.cc (tsubst_parameter_mapping): Canonicalize type
argument.

gcc/cp/ChangeLog
gcc/cp/constraint.cc
gcc/cp/cp-tree.h
gcc/cp/pt.c
gcc/testsuite/g++.dg/cpp2a/concepts-using2.C [new file with mode: 0644]

index da768cd2bbe04a130497e3ac226a784edfde04b1..8cde3000e8da083a092a11e3b15ac1af90a8c078 100644 (file)
@@ -1,3 +1,9 @@
+2020-03-11  Jason Merrill  <jason@redhat.com>
+
+       PR c++/93907
+       * constraint.cc (tsubst_parameter_mapping): Canonicalize type
+       argument.
+
 2020-03-11  Marek Polacek  <polacek@redhat.com>
            Jason Merrill  <jason@redhat.com>
 
index 4bb4a3f725228e1578d04e9493df1e1ef2834ad9..697ed6726b806c4cd0498eabfbaec24f57abf3cc 100644 (file)
@@ -2232,7 +2232,11 @@ tsubst_parameter_mapping (tree map, tree args, subst_info info)
       else if (ARGUMENT_PACK_P (arg))
        new_arg = tsubst_argument_pack (arg, args, complain, in_decl);
       if (!new_arg)
-       new_arg = tsubst_template_arg (arg, args, complain, in_decl);
+       {
+         new_arg = tsubst_template_arg (arg, args, complain, in_decl);
+         if (TYPE_P (new_arg))
+           new_arg = canonicalize_type_argument (new_arg, complain);
+       }
       if (new_arg == error_mark_node)
        return error_mark_node;
 
index 0a7381cee3f8de1a8abedb90835332b098ed6c15..757cdd8168a0cd985d406e2b29cb3a001f5e46b3 100644 (file)
@@ -7016,6 +7016,7 @@ extern tree resolve_nondeduced_context_or_error   (tree, tsubst_flags_t);
 extern hashval_t iterative_hash_template_arg (tree arg, hashval_t val);
 extern tree coerce_template_parms               (tree, tree, tree);
 extern tree coerce_template_parms               (tree, tree, tree, tsubst_flags_t);
+extern tree canonicalize_type_argument         (tree, tsubst_flags_t);
 extern void register_local_specialization       (tree, tree);
 extern tree retrieve_local_specialization       (tree);
 extern tree extract_fnparm_pack                 (tree, tree *);
index cb237ba0d9d8f2efbcdb88d0d920edc1806518a5..789ccdbbbd18efb5f554bdcc991a64f10f9cb45b 100644 (file)
@@ -7943,7 +7943,7 @@ template_template_parm_bindings_ok_p (tree tparms, tree targs)
 /* Since type attributes aren't mangled, we need to strip them from
    template type arguments.  */
 
-static tree
+tree
 canonicalize_type_argument (tree arg, tsubst_flags_t complain)
 {
   if (!arg || arg == error_mark_node || arg == TYPE_CANONICAL (arg))
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-using2.C b/gcc/testsuite/g++.dg/cpp2a/concepts-using2.C
new file mode 100644 (file)
index 0000000..b1a45d5
--- /dev/null
@@ -0,0 +1,45 @@
+// PR c++/93907
+// { dg-options -std=gnu++20 }
+
+template <int a> struct c {
+  static constexpr int d = a;
+  typedef c e;
+};
+template <typename> struct f;
+template <typename b> using g = typename f<b>::e;
+struct b;
+template <typename b> struct f { using e = b; };
+template <typename ai> struct m { typedef g<ai> aj; };
+template <typename b> class n { typedef typename m<b>::aj e; };
+template <typename b> using an = typename n<b>::e;
+template <typename> constexpr bool ao = c<true>::d;
+template <typename> constexpr bool i = c<1>::d;
+template <typename> concept bb = i<b>;
+using cc = __int128;
+template <typename> concept cd = bb<cc>;
+template <typename bt> concept ce = requires { requires cd<bt>; };
+template <typename bt> concept h = ce<bt>;
+template <typename bt> concept l = h<bt>;
+template <typename> concept cl = ao<b>;
+template <typename b> concept cp = requires(b j) {
+  requires h<an<decltype(j.begin())>>;
+};
+struct o {
+  template <cl b> requires cp<b> auto operator()(b) {}
+};
+template <typename b> using cm = decltype(o{}(b()));
+template <typename bt> concept ct = l<bt>;
+template <typename da> concept dd = ct<cm<da>>;
+template <typename da> concept de = dd<da>;
+struct {
+  template <de da, typename b> void operator()(da, b);
+} di;
+class p {
+  void begin();
+};
+template <typename> using df = p;
+template <int> void q() {
+  df<int> k;
+  int d;
+  di(k, d);
+}