diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 21eff5cb04c..83fdfe3b181 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,11 @@ +2009-10-28 Jason Merrill + + 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 * decl.c (cp_fname_init): Correct build_string argument. diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c index 6e31f8a058a..9a6991269f8 100644 --- a/gcc/cp/name-lookup.c +++ b/gcc/cp/name-lookup.c @@ -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); } diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index f4806828cc4..ace340eeb3f 100644 --- a/gcc/cp/pt.c +++ b/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 = " "; diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 129a05e5479..b1568461dc5 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2009-10-28 Jason Merrill + + * 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 PR rtl-optimization/39715 diff --git a/gcc/testsuite/g++.dg/cpp0x/inline-ns1.C b/gcc/testsuite/g++.dg/cpp0x/inline-ns1.C new file mode 100644 index 00000000000..e422d8970f1 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/inline-ns1.C @@ -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() { } diff --git a/gcc/testsuite/g++.dg/cpp0x/inline-ns2.C b/gcc/testsuite/g++.dg/cpp0x/inline-ns2.C new file mode 100644 index 00000000000..03851725bbd --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/inline-ns2.C @@ -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 "" } diff --git a/gcc/testsuite/g++.dg/cpp0x/inline-ns3.C b/gcc/testsuite/g++.dg/cpp0x/inline-ns3.C new file mode 100644 index 00000000000..8981a57ac4c --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/inline-ns3.C @@ -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(); +} diff --git a/gcc/testsuite/g++.dg/lookup/using16.C b/gcc/testsuite/g++.dg/lookup/using16.C index ff6a80ee93f..a396afb973c 100644 --- a/gcc/testsuite/g++.dg/lookup/using16.C +++ b/gcc/testsuite/g++.dg/lookup/using16.C @@ -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 {