Core issue 812, 861

Core issue 812, 861
	* name-lookup.c (set_decl_namespace): Deal properly with inline
	namespaces.
	(qualified_lookup_using_namespace): Overhaul.
	* pt.c (print_candidates): Handle getting an OVERLOAD.

change lookup algorithm

From-SVN: r153682
This commit is contained in:
Jason Merrill 2009-10-28 14:39:36 -04:00 committed by Jason Merrill
parent 34ad94d88c
commit 160594b061
8 changed files with 206 additions and 62 deletions

View file

@ -1,3 +1,11 @@
2009-10-28 Jason Merrill <jason@redhat.com>
Core issue 812, 861
* name-lookup.c (set_decl_namespace): Deal properly with inline
namespaces.
(qualified_lookup_using_namespace): Overhaul.
* pt.c (print_candidates): Handle getting an OVERLOAD.
2009-10-28 Jason Merrill <jason@redhat.com>
* decl.c (cp_fname_init): Correct build_string argument.

View file

@ -3062,7 +3062,7 @@ set_namespace_binding (tree name, tree scope, tree val)
void
set_decl_namespace (tree decl, tree scope, bool friendp)
{
tree old, fn;
tree old;
/* Get rid of namespace aliases. */
scope = ORIGINAL_NAMESPACE (scope);
@ -3087,17 +3087,25 @@ set_decl_namespace (tree decl, tree scope, bool friendp)
if (old == error_mark_node)
/* No old declaration at all. */
goto complain;
/* If it's a TREE_LIST, the result of the lookup was ambiguous. */
if (TREE_CODE (old) == TREE_LIST)
{
error ("reference to %qD is ambiguous", decl);
print_candidates (old);
return;
}
if (!is_overloaded_fn (decl))
/* Don't compare non-function decls with decls_match here, since
it can't check for the correct constness at this
point. pushdecl will find those errors later. */
return;
{
/* We might have found OLD in an inline namespace inside SCOPE. */
DECL_CONTEXT (decl) = DECL_CONTEXT (old);
/* Don't compare non-function decls with decls_match here, since
it can't check for the correct constness at this
point. pushdecl will find those errors later. */
return;
}
/* Since decl is a function, old should contain a function decl. */
if (!is_overloaded_fn (old))
goto complain;
fn = OVL_CURRENT (old);
if (!is_associated_namespace (scope, CP_DECL_CONTEXT (fn)))
goto complain;
/* A template can be explicitly specialized in any namespace. */
if (processing_explicit_instantiation)
return;
@ -3113,12 +3121,43 @@ set_decl_namespace (tree decl, tree scope, bool friendp)
return;
if (is_overloaded_fn (old))
{
for (; old; old = OVL_NEXT (old))
if (decls_match (decl, OVL_CURRENT (old)))
tree found = NULL_TREE;
tree elt = old;
for (; elt; elt = OVL_NEXT (elt))
{
tree ofn = OVL_CURRENT (elt);
/* Adjust DECL_CONTEXT first so decls_match will return true
if DECL will match a declaration in an inline namespace. */
DECL_CONTEXT (decl) = DECL_CONTEXT (ofn);
if (decls_match (decl, ofn))
{
if (found && !decls_match (found, ofn))
{
DECL_CONTEXT (decl) = FROB_CONTEXT (scope);
error ("reference to %qD is ambiguous", decl);
print_candidates (old);
return;
}
found = ofn;
}
}
if (found)
{
if (!is_associated_namespace (scope, CP_DECL_CONTEXT (found)))
goto complain;
DECL_CONTEXT (decl) = DECL_CONTEXT (found);
return;
}
}
else if (decls_match (decl, old))
return;
else
{
DECL_CONTEXT (decl) = DECL_CONTEXT (old);
if (decls_match (decl, old))
return;
}
/* It didn't work, go back to the explicit scope. */
DECL_CONTEXT (decl) = FROB_CONTEXT (scope);
complain:
error ("%qD should have been declared inside %qD", decl, scope);
}
@ -3925,6 +3964,19 @@ lookup_using_namespace (tree name, struct scope_binding *val,
POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, val->value != error_mark_node);
}
/* Returns true iff VEC contains TARGET. */
static bool
tree_vec_contains (VEC(tree,gc)* vec, tree target)
{
unsigned int i;
tree elt;
for (i = 0; VEC_iterate(tree,vec,i,elt); ++i)
if (elt == target)
return true;
return false;
}
/* [namespace.qual]
Accepts the NAME to lookup and its qualifying SCOPE.
Returns the name/type pair found into the cxx_binding *RESULT,
@ -3935,62 +3987,72 @@ qualified_lookup_using_namespace (tree name, tree scope,
struct scope_binding *result, int flags)
{
/* Maintain a list of namespaces visited... */
tree seen = NULL_TREE;
VEC(tree,gc) *seen = NULL;
VEC(tree,gc) *seen_inline = NULL;
/* ... and a list of namespace yet to see. */
tree todo = NULL_TREE;
tree todo_maybe = NULL_TREE;
tree *todo_weak = &todo_maybe;
VEC(tree,gc) *todo = NULL;
VEC(tree,gc) *todo_maybe = NULL;
VEC(tree,gc) *todo_inline = NULL;
tree usings;
timevar_push (TV_NAME_LOOKUP);
/* Look through namespace aliases. */
scope = ORIGINAL_NAMESPACE (scope);
while (scope && result->value != error_mark_node)
{
cxx_binding *binding =
cxx_scope_find_binding_for_name (NAMESPACE_LEVEL (scope), name);
seen = tree_cons (scope, NULL_TREE, seen);
if (binding)
ambiguous_decl (result, binding, flags);
/* Consider strong using directives always, and non-strong ones
if we haven't found a binding yet. */
for (usings = DECL_NAMESPACE_USING (scope); usings;
usings = TREE_CHAIN (usings))
/* If this was a real directive, and we have not seen it. */
if (!TREE_INDIRECT_USING (usings))
{
/* Try to avoid queuing the same namespace more than once,
the exception being when a namespace was already
enqueued for todo_maybe and then a strong using is
found for it. We could try to remove it from
todo_maybe, but it's probably not worth the effort. */
if (is_associated_namespace (scope, TREE_PURPOSE (usings))
&& !purpose_member (TREE_PURPOSE (usings), seen)
&& !purpose_member (TREE_PURPOSE (usings), todo))
todo = tree_cons (TREE_PURPOSE (usings), NULL_TREE, todo);
else if (!binding
&& !purpose_member (TREE_PURPOSE (usings), seen)
&& !purpose_member (TREE_PURPOSE (usings), todo)
&& !purpose_member (TREE_PURPOSE (usings), todo_maybe))
*todo_weak = tree_cons (TREE_PURPOSE (usings), NULL_TREE,
*todo_weak);
}
if (todo)
/* Algorithm: Starting with SCOPE, walk through the the set of used
namespaces. For each used namespace, look through its inline
namespace set for any bindings and usings. If no bindings are found,
add any usings seen to the set of used namespaces. */
VEC_safe_push (tree, gc, todo, scope);
while (VEC_length (tree, todo))
{
bool found_here;
scope = VEC_pop (tree, todo);
if (tree_vec_contains (seen, scope))
continue;
VEC_safe_push (tree, gc, seen, scope);
VEC_safe_push (tree, gc, todo_inline, scope);
found_here = false;
while (VEC_length (tree, todo_inline))
{
scope = TREE_PURPOSE (todo);
todo = TREE_CHAIN (todo);
}
else if (todo_maybe
&& (!result->value && !result->type))
{
scope = TREE_PURPOSE (todo_maybe);
todo = TREE_CHAIN (todo_maybe);
todo_maybe = NULL_TREE;
todo_weak = &todo;
cxx_binding *binding;
scope = VEC_pop (tree, todo_inline);
if (tree_vec_contains (seen_inline, scope))
continue;
VEC_safe_push (tree, gc, seen_inline, scope);
binding =
cxx_scope_find_binding_for_name (NAMESPACE_LEVEL (scope), name);
if (binding)
{
found_here = true;
ambiguous_decl (result, binding, flags);
}
for (usings = DECL_NAMESPACE_USING (scope); usings;
usings = TREE_CHAIN (usings))
if (!TREE_INDIRECT_USING (usings))
{
if (is_associated_namespace (scope, TREE_PURPOSE (usings)))
VEC_safe_push (tree, gc, todo_inline, TREE_PURPOSE (usings));
else
VEC_safe_push (tree, gc, todo_maybe, TREE_PURPOSE (usings));
}
}
if (found_here)
VEC_truncate (tree, todo_maybe, 0);
else
scope = NULL_TREE; /* If there never was a todo list. */
while (VEC_length (tree, todo_maybe))
VEC_safe_push (tree, gc, todo, VEC_pop (tree, todo_maybe));
}
VEC_free (tree,gc,todo);
VEC_free (tree,gc,todo_maybe);
VEC_free (tree,gc,todo_inline);
VEC_free (tree,gc,seen);
VEC_free (tree,gc,seen_inline);
POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, result->value != error_mark_node);
}

