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:
parent
34ad94d88c
commit
160594b061
8 changed files with 206 additions and 62 deletions
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
13
gcc/cp/pt.c
13
gcc/cp/pt.c
|
@ -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 = " ";
|
||||
|
|
|
@ -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
|
||||
|
|
12
gcc/testsuite/g++.dg/cpp0x/inline-ns1.C
Normal file
12
gcc/testsuite/g++.dg/cpp0x/inline-ns1.C
Normal 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() { }
|
25
gcc/testsuite/g++.dg/cpp0x/inline-ns2.C
Normal file
25
gcc/testsuite/g++.dg/cpp0x/inline-ns2.C
Normal 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 "" }
|
24
gcc/testsuite/g++.dg/cpp0x/inline-ns3.C
Normal file
24
gcc/testsuite/g++.dg/cpp0x/inline-ns3.C
Normal 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();
|
||||
}
|
|
@ -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 {
|
||||
|
|
Loading…
Add table
Reference in a new issue