When I redid namespace-scope name lookup I made overload sets ordered
hidden, then using, then other. This was with an eye to how modules
would need to extend that to add 'exported' on the end. Turns out
that's not needed, so we can simplify a bit. This patch changes things
so that using and non-using decls are unordered, but still come after
the hidden decls. We have to add another flag into the overload though
to say whether a set contains a using-decl. That engages de-duplication
machinery during the lookup. Previously that machinery could just look
at the first (non-hidden) decl to find out it was needed.
I've been using a variant of this on the modules branch for some time.
booted & tested on x86_64-linux, applying to trunk.
nathan
--
Nathan Sidwell
2018-10-31 Nathan Sidwell <nat...@acm.org>
gcc/cp/
* cp-tree.h (OVL_DEDUP_P): New.
* name-lookup.c (name_lookup::add_overload): Check OVL_DEDUP_P.
(get_class_binding_direct): Likwise.
* tree.c (ovl_make): Propagate OVL_DEDUP_P.
(ovl_copy): Copy it.
(ovl_insert): Do not keep using-decls ordered.
(lookup_maybe_add): Adjust comment.
gcc/testsuite/
* g++.dg/lookup/using60.C: New.
Index: gcc/cp/cp-tree.h
===================================================================
--- gcc/cp/cp-tree.h (revision 265671)
+++ gcc/cp/cp-tree.h (working copy)
@@ -409,6 +409,7 @@ extern GTY(()) tree cp_global_trees[CPTI
SWITCH_STMT_ALL_CASES_P (in SWITCH_STMT)
REINTERPRET_CAST_P (in NOP_EXPR)
ALIGNOF_EXPR_STD_P (in ALIGNOF_EXPR)
+ OVL_DEDUP_P (in OVERLOAD)
1: IDENTIFIER_KIND_BIT_1 (in IDENTIFIER_NODE)
TI_PENDING_TEMPLATE_FLAG.
TEMPLATE_PARMS_FOR_INLINE.
@@ -695,6 +696,8 @@ typedef struct ptrmem_cst * ptrmem_cst_t
#define OVL_CHAIN(NODE) \
(((struct tree_overload*)OVERLOAD_CHECK (NODE))->common.chain)
+/* If set, this or a subsequent overload contains decls that need deduping. */
+#define OVL_DEDUP_P(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))
/* If set, this overload is a hidden decl. */
Index: gcc/cp/name-lookup.c
===================================================================
--- gcc/cp/name-lookup.c (revision 265671)
+++ gcc/cp/name-lookup.c (working copy)
@@ -422,7 +422,8 @@ name_lookup::add_overload (tree fns)
tree probe = fns;
if (flags & LOOKUP_HIDDEN)
probe = ovl_skip_hidden (probe);
- if (probe && TREE_CODE (probe) == OVERLOAD && OVL_USING_P (probe))
+ if (probe && TREE_CODE (probe) == OVERLOAD
+ && OVL_DEDUP_P (probe))
{
/* We're about to add something found by a using
declaration, so need to engage deduping mode. */
@@ -1260,7 +1261,8 @@ get_class_binding_direct (tree klass, tr
if (type_or_fns < 0)
/* Don't bother looking for field. We don't want it. */;
- else if (!val || (TREE_CODE (val) == OVERLOAD && OVL_USING_P (val)))
+ else if (!val || (TREE_CODE (val) == OVERLOAD
+ && OVL_DEDUP_P (val)))
/* Dependent using declarations are a 'field', make sure we
return that even if we saw an overload already. */
if (tree field_val = fields_linear_search (klass, lookup,
Index: gcc/cp/tree.c
===================================================================
--- gcc/cp/tree.c (revision 265671)
+++ gcc/cp/tree.c (working copy)
@@ -2153,6 +2153,8 @@ ovl_make (tree fn, tree next)
TREE_TYPE (result) = (next || TREE_CODE (fn) == TEMPLATE_DECL
? unknown_type_node : TREE_TYPE (fn));
+ if (next && TREE_CODE (next) == OVERLOAD && OVL_DEDUP_P (next))
+ OVL_DEDUP_P (result) = true;
OVL_FUNCTION (result) = fn;
OVL_CHAIN (result) = next;
return result;
@@ -2167,64 +2169,54 @@ ovl_copy (tree ovl)
TREE_TYPE (result) = TREE_TYPE (ovl);
OVL_FUNCTION (result) = OVL_FUNCTION (ovl);
OVL_CHAIN (result) = OVL_CHAIN (ovl);
+ OVL_DEDUP_P (result) = OVL_DEDUP_P (ovl);
+ OVL_LOOKUP_P (result) = OVL_LOOKUP_P (ovl);
OVL_HIDDEN_P (result) = OVL_HIDDEN_P (ovl);
OVL_USING_P (result) = OVL_USING_P (ovl);
- OVL_LOOKUP_P (result) = OVL_LOOKUP_P (ovl);
return result;
}
/* Add FN to the (potentially NULL) overload set OVL. USING_P is
true, if FN is via a using declaration. We also pay attention to
- DECL_HIDDEN. Overloads are ordered as hidden, using, regular. */
+ DECL_HIDDEN. We keep the hidden decls first, but remaining ones
+ are unordered. */
tree
ovl_insert (tree fn, tree maybe_ovl, bool using_p)
{
- bool copying = false; /* Checking use only. */
- bool hidden_p = DECL_HIDDEN_P (fn);
- int weight = (hidden_p << 1) | (using_p << 0);
-
- tree result = NULL_TREE;
+ tree result = maybe_ovl;
tree insert_after = NULL_TREE;
- /* Find insertion point. */
- while (maybe_ovl && TREE_CODE (maybe_ovl) == OVERLOAD
- && (weight < ((OVL_HIDDEN_P (maybe_ovl) << 1)
- | (OVL_USING_P (maybe_ovl) << 0))))
+ /* Skip hidden. */
+ for (; maybe_ovl && TREE_CODE (maybe_ovl) == OVERLOAD
+ && OVL_HIDDEN_P (maybe_ovl);
+ maybe_ovl = OVL_CHAIN (maybe_ovl))
{
gcc_checking_assert (!OVL_LOOKUP_P (maybe_ovl)
- && (!copying || OVL_USED_P (maybe_ovl)));
- 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;
+ && !OVL_USED_P (maybe_ovl));
insert_after = maybe_ovl;
- maybe_ovl = OVL_CHAIN (maybe_ovl);
}
- tree trail = fn;
+ bool hidden_p = DECL_HIDDEN_P (fn);
if (maybe_ovl || using_p || hidden_p || TREE_CODE (fn) == TEMPLATE_DECL)
{
- trail = ovl_make (fn, maybe_ovl);
+ maybe_ovl = ovl_make (fn, maybe_ovl);
if (hidden_p)
- OVL_HIDDEN_P (trail) = true;
+ OVL_HIDDEN_P (maybe_ovl) = true;
if (using_p)
- OVL_USING_P (trail) = true;
+ OVL_DEDUP_P (maybe_ovl) = OVL_USING_P (maybe_ovl) = true;
}
+ else
+ maybe_ovl = fn;
if (insert_after)
{
- OVL_CHAIN (insert_after) = trail;
+ OVL_CHAIN (insert_after) = maybe_ovl;
TREE_TYPE (insert_after) = unknown_type_node;
}
else
- result = trail;
+ result = maybe_ovl;
return result;
}
@@ -2367,7 +2359,8 @@ lookup_maybe_add (tree fns, tree lookup,
for (; fns != probe; fns = OVL_CHAIN (fns))
{
lookup = lookup_add (OVL_FUNCTION (fns), lookup);
- /* Propagate OVL_USING, but OVL_HIDDEN doesn't matter. */
+ /* Propagate OVL_USING, but OVL_HIDDEN &
+ OVL_DEDUP_P don't matter. */
if (OVL_USING_P (fns))
OVL_USING_P (lookup) = true;
}
Index: gcc/testsuite/g++.dg/lookup/using60.C
===================================================================
--- gcc/testsuite/g++.dg/lookup/using60.C (revision 0)
+++ gcc/testsuite/g++.dg/lookup/using60.C (working copy)
@@ -0,0 +1,18 @@
+// ICE with overloads not ordering using decls. Failed to invoke
+// deduping logic
+
+void remove (const char *);
+
+namespace std
+{
+ using ::remove;
+
+ void remove ();
+}
+
+using namespace std;
+
+void test01 ()
+{
+ remove (0);
+}