This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

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 {

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]