diff --git a/gcc/c-family/c-ada-spec.cc b/gcc/c-family/c-ada-spec.cc
index 1a189b377..cc7625c2a 100644
--- a/gcc/c-family/c-ada-spec.cc
+++ b/gcc/c-family/c-ada-spec.cc
@@ -753,6 +753,124 @@ static tree *to_dump = NULL;
 static int to_dump_count = 0;
 static bool bitfield_used = false;
 static bool packed_layout = false;
+static tree current_namespace = NULL_TREE;
+
+static void pp_ada_namespace_name (pretty_printer *, tree);
+
+/* Return the innermost named C++ namespace containing NODE.  Anonymous
+   namespaces do not add an Ada package level.  */
+
+static tree
+named_namespace_context (tree node)
+{
+  tree context = NULL_TREE;
+  if (node && DECL_P (node))
+    context = DECL_CONTEXT (node);
+  else if (node && TYPE_P (node))
+    context = TYPE_CONTEXT (node);
+
+  while (context)
+    {
+      if (TREE_CODE (context) == NAMESPACE_DECL
+	  && DECL_NAME (context)
+	  && strcmp (IDENTIFIER_POINTER (DECL_NAME (context)), "::"))
+	return context;
+      if (DECL_P (context))
+	context = DECL_CONTEXT (context);
+      else if (TYPE_P (context))
+	context = TYPE_CONTEXT (context);
+      else
+	break;
+    }
+  return NULL_TREE;
+}
+
+/* Return the nearest named namespace containing NS.  */
+
+static tree
+parent_named_namespace (tree ns)
+{
+  return named_namespace_context (ns);
+}
+
+/* Return the direct namespace package below SCOPE that contains DECL.  */
+
+static tree
+direct_namespace_child (tree scope, tree decl)
+{
+  tree ns = named_namespace_context (decl);
+  if (!ns || ns == scope)
+    return NULL_TREE;
+
+  tree child = ns;
+  for (tree parent = parent_named_namespace (child); parent;
+	 parent = parent_named_namespace (child))
+    {
+      if (parent == scope)
+	return child;
+      child = parent;
+    }
+
+  return scope ? NULL_TREE : child;
+}
+
+/* Return true if CHILD was already encountered before LIMIT in SCOPE.  */
+
+static bool
+namespace_child_seen (tree scope, tree child, int limit)
+{
+  for (int i = 0; i < limit; ++i)
+    if (direct_namespace_child (scope, to_dump[i]) == child)
+      return true;
+  return false;
+}
+
+/* Dump all declarations and nested namespace packages directly in SCOPE.  */
+
+static void
+dump_ada_namespace_contents (pretty_printer *pp, tree scope, int spc)
+{
+  tree saved_namespace = current_namespace;
+  current_namespace = scope;
+
+  for (int i = 0; i < to_dump_count; ++i)
+    {
+      tree decl = to_dump[i];
+      tree ns = named_namespace_context (decl);
+      if (ns == scope)
+	{
+	  if (dump_ada_declaration (pp, decl, NULL_TREE, spc))
+	    {
+	      pp_newline (pp);
+	      pp_newline (pp);
+	    }
+	}
+      else
+	{
+	  tree child = direct_namespace_child (scope, decl);
+	  if (!child || namespace_child_seen (scope, child, i))
+	    continue;
+
+	  for (int indent = 0; indent < spc; ++indent)
+	    pp_space (pp);
+	  pp_string (pp, "package ");
+	  pp_ada_namespace_name (pp, child);
+	  pp_string (pp, " is");
+	  pp_newline (pp);
+	  pp_newline (pp);
+	  dump_ada_namespace_contents (pp, child, spc + INDENT_INCR);
+	  for (int indent = 0; indent < spc; ++indent)
+	    pp_space (pp);
+	  pp_string (pp, "end ");
+	  pp_ada_namespace_name (pp, child);
+	  pp_semicolon (pp);
+	  pp_newline (pp);
+	  pp_newline (pp);
+	}
+    }
+
+  current_namespace = saved_namespace;
+}
 
 /* Collect a list of declarations from T relevant to SOURCE_FILE to be dumped
    by a subsequent call to dump_ada_nodes.  */
@@ -763,9 +880,8 @@ collect_ada_nodes (tree t, const char *source_file)
   tree n;
   int i = to_dump_count;
 
