diff mbox

[C++] Implement dr2061

Message ID 37ac92c6-8e0a-6ff1-9afe-888c1d574293@acm.org
State New
Headers show

Commit Message

Nathan Sidwell May 26, 2017, 6:17 p.m. UTC
DR2061 concerns the meaning of:
inline namespace One {
   namespace Term  { }
}
namespace Term {
}

Does that second Term open a new namespace inside :: or reopen ::One::Term?

DR2061 resolves to ::One::Term -- i.e. the lookup considers inline 
namespaces.

This patch implements that behaviour.  rather than a plain 
get_namespace_binding we do a lookup.search_qualified, but ignore any 
using directives.

nathan
diff mbox

Patch

2017-05-26  Nathan Sidwell  <nathan@acm.org>

	gcc/
	Implement DR2061
	* name-lookup.c (push_inline_namespaces): New.
	(push_namespace): Look inside inline namespaces.

	testsuite/
	* g++.dg/cpp0x/dr2061.C: New.
	* g++.dg/parse/namespace-alias-1.C: Add more test.

Index: cp/name-lookup.c
===================================================================
--- cp/name-lookup.c	(revision 248520)
+++ cp/name-lookup.c	(working copy)
@@ -6057,6 +6057,23 @@  pushdecl_top_level_and_finish (tree x, t
   return x;
 }
 
+/* Enter the namespaces from current_namerspace to NS.  */
+
+static int
+push_inline_namespaces (tree ns)
+{
+  int count = 0;
+  if (ns != current_namespace)
+    {
+      gcc_assert (ns != global_namespace);
+      count += push_inline_namespaces (CP_DECL_CONTEXT (ns));
+      resume_scope (NAMESPACE_LEVEL (ns));
+      current_namespace = ns;
+      count++;
+    }
+  return count;
+}
+
 /* Push into the scope of the NAME namespace.  If NAME is NULL_TREE,
    then we enter an anonymous namespace.  If MAKE_INLINE is true, then
    we create an inline namespace (it is up to the caller to check upon
@@ -6076,43 +6093,36 @@  push_namespace (tree name, bool make_inl
   if (!name)
     name = anon_identifier;
 
-  /* Check whether this is an extended namespace definition.  */
-  tree ns = get_namespace_binding (current_namespace, name);
-  if (ns && TREE_CODE (ns) == NAMESPACE_DECL)
-    {
-      if (tree dna = DECL_NAMESPACE_ALIAS (ns))
-	{
-	  /* We do some error recovery for, eg, the redeclaration of M
-	     here:
-
-	     namespace N {}
-	     namespace M = N;
-	     namespace M {}
-
-	     However, in nasty cases like:
-
-	     namespace N
-	     {
-	       namespace M = N;
-	       namespace M {}
-	     }
-
-	     we just error out below, in duplicate_decls.  */
-	  if (NAMESPACE_LEVEL (dna)->level_chain == current_binding_level)
-	    {
-	      error ("namespace alias %qD not allowed here, "
-		     "assuming %qD", ns, dna);
-	      ns = dna;
-	    }
-	  else
-	    ns = NULL_TREE;
-	}
-    }
-  else
-    ns = NULL_TREE;
+  tree ns = NULL_TREE;
+  {
+    name_lookup lookup (name, 0);
+    if (!lookup.search_qualified (current_namespace, /*usings=*/false))
+      ;
+    else if (TREE_CODE (lookup.value) != NAMESPACE_DECL)
+      ;
+    else if (tree dna = DECL_NAMESPACE_ALIAS (lookup.value))
+      {
+	/* A namespace alias is not allowed here, but if the alias
+	   is for a namespace also inside the current scope,
+	   accept it with a diagnostic.  That's better than dying
+	   horribly.  */
+	if (is_nested_namespace (current_namespace, CP_DECL_CONTEXT (dna)))
+	  {
+	    error ("namespace alias %qD not allowed here, "
+		   "assuming %qD", lookup.value, dna);
+	    ns = dna;
+	  }
+      }
+    else
+      ns = lookup.value;
+  }
 
   bool new_ns = false;
-  if (!ns)
+  if (ns)
+    /* DR2061.  NS might be a member of an inline namespace.  We
+       need to push into those namespaces.  */
+    count += push_inline_namespaces (CP_DECL_CONTEXT (ns));
+  else
     {
       ns = build_lang_decl (NAMESPACE_DECL, name, void_type_node);
       SCOPE_DEPTH (ns) = SCOPE_DEPTH (current_namespace) + 1;
Index: testsuite/g++.dg/cpp0x/dr2061.C
===================================================================
--- testsuite/g++.dg/cpp0x/dr2061.C	(revision 0)
+++ testsuite/g++.dg/cpp0x/dr2061.C	(working copy)
@@ -0,0 +1,46 @@ 
+// { dg-do compile { target c++11 } }
+
+// DR2061, look inside inline namespace when pushing a namespace.
+
+inline namespace One
+{
+  namespace Term 
+  {
+  }
+  inline namespace Two
+  {
+    namespace Space
+    {
+    }
+  }
+}
+
+namespace Term
+{
+  void bob ();
+}
+
+namespace Space
+{
+  void bill ();
+}
+
+inline namespace Two
+{
+  void weed ();
+}
+
+void One::Term::bob () {}
+void One::Two::Space::bill () {}
+void One::Two::weed () {}
+
+void Thing ()
+{
+  Term::bob ();
+  Space::bill ();
+  weed ();
+}
+
+// { dg-final { scan-assembler "_ZN3One4Term3bobEv:" } }
+// { dg-final { scan-assembler "_ZN3One3Two5Space4billEv:" } }
+// { dg-final { scan-assembler "_ZN3One3Two4weedEv:" } }
Index: testsuite/g++.dg/parse/namespace-alias-1.C
===================================================================
--- testsuite/g++.dg/parse/namespace-alias-1.C	(revision 248520)
+++ testsuite/g++.dg/parse/namespace-alias-1.C	(working copy)
@@ -5,3 +5,18 @@  namespace N
   namespace M = N;  // { dg-message "previous declaration" }
   namespace M {}    // { dg-error "declaration of namespace" }
 }
+
+namespace A
+{
+  namespace B 
+  {
+    namespace C
+    {
+    }
+  }
+
+  namespace D = B::C;
+  namespace D  // { dg-error "not allowed" }
+  {
+  }
+}