]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c++: duplicate alias templates with decltype [PR 99425]
authorNathan Sidwell <nathan@acm.org>
Thu, 18 Mar 2021 12:12:59 +0000 (05:12 -0700)
committerNathan Sidwell <nathan@acm.org>
Mon, 22 Mar 2021 15:26:57 +0000 (08:26 -0700)
This failure was ultimately from incorrect handling of alias
templates, but required a specific set of occurrences to happen in the
specialization hash table.  This cleans up the specialization
streaming to add alias instantiations at the same point as other
instantiations.  I also removed some unneeded global variables dealing
with mapping of duplicate decl contexts.

PR c++/99425
gcc/cp/
* cp-tree.h (map_context_from, map_context_to): Delete.
(add_mergeable_specialization): Add is_alias parm.
* pt.c (add_mergeable_specialization): Add is_alias parm, add them.
* module.cc (map_context_from, map_context_to): Delete.
(trees_in::decl_value): Add specializations later, adjust call.
Drop useless alias lookup. Set duplicate fn parm context.
(check_mergeable_decl): Drop context mapping.
(trees_in::is_matching_decl): Likewise.
(trees_in::read_function_def): Drop parameter context adjustment
here.
gcc/testsuite/
* g++.dg/modules/pr99425-1.h: New.
* g++.dg/modules/pr99425-1_a.H: New.
* g++.dg/modules/pr99425-1_b.H: New.
* g++.dg/modules/pr99425-1_c.C: New.
* g++.dg/modules/pr99425-2_a.X: New.
* g++.dg/modules/pr99425-2_b.X: New.
* g++.dg/template/pr99425.C: New.

gcc/cp/cp-tree.h
gcc/cp/module.cc
gcc/cp/pt.c
gcc/testsuite/g++.dg/modules/pr99425-1.h [new file with mode: 0644]
gcc/testsuite/g++.dg/modules/pr99425-1_a.H [new file with mode: 0644]
gcc/testsuite/g++.dg/modules/pr99425-1_b.H [new file with mode: 0644]
gcc/testsuite/g++.dg/modules/pr99425-1_c.C [new file with mode: 0644]
gcc/testsuite/g++.dg/modules/pr99425-2_a.X [new file with mode: 0644]
gcc/testsuite/g++.dg/modules/pr99425-2_b.X [new file with mode: 0644]
gcc/testsuite/g++.dg/template/pr99425.C [new file with mode: 0644]

index 81ff375f8a5a93b16bd1ecd16ae27d7004f152fd..e68e3905f80a6d4d2c7202dd54ba489b17e795a7 100644 (file)
@@ -5444,10 +5444,6 @@ extern int comparing_specializations;
    FIXME we should always do this except during deduction/ordering.  */
 extern int comparing_dependent_aliases;
 
-/* When comparing specializations permit context _FROM to match _TO.  */
-extern tree map_context_from;
-extern tree map_context_to;
-
 /* In parser.c.  */
 
 /* Nonzero if we are parsing an unevaluated operand: an operand to
@@ -7241,7 +7237,8 @@ extern void walk_specializations          (bool,
                                                 void *);
 extern tree match_mergeable_specialization     (bool is_decl, spec_entry *);
 extern unsigned get_mergeable_specialization_flags (tree tmpl, tree spec);
-extern void add_mergeable_specialization        (bool is_decl, spec_entry *,
+extern void add_mergeable_specialization        (bool is_decl, bool is_alias,
+                                                spec_entry *,
                                                 tree outer, unsigned);
 extern tree add_outermost_template_args                (tree, tree);
 extern tree add_extra_args                     (tree, tree);
index 551cb66a6d48a5c12d1e9b3d51784e7442fa8e3d..ad3b7d53451abf12c8b9cb6679be2ff8aadbb510 100644 (file)
@@ -279,11 +279,6 @@ static inline tree identifier (const cpp_hashnode *node)
   return HT_IDENT_TO_GCC_IDENT (HT_NODE (const_cast<cpp_hashnode *> (node)));
 }
 
-/* During duplicate detection we need to tell some comparators that
-   these are equivalent.  */
-tree map_context_from;
-tree map_context_to;
-
 /* Id for dumping module information.  */
 int module_dump_id;
 
