2017-06-20  Nathan Sidwell  <nathan@acm.org>

	PR c++/67074 - namespace aliases
	* decl.c (duplicate_decls): Don't error here on mismatched
	namespace alias.
	* name-lookup.c (name_lookup::add_value): Matching namespaces are
	not ambiguous.
	(diagnose_name_conflict): Namespaces are never redeclarations.
	(update_binding): An alias can match a real namespace.

	PR c++/67074
	* g++.dg/lookup/pr67074.C: New.
	* g++.dg/parse/namespace-alias-1.C: Adjust.

Index: cp/decl.c
===================================================================
--- cp/decl.c	(revision 249384)
+++ cp/decl.c	(working copy)
@@ -1751,17 +1751,9 @@ duplicate_decls (tree newdecl, tree oldd
 	  && (DECL_NAMESPACE_ALIAS (newdecl)
 	      == DECL_NAMESPACE_ALIAS (olddecl)))
 	return olddecl;
-      /* [namespace.alias]
 
-	 A namespace-name or namespace-alias shall not be declared as
-	 the name of any other entity in the same declarative region.
-	 A namespace-name defined at global scope shall not be
-	 declared as the name of any other entity in any global scope
-	 of the program.  */
-      error ("conflicting declaration of namespace %q+D", newdecl);
-      inform (DECL_SOURCE_LOCATION (olddecl),
-	      "previous declaration of namespace %qD here", olddecl);
-      return error_mark_node;
+      /* Leave it to update_binding to merge or report error.  */
+      return NULL_TREE;
     }
   else
     {
Index: cp/name-lookup.c
===================================================================
--- cp/name-lookup.c	(revision 249385)
+++ cp/name-lookup.c	(working copy)
@@ -450,7 +450,13 @@ name_lookup::add_value (tree new_val)
   else if ((TREE_CODE (value) == TYPE_DECL
 	    && TREE_CODE (new_val) == TYPE_DECL
 	    && same_type_p (TREE_TYPE (value), TREE_TYPE (new_val))))
-    ;
+    /* Typedefs to the same type. */;
+  else if (TREE_CODE (value) == NAMESPACE_DECL
+	   && TREE_CODE (new_val) == NAMESPACE_DECL
+	   && ORIGINAL_NAMESPACE (value) == ORIGINAL_NAMESPACE (new_val))
+    /* Namespace (possibly aliased) to the same namespace.  Locate
+       the namespace*/
+    value = ORIGINAL_NAMESPACE (value);
   else
     {
       if (deduping)
@@ -1630,10 +1636,10 @@ static void
 diagnose_name_conflict (tree decl, tree bval)
 {
   if (TREE_CODE (decl) == TREE_CODE (bval)
-      && (TREE_CODE (decl) != TYPE_DECL
-	  || (DECL_ARTIFICIAL (decl) && DECL_ARTIFICIAL (bval))
-	  || (!DECL_ARTIFICIAL (decl) && !DECL_ARTIFICIAL (bval)))
+      && TREE_CODE (decl) != NAMESPACE_DECL
       && !DECL_DECLARES_FUNCTION_P (decl)
+      && (TREE_CODE (decl) != TYPE_DECL
+	  || DECL_ARTIFICIAL (decl) == DECL_ARTIFICIAL (bval))
       && CP_DECL_CONTEXT (decl) == CP_DECL_CONTEXT (bval))
     error ("redeclaration of %q#D", decl);
   else
@@ -1809,15 +1815,14 @@ update_binding (cp_binding_level *level,
     }
   else if (TREE_CODE (old) == NAMESPACE_DECL)
     {
-      if (DECL_NAMESPACE_ALIAS (old) && DECL_NAMESPACE_ALIAS (decl)
-	  && ORIGINAL_NAMESPACE (old) == ORIGINAL_NAMESPACE (decl))
-	/* In a declarative region, a namespace-alias-definition can be
-	   used to redefine a namespace-alias declared in that declarative
-	   region to refer only to the namespace to which it already
-	   refers.  [namespace.alias] */
-	return old;
-      else
+      /* Two maybe-aliased namespaces.  If they're to the same target
+	 namespace, that's ok.  */
+      if (ORIGINAL_NAMESPACE (old) != ORIGINAL_NAMESPACE (decl))
 	goto conflict;
+
+      /* The new one must be an alias at this point.  */
+      gcc_assert (DECL_NAMESPACE_ALIAS (decl));
+      return old;
     }
   else if (TREE_CODE (old) == VAR_DECL)
     {
Index: testsuite/g++.dg/lookup/pr67074.C
===================================================================
--- testsuite/g++.dg/lookup/pr67074.C	(nonexistent)
+++ testsuite/g++.dg/lookup/pr67074.C	(working copy)
@@ -0,0 +1,18 @@
+// PR c++/67074 namespace aliases to the same place.
+
+namespace P {
+  namespace X {
+    static int i = 1;
+  }
+}
+namespace Q {
+  namespace X = P::X;
+}
+
+using namespace P;
+using namespace Q;
+
+void Frob () { X::i; }
+
+namespace N {}
+namespace N = N;
Index: testsuite/g++.dg/parse/namespace-alias-1.C
===================================================================
--- testsuite/g++.dg/parse/namespace-alias-1.C	(revision 249384)
+++ testsuite/g++.dg/parse/namespace-alias-1.C	(working copy)
@@ -3,7 +3,7 @@
 namespace N
 {
   namespace M = N;  // { dg-message "previous declaration" }
-  namespace M {}    // { dg-error "declaration of namespace" }
+  namespace M {}    // { dg-error "conflicts with a previous declaration" }
 }
 
 namespace A
