From f35a733d3718e953065fa366bfcef1d95dfb2a10 Mon Sep 17 00:00:00 2001 From: Nathan Sidwell Date: Thu, 25 May 2017 12:51:30 +0000 Subject: [PATCH] cp-tree.h (LOOKUP_SEEN_P, [...]): New. gcc/cp/ * cp-tree.h (LOOKUP_SEEN_P, LOOKUP_FOUND_P): New. * name-lookup.h (lookup_arg_dependent): Return plain tree. * name-lookup.c (arg_lookup, arg_assoc, arg_assoc_args) arg_assoc_args_vec, arg_assoc_type, add_function, arg_assoc_namespace, arg_assoc_class_only, arg_assoc_bases, arg_assoc_class, arg_assoc_template_arg, arg_assoc, lookup_arg_dependent_1): Delete. (name_lookup): New lookup object. (name_lookup::preserve_state, name_lookup::restore_state) name_lookup::mark_seen, name_lookup::find_and_mark, name_lookup::add_fns, name_lookup::adl_namespace_only, name_lookup::adl_namespace, name_lookup::adl_class_only, name_lookup::adl_bases, name_lookup::adl_class, name_lookup::adl_expr, name_lookup::adl_type, name_lookup::adl_template_arg, name_lookup::search_adl): New. (lookup_arg_dependent): Return a plain tree. Adjust. (is_associated_namespace): Move later. gcc/cp/ * g++.dg/lookup/koenig14.C: New. From-SVN: r248457 --- gcc/cp/ChangeLog | 20 + gcc/cp/cp-tree.h | 10 +- gcc/cp/name-lookup.c | 803 +++++++++++++------------ gcc/cp/name-lookup.h | 2 +- gcc/testsuite/ChangeLog | 4 + gcc/testsuite/g++.dg/lookup/koenig14.C | 30 + 6 files changed, 494 insertions(+), 375 deletions(-) create mode 100644 gcc/testsuite/g++.dg/lookup/koenig14.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 29c95c39da8..8d4fc605e58 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,23 @@ +2017-05-25 Nathan Sidwell + + * cp-tree.h (LOOKUP_SEEN_P, LOOKUP_FOUND_P): New. + * name-lookup.h (lookup_arg_dependent): Return plain tree. + * name-lookup.c (arg_lookup, arg_assoc, arg_assoc_args, + arg_assoc_args_vec, arg_assoc_type, add_function, + arg_assoc_namespace, arg_assoc_class_only, arg_assoc_bases, + arg_assoc_class, arg_assoc_template_arg, arg_assoc, + lookup_arg_dependent_1): Delete. + (name_lookup): New lookup object. + (name_lookup::preserve_state, name_lookup::restore_state, + name_lookup::mark_seen, name_lookup::find_and_mark, + name_lookup::add_fns, name_lookup::adl_namespace_only, + name_lookup::adl_namespace, name_lookup::adl_class_only, + name_lookup::adl_bases, name_lookup::adl_class, + name_lookup::adl_expr, name_lookup::adl_type, + name_lookup::adl_template_arg, name_lookup::search_adl): New. + (lookup_arg_dependent): Return a plain tree. Adjust. + (is_associated_namespace): Move later. + 2017-05-24 Nathan Sidwell * friend.c (do_friend): Remove check for existing decl. diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 8ea4edfedc3..66bf376584c 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -395,6 +395,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX]; DECL_TINFO_P (in VAR_DECL) FUNCTION_REF_QUALIFIED (in FUNCTION_TYPE, METHOD_TYPE) OVL_LOOKUP_P (in OVERLOAD) + LOOKUP_FOUND_P (in RECORD_TYPE, UNION_TYPE, NAMESPACE_DECL) 5: C_IS_RESERVED_WORD (in IDENTIFIER_NODE) DECL_VTABLE_OR_VTT_P (in VAR_DECL) FUNCTION_RVALUE_QUALIFIED (in FUNCTION_TYPE, METHOD_TYPE) @@ -648,10 +649,17 @@ typedef struct ptrmem_cst * ptrmem_cst_t; && MAIN_NAME_P (DECL_NAME (NODE)) \ && flag_hosted) -/* The overloaded FUNCTION_DECL. */ +/* Lookup walker marking. */ +#define LOOKUP_SEEN_P(NODE) TREE_VISITED(NODE) +#define LOOKUP_FOUND_P(NODE) \ + TREE_LANG_FLAG_4 (TREE_CHECK3(NODE,RECORD_TYPE,UNION_TYPE,NAMESPACE_DECL)) + +/* These two accessors should only be used by OVL manipulators. + 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) + /* Polymorphic access to FUNCTION and CHAIN. */ #define OVL_CURRENT(NODE) \ ((TREE_CODE (NODE) == OVERLOAD) ? OVL_FUNCTION (NODE) : (NODE)) diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c index c689702722e..dd930ac5c4a 100644 --- a/gcc/cp/name-lookup.c +++ b/gcc/cp/name-lookup.c @@ -160,208 +160,274 @@ find_local_binding (cp_binding_level *b, tree name) return NULL; } -/* [basic.lookup.koenig] */ -/* A nonzero return value in the functions below indicates an error. */ - -struct arg_lookup -{ - tree name; - vec *args; - vec *namespaces; - vec *classes; - tree functions; +struct name_lookup +{ +public: + tree name; /* The identifier being looked for. */ + tree value; /* A (possibly ambiguous) set of things found. */ + tree type; /* A type that has been found. */ + vec *scopes; + name_lookup *previous; /* Previously active lookup. */ hash_set *fn_set; -}; -static bool arg_assoc (struct arg_lookup*, tree); -static bool arg_assoc_args (struct arg_lookup*, tree); -static bool arg_assoc_args_vec (struct arg_lookup*, vec *); -static bool arg_assoc_type (struct arg_lookup*, tree); -static bool add_function (struct arg_lookup *, tree); -static bool arg_assoc_namespace (struct arg_lookup *, tree); -static bool arg_assoc_class_only (struct arg_lookup *, tree); -static bool arg_assoc_bases (struct arg_lookup *, tree); -static bool arg_assoc_class (struct arg_lookup *, tree); -static bool arg_assoc_template_arg (struct arg_lookup*, tree); - -/* Add a function to the lookup structure. - Returns true on error. */ +protected: + /* Marked scope stack for outermost name lookup. */ + static vec *shared_scopes; + /* Currently active lookup. */ + static name_lookup *active; -static bool -add_function (struct arg_lookup *k, tree fn) -{ - if (!is_overloaded_fn (fn)) - /* All names except those of (possibly overloaded) functions and - function templates are ignored. */; - else if (k->fn_set && k->fn_set->add (fn)) - /* It's already in the list. */; - else if (!k->functions && TREE_CODE (fn) != TEMPLATE_DECL) - k->functions = fn; - else if (fn == k->functions) - ; - else - k->functions = lookup_add (fn, k->functions); +public: + name_lookup (tree n) + : name (n), value (NULL_TREE), type (NULL_TREE), + scopes (NULL), previous (NULL), fn_set (NULL) + { + preserve_state (); + } + ~name_lookup () + { + gcc_checking_assert (!fn_set); + restore_state (); + } - return false; -} +private: /* Uncopyable, unmovable, unassignable. I am a rock. */ + name_lookup (const name_lookup &); + name_lookup &operator= (const name_lookup &); -/* Returns true iff CURRENT has declared itself to be an associated - namespace of SCOPE via a strong using-directive (or transitive chain - thereof). Both are namespaces. */ +protected: + static bool seen_p (tree scope) + { + return LOOKUP_SEEN_P (scope); + } + static bool found_p (tree scope) + { + return LOOKUP_FOUND_P (scope); + } + + void mark_seen (tree scope); /* Mark and add to scope vector. */ + static void mark_found (tree scope) + { + gcc_checking_assert (seen_p (scope)); + LOOKUP_FOUND_P (scope) = true; + } + bool see_and_mark (tree scope) + { + bool ret = seen_p (scope); + if (!ret) + mark_seen (scope); + return ret; + } + bool find_and_mark (tree scope); + +private: + void preserve_state (); + void restore_state (); + + private: + void add_fns (tree); + + void adl_expr (tree); + void adl_type (tree); + void adl_template_arg (tree); + void adl_class (tree); + void adl_bases (tree); + void adl_class_only (tree); + void adl_namespace (tree); + void adl_namespace_only (tree); + +public: + tree search_adl (tree fns, vec *args); +}; -bool -is_associated_namespace (tree current, tree scope) -{ - vec *seen = make_tree_vector (); - vec *todo = make_tree_vector (); - tree t; - bool ret; +/* Scope stack shared by all outermost lookups. This avoids us + allocating and freeing on every single lookup. */ +vec *name_lookup::shared_scopes; - while (1) +/* Currently active lookup. */ +name_lookup *name_lookup::active; + +/* Name lookup is recursive, becase ADL can cause template + instatiation. This is of course a rare event, so we optimize for + it not happening. When we discover an active name-lookup, which + must be an ADL lookup, we need to unmark the marked scopes and also + unmark the lookup we might have been accumulating. */ + +void +name_lookup::preserve_state () +{ + previous = active; + if (previous) { - if (scope == current) - { - ret = true; - break; - } - vec_safe_push (seen, scope); - for (t = DECL_NAMESPACE_ASSOCIATIONS (scope); t; t = TREE_CHAIN (t)) - if (!vec_member (TREE_PURPOSE (t), seen)) - vec_safe_push (todo, TREE_PURPOSE (t)); - if (!todo->is_empty ()) + unsigned length = vec_safe_length (previous->scopes); + vec_safe_reserve (previous->scopes, length * 2); + for (unsigned ix = length; ix--;) { - scope = todo->last (); - todo->pop (); - } - else - { - ret = false; - break; - } - } + tree decl = (*previous->scopes)[ix]; - release_tree_vector (seen); - release_tree_vector (todo); + gcc_checking_assert (LOOKUP_SEEN_P (decl)); + LOOKUP_SEEN_P (decl) = false; - return ret; + /* Preserve the FOUND_P state on the interrupted lookup's + stack. */ + if (LOOKUP_FOUND_P (decl)) + { + LOOKUP_FOUND_P (decl) = false; + previous->scopes->quick_push (decl); + } + } + } + else + scopes = shared_scopes; + active = this; } -/* Add functions of a namespace to the lookup structure. - Returns true on error. */ +/* Restore the marking state of a lookup we interrupted. */ -static bool -arg_assoc_namespace (struct arg_lookup *k, tree scope) +void +name_lookup::restore_state () { - tree value; + /* Unmark and empty this lookup's scope stack. */ + for (unsigned ix = vec_safe_length (scopes); ix--;) + { + tree decl = scopes->pop (); + gcc_checking_assert (LOOKUP_SEEN_P (decl)); + LOOKUP_SEEN_P (decl) = false; + LOOKUP_FOUND_P (decl) = false; + } - if (vec_member (scope, k->namespaces)) - return false; - vec_safe_push (k->namespaces, scope); + active = previous; + if (previous) + { + unsigned length = vec_safe_length (previous->scopes); + for (unsigned ix = 0; ix != length; ix++) + { + tree decl = (*previous->scopes)[ix]; + if (LOOKUP_SEEN_P (decl)) + { + /* The remainder of the scope stack must be recording + FOUND_P decls, which we want to pop off. */ + do + { + tree decl = previous->scopes->pop (); + gcc_checking_assert (LOOKUP_SEEN_P (decl) + && !LOOKUP_FOUND_P (decl)); + LOOKUP_FOUND_P (decl) = true; + } + while (++ix != length); + break; + } - /* Check out our super-users. */ - for (value = DECL_NAMESPACE_ASSOCIATIONS (scope); value; - value = TREE_CHAIN (value)) - if (arg_assoc_namespace (k, TREE_PURPOSE (value))) - return true; + gcc_checking_assert (!LOOKUP_FOUND_P (decl)); + LOOKUP_SEEN_P (decl) = true; + } - /* Also look down into inline namespaces. */ - for (value = DECL_NAMESPACE_USING (scope); value; - value = TREE_CHAIN (value)) - if (is_associated_namespace (scope, TREE_PURPOSE (value))) - if (arg_assoc_namespace (k, TREE_PURPOSE (value))) - return true; + free (scopes); + } + else + shared_scopes = scopes; +} - value = get_namespace_binding (scope, k->name); - if (!value) - return false; +void +name_lookup::mark_seen (tree scope) +{ + gcc_checking_assert (!seen_p (scope)); + LOOKUP_SEEN_P (scope) = true; + vec_safe_push (scopes, scope); +} - value = ovl_skip_hidden (value); - - for (; value; value = OVL_NEXT (value)) +bool +name_lookup::find_and_mark (tree scope) +{ + bool result = LOOKUP_FOUND_P (scope); + if (!result) { - if (add_function (k, OVL_CURRENT (value))) - return true; + LOOKUP_FOUND_P (scope) = true; + if (!LOOKUP_SEEN_P (scope)) + vec_safe_push (scopes, scope); } - return false; + return result; } -/* Adds everything associated with a template argument to the lookup - structure. Returns true on error. */ +/* FNS is a value binding. If it is a (set of overloaded) functions, + add them into the current value. */ -static bool -arg_assoc_template_arg (struct arg_lookup *k, tree arg) +void +name_lookup::add_fns (tree fns) { - /* [basic.lookup.koenig] + if (!fns) + return; + else if (TREE_CODE (fns) == OVERLOAD) + { + if (TREE_TYPE (fns) != unknown_type_node) + fns = OVL_FUNCTION (fns); + } + else if (!DECL_DECLARES_FUNCTION_P (fns)) + return; - If T is a template-id, its associated namespaces and classes are - ... the namespaces and classes associated with the types of the - template arguments provided for template type parameters - (excluding template template parameters); the namespaces in which - any template template arguments are defined; and the classes in - which any member templates used as template template arguments - are defined. [Note: non-type template arguments do not - contribute to the set of associated namespaces. ] */ + /* 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); +} - /* Consider first template template arguments. */ - if (TREE_CODE (arg) == TEMPLATE_TEMPLATE_PARM - || TREE_CODE (arg) == UNBOUND_CLASS_TEMPLATE) - return false; - else if (TREE_CODE (arg) == TEMPLATE_DECL) - { - tree ctx = CP_DECL_CONTEXT (arg); +/* Add functions of a namespace to the lookup structure. */ - /* It's not a member template. */ - if (TREE_CODE (ctx) == NAMESPACE_DECL) - return arg_assoc_namespace (k, ctx); - /* Otherwise, it must be member template. */ - else - return arg_assoc_class_only (k, ctx); - } - /* It's an argument pack; handle it recursively. */ - else if (ARGUMENT_PACK_P (arg)) - { - tree args = ARGUMENT_PACK_ARGS (arg); - int i, len = TREE_VEC_LENGTH (args); - for (i = 0; i < len; ++i) - if (arg_assoc_template_arg (k, TREE_VEC_ELT (args, i))) - return true; +void +name_lookup::adl_namespace_only (tree scope) +{ + mark_seen (scope); - return false; - } - /* It's not a template template argument, but it is a type template - argument. */ - else if (TYPE_P (arg)) - return arg_assoc_type (k, arg); - /* It's a non-type template argument. */ - else - return false; + /* Look down into inline namespaces. */ + for (tree inner = NAMESPACE_LEVEL (scope)->namespaces; + inner; inner = TREE_CHAIN (inner)) + if (DECL_NAMESPACE_INLINE_P (inner)) + adl_namespace_only (inner); + + if (cxx_binding *binding = find_namespace_binding (scope, name)) + add_fns (ovl_skip_hidden (binding->value)); } -/* Adds the class and its friends to the lookup structure. - Returns true on error. */ +/* Find the containing non-inlined namespace, add it and all its + inlinees. */ -static bool -arg_assoc_class_only (struct arg_lookup *k, tree type) +void +name_lookup::adl_namespace (tree scope) { - tree list, friends, context; + if (seen_p (scope)) + return; + + /* Find the containing non-inline namespace. */ + while (DECL_NAMESPACE_INLINE_P (scope)) + scope = CP_DECL_CONTEXT (scope); + + adl_namespace_only (scope); +} +/* Adds the class and its friends to the lookup structure. */ + +void +name_lookup::adl_class_only (tree type) +{ /* Backend-built structures, such as __builtin_va_list, aren't affected by all this. */ if (!CLASS_TYPE_P (type)) - return false; + return; - context = decl_namespace_context (type); - if (arg_assoc_namespace (k, context)) - return true; + type = TYPE_MAIN_VARIANT (type); + + if (see_and_mark (type)) + return; + + tree context = decl_namespace_context (type); + adl_namespace (context); complete_type (type); - /* Process friends. */ - for (list = DECL_FRIENDLIST (TYPE_MAIN_DECL (type)); list; + /* Add friends. */ + for (tree list = DECL_FRIENDLIST (TYPE_MAIN_DECL (type)); list; list = TREE_CHAIN (list)) - if (k->name == FRIEND_NAME (list)) - for (friends = FRIEND_DECLS (list); friends; + if (name == FRIEND_NAME (list)) + for (tree friends = FRIEND_DECLS (list); friends; friends = TREE_CHAIN (friends)) { tree fn = TREE_VALUE (friends); @@ -370,40 +436,34 @@ arg_assoc_class_only (struct arg_lookup *k, tree type) (i.e. unqualified) declarations. */ if (CP_DECL_CONTEXT (fn) != context) continue; + /* Template specializations are never found by name lookup. (Templates themselves can be found, but not template specializations.) */ if (TREE_CODE (fn) == FUNCTION_DECL && DECL_USE_TEMPLATE (fn)) continue; - if (add_function (k, fn)) - return true; - } - return false; + add_fns (fn); + } } /* Adds the class and its bases to the lookup structure. Returns true on error. */ -static bool -arg_assoc_bases (struct arg_lookup *k, tree type) +void +name_lookup::adl_bases (tree type) { - if (arg_assoc_class_only (k, type)) - return true; + adl_class_only (type); - if (TYPE_BINFO (type)) + /* Process baseclasses. */ + if (tree binfo = TYPE_BINFO (type)) { - /* Process baseclasses. */ - tree binfo, base_binfo; + tree base_binfo; int i; - for (binfo = TYPE_BINFO (type), i = 0; - BINFO_BASE_ITERATE (binfo, i, base_binfo); i++) - if (arg_assoc_bases (k, BINFO_TYPE (base_binfo))) - return true; + for (i = 0; BINFO_BASE_ITERATE (binfo, i, base_binfo); i++) + adl_bases (BINFO_TYPE (base_binfo)); } - - return false; } /* Adds everything associated with a class argument type to the lookup @@ -422,271 +482,268 @@ arg_assoc_bases (struct arg_lookup *k, tree type) non-type template arguments do not contribute to the set of associated namespaces. --end note] */ -static bool -arg_assoc_class (struct arg_lookup *k, tree type) +void +name_lookup::adl_class (tree type) { - tree list; - int i; - /* Backend build structures, such as __builtin_va_list, aren't affected by all this. */ if (!CLASS_TYPE_P (type)) - return false; + return; - if (vec_member (type, k->classes)) - return false; - vec_safe_push (k->classes, type); + type = TYPE_MAIN_VARIANT (type); + /* We don't set found here because we have to have set seen first, + which is done in the adl_bases walk. */ + if (found_p (type)) + return; - if (TYPE_CLASS_SCOPE_P (type) - && arg_assoc_class_only (k, TYPE_CONTEXT (type))) - return true; + adl_bases (type); + mark_found (type); - if (arg_assoc_bases (k, type)) - return true; + if (TYPE_CLASS_SCOPE_P (type)) + adl_class_only (TYPE_CONTEXT (type)); /* Process template arguments. */ if (CLASSTYPE_TEMPLATE_INFO (type) && PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (type))) { - list = INNERMOST_TEMPLATE_ARGS (CLASSTYPE_TI_ARGS (type)); - for (i = 0; i < TREE_VEC_LENGTH (list); ++i) - if (arg_assoc_template_arg (k, TREE_VEC_ELT (list, i))) - return true; + tree list = INNERMOST_TEMPLATE_ARGS (CLASSTYPE_TI_ARGS (type)); + for (int i = 0; i < TREE_VEC_LENGTH (list); ++i) + adl_template_arg (TREE_VEC_ELT (list, i)); } - - return false; } -/* Adds everything associated with a given type. - Returns 1 on error. */ +void +name_lookup::adl_expr (tree expr) +{ + if (!expr) + return; -static bool -arg_assoc_type (struct arg_lookup *k, tree type) + gcc_assert (!TYPE_P (expr)); + + if (TREE_TYPE (expr) != unknown_type_node) + { + adl_type (TREE_TYPE (expr)); + return; + } + + if (TREE_CODE (expr) == ADDR_EXPR) + expr = TREE_OPERAND (expr, 0); + if (TREE_CODE (expr) == COMPONENT_REF + || TREE_CODE (expr) == OFFSET_REF) + expr = TREE_OPERAND (expr, 1); + expr = MAYBE_BASELINK_FUNCTIONS (expr); + + if (OVL_P (expr)) + for (lkp_iterator iter (expr); iter; ++iter) + adl_type (TREE_TYPE (*iter)); + else if (TREE_CODE (expr) == TEMPLATE_ID_EXPR) + { + /* The working paper doesn't currently say how to handle + template-id arguments. The sensible thing would seem to be + to handle the list of template candidates like a normal + overload set, and handle the template arguments like we do + for class template specializations. */ + + /* First the templates. */ + adl_expr (TREE_OPERAND (expr, 0)); + + /* Now the arguments. */ + if (tree args = TREE_OPERAND (expr, 1)) + for (int ix = TREE_VEC_LENGTH (args); ix--;) + adl_template_arg (TREE_VEC_ELT (args, ix)); + } +} + +void +name_lookup::adl_type (tree type) { - /* As we do not get the type of non-type dependent expressions - right, we can end up with such things without a type. */ if (!type) - return false; + return; if (TYPE_PTRDATAMEM_P (type)) { /* Pointer to member: associate class type and value type. */ - if (arg_assoc_type (k, TYPE_PTRMEM_CLASS_TYPE (type))) - return true; - return arg_assoc_type (k, TYPE_PTRMEM_POINTED_TO_TYPE (type)); + adl_type (TYPE_PTRMEM_CLASS_TYPE (type)); + adl_type (TYPE_PTRMEM_POINTED_TO_TYPE (type)); + return; } - else switch (TREE_CODE (type)) + + switch (TREE_CODE (type)) { - case ERROR_MARK: - return false; - case VOID_TYPE: - case INTEGER_TYPE: - case REAL_TYPE: - case COMPLEX_TYPE: - case VECTOR_TYPE: - case BOOLEAN_TYPE: - case FIXED_POINT_TYPE: - case DECLTYPE_TYPE: - case NULLPTR_TYPE: - return false; case RECORD_TYPE: if (TYPE_PTRMEMFUNC_P (type)) - return arg_assoc_type (k, TYPE_PTRMEMFUNC_FN_TYPE (type)); + { + adl_type (TYPE_PTRMEMFUNC_FN_TYPE (type)); + return; + } /* FALLTHRU */ case UNION_TYPE: - return arg_assoc_class (k, type); - case POINTER_TYPE: - case REFERENCE_TYPE: - case ARRAY_TYPE: - return arg_assoc_type (k, TREE_TYPE (type)); - case ENUMERAL_TYPE: - if (TYPE_CLASS_SCOPE_P (type) - && arg_assoc_class_only (k, TYPE_CONTEXT (type))) - return true; - return arg_assoc_namespace (k, decl_namespace_context (type)); + adl_class (type); + return; + case METHOD_TYPE: /* The basetype is referenced in the first arg type, so just fall through. */ case FUNCTION_TYPE: /* Associate the parameter types. */ - if (arg_assoc_args (k, TYPE_ARG_TYPES (type))) - return true; - /* Associate the return type. */ - return arg_assoc_type (k, TREE_TYPE (type)); - case TEMPLATE_TYPE_PARM: - case BOUND_TEMPLATE_TEMPLATE_PARM: - return false; - case TYPENAME_TYPE: - return false; + for (tree args = TYPE_ARG_TYPES (type); args; args = TREE_CHAIN (args)) + adl_type (TREE_VALUE (args)); + /* FALLTHROUGH */ + + case POINTER_TYPE: + case REFERENCE_TYPE: + case ARRAY_TYPE: + adl_type (TREE_TYPE (type)); + return; + + case ENUMERAL_TYPE: + if (TYPE_CLASS_SCOPE_P (type)) + adl_class_only (TYPE_CONTEXT (type)); + adl_namespace (decl_namespace_context (type)); + return; + case LANG_TYPE: gcc_assert (type == unknown_type_node || type == init_list_type_node); - return false; + return; + case TYPE_PACK_EXPANSION: - return arg_assoc_type (k, PACK_EXPANSION_PATTERN (type)); + adl_type (PACK_EXPANSION_PATTERN (type)); + return; default: - gcc_unreachable (); + break; } - return false; -} - -/* Adds everything associated with arguments. Returns true on error. */ - -static bool -arg_assoc_args (struct arg_lookup *k, tree args) -{ - for (; args; args = TREE_CHAIN (args)) - if (arg_assoc (k, TREE_VALUE (args))) - return true; - return false; } -/* Adds everything associated with an argument vector. Returns true - on error. */ - -static bool -arg_assoc_args_vec (struct arg_lookup *k, vec *args) -{ - unsigned int ix; - tree arg; - - FOR_EACH_VEC_SAFE_ELT (args, ix, arg) - if (arg_assoc (k, arg)) - return true; - return false; -} - -/* Adds everything associated with a given tree_node. Returns 1 on error. */ +/* Adds everything associated with a template argument to the lookup + structure. */ -static bool -arg_assoc (struct arg_lookup *k, tree n) +void +name_lookup::adl_template_arg (tree arg) { - if (n == error_mark_node) - return false; + /* [basic.lookup.koenig] - if (TYPE_P (n)) - return arg_assoc_type (k, n); - - if (! type_unknown_p (n)) - return arg_assoc_type (k, TREE_TYPE (n)); - - if (TREE_CODE (n) == ADDR_EXPR) - n = TREE_OPERAND (n, 0); - if (TREE_CODE (n) == COMPONENT_REF) - n = TREE_OPERAND (n, 1); - if (TREE_CODE (n) == OFFSET_REF) - n = TREE_OPERAND (n, 1); - while (TREE_CODE (n) == TREE_LIST) - n = TREE_VALUE (n); - if (BASELINK_P (n)) - n = BASELINK_FUNCTIONS (n); - - if (TREE_CODE (n) == FUNCTION_DECL) - return arg_assoc_type (k, TREE_TYPE (n)); - if (TREE_CODE (n) == TEMPLATE_ID_EXPR) - { - /* The working paper doesn't currently say how to handle template-id - arguments. The sensible thing would seem to be to handle the list - of template candidates like a normal overload set, and handle the - template arguments like we do for class template - specializations. */ - tree templ = TREE_OPERAND (n, 0); - tree args = TREE_OPERAND (n, 1); - int ix; + If T is a template-id, its associated namespaces and classes are + ... the namespaces and classes associated with the types of the + template arguments provided for template type parameters + (excluding template template parameters); the namespaces in which + any template template arguments are defined; and the classes in + which any member templates used as template template arguments + are defined. [Note: non-type template arguments do not + contribute to the set of associated namespaces. ] */ - /* First the templates. */ - if (arg_assoc (k, templ)) - return true; + /* Consider first template template arguments. */ + if (TREE_CODE (arg) == TEMPLATE_TEMPLATE_PARM + || TREE_CODE (arg) == UNBOUND_CLASS_TEMPLATE) + ; + else if (TREE_CODE (arg) == TEMPLATE_DECL) + { + tree ctx = CP_DECL_CONTEXT (arg); - /* Now the arguments. */ - if (args) - for (ix = TREE_VEC_LENGTH (args); ix--;) - if (arg_assoc_template_arg (k, TREE_VEC_ELT (args, ix)) == 1) - return true; + /* It's not a member template. */ + if (TREE_CODE (ctx) == NAMESPACE_DECL) + adl_namespace (ctx); + /* Otherwise, it must be member template. */ + else + adl_class_only (ctx); } - else if (TREE_CODE (n) == OVERLOAD) + /* It's an argument pack; handle it recursively. */ + else if (ARGUMENT_PACK_P (arg)) { - for (; n; n = OVL_NEXT (n)) - if (arg_assoc_type (k, TREE_TYPE (OVL_CURRENT (n)))) - return true; + tree args = ARGUMENT_PACK_ARGS (arg); + int i, len = TREE_VEC_LENGTH (args); + for (i = 0; i < len; ++i) + adl_template_arg (TREE_VEC_ELT (args, i)); } - - return false; + /* It's not a template template argument, but it is a type template + argument. */ + else if (TYPE_P (arg)) + adl_type (arg); } -/* Performs Koenig lookup depending on arguments, where fns - are the functions found in normal lookup. */ +/* Perform ADL lookup. FNS is the existing lookup result and ARGS are + the call arguments. */ -static cp_expr -lookup_arg_dependent_1 (tree name, tree fns, vec *args) +tree +name_lookup::search_adl (tree fns, vec *args) { - struct arg_lookup k; + value = fns; - /* Remove any hidden friend functions from the list of functions - found so far. They will be added back by arg_assoc_class as - appropriate. */ - fns = ovl_skip_hidden (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); - k.name = name; - k.args = args; - k.functions = fns; - k.classes = make_tree_vector (); - - /* We previously performed an optimization here by setting - NAMESPACES to the current namespace when it was safe. However, DR - 164 says that namespaces that were already searched in the first - stage of template processing are searched again (potentially - picking up later definitions) in the second stage. */ - k.namespaces = make_tree_vector (); + unsigned ix; + tree arg; - /* We used to allow duplicates and let joust discard them, but - since the above change for DR 164 we end up with duplicates of - all the functions found by unqualified lookup. So keep track - of which ones we've seen. */ - if (fns) - { - tree ovl; - /* We shouldn't be here if lookup found something other than - namespace-scope functions. */ - gcc_assert (DECL_NAMESPACE_SCOPE_P (OVL_CURRENT (fns))); - k.fn_set = new hash_set; - for (ovl = fns; ovl; ovl = OVL_NEXT (ovl)) - k.fn_set->add (OVL_CURRENT (ovl)); - } - else - k.fn_set = NULL; + FOR_EACH_VEC_ELT_REVERSE (*args, ix, arg) + /* OMP reduction operators put a type as the first arg. I don't + suppose we should ADL on that? */ + if (!TYPE_P (arg)) + adl_expr (arg); - arg_assoc_args_vec (&k, args); + delete fn_set; + fn_set = NULL; - fns = k.functions; - - if (fns - && !VAR_P (fns) - && !is_overloaded_fn (fns)) - { - error ("argument dependent lookup finds %q+D", fns); - error (" in call to %qD", name); - fns = error_mark_node; - } + fns = value; - release_tree_vector (k.classes); - release_tree_vector (k.namespaces); - delete k.fn_set; - return fns; } -/* Wrapper for lookup_arg_dependent_1. */ +/* ADL lookup of NAME. FNS is the result of regular lookup, and we + don't add duplicates to it. ARGS is the vector of call + arguments (which will not be empty). */ -cp_expr +tree lookup_arg_dependent (tree name, tree fns, vec *args) { - cp_expr ret; - bool subtime; - subtime = timevar_cond_start (TV_NAME_LOOKUP); - ret = lookup_arg_dependent_1 (name, fns, args); + bool subtime = timevar_cond_start (TV_NAME_LOOKUP); + name_lookup lookup (name); + fns = lookup.search_adl (fns, args); timevar_cond_stop (TV_NAME_LOOKUP, subtime); + return fns; +} + +/* Returns true iff CURRENT has declared itself to be an associated + namespace of SCOPE via a strong using-directive (or transitive chain + thereof). Both are namespaces. */ + +bool +is_associated_namespace (tree current, tree scope) +{ + vec *seen = make_tree_vector (); + vec *todo = make_tree_vector (); + tree t; + bool ret; + + while (1) + { + if (scope == current) + { + ret = true; + break; + } + vec_safe_push (seen, scope); + for (t = DECL_NAMESPACE_ASSOCIATIONS (scope); t; t = TREE_CHAIN (t)) + if (!vec_member (TREE_PURPOSE (t), seen)) + vec_safe_push (todo, TREE_PURPOSE (t)); + if (!todo->is_empty ()) + { + scope = todo->last (); + todo->pop (); + } + else + { + ret = false; + break; + } + } + + release_tree_vector (seen); + release_tree_vector (todo); + return ret; } diff --git a/gcc/cp/name-lookup.h b/gcc/cp/name-lookup.h index 637599c9be1..a2454bbcf45 100644 --- a/gcc/cp/name-lookup.h +++ b/gcc/cp/name-lookup.h @@ -324,7 +324,7 @@ extern void pop_decl_namespace (void); extern void do_namespace_alias (tree, tree); extern tree do_class_using_decl (tree, tree); extern void do_using_directive (tree); -extern cp_expr lookup_arg_dependent (tree, tree, vec *); +extern tree lookup_arg_dependent (tree, tree, vec *); extern bool is_associated_namespace (tree, tree); extern tree innermost_non_namespace_value (tree); extern cxx_binding *outer_binding (tree, cxx_binding *, bool); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index ab09dcba25b..a0f81818395 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2017-05-25 Nathan Sidwell + + * g++.dg/lookup/koenig14.C: New. + 2017-05-25 Paolo Carlini PR c++/79583 diff --git a/gcc/testsuite/g++.dg/lookup/koenig14.C b/gcc/testsuite/g++.dg/lookup/koenig14.C new file mode 100644 index 00000000000..d901591053e --- /dev/null +++ b/gcc/testsuite/g++.dg/lookup/koenig14.C @@ -0,0 +1,30 @@ +// ADL can be recursive (via instantiation), make sure that works. + +namespace X +{ + class B {}; + + void frob (); + int frob (B); // Inner ADL resolves here +} + +void frob (int); +void frob (float); + +namespace Y +{ + struct A {}; + void frob (void*, void *, void *); // Outer ADL resolves here +} + +template +struct C : U +{ + int ary[sizeof frob(T())]; // ADL occurs here during instantiation +}; + +void Foo (C *p, X::B *q) +{ + frob(q, p, q); // ADL causes instantation of C<...> + // We will have already searched X by the time the instantation happens +} -- 2.30.2