@@ -8074,16 +8069,6 @@ trees_in::decl_value ()
 
       if (spec.spec)
        set_constraints (decl, spec.spec);
-      if (mk & MK_template_mask
-         || mk == MK_partial)
-       {
-         /* Add to specialization tables now that constraints etc are
-            added.  */
-         bool is_type = mk == MK_partial || !(mk & MK_tmpl_decl_mask);
-
-         spec.spec = is_type ? type : mk & MK_tmpl_tmpl_mask ? inner : decl;
-         add_mergeable_specialization (!is_type, &spec, decl, spec_flags);
-       }
 
       if (TREE_CODE (decl) == INTEGER_CST && !TREE_OVERFLOW (decl))
        {
@@ -8111,28 +8096,25 @@ trees_in::decl_value ()
        /* Set the TEMPLATE_DECL's type.  */
        TREE_TYPE (decl) = TREE_TYPE (inner);
 
+      if (mk & MK_template_mask
+         || mk == MK_partial)
+       {
+         /* Add to specialization tables now that constraints etc are
+            added.  */
+         bool is_type = mk == MK_partial || !(mk & MK_tmpl_decl_mask);
+
+         spec.spec = is_type ? type : mk & MK_tmpl_tmpl_mask ? inner : decl;
+         add_mergeable_specialization (!is_type,
+                                       !is_type && mk & MK_tmpl_alias_mask,
+                                       &spec, decl, spec_flags);
+       }
+
       if (NAMESPACE_SCOPE_P (decl)
          && (mk == MK_named || mk == MK_unique
              || mk == MK_enum || mk == MK_friend_spec)
          && !(VAR_OR_FUNCTION_DECL_P (decl) && DECL_LOCAL_DECL_P (decl)))
        add_module_namespace_decl (CP_DECL_CONTEXT (decl), decl);
 
-      /* The late insertion of an alias here or an implicit member
-         (next block), is ok, because we ensured that all imports were
-         loaded up before we started this cluster.  Thus an insertion
-         from some other import cannot have happened between the
-         merged insertion above and these insertions down here.  */
-      if (mk == MK_alias_spec)
-       {
-         /* Insert into type table.  */
-         tree ti = DECL_TEMPLATE_INFO (inner);
-         spec_entry elt = 
-           {TI_TEMPLATE (ti), TI_ARGS (ti), TREE_TYPE (inner)};
-         tree texist = match_mergeable_specialization (false, &elt);
-         if (texist)
-           set_overrun ();
-       }
-
       if (DECL_ARTIFICIAL (decl)
          && TREE_CODE (decl) == FUNCTION_DECL
          && !DECL_TEMPLATE_INFO (decl)
@@ -8176,6 +8158,14 @@ trees_in::decl_value ()
       if (!is_matching_decl (existing, decl, is_typedef))
        unmatched_duplicate (existing);
 
+      if (inner && TREE_CODE (inner) == FUNCTION_DECL)
+       {
+         tree e_inner = STRIP_TEMPLATE (existing);
+         for (auto parm = DECL_ARGUMENTS (inner);
+              parm; parm = DECL_CHAIN (parm))
+           DECL_CONTEXT (parm) = e_inner;
+       }
+
       /* And our result is the existing node.  */
       decl = existing;
     }
@@ -8186,7 +8176,7 @@ trees_in::decl_value ()
       if (!e)
        {
          spec.spec = inner;
-         add_mergeable_specialization (true, &spec, decl, spec_flags);
+         add_mergeable_specialization (true, false, &spec, decl, spec_flags);
        }
       else if (e != existing)
        set_overrun ();
@@ -10378,8 +10368,9 @@ trees_out::key_mergeable (int tag, merge_kind mk, tree decl, tree inner,
            {
              if (mk & MK_tmpl_alias_mask)
                /* It should be in both tables.  */
-               gcc_assert (match_mergeable_specialization (false, entry)
-                           == TREE_TYPE (existing));
+               gcc_checking_assert
+                 (match_mergeable_specialization (false, entry)
+                  == TREE_TYPE (existing));
              else if (mk & MK_tmpl_tmpl_mask)
                existing = DECL_TI_TEMPLATE (existing);
            }
@@ -10392,7 +10383,7 @@ trees_out::key_mergeable (int tag, merge_kind mk, tree decl, tree inner,
            }
 
          /* The walkabout should have found ourselves.  */
-         gcc_assert (existing == decl);
+         gcc_checking_assert (existing == decl);
        }
     }
   else if (mk != MK_unique)
