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; 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 protected:
namespace of SCOPE via a strong using-directive (or transitive chain static bool seen_p (tree scope)
thereof). Both are namespaces. */ {
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<tree, va_gc> *args);
};
bool /* Scope stack shared by all outermost lookups. This avoids us
is_associated_namespace (tree current, tree scope) allocating and freeing on every single lookup. */
{ vec<tree, va_heap, vl_embed> *name_lookup::shared_scopes;
vec<tree, va_gc> *seen = make_tree_vector ();
vec<tree, va_gc> *todo = make_tree_vector ();
tree t;
bool ret;
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) unsigned length = vec_safe_length (previous->scopes);
{ vec_safe_reserve (previous->scopes, length * 2);
ret = true; for (unsigned ix = length; ix--;)
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 (); tree decl = (*previous->scopes)[ix];
todo->pop ();
}
else
{
ret = false;
break;
}
}
release_tree_vector (seen); gcc_checking_assert (LOOKUP_SEEN_P (decl));
release_tree_vector (todo); 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. /* Restore the marking state of a lookup we interrupted. */
Returns true on error. */
static bool void
arg_assoc_namespace (struct arg_lookup *k, tree scope) 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)) active = previous;
return false; if (previous)
vec_safe_push (k->namespaces, scope); {
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. */ gcc_checking_assert (!LOOKUP_FOUND_P (decl));
for (value = DECL_NAMESPACE_ASSOCIATIONS (scope); value; LOOKUP_SEEN_P (decl) = true;
value = TREE_CHAIN (value)) }
if (arg_assoc_namespace (k, TREE_PURPOSE (value)))
return true;
/* Also look down into inline namespaces. */ free (scopes);
for (value = DECL_NAMESPACE_USING (scope); value; }
value = TREE_CHAIN (value)) else
if (is_associated_namespace (scope, TREE_PURPOSE (value))) shared_scopes = scopes;
if (arg_assoc_namespace (k, TREE_PURPOSE (value))) }
return true;
value = get_namespace_binding (scope, k->name); void
if (!value) name_lookup::mark_seen (tree scope)
return false; {
gcc_checking_assert (!seen_p (scope));
LOOKUP_SEEN_P (scope) = true;
vec_safe_push (scopes, scope);
}
value = ovl_skip_hidden (value); bool
name_lookup::find_and_mark (tree scope)
for (; value; value = OVL_NEXT (value)) {
bool result = LOOKUP_FOUND_P (scope);
if (!result)
{ {
if (add_function (k, OVL_CURRENT (value))) LOOKUP_FOUND_P (scope) = true;
return 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 /* FNS is a value binding. If it is a (set of overloaded) functions,
structure. Returns true on error. */ add them into the current value. */
static bool void
arg_assoc_template_arg (struct arg_lookup *k, tree arg) 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 /* Only add those that aren't already there. */
... the namespaces and classes associated with the types of the for (ovl_iterator iter (fns); iter; ++iter)
template arguments provided for template type parameters if (!fn_set->add (*iter))
(excluding template template parameters); the namespaces in which value = lookup_add (*iter, value);
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. ] */
/* Consider first template template arguments. */ /* Add functions of a namespace to the lookup structure. */
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);
/* It's not a member template. */ void
if (TREE_CODE (ctx) == NAMESPACE_DECL) name_lookup::adl_namespace_only (tree scope)
return arg_assoc_namespace (k, ctx); {
/* Otherwise, it must be member template. */ mark_seen (scope);
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; /* Look down into inline namespaces. */
} for (tree inner = NAMESPACE_LEVEL (scope)->namespaces;
/* It's not a template template argument, but it is a type template inner; inner = TREE_CHAIN (inner))
argument. */ if (DECL_NAMESPACE_INLINE_P (inner))
else if (TYPE_P (arg)) adl_namespace_only (inner);
return arg_assoc_type (k, arg);
/* It's a non-type template argument. */ if (cxx_binding *binding = find_namespace_binding (scope, name))
else add_fns (ovl_skip_hidden (binding->value));
return false;
} }
/* Adds the class and its friends to the lookup structure. /* Find the containing non-inlined namespace, add it and all its
Returns true on error. */ inlinees. */
static bool void
arg_assoc_class_only (struct arg_lookup *k, tree type) 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. */
if (tree binfo = TYPE_BINFO (type))
{ {
/* Process baseclasses. */ tree base_binfo;
tree binfo, 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;
static bool gcc_assert (!TYPE_P (expr));
arg_assoc_type (struct arg_lookup *k, tree type)
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) 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. */
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 /* Adds everything associated with a template argument to the lookup
on error. */ structure. */
static bool
arg_assoc_args_vec (struct arg_lookup *k, vec<tree, va_gc> *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. */
static bool void
arg_assoc (struct arg_lookup *k, tree n) name_lookup::adl_template_arg (tree arg)
{ {
if (n == error_mark_node) /* [basic.lookup.koenig]
return false;
if (TYPE_P (n)) If T is a template-id, its associated namespaces and classes are
return arg_assoc_type (k, n); ... the namespaces and classes associated with the types of the
template arguments provided for template type parameters
if (! type_unknown_p (n)) (excluding template template parameters); the namespaces in which
return arg_assoc_type (k, TREE_TYPE (n)); any template template arguments are defined; and the classes in
which any member templates used as template template arguments
if (TREE_CODE (n) == ADDR_EXPR) are defined. [Note: non-type template arguments do not
n = TREE_OPERAND (n, 0); contribute to the set of associated namespaces. ] */
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. */ /* Consider first template template arguments. */
if (arg_assoc (k, templ)) if (TREE_CODE (arg) == TEMPLATE_TEMPLATE_PARM
return true; || TREE_CODE (arg) == UNBOUND_CLASS_TEMPLATE)
;
else if (TREE_CODE (arg) == TEMPLATE_DECL)
{
tree ctx = CP_DECL_CONTEXT (arg);
/* Now the arguments. */ /* It's not a member template. */
if (args) if (TREE_CODE (ctx) == NAMESPACE_DECL)
for (ix = TREE_VEC_LENGTH (args); ix--;) adl_namespace (ctx);
if (arg_assoc_template_arg (k, TREE_VEC_ELT (args, ix)) == 1) /* Otherwise, it must be member template. */
return true; 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)) tree args = ARGUMENT_PACK_ARGS (arg);
if (arg_assoc_type (k, TREE_TYPE (OVL_CURRENT (n)))) int i, len = TREE_VEC_LENGTH (args);
return true; 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
return false; argument. */
else if (TYPE_P (arg))
adl_type (arg);
} }
/* Performs Koenig lookup depending on arguments, where fns /* Perform ADL lookup. FNS is the existing lookup result and ARGS are
are the functions found in normal lookup. */ the call arguments. */
static cp_expr tree
lookup_arg_dependent_1 (tree name, tree fns, vec<tree, va_gc> *args) name_lookup::search_adl (tree fns, vec<tree, va_gc> *args)
{ {
struct arg_lookup k; value = fns;
/* Remove any hidden friend functions from the list of functions /* Add the current overload set into the hash table. */
found so far. They will be added back by arg_assoc_class as fn_set = new hash_set<tree>;
appropriate. */ for (lkp_iterator iter (fns); iter; ++iter)
fns = ovl_skip_hidden (fns); fn_set->add (*iter);
k.name = name; unsigned ix;
k.args = args; tree arg;
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 ();
/* We used to allow duplicates and let joust discard them, but FOR_EACH_VEC_ELT_REVERSE (*args, ix, arg)
since the above change for DR 164 we end up with duplicates of /* OMP reduction operators put a type as the first arg. I don't
all the functions found by unqualified lookup. So keep track suppose we should ADL on that? */
of which ones we've seen. */ if (!TYPE_P (arg))
if (fns) adl_expr (arg);
{
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<tree>;
for (ovl = fns; ovl; ovl = OVL_NEXT (ovl))
k.fn_set->add (OVL_CURRENT (ovl));
}
else
k.fn_set = NULL;
arg_assoc_args_vec (&k, args); delete fn_set;
fn_set = NULL;
fns = k.functions; fns = value;
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;
}
release_tree_vector (k.classes);
release_tree_vector (k.namespaces);
delete k.fn_set;
return fns; 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<tree, va_gc> *args) lookup_arg_dependent (tree name, tree fns, vec<tree, va_gc> *args)
{ {
cp_expr ret; bool subtime = timevar_cond_start (TV_NAME_LOOKUP);
bool subtime; name_lookup lookup (name);
subtime = timevar_cond_start (TV_NAME_LOOKUP); fns = lookup.search_adl (fns, args);
ret = lookup_arg_dependent_1 (name, fns, args);
timevar_cond_stop (TV_NAME_LOOKUP, subtime); 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<tree, va_gc> *seen = make_tree_vector ();
vec<tree, va_gc> *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; 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