-  /* Count the likely relevant nodes: do not dump builtins (they are irrelevant
-     in the context of bindings) and namespaces (we do not handle them properly
-     yet).  */
+  /* Count the likely relevant nodes.  Namespace declarations themselves are
+     represented by packages around their collected children.  */
   for (n = t; n; n = TREE_CHAIN (n))
     if (!DECL_IS_UNDECLARED_BUILTIN (n)
 	&& TREE_CODE (n) != NAMESPACE_DECL
@@ -877,8 +993,32 @@ dump_ada_nodes (pretty_printer *pp, const char *source_file)
 	    {
 	      current_source_file = source_file;
 
-	      if (dump_ada_declaration (pp, to_dump[i++], NULL_TREE,
-					 INDENT_INCR))
+	      tree decl = to_dump[i++];
+	      tree child = direct_namespace_child (NULL_TREE, decl);
+	      if (child)
+		{
+		  if (!namespace_child_seen (NULL_TREE, child, i - 1))
+		    {
+		      for (int indent = 0; indent < INDENT_INCR; ++indent)
+			pp_space (pp);
+		      pp_string (pp, "package ");
+		      pp_ada_namespace_name (pp, child);
+		      pp_string (pp, " is");
+		      pp_newline (pp);
+		      pp_newline (pp);
+		      dump_ada_namespace_contents (pp, child,
+					   INDENT_INCR * 2);
+		      for (int indent = 0; indent < INDENT_INCR; ++indent)
+			pp_space (pp);
+		      pp_string (pp, "end ");
+		      pp_ada_namespace_name (pp, child);
+		      pp_semicolon (pp);
+		      pp_newline (pp);
+		      pp_newline (pp);
+		    }
+		}
+	      else if (dump_ada_declaration (pp, decl, NULL_TREE,
+					    INDENT_INCR))
 		{
 		  pp_newline (pp);
 		  pp_newline (pp);
@@ -1370,6 +1510,42 @@ to_ada_name (const char *name, bool *space_found)
   return s;
 }
 
+/* Dump the Ada package name corresponding to named namespace NS.  */
+
+static void
+pp_ada_namespace_name (pretty_printer *pp, tree ns)
+{
+  bool space_found = false;
+  char *name = to_ada_name (IDENTIFIER_POINTER (DECL_NAME (ns)),
+			    &space_found);
+  pp_string (pp, name);
+  free (name);
+}
+
+/* Dump the complete nested Ada package path containing DECL, unless DECL is
+   already in the namespace package currently being emitted.  */
+
+static void
+pp_ada_namespace_path (pretty_printer *pp, tree ns)
+{
+  if (!ns)
+    return;
+
+  tree parent = parent_named_namespace (ns);
+  if (parent)
+    pp_ada_namespace_path (pp, parent);
+  pp_ada_namespace_name (pp, ns);
+  pp_dot (pp);
+}
+
+static void
+pp_ada_namespace_prefix (pretty_printer *pp, tree decl)
+{
+  tree ns = named_namespace_context (decl);
+  if (ns && ns != current_namespace)
+    pp_ada_namespace_path (pp, ns);
+}
+
 /* Return true if DECL refers to a C++ class type for which a
    separate enclosing package has been or should be generated.  */
 
@@ -1397,6 +1573,7 @@ pp_ada_tree_identifier (pretty_printer *pp, tree node, tree type,
   char *s = to_ada_name (name, &space_found);
   tree decl = get_underlying_decl (type);
 
+  bool external_decl = false;
   if (decl)
     {
       /* If the entity comes from another file, generate a package prefix.  */
@@ -1404,6 +1581,7 @@ pp_ada_tree_identifier (pretty_printer *pp, tree node, tree type,
 
       if (xloc.line && xloc.file && xloc.file != current_source_file)
 	{
+	  external_decl = true;
 	  switch (TREE_CODE (type))
 	    {
 	      case ENUMERAL_TYPE:
@@ -1430,13 +1608,19 @@ pp_ada_tree_identifier (pretty_printer *pp, tree node, tree type,
 		break;
 	    }
 
-	  /* Generate the additional package prefix for C++ classes.  */
-	  if (separate_class_package (decl))
-	    {
-	      pp_string (pp, "Class_");
-	      pp_string (pp, s);
-	      pp_dot (pp);
-	    }
+	}
+
+      pp_ada_namespace_prefix (pp, decl);
+
+      /* Generate the additional package prefix for C++ classes when the
+	 declaration is outside the namespace package currently being emitted.  */
+      if (separate_class_package (decl)
+	  && (external_decl
+	      || named_namespace_context (decl) != current_namespace))
+	{
+	  pp_string (pp, "Class_");
+	  pp_string (pp, s);
+	  pp_dot (pp);
 	}
     }
 
diff --git a/gcc/testsuite/g++.dg/ada-spec/namespace-identity.C b/gcc/testsuite/g++.dg/ada-spec/namespace-identity.C
new file mode 100644
index 000000000..38f4ff233
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ada-spec/namespace-identity.C
@@ -0,0 +1,60 @@
+/* { dg-do compile } */
+/* { dg-options "-fdump-ada-spec-slim" } */
+/* { dg-final { scan-file namespace_identity_c.ads "package first is" } } */
+/* { dg-final { scan-file namespace_identity_c.ads "package inner is" } } */
+/* { dg-final { scan-file namespace_identity_c.ads "function transform \(value : Item\) return Item" } } */
+/* { dg-final { scan-file namespace_identity_c.ads "package Class_Object is" } } */
+/* { dg-final { scan-file namespace_identity_c.ads "package a_b is" } } */
+/* { dg-final { scan-file namespace_identity_c.ads "package a is" } } */
+/* { dg-final { scan-file namespace_identity_c.ads "type Again is record" } } */
+/* { dg-final { scan-file-not namespace_identity_c.ads "package :: is" } } */
+
+namespace first::inner
+{
+  struct Item { int value; };
+  Item transform (Item value) { value.value += 1; return value; }
+
+  class Object
+  {
+  public:
+    int get () const;
+  private:
+    int value_;
+  };
+}
+
+namespace second::inner
+{
+  struct Item { double value; };
+  Item transform (Item value) { value.value += 2.0; return value; }
+
+  class Object
+  {
+  public:
+    int get () const;
+  private:
+    double value_;
+  };
+}
+
+namespace a_b
+{
+  struct Marker { int value; };
+}
+
+namespace a::b
+{
+  struct Marker { double value; };
+}
+
+namespace first::inner
+{
+  struct Again { long value; };
+}
+
+using First_Item = first::inner::Item;
+using Second_Item = second::inner::Item;
+
+extern "C" int namespace_identity_oracle () { return 73; }
+
+/* { dg-final { cleanup-ada-spec } } */