@@ -10622,8 +10613,6 @@ check_mergeable_decl (merge_kind mk, tree decl, tree ovl, merge_key const &key)
          break;
 
        case FUNCTION_DECL:
-         map_context_from = d_inner;
-         map_context_to = m_inner;
          if (tree m_type = TREE_TYPE (m_inner))
            if ((!key.ret
                 || same_type_p (key.ret, fndecl_declared_return_type (m_inner)))
@@ -10647,7 +10636,6 @@ check_mergeable_decl (merge_kind mk, tree decl, tree ovl, merge_key const &key)
                if (cp_tree_equal (key.constraints, m_reqs))
                  found = match;
              }
-         map_context_from = map_context_to = NULL_TREE;
          break;
 
        case TYPE_DECL:
@@ -11022,12 +11010,6 @@ trees_in::is_matching_decl (tree existing, tree decl, bool is_typedef)
       gcc_checking_assert (TREE_CODE (e_inner) == TREE_CODE (d_inner));
     }
 
-  gcc_checking_assert (!map_context_from);
-  /* This mapping requres the new decl on the lhs and the existing
-     entity on the rhs of the comparitors below.  */
-  map_context_from = d_inner;
-  map_context_to = e_inner;
-
   if (TREE_CODE (d_inner) == FUNCTION_DECL)
     {
       tree e_ret = fndecl_declared_return_type (existing);
@@ -11104,7 +11086,6 @@ trees_in::is_matching_decl (tree existing, tree decl, bool is_typedef)
   else if (!cp_tree_equal (TREE_TYPE (decl), TREE_TYPE (existing)))
     {
     mismatch:
-      map_context_from = map_context_to = NULL_TREE;
       if (DECL_IS_UNDECLARED_BUILTIN (existing))
        /* Just like duplicate_decls, presum the user knows what
           they're doing in overriding a builtin.   */
@@ -11121,8 +11102,6 @@ trees_in::is_matching_decl (tree existing, tree decl, bool is_typedef)
        }
     }
 
-  map_context_from = map_context_to = NULL_TREE;
-
   if (DECL_IS_UNDECLARED_BUILTIN (existing)
       && !DECL_IS_UNDECLARED_BUILTIN (decl))
     {
@@ -11463,10 +11442,6 @@ trees_in::read_function_def (tree decl, tree maybe_template)
   tree maybe_dup = odr_duplicate (maybe_template, DECL_SAVED_TREE (decl));
   bool installing = maybe_dup && !DECL_SAVED_TREE (decl);
 
-  if (maybe_dup)
-    for (auto parm = DECL_ARGUMENTS (maybe_dup); parm; parm = DECL_CHAIN (parm))
-      DECL_CONTEXT (parm) = decl;
-
   if (int wtag = i ())
     {
       int tag = 1;
@@ -12881,10 +12856,11 @@ specialization_add (bool decl_p, spec_entry *entry, void *data_)
                           || DECL_CLASS_TEMPLATE_P (entry->tmpl));
 
        /* Only alias templates can appear in both tables (and
-         if they're in the type table they must also be in the decl table).  */
+         if they're in the type table they must also be in the decl
+         table).  */
        gcc_checking_assert
         (!match_mergeable_specialization (true, entry)
-         == (decl_p || !DECL_ALIAS_TEMPLATE_P (entry->tmpl)));
+         == !DECL_ALIAS_TEMPLATE_P (entry->tmpl));
     }
   else if (VAR_OR_FUNCTION_DECL_P (entry->spec))
     gcc_checking_assert (!DECL_LOCAL_DECL_P (entry->spec));
