This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
C++ PATCH to qualified namespace lookup for core issue 861
- From: Jason Merrill <jason at redhat dot com>
- To: gcc-patches List <gcc-patches at gcc dot gnu dot org>
- Date: Wed, 28 Oct 2009 15:01:19 -0400
- Subject: C++ PATCH to qualified namespace lookup for core issue 861
At the C++ meeting last week someone pointed out a flaw in my proposed
wording for qualified namespace lookup. While looking at this, I
noticed that the algorithm in G++ wasn't right yet, either. Fixed thus.
Tested x86_64-pc-linux-gnu, applied to trunk.
commit 71893b0a62f02d77b1ff428ff1e9961035696c37
Author: jason <jason@138bc75d-0d04-0410-961f-82ee72b054a4>
Date: Wed Oct 28 18:39:36 2009 +0000
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.
diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c
index 6e31f8a..9a69912 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)
+
+ /* 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))
{
- 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)
+ 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 f480682..ace340e 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/g++.dg/cpp0x/inline-ns1.C b/gcc/testsuite/g++.dg/cpp0x/inline-ns1.C
new file mode 100644
index 0000000..e422d89
--- /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 0000000..0385172
--- /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 0000000..8981a57
--- /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 ff6a80e..a396afb 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 {