From 1bf07cc3ff38a893fd8daa248e834e9dac567b88 Mon Sep 17 00:00:00 2001 From: Nathan Sidwell Date: Thu, 18 May 2017 18:18:04 +0000 Subject: [PATCH] cp-tree.h (OVL_ARG_DEPENDENT): Delete. * cp-tree.h (OVL_ARG_DEPENDENT): Delete. (OVL_USED_P): New. (lookup_keep): Declare. * name-lookup.c (add_function): Don't set OVL_ARG_DEPENDENT. * pt.c (tsubst_copy): Assert lookup is persistent. * semantics.c (finish_call_expr): Use lkp_iterator, call lookup_keep. * tree.c (ovl_copy): New. (ovl_insert, ovl_iterator::remove_node): Copy immutable nodes. (lookup_keep): New. From-SVN: r248250 --- gcc/cp/ChangeLog | 11 +++++++ gcc/cp/cp-tree.h | 7 ++-- gcc/cp/name-lookup.c | 6 +--- gcc/cp/pt.c | 2 ++ gcc/cp/semantics.c | 43 +++++++++++------------- gcc/cp/tree.c | 78 ++++++++++++++++++++++++++++++++++++++++++-- 6 files changed, 111 insertions(+), 36 deletions(-) diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 01c506b9f1e..e903bfd1d71 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,16 @@ 2017-05-18 Nathan Sidwell + * cp-tree.h (OVL_ARG_DEPENDENT): Delete. + (OVL_USED_P): New. + (lookup_keep): Declare. + * name-lookup.c (add_function): Don't set OVL_ARG_DEPENDENT. + * pt.c (tsubst_copy): Assert lookup is persistent. + * semantics.c (finish_call_expr): Use lkp_iterator, call + lookup_keep. + * tree.c (ovl_copy): New. + (ovl_insert, ovl_iterator::remove_node): Copy immutable nodes. + (lookup_keep): New. + * cp-tree.h (OVL_USED): Replace with ... (OVL_USING_P): ... this. (ovl_iterator::using_p): Adjust. diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index bd312521377..82bb9650106 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -323,7 +323,6 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX]; IMPLICIT_CONV_EXPR_DIRECT_INIT (in IMPLICIT_CONV_EXPR) TRANSACTION_EXPR_IS_STMT (in TRANSACTION_EXPR) CONVERT_EXPR_VBASE_PATH (in CONVERT_EXPR) - OVL_ARG_DEPENDENT (in OVERLOAD) PACK_EXPANSION_LOCAL_P (in *_PACK_EXPANSION) TINFO_HAS_ACCESS_ERRORS (in TEMPLATE_INFO) SIZEOF_EXPR_TYPE_P (in SIZEOF_EXPR) @@ -641,9 +640,6 @@ typedef struct ptrmem_cst * ptrmem_cst_t; ((TREE_CODE (NODE) == OVERLOAD) ? OVL_FUNCTION (NODE) : (NODE)) #define OVL_NEXT(NODE) \ ((TREE_CODE (NODE) == OVERLOAD) ? TREE_CHAIN (NODE) : NULL_TREE) -/* If set, this OVERLOAD was created for argument-dependent lookup - and can be freed afterward. */ -#define OVL_ARG_DEPENDENT(NODE) TREE_LANG_FLAG_0 (OVERLOAD_CHECK (NODE)) /* If set, this was imported in a using declaration. */ #define OVL_USING_P(NODE) TREE_LANG_FLAG_1 (OVERLOAD_CHECK (NODE)) @@ -651,6 +647,8 @@ typedef struct ptrmem_cst * ptrmem_cst_t; #define OVL_NESTED_P(NODE) TREE_LANG_FLAG_3 (OVERLOAD_CHECK (NODE)) /* If set, this overload was constructed during lookup. */ #define OVL_LOOKUP_P(NODE) TREE_LANG_FLAG_4 (OVERLOAD_CHECK (NODE)) +/* If set, this is a persistant lookup. */ +#define OVL_USED_P(NODE) TREE_USED (OVERLOAD_CHECK (NODE)) /* The first decl of an overload. */ #define OVL_FIRST(NODE) ovl_first (NODE) @@ -6809,6 +6807,7 @@ extern tree ovl_make (tree fn, extern tree ovl_insert (tree fn, tree maybe_ovl, bool using_p = false); extern tree lookup_add (tree fns, tree lookup); +extern void lookup_keep (tree lookup, bool keep); extern int is_overloaded_fn (tree); extern tree dependent_name (tree); extern tree get_fns (tree) ATTRIBUTE_PURE; diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c index e55b48dd7ff..88a2ee586c7 100644 --- a/gcc/cp/name-lookup.c +++ b/gcc/cp/name-lookup.c @@ -159,11 +159,7 @@ add_function (struct arg_lookup *k, tree fn) else if (fn == k->functions) ; else - { - k->functions = lookup_add (fn, k->functions); - if (TREE_CODE (k->functions) == OVERLOAD) - OVL_ARG_DEPENDENT (k->functions) = true; - } + k->functions = lookup_add (fn, k->functions); return false; } diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index ed3f45ed84e..eef6c0e72dc 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -14565,6 +14565,8 @@ tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl) overload set from function scope will just be represented with an IDENTIFIER_NODE, and from class scope with a BASELINK. */ gcc_assert (!uses_template_parms (t)); + /* We must have marked any lookups as persistent. */ + gcc_assert (!OVL_LOOKUP_P (t) || OVL_USED_P (t)); return t; case BASELINK: diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index fa02b27145a..1ba961ec226 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -2304,18 +2304,28 @@ finish_call_expr (tree fn, vec **args, bool disallow_virtual, result = build_nt_call_vec (fn, *args); SET_EXPR_LOCATION (result, EXPR_LOC_OR_LOC (fn, input_location)); KOENIG_LOOKUP_P (result) = koenig_p; + if (is_overloaded_fn (fn)) + { + fn = get_fns (fn); + lookup_keep (fn, true); + } + if (cfun) { - do + bool abnormal = true; + for (lkp_iterator iter (fn); abnormal && iter; ++iter) { - tree fndecl = OVL_CURRENT (fn); + tree fndecl = *iter; if (TREE_CODE (fndecl) != FUNCTION_DECL || !TREE_THIS_VOLATILE (fndecl)) - break; - fn = OVL_NEXT (fn); + abnormal = false; } - while (fn); - if (!fn) + /* FIXME: Stop warning about falling off end of non-void + function. But this is wrong. Even if we only see + no-return fns at this point, we could select a + future-defined return fn during instantiation. Or + vice-versa. */ + if (abnormal) current_function_returns_abnormally = 1; } return result; @@ -2469,24 +2479,9 @@ finish_call_expr (tree fn, vec **args, bool disallow_virtual, result = convert_from_reference (result); } - if (koenig_p) - { - /* Free garbage OVERLOADs from arg-dependent lookup. */ - tree next = NULL_TREE; - for (fn = orig_fn; - fn && TREE_CODE (fn) == OVERLOAD && OVL_ARG_DEPENDENT (fn); - fn = next) - { - if (processing_template_decl) - /* In a template, we'll re-use them at instantiation time. */ - OVL_ARG_DEPENDENT (fn) = false; - else - { - next = OVL_CHAIN (fn); - ggc_free (fn); - } - } - } + /* Free or retain OVERLOADs from lookup. */ + if (is_overloaded_fn (orig_fn)) + lookup_keep (get_fns (orig_fn), processing_template_decl); return result; } diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index 61254c072ed..e2d02251aa6 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -2124,6 +2124,30 @@ ovl_make (tree fn, tree next) return result; } +static tree +ovl_copy (tree ovl) +{ + tree result = ovl_cache; + + if (result) + { + ovl_cache = OVL_FUNCTION (result); + /* Zap the flags. */ + memset (result, 0, sizeof (tree_base)); + TREE_SET_CODE (result, OVERLOAD); + } + else + result = make_node (OVERLOAD); + + gcc_assert (!OVL_NESTED_P (ovl) && !OVL_LOOKUP_P (ovl)); + TREE_TYPE (result) = TREE_TYPE (ovl); + OVL_FUNCTION (result) = OVL_FUNCTION (ovl); + OVL_CHAIN (result) = OVL_CHAIN (ovl); + OVL_USING_P (ovl) = OVL_USING_P (ovl); + + return result; +} + /* 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. */ @@ -2131,6 +2155,7 @@ ovl_make (tree fn, tree next) tree ovl_insert (tree fn, tree maybe_ovl, bool using_p) { + bool copying = false; /* Checking use only. */ int weight = using_p; tree result = NULL_TREE; @@ -2140,6 +2165,15 @@ ovl_insert (tree fn, tree maybe_ovl, bool using_p) while (maybe_ovl && TREE_CODE (maybe_ovl) == OVERLOAD && (weight < OVL_USING_P (maybe_ovl))) { + gcc_checking_assert (!OVL_LOOKUP_P (maybe_ovl) + && (!OVL_USED_P (maybe_ovl) || !copying)); + if (OVL_USED_P (maybe_ovl)) + { + copying = true; + maybe_ovl = ovl_copy (maybe_ovl); + if (insert_after) + OVL_CHAIN (insert_after) = maybe_ovl; + } if (!result) result = maybe_ovl; insert_after = maybe_ovl; @@ -2156,7 +2190,7 @@ ovl_insert (tree fn, tree maybe_ovl, bool using_p) if (insert_after) { - TREE_CHAIN (insert_after) = trail; + OVL_CHAIN (insert_after) = trail; TREE_TYPE (insert_after) = unknown_type_node; } else @@ -2165,14 +2199,32 @@ ovl_insert (tree fn, tree maybe_ovl, bool using_p) return result; } -/* NODE is on the overloads of OVL. Remove it. */ +/* NODE is on the overloads of OVL. Remove it. If a predecessor is + OVL_USED_P we must copy OVL nodes, because those are immutable. + The removed node is unaltered and may continue to be iterated + from (i.e. it is safe to remove a node from an overload one is + currently iterating over). */ tree ovl_iterator::remove_node (tree overload, tree node) { + bool copying = false; /* Checking use only. */ + tree *slot = &overload; while (*slot != node) - slot = &OVL_CHAIN (*slot); + { + tree probe = *slot; + gcc_checking_assert (!OVL_LOOKUP_P (probe) + && (!OVL_USED_P (probe) || !copying)); + if (OVL_USED_P (probe)) + { + copying = true; + probe = ovl_copy (probe); + *slot = probe; + } + + slot = &OVL_CHAIN (probe); + } /* Stitch out NODE. We don't have to worry about now making a singleton overload (and consequently maybe setting its type), @@ -2199,6 +2251,26 @@ lookup_add (tree fns, tree lookup) return 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. */ + +void +lookup_keep (tree lookup, bool keep) +{ + for (; + lookup && TREE_CODE (lookup) == OVERLOAD + && OVL_LOOKUP_P (lookup) && !OVL_USED_P (lookup); + lookup = OVL_CHAIN (lookup)) + if (keep) + OVL_USED_P (lookup) = true; + else + { + OVL_FUNCTION (lookup) = ovl_cache; + ovl_cache = lookup; + } +} + /* Returns nonzero if X is an expression for a (possibly overloaded) function. If "f" is a function or function template, "f", "c->f", "c.f", "C::f", and "f" will all be considered possibly