From 32196b873a1ba319e9b3fc4cccb910d8cc4d6b31 Mon Sep 17 00:00:00 2001 From: Nathan Sidwell Date: Fri, 26 May 2017 15:01:07 +0000 Subject: [PATCH] cp-tree.h (OVL_CHAIN): Check looking at OVERLOAD. * cp-tree.h (OVL_CHAIN): Check looking at OVERLOAD. (ovl_iterator): Add allow_inner field. Adjust ctor. Make unduplicatable. (ovl_iterator::maybe_push, ovl_iterator::pop): New. (lkp_iterator): Add outer field. Adjust ctor. (lkp_iterator::operator++): New. (lookup_mark, lookup_maybe_add): Declare. * name-lookup.c (name_lookup): Delete fn_set member. (name_lookup::preserve_state, name_lookup::restore_state): Unmark and mark lookup. (name_lookup::add_value): Use lookup_add directly. (name_lookup::add_fns: Use lookup_maybe_add. (name_lookup::search_adl): Mark and unmark fns. (pushdecl): Adjust. * pt.c (check_explicit_specialization): Use lookup_add directly. * ptree.c (cxx_print_xnode): Show complete overload structure. * tree.c (lookup_mark, lookup_maybe_add): New. From-SVN: r248517 --- gcc/cp/ChangeLog | 18 +++++++++ gcc/cp/cp-tree.h | 73 ++++++++++++++++++++++++++------- gcc/cp/name-lookup.c | 40 ++++++++---------- gcc/cp/pt.c | 3 +- gcc/cp/ptree.c | 6 ++- gcc/cp/tree.c | 96 +++++++++++++++++++++++++++++++++++++++++++- 6 files changed, 191 insertions(+), 45 deletions(-) diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index bd6fcde0e22..b1a72ee5fb7 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,23 @@ 2017-05-26 Nathan Sidwell + * cp-tree.h (OVL_CHAIN): Check looking at OVERLOAD. + (ovl_iterator): Add allow_inner field. Adjust ctor. Make + unduplicatable. + (ovl_iterator::maybe_push, ovl_iterator::pop): New. + (lkp_iterator): Add outer field. Adjust ctor. + (lkp_iterator::operator++): New. + (lookup_mark, lookup_maybe_add): Declare. + * name-lookup.c (name_lookup): Delete fn_set member. + (name_lookup::preserve_state, name_lookup::restore_state): Unmark + and mark lookup. + (name_lookup::add_value): Use lookup_add directly. + (name_lookup::add_fns: Use lookup_maybe_add. + (name_lookup::search_adl): Mark and unmark fns. + (pushdecl): Adjust. + * pt.c (check_explicit_specialization): Use lookup_add directly. + * ptree.c (cxx_print_xnode): Show complete overload structure. + * tree.c (lookup_mark, lookup_maybe_add): New. + * name-lookup.c (name_lookup::search_adl): ADL OMP UDR type args. 2017-05-26 Jakub Jelinek diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index a471a639742..64dca460394 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -657,7 +657,8 @@ typedef struct ptrmem_cst * ptrmem_cst_t; Other users should use iterators and convenience functions. */ #define OVL_FUNCTION(NODE) \ (((struct tree_overload*)OVERLOAD_CHECK (NODE))->function) -#define OVL_CHAIN(NODE) TREE_CHAIN (NODE) +#define OVL_CHAIN(NODE) \ + (((struct tree_overload*)OVERLOAD_CHECK (NODE))->common.chain) /* If set, this was imported in a using declaration. */ #define OVL_USING_P(NODE) TREE_LANG_FLAG_1 (OVERLOAD_CHECK (NODE)) @@ -684,6 +685,9 @@ typedef struct ptrmem_cst * ptrmem_cst_t; #define OVL_SINGLE_P(NODE) \ (TREE_CODE (NODE) != OVERLOAD || !OVL_CHAIN (NODE)) +/* OVL_HIDDEN_P nodes come first, then OVL_USING_P nodes, then regular + fns. */ + struct GTY(()) tree_overload { struct tree_common common; tree function; @@ -694,19 +698,19 @@ struct GTY(()) tree_overload { class ovl_iterator { tree ovl; + const bool allow_inner; /* Only used when checking. */ public: - ovl_iterator (tree o) - :ovl (o) - {} - - ovl_iterator &operator= (const ovl_iterator &from) + explicit ovl_iterator (tree o, bool allow = false) + : ovl (o), allow_inner (allow) { - ovl = from.ovl; - - return *this; } + private: + /* Do not duplicate. */ + ovl_iterator &operator= (const ovl_iterator &); + ovl_iterator (const ovl_iterator &); + public: operator bool () const { @@ -722,7 +726,7 @@ class ovl_iterator tree fn = TREE_CODE (ovl) != OVERLOAD ? ovl : OVL_FUNCTION (ovl); /* Check this is not an unexpected 2-dimensional overload. */ - gcc_checking_assert (TREE_CODE (fn) != OVERLOAD); + gcc_checking_assert (allow_inner || TREE_CODE (fn) != OVERLOAD); return fn; } @@ -748,6 +752,27 @@ class ovl_iterator return reveal_node (head, ovl); } + protected: + /* If we have a nested overload, point at the inner overload and + return the next link on the outer one. */ + tree maybe_push () + { + tree r = NULL_TREE; + + if (ovl && TREE_CODE (ovl) == OVERLOAD && OVL_NESTED_P (ovl)) + { + r = OVL_CHAIN (ovl); + ovl = OVL_FUNCTION (ovl); + } + return r; + } + /* Restore an outer nested overload. */ + void pop (tree outer) + { + gcc_checking_assert (!ovl); + ovl = outer; + } + private: /* We make these static functions to avoid the address of the iterator escaping the local context. */ @@ -758,17 +783,33 @@ class ovl_iterator /* Iterator over a (potentially) 2 dimensional overload, which is produced by name lookup. */ -/* Note this is currently a placeholder, as the name-lookup changes - are not yet committed. */ - class lkp_iterator : public ovl_iterator { typedef ovl_iterator parent; + tree outer; + + public: + explicit lkp_iterator (tree o) + : parent (o, true), outer (maybe_push ()) + { + } + public: - lkp_iterator (tree o) - : parent (o) + lkp_iterator &operator++ () { + bool repush = !outer; + + if (!parent::operator++ () && !repush) + { + pop (outer); + repush = true; + } + + if (repush) + outer = maybe_push (); + + return *this; } }; @@ -6865,7 +6906,9 @@ extern tree ovl_make (tree fn, extern tree ovl_insert (tree fn, tree maybe_ovl, bool using_p = false); extern tree ovl_skip_hidden (tree) ATTRIBUTE_PURE; +extern void lookup_mark (tree lookup, bool val); extern tree lookup_add (tree fns, tree lookup); +extern tree lookup_maybe_add (tree fns, tree lookup); extern void lookup_keep (tree lookup, bool keep); extern int is_overloaded_fn (tree) ATTRIBUTE_PURE; extern bool really_overloaded_fn (tree) ATTRIBUTE_PURE; diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c index 02ed39ac988..b85061fd843 100644 --- a/gcc/cp/name-lookup.c +++ b/gcc/cp/name-lookup.c @@ -161,7 +161,6 @@ public: int flags; /* Lookup flags. */ vec *scopes; name_lookup *previous; /* Previously active lookup. */ - hash_set *fn_set; protected: /* Marked scope stack for outermost name lookup. */ @@ -172,13 +171,12 @@ protected: public: name_lookup (tree n, int f = 0) : name (n), value (NULL_TREE), type (NULL_TREE), flags (f), - scopes (NULL), previous (NULL), fn_set (NULL) + scopes (NULL), previous (NULL) { preserve_state (); } ~name_lookup () { - gcc_checking_assert (!fn_set); restore_state (); } @@ -299,6 +297,9 @@ name_lookup::preserve_state () previous->scopes->quick_push (decl); } } + + /* Unmark the outer partial lookup. */ + lookup_mark (previous->value, false); } else scopes = shared_scopes; @@ -322,6 +323,8 @@ name_lookup::restore_state () active = previous; if (previous) { + free (scopes); + unsigned length = vec_safe_length (previous->scopes); for (unsigned ix = 0; ix != length; ix++) { @@ -345,7 +348,8 @@ name_lookup::restore_state () LOOKUP_SEEN_P (decl) = true; } - free (scopes); + /* Remark the outer partial lookup. */ + lookup_mark (previous->value, true); } else shared_scopes = scopes; @@ -403,10 +407,7 @@ name_lookup::add_value (tree new_val) && same_type_p (TREE_TYPE (value), TREE_TYPE (new_val)))) ; else if (OVL_P (value) && OVL_P (new_val)) - { - for (ovl_iterator iter (new_val); iter; ++iter) - value = lookup_add (*iter, value); - } + value = lookup_add (new_val, value); else value = ambiguous (new_val, value); } @@ -684,9 +685,7 @@ name_lookup::add_fns (tree fns) return; /* Only add those that aren't already there. */ - for (ovl_iterator iter (fns); iter; ++iter) - if (!fn_set->add (*iter)) - value = lookup_add (*iter, value); + value = lookup_maybe_add (fns, value); } /* Add functions of a namespace to the lookup structure. */ @@ -987,13 +986,9 @@ name_lookup::adl_template_arg (tree arg) tree name_lookup::search_adl (tree fns, vec *args) { + lookup_mark (fns, true); value = fns; - /* Add the current overload set into the hash table. */ - fn_set = new hash_set; - for (lkp_iterator iter (fns); iter; ++iter) - fn_set->add (*iter); - unsigned ix; tree arg; @@ -1005,10 +1000,8 @@ name_lookup::search_adl (tree fns, vec *args) else adl_expr (arg); - delete fn_set; - fn_set = NULL; - fns = value; + lookup_mark (fns, false); return fns; } @@ -2101,7 +2094,6 @@ check_local_shadow (tree decl) inform (DECL_SOURCE_LOCATION (shadowed), "shadowed declaration is here"); } - /* DECL is being pushed inside function CTX. Set its context, if needed. */ @@ -2394,14 +2386,14 @@ do_pushdecl (tree decl, bool is_friend) } /* Record a decl-node X as belonging to the current lexical scope. - It's a friend if IS_FRIEND is true. */ + It's a friend if IS_FRIEND is true -- which affects exactly where + we push it. */ tree pushdecl (tree x, bool is_friend) { - tree ret; bool subtime = timevar_cond_start (TV_NAME_LOOKUP); - ret = do_pushdecl (x, is_friend); + tree ret = do_pushdecl (x, is_friend); timevar_cond_stop (TV_NAME_LOOKUP, subtime); return ret; } @@ -4199,7 +4191,7 @@ set_namespace_binding (tree scope, tree name, tree val) supplement_binding (binding, val); } -/* Set value binding og NAME in the global namespace to VAL. Does not +/* Set value binding of NAME in the global namespace to VAL. Does not add it to the list of things in the namespace. */ void diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 306838550a6..68514c911e9 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -2931,8 +2931,7 @@ check_explicit_specialization (tree declarator, /* Glue all these conversion functions together with those we already have. */ - for (ovl_iterator iter (ovl); iter; ++iter) - fns = lookup_add (*iter, fns); + fns = lookup_add (ovl, fns); } } diff --git a/gcc/cp/ptree.c b/gcc/cp/ptree.c index 5c7548adbda..a2977e86e7b 100644 --- a/gcc/cp/ptree.c +++ b/gcc/cp/ptree.c @@ -237,8 +237,10 @@ cxx_print_xnode (FILE *file, tree node, int indent) break; case OVERLOAD: print_node (file, "name", OVL_NAME (node), indent+4); - for (lkp_iterator iter (node); iter; ++iter) - print_node (file, "function", *iter, indent+4); + for (ovl_iterator iter (node, true); iter; ++iter) + print_node (file, + TREE_CODE (*iter) == OVERLOAD ? "inner" : "function", + *iter, indent+4); break; case TEMPLATE_PARM_INDEX: print_node (file, "decl", TEMPLATE_PARM_DECL (node), indent+4); diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index c2d6b1c3c7f..343708f4302 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -2150,8 +2150,8 @@ ovl_copy (tree ovl) } /* Add FN to the (potentially NULL) overload set OVL. USING_P is - true, if FN is via a using declaration. Overloads are ordered as - using, regular. */ + true, if FN is via a using declaration. We also pay attention to + DECL_HIDDEN. Overloads are ordered as hidden, using, regular. */ tree ovl_insert (tree fn, tree maybe_ovl, bool using_p) @@ -2287,6 +2287,29 @@ ovl_iterator::remove_node (tree overload, tree node) return overload; } +/* Mark or unmark a lookup set. */ + +void +lookup_mark (tree ovl, bool val) +{ + /* For every node that is a lookup, mark the thing it points to. */ + for (; ovl && TREE_CODE (ovl) == OVERLOAD && OVL_LOOKUP_P (ovl); + ovl = OVL_CHAIN (ovl)) + { + tree targ = OVL_FUNCTION (ovl); + gcc_checking_assert (LOOKUP_SEEN_P (targ) != val); + LOOKUP_SEEN_P (targ) = val; + } + + if (ovl && (TREE_CODE (ovl) == OVERLOAD || + TREE_CODE (ovl) == FUNCTION_DECL)) + { + /* Mark the overload itsef. */ + gcc_checking_assert (LOOKUP_SEEN_P (ovl) != val); + LOOKUP_SEEN_P (ovl) = val; + } +} + /* Add a set of new FNS into a lookup. */ tree @@ -2303,6 +2326,75 @@ lookup_add (tree fns, tree lookup) return lookup; } +/* FNS is a new overload set, add it to LOOKUP, if it is not already + present there. */ + +tree +lookup_maybe_add (tree fns, tree lookup) +{ + if (LOOKUP_SEEN_P (fns)) + return lookup; + + if (lookup && TREE_CODE (fns) == OVERLOAD) + { + /* Determine if we already have some part of this overload in + the overload set. If so fix things up so we only have the + overload set once. */ + tree marked = NULL_TREE; + + for (tree probe = fns; probe; probe = OVL_CHAIN (probe)) + if (LOOKUP_SEEN_P (probe)) + { + marked = probe; + break; + } + else if (TREE_CODE (probe) != OVERLOAD) + break; + + if (marked) + { + /* The tail of this overload is already in the lookup + set. Stitch out the tail case, which might involve + copying. */ + bool rewrite = false; + + LOOKUP_SEEN_P (marked) = false; + for (tree *prev = &lookup, probe = *prev; + ; prev = &OVL_CHAIN (probe), probe = *prev) + { + if (probe == marked) + { + *prev = NULL_TREE; + break; + } + gcc_checking_assert (OVL_LOOKUP_P (probe)); + if (marked == OVL_FUNCTION (probe)) + { + *prev = OVL_CHAIN (probe); + break; + } + + /* If we're in a used part of the lookup set, copy the + node, so as to not disturb stored uses. */ + gcc_checking_assert (!rewrite || OVL_USED_P (probe)); + if (OVL_USED_P (probe)) + { + rewrite = true; + probe = ovl_copy (probe); + OVL_LOOKUP_P (probe) = true; + *prev = probe; + } + } + } + } + + /* Finally mark the new overload and prepend it to the current + lookup. */ + LOOKUP_SEEN_P (fns) = true; + + return lookup_add (fns, lookup); +} + /* If KEEP is true, preserve the contents of a lookup so that it is available for a later instantiation. Otherwise release the LOOKUP nodes for reuse. */ -- 2.30.2