View file

@ -1640,13 +1640,20 @@ void
print_candidates (tree fns)
{
tree fn;
tree f;
const char *str = "candidates are:";
for (fn = fns; fn != NULL_TREE; fn = TREE_CHAIN (fn))
if (is_overloaded_fn (fns))
{
for (f = fns; f; f = OVL_NEXT (f))
{
error ("%s %+#D", str, OVL_CURRENT (f));
str = " ";
}
}
else for (fn = fns; fn != NULL_TREE; fn = TREE_CHAIN (fn))
{
tree f;
for (f = TREE_VALUE (fn); f; f = OVL_NEXT (f))
error ("%s %+#D", str, OVL_CURRENT (f));
str = " ";

View file

@ -1,3 +1,9 @@
2009-10-28 Jason Merrill <jason@redhat.com>
* g++.dg/cpp0x/inline-ns1.C: New.
* g++.dg/cpp0x/inline-ns2.C: New.
* g++.dg/cpp0x/inline-ns3.C: New.
2009-10-28 Paolo Bonzini <bonzini@gnu.org>
PR rtl-optimization/39715

View file

@ -0,0 +1,12 @@
// { dg-options -std=c++0x }
// { dg-final { scan-assembler "_ZN1Q2V11fEv" } }
// { dg-final { scan-assembler "_ZN1Q2V11iE" } }
namespace Q {
inline namespace V1 {
extern int i;
void f();
}
}
int Q::i = 1;
void Q::f() { }

View file

@ -0,0 +1,25 @@
// { dg-options -std=c++0x }
namespace Q {
inline namespace V1 {
extern int i; // { dg-error "" }
extern int j; // { dg-error "" }
void f(); // { dg-error "" }
void g(); // { dg-error "" }
}
inline namespace V2 {
extern int j; // { dg-error "" }
void g(); // { dg-error "" }
}
extern int i; // { dg-error "" }
void f(); // { dg-error "" }
void h();
}
namespace R {
using namespace Q;
}
int Q::i = 1; // { dg-error "ambiguous" }
int Q::j = 1; // { dg-error "ambiguous" }
void Q::f() { } // { dg-error "ambiguous" }
void Q::g() { } // { dg-error "ambiguous" }
void R::h() { } // { dg-error "" }

View file

@ -0,0 +1,24 @@
namespace C
{
void f();
}
namespace B
{
using namespace C;
inline namespace B1
{
void f();
}
}
namespace A
{
using namespace B;
}
int main()
{
A::f();
}

View file

@ -3,7 +3,7 @@
// { dg-do compile }
namespace M {
struct S {}; // { dg-error "candidates are: struct M::S" "candidate 1" }
struct S {}; // { dg-error "struct M::S" "candidate 1" }
}
namespace N {