c++: Template hash access
authorNathan Sidwell <nathan@acm.org>
Thu, 19 Nov 2020 21:18:09 +0000 (13:18 -0800)
committerNathan Sidwell <nathan@acm.org>
Thu, 19 Nov 2020 21:25:00 +0000 (13:25 -0800)
This exposes the template specialization table, so the modules
machinery may access it.  The hashed entity (tmpl, args & spec) is
available, along with a hash table walker.  We also need a way of
finding or inserting entries, along with some bookkeeping fns to deal
with the instantiation and (partial) specialization lists.

gcc/cp/
* cp-tree.h (struct spec_entry): Moved from pt.c.
(walk_specializations, match_mergeable_specialization)
(get_mergeable_specialization_flags)
(add_mergeable_specialization): Declare.
* pt.c (struct spec_entry): Moved to cp-tree.h.
(walk_specializations, match_mergeable_specialization)
(get_mergeable_specialization_flags)
(add_mergeable_specialization): New.

gcc/cp/cp-tree.h
gcc/cp/pt.c

index 0c4b74a8895012440c89f69defebaa8e7e0980f3..021de76e14255eaae8990748270734053b255710 100644 (file)
@@ -5403,6 +5403,14 @@ public:
   hash_map<tree, tree> *saved;
 };
 
+/* Entry in the specialization hash table.  */
+struct GTY((for_user)) spec_entry
+{
+  tree tmpl;  /* The general template this is a specialization of.  */
+  tree args;  /* The args for this (maybe-partial) specialization.  */
+  tree spec;  /* The specialization itself.  */
+};
+
 /* in class.c */
 
 extern int current_class_depth;
@@ -6994,6 +7002,15 @@ extern bool copy_guide_p                 (const_tree);
 extern bool template_guide_p                   (const_tree);
 extern bool builtin_guide_p                    (const_tree);
 extern void store_explicit_specifier           (tree, tree);
+extern void walk_specializations               (bool,
+                                                void (*)(bool, spec_entry *,
+                                                         void *),
+                                                void *);
+extern tree match_mergeable_specialization     (bool is_decl, tree tmpl,
+                                                tree args, tree spec);
+extern unsigned get_mergeable_specialization_flags (tree tmpl, tree spec);
+extern void add_mergeable_specialization        (tree tmpl, tree args,
+                                                tree spec, unsigned);
 extern tree add_outermost_template_args                (tree, tree);
 extern tree add_extra_args                     (tree, tree);
 extern tree build_extra_args                   (tree, tree, tsubst_flags_t);
index a1b6631d6915cefac8b5f36fcb87603b019e7821..463b1c3a57d6de4ab6e2c39792474e9c1a858241 100644 (file)
@@ -103,13 +103,6 @@ local_specialization_stack::~local_specialization_stack ()
 /* True if we've recursed into fn_type_unification too many times.  */
 static bool excessive_deduction_depth;
 
-struct GTY((for_user)) spec_entry
-{
-  tree tmpl;
-  tree args;
-  tree spec;
-};
-
 struct spec_hasher : ggc_ptr_hash<spec_entry>
 {
   static hashval_t hash (spec_entry *);
@@ -29625,6 +29618,101 @@ declare_integer_pack (void)
                              CP_BUILT_IN_INTEGER_PACK);
 }
 
+/* Walk the decl or type specialization table calling FN on each
+   entry.  */
+
+void
+walk_specializations (bool decls_p,
+                     void (*fn) (bool decls_p, spec_entry *entry, void *data),
+                     void *data)
+{
+  spec_hash_table *table = decls_p ? decl_specializations
+    : type_specializations;
+  spec_hash_table::iterator end (table->end ());
+  for (spec_hash_table::iterator iter (table->begin ()); iter != end; ++iter)
+    fn (decls_p, *iter, data);
+}
+
+/* Lookup the specialization of TMPL, ARGS in the decl or type
+   specialization table.  Return what's there, or if SPEC is non-null,
+   add it and return NULL.  */
+
+tree
+match_mergeable_specialization (bool decl_p, tree tmpl, tree args, tree spec)
+{
+  spec_entry elt = {tmpl, args, spec};
+  hash_table<spec_hasher> *specializations
+    = decl_p ? decl_specializations : type_specializations;
+  hashval_t hash = spec_hasher::hash (&elt);
+  spec_entry **slot
+    = specializations->find_slot_with_hash (&elt, hash,
+                                           spec ? INSERT : NO_INSERT);
+  spec_entry *entry = slot ? *slot: NULL;
+  
+  if (entry)
+    return entry->spec;
+
+  if (spec)
+    {
+      entry = ggc_alloc<spec_entry> ();
+      *entry = elt;
+      *slot = entry;
+    }
+
+  return NULL_TREE;
+}
+
+/* Return flags encoding whether SPEC is on the instantiation and/or
+   specialization lists of TMPL.  */
+
+unsigned
+get_mergeable_specialization_flags (tree tmpl, tree decl)
+{
+  unsigned flags = 0;
+
+  for (tree inst = DECL_TEMPLATE_INSTANTIATIONS (tmpl);
+       inst; inst = TREE_CHAIN (inst))
+    if (TREE_VALUE (inst) == decl)
+      {
+       flags |= 1;
+       break;
+      }
+
+  if (CLASS_TYPE_P (TREE_TYPE (decl))
+      && CLASSTYPE_TEMPLATE_INFO (TREE_TYPE (decl))
+      && CLASSTYPE_USE_TEMPLATE (TREE_TYPE (decl)) == 2)
+    /* Only need to search if DECL is a partial specialization.  */
+    for (tree part = DECL_TEMPLATE_SPECIALIZATIONS (tmpl);
+        part; part = TREE_CHAIN (part))
+      if (TREE_VALUE (part) == decl)
+       {
+         flags |= 2;
+         break;
+       }
+
+  return flags;
+}
+
+/* Add a new specialization of TMPL.  FLAGS is as returned from
+   get_mergeable_specialization_flags.  */
+
+void
+add_mergeable_specialization (tree tmpl, tree args, tree decl, unsigned flags)
+{
+  if (flags & 1)
+    DECL_TEMPLATE_INSTANTIATIONS (tmpl)
+      = tree_cons (args, decl, DECL_TEMPLATE_INSTANTIATIONS (tmpl));
+
+  if (flags & 2)
+    {
+      /* A partial specialization.  */
+      DECL_TEMPLATE_SPECIALIZATIONS (tmpl)
+       = tree_cons (args, decl, DECL_TEMPLATE_SPECIALIZATIONS (tmpl));
+      TREE_TYPE (DECL_TEMPLATE_SPECIALIZATIONS (tmpl))
+       = TREE_TYPE (DECL_TEMPLATE_RESULT (decl));
+    }
+}
+
 /* Set up the hash tables for template instantiations.  */
 
 void