From 2c169babb627a91c6dd3900707cdc53f170a9b70 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Sat, 14 Aug 1999 11:08:53 +0000 Subject: [PATCH] Speed up Koenig lookup. * decl.c (unqualified_namespace_lookup): Nonstatic. Add spacep parm to return namespaces we've looked at. * decl2.c (lookup_using_namespace): Likewise. (add_function): Don't call ovl_member. (lookup_arg_dependent): Initialize k.namespaces to the list of namespaces seen in unqualified lookup. * call.c (equal_functions): Move here from tree.c. (joust): Use it to handle duplicate candidates. * tree.c (ovl_member): Use ==. From-SVN: r28710 --- gcc/cp/ChangeLog | 13 ++++++++++ gcc/cp/call.c | 21 +++++++++++++++ gcc/cp/cp-tree.h | 5 ++-- gcc/cp/decl.c | 25 ++++++++++-------- gcc/cp/decl2.c | 66 ++++++++++++++++++++++++++++++------------------ gcc/cp/lex.c | 9 ++++--- gcc/cp/tree.c | 19 ++------------ 7 files changed, 102 insertions(+), 56 deletions(-) diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 4b882a6c730..b5ce2890675 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,16 @@ +1999-08-14 Jason Merrill + + Speed up Koenig lookup. + * decl.c (unqualified_namespace_lookup): Nonstatic. Add spacep parm + to return namespaces we've looked at. + * decl2.c (lookup_using_namespace): Likewise. + (add_function): Don't call ovl_member. + (lookup_arg_dependent): Initialize k.namespaces to the list of + namespaces seen in unqualified lookup. + * call.c (equal_functions): Move here from tree.c. + (joust): Use it to handle duplicate candidates. + * tree.c (ovl_member): Use ==. + 1999-08-13 Mark Mitchell * cp-tree.def (DECL_STMT): Make it smaller. diff --git a/gcc/cp/call.c b/gcc/cp/call.c index fda38de4d9a..f193a4b7b16 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -44,6 +44,7 @@ static tree build_new_method_call PROTO((tree, tree, tree, tree, int)); static tree build_field_call PROTO((tree, tree, tree, tree)); static struct z_candidate * tourney PROTO((struct z_candidate *)); +static int equal_functions PROTO((tree, tree)); static int joust PROTO((struct z_candidate *, struct z_candidate *, int)); static int compare_ics PROTO((tree, tree)); static tree build_over_call PROTO((struct z_candidate *, tree, int)); @@ -4768,6 +4769,20 @@ add_warning (winner, loser) winner->warnings); } +/* Returns true iff functions are equivalent. Equivalent functions are + not identical only if one is a function-local extern function. + This assumes that function-locals don't have TREE_PERMANENT. */ + +static inline int +equal_functions (fn1, fn2) + tree fn1; + tree fn2; +{ + if (!TREE_PERMANENT (fn1) || !TREE_PERMANENT (fn2)) + return decls_match (fn1, fn2); + return fn1 == fn2; +} + /* Compare two candidates for overloading as described in [over.match.best]. Return values: @@ -4963,6 +4978,12 @@ joust (cand1, cand2, warn) } } + /* If the two functions are the same (this can happen with declarations + in multiple scopes and arg-dependent lookup), arbitrarily choose one. */ + if (DECL_P (cand1->fn) && DECL_P (cand2->fn) + && equal_functions (cand1->fn, cand2->fn)) + return 1; + tweak: /* Extension: If the worst conversion for one candidate is worse than the diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 410dc7a8681..82022fadd3c 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -2886,8 +2886,9 @@ extern tree lookup_name_namespace_only PROTO((tree)); extern void begin_only_namespace_names PROTO((void)); extern void end_only_namespace_names PROTO((void)); extern tree namespace_ancestor PROTO((tree, tree)); -extern int lookup_using_namespace PROTO((tree,tree,tree,tree,int)); -extern int qualified_lookup_using_namespace PROTO((tree,tree,tree,int)); +extern tree unqualified_namespace_lookup PROTO((tree, int, tree *)); +extern int lookup_using_namespace PROTO((tree, tree, tree, tree, int, tree *)); +extern int qualified_lookup_using_namespace PROTO((tree, tree, tree, int)); extern tree auto_function PROTO((tree, tree, enum built_in_function)); extern void init_decl_processing PROTO((void)); extern int init_type_desc PROTO((void)); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 8c960202514..6fb61f72eb7 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -179,7 +179,6 @@ static void pop_binding PROTO((tree, tree)); static tree local_variable_p PROTO((tree)); static tree find_binding PROTO((tree, tree)); static tree select_decl PROTO((tree, int)); -static tree unqualified_namespace_lookup PROTO((tree, int)); static int lookup_flags PROTO((int, int)); static tree qualify_lookup PROTO((tree, int)); static tree record_builtin_java_type PROTO((const char *, int)); @@ -5557,13 +5556,15 @@ select_decl (binding, flags) return val; } -/* Unscoped lookup of a global, iterate over namespaces, considering - using namespace statements. */ +/* Unscoped lookup of a global: iterate over current namespaces, + considering using-directives. If SPACESP is non-NULL, store a list + of the namespaces we've considered in it. */ -static tree -unqualified_namespace_lookup (name, flags) +tree +unqualified_namespace_lookup (name, flags, spacesp) tree name; int flags; + tree *spacesp; { struct tree_binding _binding; tree b = binding_init (&_binding); @@ -5573,8 +5574,13 @@ unqualified_namespace_lookup (name, flags) struct binding_level *level; tree val = NULL_TREE; - while (!val) + if (spacesp) + *spacesp = NULL_TREE; + + for (; !val; scope = CP_DECL_CONTEXT (scope)) { + if (spacesp) + *spacesp = scratch_tree_cons (scope, NULL_TREE, *spacesp); val = binding_for_name (name, scope); /* Initialize binding for this context. */ @@ -5586,7 +5592,7 @@ unqualified_namespace_lookup (name, flags) !level->namespace_p; level = level->level_chain) if (!lookup_using_namespace (name, b, level->using_directives, - scope, flags)) + scope, flags, spacesp)) /* Give up because of error. */ return error_mark_node; @@ -5596,7 +5602,7 @@ unqualified_namespace_lookup (name, flags) while (1) { if (!lookup_using_namespace (name, b, DECL_NAMESPACE_USING (siter), - scope, flags)) + scope, flags, spacesp)) /* Give up because of error. */ return error_mark_node; if (siter == scope) break; @@ -5606,7 +5612,6 @@ unqualified_namespace_lookup (name, flags) val = select_decl (b, flags); if (scope == global_namespace) break; - scope = CP_DECL_CONTEXT (scope); } return val; } @@ -5811,7 +5816,7 @@ lookup_name_real (name, prefer_type, nonclass, namespaces_only) /* Now lookup in namespace scopes. */ if (!val || val_is_implicit_typename) { - t = unqualified_namespace_lookup (name, flags); + t = unqualified_namespace_lookup (name, flags, 0); if (t) { if (val_is_implicit_typename && !yylex) diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index 3cebe815640..ab82a8ee667 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -4349,14 +4349,18 @@ ambiguous_decl (name, old, new, flags) return old; } -/* Add the bindings of name in used namespaces to val. - The using list is defined by usings, and the lookup goes to scope. +/* Subroutine of unualified_namespace_lookup: + Add the bindings of NAME in used namespaces to VAL. + We are currently looking for names in namespace SCOPE, so we + look through USINGS for using-directives of namespaces + which have SCOPE as a common ancestor with the current scope. Returns zero on errors. */ int -lookup_using_namespace (name, val, usings, scope, flags) +lookup_using_namespace (name, val, usings, scope, flags, spacesp) tree name, val, usings, scope; int flags; + tree *spacesp; { tree iter; tree val1; @@ -4365,6 +4369,9 @@ lookup_using_namespace (name, val, usings, scope, flags) for (iter = usings; iter; iter = TREE_CHAIN (iter)) if (TREE_VALUE (iter) == scope) { + if (spacesp) + *spacesp = scratch_tree_cons (TREE_PURPOSE (iter), NULL_TREE, + *spacesp); val1 = binding_for_name (name, TREE_PURPOSE (iter)); /* Resolve ambiguities. */ val = ambiguous_decl (name, val, val1, flags); @@ -4573,28 +4580,32 @@ add_function (k, fn) struct arg_lookup *k; tree fn; { - if (ovl_member (fn, k->functions)) - return 0; + /* We used to check here to see if the function was already in the list, + but that's O(n^2), which is just too expensive for function lookup. + Now we deal with the occasional duplicate in joust. In doing this, we + assume that the number of duplicates will be small compared to the + total number of functions being compared, which should usually be the + case. */ + /* We must find only functions, or exactly one non-function. */ if (k->functions && is_overloaded_fn (k->functions) && is_overloaded_fn (fn)) k->functions = build_overload (fn, k->functions); - else - if(k->functions) - { - tree f1 = OVL_CURRENT (k->functions); - tree f2 = fn; - if (is_overloaded_fn (f1)) - { - fn = f1; f1 = f2; f2 = fn; - } - cp_error_at ("`%D' is not a function,", f1); - cp_error_at (" conflict with `%D'", f2); - cp_error (" in call to `%D'", k->name); - return 1; - } - else - k->functions = fn; + else if (k->functions) + { + tree f1 = OVL_CURRENT (k->functions); + tree f2 = fn; + if (is_overloaded_fn (f1)) + { + fn = f1; f1 = f2; f2 = fn; + } + cp_error_at ("`%D' is not a function,", f1); + cp_error_at (" conflict with `%D'", f2); + cp_error (" in call to `%D'", k->name); + return 1; + } + else + k->functions = fn; return 0; } @@ -4615,7 +4626,7 @@ arg_assoc_namespace (k, scope) value = namespace_binding (k->name, scope); if (!value) return 0; - + for (; value; value = OVL_NEXT (value)) if (add_function (k, OVL_CURRENT (value))) return 1; @@ -4845,11 +4856,18 @@ lookup_arg_dependent (name, fns, args) tree args; { struct arg_lookup k; + k.name = name; k.functions = fns; - k.namespaces = NULL_TREE; k.classes = NULL_TREE; - + + /* Note that we've already looked at some namespaces during normal + unqualified lookup, unless we found a decl in function scope. */ + if (fns && ! TREE_PERMANENT (OVL_CURRENT (fns))) + k.namespaces = NULL_TREE; + else + unqualified_namespace_lookup (name, 0, &k.namespaces); + push_scratch_obstack (); arg_assoc_args (&k, args); pop_obstacks (); diff --git a/gcc/cp/lex.c b/gcc/cp/lex.c index f36da531991..c28bba06f4e 100644 --- a/gcc/cp/lex.c +++ b/gcc/cp/lex.c @@ -3078,10 +3078,13 @@ do_identifier (token, parsing, args) id = lastiddecl; /* Do Koenig lookup if appropriate (inside templates we build lookup - expressions instead). */ + expressions instead). + + [basic.lookup.koenig]: If the ordinary unqualified lookup of the name + finds the declaration of a class member function, the associated + namespaces and classes are not considered. */ + if (args && !current_template_parms && (!id || is_global (id))) - /* If we have arguments and we only found global names, do Koenig - lookup. */ id = lookup_arg_dependent (token, id, args); /* Remember that this name has been used in the class definition, as per diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index 7a35b47a0b1..f2e8257b30b 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -37,7 +37,6 @@ static tree list_hash_lookup PROTO((int, tree, tree, tree)); static void propagate_binfo_offsets PROTO((tree, tree)); static int avoid_overlap PROTO((tree, tree)); static cp_lvalue_kind lvalue_p_1 PROTO((tree, int)); -static int equal_functions PROTO((tree, tree)); static tree no_linkage_helper PROTO((tree)); static tree build_srcloc PROTO((char *, int)); @@ -1411,20 +1410,6 @@ build_overload (decl, chain) return ovl_cons (decl, chain); } -/* Returns true iff functions are equivalent. Equivalent functions are - not identical only if one is a function-local extern function. - This assumes that function-locals don't have TREE_PERMANENT. */ - -static int -equal_functions (fn1, fn2) - tree fn1; - tree fn2; -{ - if (!TREE_PERMANENT (fn1) || !TREE_PERMANENT (fn2)) - return decls_match (fn1, fn2); - return fn1 == fn2; -} - /* True if fn is in ovl. */ int @@ -1435,9 +1420,9 @@ ovl_member (fn, ovl) if (ovl == NULL_TREE) return 0; if (TREE_CODE (ovl) != OVERLOAD) - return equal_functions (ovl, fn); + return ovl == fn; for (; ovl; ovl = OVL_CHAIN (ovl)) - if (equal_functions (OVL_FUNCTION (ovl), fn)) + if (OVL_FUNCTION (ovl) == fn) return 1; return 0; }