index 933dfc392080d5798c63c6244093302d8e3c78cb..2736bb43299e9d156175951fb79e6e9a2f2d98e5 100644 (file)
@@ -30009,25 +30009,41 @@ get_mergeable_specialization_flags (tree tmpl, tree decl)
    get_mergeable_specialization_flags.  */
 
 void
-add_mergeable_specialization (bool decl_p, spec_entry *elt,
+add_mergeable_specialization (bool decl_p, bool alias_p, spec_entry *elt,
                              tree decl, unsigned flags)
 {
-  hash_table<spec_hasher> *specializations
-    = decl_p ? decl_specializations : type_specializations;
-
   hashval_t hash = spec_hasher::hash (elt);
-  auto *slot = specializations->find_slot_with_hash (elt, hash, INSERT);
-
-  /* We don't distinguish different constrained partial type
-     specializations, so there could be duplicates.  Everything else
-     must be new.   */
-  if (!(flags & 2 && *slot))
+  if (decl_p)
     {
-      gcc_checking_assert (!*slot);
+      auto *slot = decl_specializations->find_slot_with_hash (elt, hash, INSERT);
 
+      gcc_checking_assert (!*slot);
       auto entry = ggc_alloc<spec_entry> ();
       *entry = *elt;
       *slot = entry;
+
+      if (alias_p)
+       {
+         elt->spec = TREE_TYPE (elt->spec);
+         gcc_checking_assert (elt->spec);
+       }
+    }
+
+  if (!decl_p || alias_p)
+    {
+      auto *slot = type_specializations->find_slot_with_hash (elt, hash, INSERT);
+
+      /* We don't distinguish different constrained partial type
+        specializations, so there could be duplicates.  Everything else
+        must be new.   */
+      if (!(flags & 2 && *slot))
+       {
+         gcc_checking_assert (!*slot);
+
+         auto entry = ggc_alloc<spec_entry> ();
+         *entry = *elt;
+         *slot = entry;
+       }
     }
 
   if (flags & 1)
diff --git a/gcc/testsuite/g++.dg/modules/pr99425-1.h b/gcc/testsuite/g++.dg/modules/pr99425-1.h
new file mode 100644 (file)
index 0000000..de167a6
--- /dev/null
@@ -0,0 +1,11 @@
+template<typename T>
+struct make_signed 
+{
+  using type = int;
+};
+
+template<typename S>
+using make_signed_t = typename make_signed<S>::type;
+
+template<typename U>
+auto ssize (U &parm) -> make_signed_t<decltype(parm.call())>;
diff --git a/gcc/testsuite/g++.dg/modules/pr99425-1_a.H b/gcc/testsuite/g++.dg/modules/pr99425-1_a.H
new file mode 100644 (file)
index 0000000..6117d4a
--- /dev/null
@@ -0,0 +1,4 @@
+// PR 99425 alias dependent specializations
+// { dg-additional-options {-fmodule-header} }
+// { dg-module-cmi {} }
+#include "pr99425-1.h"
diff --git a/gcc/testsuite/g++.dg/modules/pr99425-1_b.H b/gcc/testsuite/g++.dg/modules/pr99425-1_b.H
new file mode 100644 (file)
index 0000000..98303a0
--- /dev/null
@@ -0,0 +1,19 @@
+// { dg-additional-options {-fmodule-header -fdump-lang-module-alias} }
+// { dg-module-cmi {} }
+
+#include "pr99425-1.h"
+
+import "pr99425-1_a.H";
+
+struct Cont
+{
+  int call ();
+};
+
+inline void widget (Cont parm)
+{
+  ssize (parm);
+}
+
+// { dg-final { scan-lang-dump {Read:-[0-9]*'s alias spec merge key \(new\) type_decl:'::make_signed_t'\n  ...  Read:-[0-9]*'s type spec merge key \(new\) type_decl:'::make_signed'\n  Read:-1's named merge key \(matched\) template_decl:'::template ssize'} module } }
+
diff --git a/gcc/testsuite/g++.dg/modules/pr99425-1_c.C b/gcc/testsuite/g++.dg/modules/pr99425-1_c.C
new file mode 100644 (file)
index 0000000..28ef3a1
--- /dev/null
@@ -0,0 +1,11 @@
+// { dg-additional-options {-fmodules-ts -fdump-lang-module-alias} }
+import "pr99425-1_a.H";
+import "pr99425-1_b.H";
+
+void frob (Cont parm)
+{
+  ssize (parm);
+}
+
+// { dg-final { scan-lang-dump {Read:-1's named merge key \(new\) template_decl:'::template ssize'} module } }
+// { dg-final { scan-lang-dump {Read:-1's named merge key \(matched\) template_decl:'::template ssize'} module } }
diff --git a/gcc/testsuite/g++.dg/modules/pr99425-2_a.X b/gcc/testsuite/g++.dg/modules/pr99425-2_a.X
new file mode 100644 (file)
index 0000000..9a44dc3
--- /dev/null
@@ -0,0 +1,7 @@
+// PR 99425 template aliases can cause equivalences in the hash
+// tables, and for extra excitement be reordered on rehash.
+
+// { dg-additional-options {-x c++-system-header stdexcept -fmodules-ts} }
+// { dg-prune-output {linker input file unused} }
+
+No! DO NOT COMPILE;
diff --git a/gcc/testsuite/g++.dg/modules/pr99425-2_b.X b/gcc/testsuite/g++.dg/modules/pr99425-2_b.X
new file mode 100644 (file)
index 0000000..5e45354
--- /dev/null
@@ -0,0 +1,4 @@
+// { dg-additional-options {-x c++-system-header mutex -fmodules-ts} }
+// { dg-prune-output {linker input file unused} }
+
+No! DO NOT COMPILE;
diff --git a/gcc/testsuite/g++.dg/template/pr99425.C b/gcc/testsuite/g++.dg/template/pr99425.C
new file mode 100644 (file)
index 0000000..fd49c86
--- /dev/null
@@ -0,0 +1,45 @@
+// { dg-do compile { target c++20 } }
+// a potential fix for 99425 generated an ICE here.
+
+template<typename _Tp>
+struct is_nothrow_destructible;
+
+template<typename _Tp>
+struct common_reference;
+
+template<typename _Tp>
+concept same_as
+  = true;
+
+template<typename _Sent, typename _Iter>
+concept sentinel_for
+  = same_as<common_reference<_Sent>>
+  && is_nothrow_destructible<_Iter>::value;
+
+template<typename _Tp>
+concept __member_end
+  = requires (_Tp& __t)
+  {
+    { true }
+    -> sentinel_for<decltype(__t)>;
+  };
+
+template<typename _Tp>
+concept __adl_end
+  = requires (_Tp& __t)
+  {
+    { true }
+    -> sentinel_for<decltype(__t)>;
+  };
+
+template<typename _Tp>
+requires __member_end<_Tp> || __adl_end<_Tp>
+  void
+  Bar (_Tp&& __t)
+{
+}
+
+void test03 ()
+{
+  Bar (1); // { dg-error "no matching function" }
+}