Commit f35a733d by Nathan Sidwell Committed by Nathan Sidwell

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
parent 8442a5fb
2017-05-25 Nathan Sidwell <nathan@acm.org>
* 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 <nathan@acm.org> 2017-05-24 Nathan Sidwell <nathan@acm.org>
* friend.c (do_friend): Remove check for existing decl. * friend.c (do_friend): Remove check for existing decl.
......
...@@ -395,6 +395,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX]; ...@@ -395,6 +395,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
DECL_TINFO_P (in VAR_DECL) DECL_TINFO_P (in VAR_DECL)
FUNCTION_REF_QUALIFIED (in FUNCTION_TYPE, METHOD_TYPE) FUNCTION_REF_QUALIFIED (in FUNCTION_TYPE, METHOD_TYPE)
OVL_LOOKUP_P (in OVERLOAD) OVL_LOOKUP_P (in OVERLOAD)
LOOKUP_FOUND_P (in RECORD_TYPE, UNION_TYPE, NAMESPACE_DECL)
5: C_IS_RESERVED_WORD (in IDENTIFIER_NODE) 5: C_IS_RESERVED_WORD (in IDENTIFIER_NODE)
DECL_VTABLE_OR_VTT_P (in VAR_DECL) DECL_VTABLE_OR_VTT_P (in VAR_DECL)
FUNCTION_RVALUE_QUALIFIED (in FUNCTION_TYPE, METHOD_TYPE) FUNCTION_RVALUE_QUALIFIED (in FUNCTION_TYPE, METHOD_TYPE)
...@@ -648,10 +649,17 @@ typedef struct ptrmem_cst * ptrmem_cst_t; ...@@ -648,10 +649,17 @@ typedef struct ptrmem_cst * ptrmem_cst_t;
&& MAIN_NAME_P (DECL_NAME (NODE)) \ && MAIN_NAME_P (DECL_NAME (NODE)) \
&& flag_hosted) && 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) \ #define OVL_FUNCTION(NODE) \
(((struct tree_overload*)OVERLOAD_CHECK (NODE))->function) (((struct tree_overload*)OVERLOAD_CHECK (NODE))->function)
#define OVL_CHAIN(NODE) TREE_CHAIN (NODE) #define OVL_CHAIN(NODE) TREE_CHAIN (NODE)
/* Polymorphic access to FUNCTION and CHAIN. */ /* Polymorphic access to FUNCTION and CHAIN. */
#define OVL_CURRENT(NODE) \ #define OVL_CURRENT(NODE) \
((TREE_CODE (NODE) == OVERLOAD) ? OVL_FUNCTION (NODE) : (NODE)) ((TREE_CODE (NODE) == OVERLOAD) ? OVL_FUNCTION (NODE) : (NODE))
......
...@@ -160,208 +160,274 @@ find_local_binding (cp_binding_level *b, tree name) ...@@ -160,208 +160,274 @@ find_local_binding (cp_binding_level *b, tree name)
return NULL; return NULL;
} }
/* [basic.lookup.koenig] */ struct name_lookup
/* A nonzero return value in the functions below indicates an error. */ {
public:
struct arg_lookup tree name; /* The identifier being looked for. */
{ tree value; /* A (possibly ambiguous) set of things found. */
tree name; tree type; /* A type that has been found. */
vec<tree, va_gc> *args; vec<tree, va_heap, vl_embed> *scopes;
vec<tree, va_gc> *namespaces; name_lookup *previous; /* Previously active lookup. */
vec<tree, va_gc> *classes;
tree functions;
hash_set<tree> *fn_set; hash_set<tree> *fn_set;
};
static bool arg_assoc (struct arg_lookup*, tree); protected:
static bool arg_assoc_args (struct arg_lookup*, tree); /* Marked scope stack for outermost name lookup. */
static bool arg_assoc_args_vec (struct arg_lookup*, vec<tree, va_gc> *); static vec<tree, va_heap, vl_embed> *shared_scopes;
static bool arg_assoc_type (struct arg_lookup*, tree); /* Currently active lookup. */
static bool add_function (struct arg_lookup *, tree); static name_lookup *active;
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. */
static bool public:
add_function (struct arg_lookup *k, tree fn) name_lookup (tree n)
{ : name (n), value (NULL_TREE), type (NULL_TREE),
if (!is_overloaded_fn (fn)) scopes (NULL), previous (NULL), fn_set (NULL)
/* All names except those of (possibly overloaded) functions and {
function templates are ignored. */; preserve_state ();
else if (k->fn_set && k->fn_set->add (fn)) }
/* It's already in the list. */; ~name_lookup ()
else if (!k->functions && TREE_CODE (fn) != TEMPLATE_DECL) {
k->functions = fn; gcc_checking_assert (!fn_set);
else if (fn == k->functions) restore_state ();
; }
else
k->functions = lookup_add (fn, k->functions);
return false;
}
/* Returns true iff CURRENT has declared itself to be an associated private: /* Uncopyable, unmovable, unassignable. I am a rock. */
namespace of SCOPE via a strong using-directive (or transitive chain name_lookup (const name_lookup &);
thereof). Both are namespaces. */ name_lookup &operator= (const name_lookup &);
bool protected:
is_associated_namespace (tree current, tree scope) static bool seen_p (tree scope)
{
vec<tree, va_gc> *seen = make_tree_vector ();
vec<tree, va_gc> *todo = make_tree_vector ();
tree t;
bool ret;
while (1)
{ {
if (scope == current) return LOOKUP_SEEN_P (scope);
{
ret = true;
break;
} }
vec_safe_push (seen, scope); static bool found_p (tree 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 (); return LOOKUP_FOUND_P (scope);
todo->pop ();
} }
else
void mark_seen (tree scope); /* Mark and add to scope vector. */
static void mark_found (tree scope)
{ {
ret = false; gcc_checking_assert (seen_p (scope));
break; 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);
release_tree_vector (seen); private:
release_tree_vector (todo); void preserve_state ();
void restore_state ();
return ret; private:
} void add_fns (tree);
/* Add functions of a namespace to the lookup structure. void adl_expr (tree);
Returns true on error. */ 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);
static bool public:
arg_assoc_namespace (struct arg_lookup *k, tree scope) tree search_adl (tree fns, vec<tree, va_gc> *args);
{ };
tree value;
if (vec_member (scope, k->namespaces)) /* Scope stack shared by all outermost lookups. This avoids us
return false; allocating and freeing on every single lookup. */
vec_safe_push (k->namespaces, scope); vec<tree, va_heap, vl_embed> *name_lookup::shared_scopes;
/* Check out our super-users. */ /* Currently active lookup. */
for (value = DECL_NAMESPACE_ASSOCIATIONS (scope); value; name_lookup *name_lookup::active;
value = TREE_CHAIN (value))
if (arg_assoc_namespace (k, TREE_PURPOSE (value)))
return true;
/* Also look down into inline namespaces. */ /* Name lookup is recursive, becase ADL can cause template
for (value = DECL_NAMESPACE_USING (scope); value; instatiation. This is of course a rare event, so we optimize for
value = TREE_CHAIN (value)) it not happening. When we discover an active name-lookup, which
if (is_associated_namespace (scope, TREE_PURPOSE (value))) must be an ADL lookup, we need to unmark the marked scopes and also
if (arg_assoc_namespace (k, TREE_PURPOSE (value))) unmark the lookup we might have been accumulating. */
return true;
value = get_namespace_binding (scope, k->name); void
if (!value) name_lookup::preserve_state ()
return false; {
previous = active;
if (previous)
{
unsigned length = vec_safe_length (previous->scopes);
vec_safe_reserve (previous->scopes, length * 2);
for (unsigned ix = length; ix--;)
{
tree decl = (*previous->scopes)[ix];
value = ovl_skip_hidden (value); gcc_checking_assert (LOOKUP_SEEN_P (decl));
LOOKUP_SEEN_P (decl) = false;
for (; value; value = OVL_NEXT (value)) /* Preserve the FOUND_P state on the interrupted lookup's
stack. */
if (LOOKUP_FOUND_P (decl))
{ {
if (add_function (k, OVL_CURRENT (value))) LOOKUP_FOUND_P (decl) = false;
return true; previous->scopes->quick_push (decl);
} }
}
return false; }
else
scopes = shared_scopes;
active = this;
} }
/* Adds everything associated with a template argument to the lookup /* Restore the marking state of a lookup we interrupted. */
structure. Returns true on error. */
static bool void
arg_assoc_template_arg (struct arg_lookup *k, tree arg) name_lookup::restore_state ()
{ {
/* [basic.lookup.koenig] /* Unmark and empty this lookup's scope stack. */
for (unsigned ix = vec_safe_length (scopes); ix--;)
If T is a template-id, its associated namespaces and classes are {
... the namespaces and classes associated with the types of the tree decl = scopes->pop ();
template arguments provided for template type parameters gcc_checking_assert (LOOKUP_SEEN_P (decl));
(excluding template template parameters); the namespaces in which LOOKUP_SEEN_P (decl) = false;
any template template arguments are defined; and the classes in LOOKUP_FOUND_P (decl) = false;
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. ] */
/* Consider first template template arguments. */ active = previous;
if (TREE_CODE (arg) == TEMPLATE_TEMPLATE_PARM if (previous)
|| TREE_CODE (arg) == UNBOUND_CLASS_TEMPLATE)
return false;
else if (TREE_CODE (arg) == TEMPLATE_DECL)
{ {
tree ctx = CP_DECL_CONTEXT (arg); 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;
}
/* It's not a member template. */ gcc_checking_assert (!LOOKUP_FOUND_P (decl));
if (TREE_CODE (ctx) == NAMESPACE_DECL) LOOKUP_SEEN_P (decl) = true;
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;
return false; free (scopes);
} }
/* 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 else
return false; shared_scopes = scopes;
} }
/* Adds the class and its friends to the lookup structure. void
Returns true on error. */ name_lookup::mark_seen (tree scope)
{
gcc_checking_assert (!seen_p (scope));
LOOKUP_SEEN_P (scope) = true;
vec_safe_push (scopes, scope);
}
static bool bool
arg_assoc_class_only (struct arg_lookup *k, tree type) name_lookup::find_and_mark (tree scope)
{
bool result = LOOKUP_FOUND_P (scope);
if (!result)
{
LOOKUP_FOUND_P (scope) = true;
if (!LOOKUP_SEEN_P (scope))
vec_safe_push (scopes, scope);
}
return result;
}
/* FNS is a value binding. If it is a (set of overloaded) functions,
add them into the current value. */
void
name_lookup::add_fns (tree fns)
{
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;
/* 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);
}
/* Add functions of a namespace to the lookup structure. */
void
name_lookup::adl_namespace_only (tree scope)
{
mark_seen (scope);
/* 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));
}
/* Find the containing non-inlined namespace, add it and all its
inlinees. */
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 /* Backend-built structures, such as __builtin_va_list, aren't
affected by all this. */ affected by all this. */
if (!CLASS_TYPE_P (type)) if (!CLASS_TYPE_P (type))
return false; return;
context = decl_namespace_context (type); type = TYPE_MAIN_VARIANT (type);
if (arg_assoc_namespace (k, context))
return true; if (see_and_mark (type))
return;
tree context = decl_namespace_context (type);
adl_namespace (context);
complete_type (type); complete_type (type);
/* Process friends. */ /* Add friends. */
for (list = DECL_FRIENDLIST (TYPE_MAIN_DECL (type)); list; for (tree list = DECL_FRIENDLIST (TYPE_MAIN_DECL (type)); list;
list = TREE_CHAIN (list)) list = TREE_CHAIN (list))
if (k->name == FRIEND_NAME (list)) if (name == FRIEND_NAME (list))
for (friends = FRIEND_DECLS (list); friends; for (tree friends = FRIEND_DECLS (list); friends;
friends = TREE_CHAIN (friends)) friends = TREE_CHAIN (friends))
{ {
tree fn = TREE_VALUE (friends); tree fn = TREE_VALUE (friends);
...@@ -370,40 +436,34 @@ arg_assoc_class_only (struct arg_lookup *k, tree type) ...@@ -370,40 +436,34 @@ arg_assoc_class_only (struct arg_lookup *k, tree type)
(i.e. unqualified) declarations. */ (i.e. unqualified) declarations. */
if (CP_DECL_CONTEXT (fn) != context) if (CP_DECL_CONTEXT (fn) != context)
continue; continue;
/* Template specializations are never found by name lookup. /* Template specializations are never found by name lookup.
(Templates themselves can be found, but not template (Templates themselves can be found, but not template
specializations.) */ specializations.) */
if (TREE_CODE (fn) == FUNCTION_DECL && DECL_USE_TEMPLATE (fn)) if (TREE_CODE (fn) == FUNCTION_DECL && DECL_USE_TEMPLATE (fn))
continue; continue;
if (add_function (k, fn))
return true;
}
return false; add_fns (fn);
}
} }
/* Adds the class and its bases to the lookup structure. /* Adds the class and its bases to the lookup structure.
Returns true on error. */ Returns true on error. */
static bool void
arg_assoc_bases (struct arg_lookup *k, tree type) name_lookup::adl_bases (tree type)
{ {
if (arg_assoc_class_only (k, type)) adl_class_only (type);
return true;
if (TYPE_BINFO (type))
{
/* Process baseclasses. */ /* Process baseclasses. */
tree binfo, base_binfo; if (tree binfo = TYPE_BINFO (type))
{
tree base_binfo;
int i; int i;
for (binfo = TYPE_BINFO (type), i = 0; for (i = 0; BINFO_BASE_ITERATE (binfo, i, base_binfo); i++)
BINFO_BASE_ITERATE (binfo, i, base_binfo); i++) adl_bases (BINFO_TYPE (base_binfo));
if (arg_assoc_bases (k, BINFO_TYPE (base_binfo)))
return true;
} }
return false;
} }
/* Adds everything associated with a class argument type to the lookup /* Adds everything associated with a class argument type to the lookup
...@@ -422,271 +482,268 @@ arg_assoc_bases (struct arg_lookup *k, tree type) ...@@ -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 non-type template arguments do not contribute to the set of associated
namespaces. --end note] */ namespaces. --end note] */
static bool void
arg_assoc_class (struct arg_lookup *k, tree type) name_lookup::adl_class (tree type)
{ {
tree list;
int i;
/* Backend build structures, such as __builtin_va_list, aren't /* Backend build structures, such as __builtin_va_list, aren't
affected by all this. */ affected by all this. */
if (!CLASS_TYPE_P (type)) if (!CLASS_TYPE_P (type))
return false; return;
if (vec_member (type, k->classes)) type = TYPE_MAIN_VARIANT (type);
return false; /* We don't set found here because we have to have set seen first,
vec_safe_push (k->classes, type); which is done in the adl_bases walk. */
if (found_p (type))
return;
if (TYPE_CLASS_SCOPE_P (type) adl_bases (type);
&& arg_assoc_class_only (k, TYPE_CONTEXT (type))) mark_found (type);
return true;
if (arg_assoc_bases (k, type)) if (TYPE_CLASS_SCOPE_P (type))
return true; adl_class_only (TYPE_CONTEXT (type));
/* Process template arguments. */ /* Process template arguments. */
if (CLASSTYPE_TEMPLATE_INFO (type) if (CLASSTYPE_TEMPLATE_INFO (type)
&& PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (type))) && PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (type)))
{ {
list = INNERMOST_TEMPLATE_ARGS (CLASSTYPE_TI_ARGS (type)); tree list = INNERMOST_TEMPLATE_ARGS (CLASSTYPE_TI_ARGS (type));
for (i = 0; i < TREE_VEC_LENGTH (list); ++i) for (int i = 0; i < TREE_VEC_LENGTH (list); ++i)
if (arg_assoc_template_arg (k, TREE_VEC_ELT (list, i))) adl_template_arg (TREE_VEC_ELT (list, i));
return true;
} }
return false;
} }
/* Adds everything associated with a given type. void
Returns 1 on error. */ name_lookup::adl_expr (tree expr)
{
if (!expr)
return;
gcc_assert (!TYPE_P (expr));
static bool if (TREE_TYPE (expr) != unknown_type_node)
arg_assoc_type (struct arg_lookup *k, tree type) {
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) if (!type)
return false; return;
if (TYPE_PTRDATAMEM_P (type)) if (TYPE_PTRDATAMEM_P (type))
{ {
/* Pointer to member: associate class type and value type. */ /* Pointer to member: associate class type and value type. */
if (arg_assoc_type (k, TYPE_PTRMEM_CLASS_TYPE (type))) adl_type (TYPE_PTRMEM_CLASS_TYPE (type));
return true; adl_type (TYPE_PTRMEM_POINTED_TO_TYPE (type));
return arg_assoc_type (k, 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: case RECORD_TYPE:
if (TYPE_PTRMEMFUNC_P (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 */ /* FALLTHRU */
case UNION_TYPE: case UNION_TYPE:
return arg_assoc_class (k, type); adl_class (type);
case POINTER_TYPE: return;
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));
case METHOD_TYPE: case METHOD_TYPE:
/* The basetype is referenced in the first arg type, so just /* The basetype is referenced in the first arg type, so just
fall through. */ fall through. */
case FUNCTION_TYPE: case FUNCTION_TYPE:
/* Associate the parameter types. */ /* Associate the parameter types. */
if (arg_assoc_args (k, TYPE_ARG_TYPES (type))) for (tree args = TYPE_ARG_TYPES (type); args; args = TREE_CHAIN (args))
return true; adl_type (TREE_VALUE (args));
/* Associate the return type. */ /* FALLTHROUGH */
return arg_assoc_type (k, TREE_TYPE (type));
case TEMPLATE_TYPE_PARM: case POINTER_TYPE:
case BOUND_TEMPLATE_TEMPLATE_PARM: case REFERENCE_TYPE:
return false; case ARRAY_TYPE:
case TYPENAME_TYPE: adl_type (TREE_TYPE (type));
return false; 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: case LANG_TYPE:
gcc_assert (type == unknown_type_node gcc_assert (type == unknown_type_node
|| type == init_list_type_node); || type == init_list_type_node);
return false; return;
case TYPE_PACK_EXPANSION: case TYPE_PACK_EXPANSION:
return arg_assoc_type (k, PACK_EXPANSION_PATTERN (type)); adl_type (PACK_EXPANSION_PATTERN (type));
return;
default: default:
gcc_unreachable (); break;
} }
return false;
} }
/* Adds everything associated with arguments. Returns true on error. */ /* Adds everything associated with a template argument to the lookup
structure. */
static bool void
arg_assoc_args (struct arg_lookup *k, tree args) name_lookup::adl_template_arg (tree arg)
{ {
for (; args; args = TREE_CHAIN (args)) /* [basic.lookup.koenig]
if (arg_assoc (k, TREE_VALUE (args)))
return true;
return false;
}
/* Adds everything associated with an argument vector. Returns true If T is a template-id, its associated namespaces and classes are
on error. */ ... 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. ] */
static bool /* Consider first template template arguments. */
arg_assoc_args_vec (struct arg_lookup *k, vec<tree, va_gc> *args) if (TREE_CODE (arg) == TEMPLATE_TEMPLATE_PARM
{ || TREE_CODE (arg) == UNBOUND_CLASS_TEMPLATE)
unsigned int ix; ;
tree arg; else if (TREE_CODE (arg) == TEMPLATE_DECL)
{
tree ctx = CP_DECL_CONTEXT (arg);
FOR_EACH_VEC_SAFE_ELT (args, ix, arg) /* It's not a member template. */
if (arg_assoc (k, arg)) if (TREE_CODE (ctx) == NAMESPACE_DECL)
return true; adl_namespace (ctx);
return false; /* Otherwise, it must be member template. */
else
adl_class_only (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)
adl_template_arg (TREE_VEC_ELT (args, i));
}
/* It's not a template template argument, but it is a type template
argument. */
else if (TYPE_P (arg))
adl_type (arg);
} }
/* Adds everything associated with a given tree_node. Returns 1 on error. */ /* Perform ADL lookup. FNS is the existing lookup result and ARGS are
the call arguments. */
static bool tree
arg_assoc (struct arg_lookup *k, tree n) name_lookup::search_adl (tree fns, vec<tree, va_gc> *args)
{ {
if (n == error_mark_node) value = fns;
return false;
if (TYPE_P (n)) /* Add the current overload set into the hash table. */
return arg_assoc_type (k, n); fn_set = new hash_set<tree>;
for (lkp_iterator iter (fns); iter; ++iter)
if (! type_unknown_p (n)) fn_set->add (*iter);
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;
/* First the templates. */ unsigned ix;
if (arg_assoc (k, templ)) tree arg;
return true;
/* Now the arguments. */ FOR_EACH_VEC_ELT_REVERSE (*args, ix, arg)
if (args) /* OMP reduction operators put a type as the first arg. I don't
for (ix = TREE_VEC_LENGTH (args); ix--;) suppose we should ADL on that? */
if (arg_assoc_template_arg (k, TREE_VEC_ELT (args, ix)) == 1) if (!TYPE_P (arg))
return true; adl_expr (arg);
}
else if (TREE_CODE (n) == OVERLOAD)
{
for (; n; n = OVL_NEXT (n))
if (arg_assoc_type (k, TREE_TYPE (OVL_CURRENT (n))))
return true;
}
return false; delete fn_set;
fn_set = NULL;
fns = value;
return fns;
} }
/* Performs Koenig lookup depending on arguments, where fns /* ADL lookup of NAME. FNS is the result of regular lookup, and we
are the functions found in normal lookup. */ don't add duplicates to it. ARGS is the vector of call
arguments (which will not be empty). */
static cp_expr tree
lookup_arg_dependent_1 (tree name, tree fns, vec<tree, va_gc> *args) lookup_arg_dependent (tree name, tree fns, vec<tree, va_gc> *args)
{ {
struct arg_lookup k; bool subtime = timevar_cond_start (TV_NAME_LOOKUP);
name_lookup lookup (name);
/* Remove any hidden friend functions from the list of functions fns = lookup.search_adl (fns, args);
found so far. They will be added back by arg_assoc_class as timevar_cond_stop (TV_NAME_LOOKUP, subtime);
appropriate. */ return fns;
fns = ovl_skip_hidden (fns); }
k.name = name; /* Returns true iff CURRENT has declared itself to be an associated
k.args = args; namespace of SCOPE via a strong using-directive (or transitive chain
k.functions = fns; thereof). Both are namespaces. */
k.classes = make_tree_vector ();
/* We previously performed an optimization here by setting bool
NAMESPACES to the current namespace when it was safe. However, DR is_associated_namespace (tree current, tree scope)
164 says that namespaces that were already searched in the first {
stage of template processing are searched again (potentially vec<tree, va_gc> *seen = make_tree_vector ();
picking up later definitions) in the second stage. */ vec<tree, va_gc> *todo = make_tree_vector ();
k.namespaces = make_tree_vector (); tree t;
bool ret;
/* We used to allow duplicates and let joust discard them, but while (1)
since the above change for DR 164 we end up with duplicates of {
all the functions found by unqualified lookup. So keep track if (scope == current)
of which ones we've seen. */
if (fns)
{ {
tree ovl; ret = true;
/* We shouldn't be here if lookup found something other than break;
namespace-scope functions. */ }
gcc_assert (DECL_NAMESPACE_SCOPE_P (OVL_CURRENT (fns))); vec_safe_push (seen, scope);
k.fn_set = new hash_set<tree>; for (t = DECL_NAMESPACE_ASSOCIATIONS (scope); t; t = TREE_CHAIN (t))
for (ovl = fns; ovl; ovl = OVL_NEXT (ovl)) if (!vec_member (TREE_PURPOSE (t), seen))
k.fn_set->add (OVL_CURRENT (ovl)); vec_safe_push (todo, TREE_PURPOSE (t));
if (!todo->is_empty ())
{
scope = todo->last ();
todo->pop ();
} }
else else
k.fn_set = NULL;
arg_assoc_args_vec (&k, args);
fns = k.functions;
if (fns
&& !VAR_P (fns)
&& !is_overloaded_fn (fns))
{ {
error ("argument dependent lookup finds %q+D", fns); ret = false;
error (" in call to %qD", name); break;
fns = error_mark_node; }
} }
release_tree_vector (k.classes); release_tree_vector (seen);
release_tree_vector (k.namespaces); release_tree_vector (todo);
delete k.fn_set;
return fns;
}
/* Wrapper for lookup_arg_dependent_1. */
cp_expr
lookup_arg_dependent (tree name, tree fns, vec<tree, va_gc> *args)
{
cp_expr ret;
bool subtime;
subtime = timevar_cond_start (TV_NAME_LOOKUP);
ret = lookup_arg_dependent_1 (name, fns, args);
timevar_cond_stop (TV_NAME_LOOKUP, subtime);
return ret; return ret;
} }
......
...@@ -324,7 +324,7 @@ extern void pop_decl_namespace (void); ...@@ -324,7 +324,7 @@ extern void pop_decl_namespace (void);
extern void do_namespace_alias (tree, tree); extern void do_namespace_alias (tree, tree);
extern tree do_class_using_decl (tree, tree); extern tree do_class_using_decl (tree, tree);
extern void do_using_directive (tree); extern void do_using_directive (tree);
extern cp_expr lookup_arg_dependent (tree, tree, vec<tree, va_gc> *); extern tree lookup_arg_dependent (tree, tree, vec<tree, va_gc> *);
extern bool is_associated_namespace (tree, tree); extern bool is_associated_namespace (tree, tree);
extern tree innermost_non_namespace_value (tree); extern tree innermost_non_namespace_value (tree);
extern cxx_binding *outer_binding (tree, cxx_binding *, bool); extern cxx_binding *outer_binding (tree, cxx_binding *, bool);
......
2017-05-25 Nathan Sidwell <nathan@acm.org>
* g++.dg/lookup/koenig14.C: New.
2017-05-25 Paolo Carlini <paolo.carlini@oracle.com> 2017-05-25 Paolo Carlini <paolo.carlini@oracle.com>
PR c++/79583 PR c++/79583
......
// 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 <typename T, typename U>
struct C : U
{
int ary[sizeof frob(T())]; // ADL occurs here during instantiation
};
void Foo (C<X::B, Y::A> *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
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment