cxx-ada-namespace-identity

C++ Ada namespace identity

The C++ Ada spec dumper flattens named namespaces, causing unrelated declarations with the same unqualified name to collide in Ada.

AcceptedApplies standaloneSince 1.2.0

Where it applies.

How each patchset treats this bundle on each GCC major
PatchsetGCC 13GCC 14GCC 15GCC 16
1.2.0 (latest)Patchedgcc-13-1413.2.0Patchedgcc-13-1414.2.0Patchedgcc-15-1615.3.0Patchedgcc-15-1616.2.0
1.1.0Not applicable13.2.0Not applicable14.2.0Not applicable15.3.0Not applicable16.2.0
1.0.1Not applicable13.2.0Not applicable14.2.0Not applicable15.3.0Not applicable16.1.0
1.0.0Not applicable13.2.0Not applicable14.2.0Not applicable15.3.0Not applicable16.1.0

Explanation.

The C++ front end recursively collects declarations from namespaces, but the Ada dumper discards the namespace nodes. Distinct declarations consequently collapse into the same Ada identifier.

For example:

namespace left  { struct Entry { int value; }; }
namespace right { struct Entry { double value; }; }

The unpatched output contains two declarations of the same Ada type:

type c_Entry is record
   value : aliased int;
end record;

type c_Entry is record
   value : aliased double;
end record;

The corrected output preserves the C++ hierarchy as nested Ada packages. The c_ prefix that keeps entry from colliding with the Ada reserved word is unchanged; what the patch adds is the enclosing package, which is what makes the two declarations distinct:

package left is
   type c_Entry is record
      value : aliased int;
   end record;
end left;

package right is
   type c_Entry is record
      value : aliased double;
   end record;
end right;

This also distinguishes an underscore from a namespace boundary without an encoded flat name:

namespace a_b { struct Marker { int value; }; }
namespace a::b { struct Marker { double value; }; }
package a_b is
   type Marker is record ... end record;
end a_b;

package a is
   package b is
      type Marker is record ... end record;
   end b;
end a;

Functions, aliases, reopened namespaces, and generated Class_ packages stay inside the corresponding package. Anonymous namespaces remain transparent because they have no source-level name and their declarations already have translation-unit-local linkage.

The executable regression generates and compiles Ada for duplicate records, functions, nontrivial classes, reopened namespaces, and the a_b versus a::b boundary case at -O0 and -O2.

Patch.

Variant gcc-13-14

Applies to 13.2.0, 14.2.0. Source flavors: linux, darwin_arm64.

+257 −12 2 files

Download the patch

gcc/c-family/c-ada-spec.cc +197−12modified
Unified diff for gcc/c-family/c-ada-spec.cc: original line, patched line, change, source
@@ -699 +699 @@compare_comment (const void *lp, const void *rp)
699699
700700static tree *to_dump = NULL;
701701static int to_dump_count = 0;
702Added line. static tree current_namespace = NULL_TREE;
703Added line.
704Added line. static void pp_ada_namespace_name (pretty_printer *, tree);
705Added line.
706Added line. /* Return the innermost named C++ namespace containing NODE. Anonymous
707Added line. namespaces do not add an Ada package level. */
708Added line.
709Added line. static tree
710Added line. named_namespace_context (tree node)
711Added line. {
712Added line. tree context = NULL_TREE;
713Added line. if (node && DECL_P (node))
714Added line. context = DECL_CONTEXT (node);
715Added line. else if (node && TYPE_P (node))
716Added line. context = TYPE_CONTEXT (node);
717Added line.
718Added line. while (context)
719Added line. {
720Added line. if (TREE_CODE (context) == NAMESPACE_DECL
721Added line. && DECL_NAME (context)
722Added line. && strcmp (IDENTIFIER_POINTER (DECL_NAME (context)), "::"))
723Added line. return context;
724Added line. if (DECL_P (context))
725Added line. context = DECL_CONTEXT (context);
726Added line. else if (TYPE_P (context))
727Added line. context = TYPE_CONTEXT (context);
728Added line. else
729Added line. break;
730Added line. }
731Added line. return NULL_TREE;
732Added line. }
733Added line.
734Added line. /* Return the nearest named namespace containing NS. */
735Added line.
736Added line. static tree
737Added line. parent_named_namespace (tree ns)
738Added line. {
739Added line. return named_namespace_context (ns);
740Added line. }
741Added line.
742Added line. /* Return the direct namespace package below SCOPE that contains DECL. */
743Added line.
744Added line. static tree
745Added line. direct_namespace_child (tree scope, tree decl)
746Added line. {
747Added line. tree ns = named_namespace_context (decl);
748Added line. if (!ns || ns == scope)
749Added line. return NULL_TREE;
750Added line.
751Added line. tree child = ns;
752Added line. for (tree parent = parent_named_namespace (child); parent;
753Added line. parent = parent_named_namespace (child))
754Added line. {
755Added line. if (parent == scope)
756Added line. return child;
757Added line. child = parent;
758Added line. }
759Added line.
760Added line. return scope ? NULL_TREE : child;
761Added line. }
762Added line.
763Added line. /* Return true if CHILD was already encountered before LIMIT in SCOPE. */
764Added line.
765Added line. static bool
766Added line. namespace_child_seen (tree scope, tree child, int limit)
767Added line. {
768Added line. for (int i = 0; i < limit; ++i)
769Added line. if (direct_namespace_child (scope, to_dump[i]) == child)
770Added line. return true;
771Added line. return false;
772Added line. }
773Added line.
774Added line. /* Dump all declarations and nested namespace packages directly in SCOPE. */
775Added line.
776Added line. static void
777Added line. dump_ada_namespace_contents (pretty_printer *pp, tree scope, int spc)
778Added line. {
779Added line. tree saved_namespace = current_namespace;
780Added line. current_namespace = scope;
781Added line.
782Added line. for (int i = 0; i < to_dump_count; ++i)
783Added line. {
784Added line. tree decl = to_dump[i];
785Added line. tree ns = named_namespace_context (decl);
786Added line. if (ns == scope)
787Added line. {
788Added line. if (dump_ada_declaration (pp, decl, NULL_TREE, spc))
789Added line. {
790Added line. pp_newline (pp);
791Added line. pp_newline (pp);
792Added line. }
793Added line. }
794Added line. else
795Added line. {
796Added line. tree child = direct_namespace_child (scope, decl);
797Added line. if (!child || namespace_child_seen (scope, child, i))
798Added line. continue;
799Added line.
800Added line. for (int indent = 0; indent < spc; ++indent)
801Added line. pp_space (pp);
802Added line. pp_string (pp, "package ");
803Added line. pp_ada_namespace_name (pp, child);
804Added line. pp_string (pp, " is");
805Added line. pp_newline (pp);
806Added line. pp_newline (pp);
807Added line. dump_ada_namespace_contents (pp, child, spc + INDENT_INCR);
808Added line. for (int indent = 0; indent < spc; ++indent)
809Added line. pp_space (pp);
810Added line. pp_string (pp, "end ");
811Added line. pp_ada_namespace_name (pp, child);
812Added line. pp_semicolon (pp);
813Added line. pp_newline (pp);
814Added line. pp_newline (pp);
815Added line. }
816Added line. }
817Added line.
818Added line. current_namespace = saved_namespace;
819Added line. }
702820
703821/* Collect a list of declarations from T relevant to SOURCE_FILE to be dumped
704822 by a subsequent call to dump_ada_nodes. */
@@ -709 +826 @@collect_ada_nodes (tree t, const char *source_file)
709826 tree n;
710827 int i = to_dump_count;
711828
712Removed line. /* Count the likely relevant nodes: do not dump builtins (they are irrelevant
713Removed line. in the context of bindings) and namespaces (we do not handle them properly
714Removed line. yet). */
829Added line. /* Count the likely relevant nodes. Namespace declarations themselves are
830Added line. represented by packages around their collected children. */
715831 for (n = t; n; n = TREE_CHAIN (n))
716832 if (!DECL_IS_UNDECLARED_BUILTIN (n)
717833 && TREE_CODE (n) != NAMESPACE_DECL
@@ -823 +939 @@dump_ada_nodes (pretty_printer *pp, const char *source_file)
823939 {
824940 current_source_file = source_file;
825941
826Removed line. if (dump_ada_declaration (pp, to_dump[i++], NULL_TREE,
827Removed line. INDENT_INCR))
942Added line. tree decl = to_dump[i++];
943Added line. tree child = direct_namespace_child (NULL_TREE, decl);
944Added line. if (child)
945Added line. {
946Added line. if (!namespace_child_seen (NULL_TREE, child, i - 1))
947Added line. {
948Added line. for (int indent = 0; indent < INDENT_INCR; ++indent)
949Added line. pp_space (pp);
950Added line. pp_string (pp, "package ");
951Added line. pp_ada_namespace_name (pp, child);
952Added line. pp_string (pp, " is");
953Added line. pp_newline (pp);
954Added line. pp_newline (pp);
955Added line. dump_ada_namespace_contents (pp, child,
956Added line. INDENT_INCR * 2);
957Added line. for (int indent = 0; indent < INDENT_INCR; ++indent)
958Added line. pp_space (pp);
959Added line. pp_string (pp, "end ");
960Added line. pp_ada_namespace_name (pp, child);
961Added line. pp_semicolon (pp);
962Added line. pp_newline (pp);
963Added line. pp_newline (pp);
964Added line. }
965Added line. }
966Added line. else if (dump_ada_declaration (pp, decl, NULL_TREE,
967Added line. INDENT_INCR))
828968 {
829969 pp_newline (pp);
830970 pp_newline (pp);
@@ -1316 +1456 @@to_ada_name (const char *name, bool *space_found)
13161456 return s;
13171457}
13181458
1459Added line. /* Dump the Ada package name corresponding to named namespace NS. */
1460Added line.
1461Added line. static void
1462Added line. pp_ada_namespace_name (pretty_printer *pp, tree ns)
1463Added line. {
1464Added line. bool space_found = false;
1465Added line. char *name = to_ada_name (IDENTIFIER_POINTER (DECL_NAME (ns)),
1466Added line. &space_found);
1467Added line. pp_string (pp, name);
1468Added line. free (name);
1469Added line. }
1470Added line.
1471Added line. /* Dump the complete nested Ada package path containing DECL, unless DECL is
1472Added line. already in the namespace package currently being emitted. */
1473Added line.
1474Added line. static void
1475Added line. pp_ada_namespace_path (pretty_printer *pp, tree ns)
1476Added line. {
1477Added line. if (!ns)
1478Added line. return;
1479Added line.
1480Added line. tree parent = parent_named_namespace (ns);
1481Added line. if (parent)
1482Added line. pp_ada_namespace_path (pp, parent);
1483Added line. pp_ada_namespace_name (pp, ns);
1484Added line. pp_dot (pp);
1485Added line. }
1486Added line.
1487Added line. static void
1488Added line. pp_ada_namespace_prefix (pretty_printer *pp, tree decl)
1489Added line. {
1490Added line. tree ns = named_namespace_context (decl);
1491Added line. if (ns && ns != current_namespace)
1492Added line. pp_ada_namespace_path (pp, ns);
1493Added line. }
1494Added line.
13191495/* Return true if DECL refers to a C++ class type for which a
13201496 separate enclosing package has been or should be generated. */
13211497
@@ -1343 +1519 @@pp_ada_tree_identifier (pretty_printer *buffer, tree node, tree type,
13431519 char *s = to_ada_name (name, &space_found);
13441520 tree decl = get_underlying_decl (type);
13451521
1522Added line. bool external_decl = false;
13461523 if (decl)
13471524 {
13481525 /* If the entity comes from another file, generate a package prefix. */
@@ -1350 +1527 @@pp_ada_tree_identifier (pretty_printer *buffer, tree node, tree type,
13501527
13511528 if (xloc.line && xloc.file && xloc.file != current_source_file)
13521529 {
1530Added line. external_decl = true;
13531531 switch (TREE_CODE (type))
13541532 {
13551533 case ENUMERAL_TYPE:
@@ -1376 +1554 @@pp_ada_tree_identifier (pretty_printer *buffer, tree node, tree type,
13761554 break;
13771555 }
13781556
1379Removed line. /* Generate the additional package prefix for C++ classes. */
1380Removed line. if (separate_class_package (decl))
1381Removed line. {
1382Removed line. pp_string (buffer, "Class_");
1383Removed line. pp_string (buffer, s);
1384Removed line. pp_dot (buffer);
1385Removed line. }
1557Added line. }
1558Added line.
1559Added line. pp_ada_namespace_prefix (buffer, decl);
1560Added line.
1561Added line. /* Generate the additional package prefix for C++ classes when the
1562Added line. declaration is outside the namespace package currently being emitted. */
1563Added line. if (separate_class_package (decl)
1564Added line. && (external_decl
1565Added line. || named_namespace_context (decl) != current_namespace))
1566Added line. {
1567Added line. pp_string (buffer, "Class_");
1568Added line. pp_string (buffer, s);
1569Added line. pp_dot (buffer);
13861570 }
13871571 }
13881572
gcc/testsuite/g++.dg/ada-spec/namespace-identity.C +60−0new file
Unified diff for gcc/testsuite/g++.dg/ada-spec/namespace-identity.C: original line, patched line, change, source
@@ -0 +1 @@
1Added line. /* { dg-do compile } */
2Added line. /* { dg-options "-fdump-ada-spec-slim" } */
3Added line. /* { dg-final { scan-file namespace_identity_c.ads "package first is" } } */
4Added line. /* { dg-final { scan-file namespace_identity_c.ads "package inner is" } } */
5Added line. /* { dg-final { scan-file namespace_identity_c.ads "function transform \(value : Item\) return Item" } } */
6Added line. /* { dg-final { scan-file namespace_identity_c.ads "package Class_Object is" } } */
7Added line. /* { dg-final { scan-file namespace_identity_c.ads "package a_b is" } } */
8Added line. /* { dg-final { scan-file namespace_identity_c.ads "package a is" } } */
9Added line. /* { dg-final { scan-file namespace_identity_c.ads "type Again is record" } } */
10Added line. /* { dg-final { scan-file-not namespace_identity_c.ads "package :: is" } } */
11Added line.
12Added line. namespace first::inner
13Added line. {
14Added line. struct Item { int value; };
15Added line. Item transform (Item value) { value.value += 1; return value; }
16Added line.
17Added line. class Object
18Added line. {
19Added line. public:
20Added line. int get () const;
21Added line. private:
22Added line. int value_;
23Added line. };
24Added line. }
25Added line.
26Added line. namespace second::inner
27Added line. {
28Added line. struct Item { double value; };
29Added line. Item transform (Item value) { value.value += 2.0; return value; }
30Added line.
31Added line. class Object
32Added line. {
33Added line. public:
34Added line. int get () const;
35Added line. private:
36Added line. double value_;
37Added line. };
38Added line. }
39Added line.
40Added line. namespace a_b
41Added line. {
42Added line. struct Marker { int value; };
43Added line. }
44Added line.
45Added line. namespace a::b
46Added line. {
47Added line. struct Marker { double value; };
48Added line. }
49Added line.
50Added line. namespace first::inner
51Added line. {
52Added line. struct Again { long value; };
53Added line. }
54Added line.
55Added line. using First_Item = first::inner::Item;
56Added line. using Second_Item = second::inner::Item;
57Added line.
58Added line. extern "C" int namespace_identity_oracle () { return 73; }
59Added line.
60Added line. /* { dg-final { cleanup-ada-spec } } */
61

Variant gcc-15-16

Applies to 15.3.0, 16.1.0, 16.2.0. Source flavors: linux, darwin_arm64.

+257 −12 2 files

Download the patch

gcc/c-family/c-ada-spec.cc +197−12modified
Unified diff for gcc/c-family/c-ada-spec.cc: original line, patched line, change, source
@@ -753 +753 @@static tree *to_dump = NULL;
753753static int to_dump_count = 0;
754754static bool bitfield_used = false;
755755static bool packed_layout = false;
756Added line. static tree current_namespace = NULL_TREE;
757Added line.
758Added line. static void pp_ada_namespace_name (pretty_printer *, tree);
759Added line.
760Added line. /* Return the innermost named C++ namespace containing NODE. Anonymous
761Added line. namespaces do not add an Ada package level. */
762Added line.
763Added line. static tree
764Added line. named_namespace_context (tree node)
765Added line. {
766Added line. tree context = NULL_TREE;
767Added line. if (node && DECL_P (node))
768Added line. context = DECL_CONTEXT (node);
769Added line. else if (node && TYPE_P (node))
770Added line. context = TYPE_CONTEXT (node);
771Added line.
772Added line. while (context)
773Added line. {
774Added line. if (TREE_CODE (context) == NAMESPACE_DECL
775Added line. && DECL_NAME (context)
776Added line. && strcmp (IDENTIFIER_POINTER (DECL_NAME (context)), "::"))
777Added line. return context;
778Added line. if (DECL_P (context))
779Added line. context = DECL_CONTEXT (context);
780Added line. else if (TYPE_P (context))
781Added line. context = TYPE_CONTEXT (context);
782Added line. else
783Added line. break;
784Added line. }
785Added line. return NULL_TREE;
786Added line. }
787Added line.
788Added line. /* Return the nearest named namespace containing NS. */
789Added line.
790Added line. static tree
791Added line. parent_named_namespace (tree ns)
792Added line. {
793Added line. return named_namespace_context (ns);
794Added line. }
795Added line.
796Added line. /* Return the direct namespace package below SCOPE that contains DECL. */
797Added line.
798Added line. static tree
799Added line. direct_namespace_child (tree scope, tree decl)
800Added line. {
801Added line. tree ns = named_namespace_context (decl);
802Added line. if (!ns || ns == scope)
803Added line. return NULL_TREE;
804Added line.
805Added line. tree child = ns;
806Added line. for (tree parent = parent_named_namespace (child); parent;
807Added line. parent = parent_named_namespace (child))
808Added line. {
809Added line. if (parent == scope)
810Added line. return child;
811Added line. child = parent;
812Added line. }
813Added line.
814Added line. return scope ? NULL_TREE : child;
815Added line. }
816Added line.
817Added line. /* Return true if CHILD was already encountered before LIMIT in SCOPE. */
818Added line.
819Added line. static bool
820Added line. namespace_child_seen (tree scope, tree child, int limit)
821Added line. {
822Added line. for (int i = 0; i < limit; ++i)
823Added line. if (direct_namespace_child (scope, to_dump[i]) == child)
824Added line. return true;
825Added line. return false;
826Added line. }
827Added line.
828Added line. /* Dump all declarations and nested namespace packages directly in SCOPE. */
829Added line.
830Added line. static void
831Added line. dump_ada_namespace_contents (pretty_printer *pp, tree scope, int spc)
832Added line. {
833Added line. tree saved_namespace = current_namespace;
834Added line. current_namespace = scope;
835Added line.
836Added line. for (int i = 0; i < to_dump_count; ++i)
837Added line. {
838Added line. tree decl = to_dump[i];
839Added line. tree ns = named_namespace_context (decl);
840Added line. if (ns == scope)
841Added line. {
842Added line. if (dump_ada_declaration (pp, decl, NULL_TREE, spc))
843Added line. {
844Added line. pp_newline (pp);
845Added line. pp_newline (pp);
846Added line. }
847Added line. }
848Added line. else
849Added line. {
850Added line. tree child = direct_namespace_child (scope, decl);
851Added line. if (!child || namespace_child_seen (scope, child, i))
852Added line. continue;
853Added line.
854Added line. for (int indent = 0; indent < spc; ++indent)
855Added line. pp_space (pp);
856Added line. pp_string (pp, "package ");
857Added line. pp_ada_namespace_name (pp, child);
858Added line. pp_string (pp, " is");
859Added line. pp_newline (pp);
860Added line. pp_newline (pp);
861Added line. dump_ada_namespace_contents (pp, child, spc + INDENT_INCR);
862Added line. for (int indent = 0; indent < spc; ++indent)
863Added line. pp_space (pp);
864Added line. pp_string (pp, "end ");
865Added line. pp_ada_namespace_name (pp, child);
866Added line. pp_semicolon (pp);
867Added line. pp_newline (pp);
868Added line. pp_newline (pp);
869Added line. }
870Added line. }
871Added line.
872Added line. current_namespace = saved_namespace;
873Added line. }
756874
757875/* Collect a list of declarations from T relevant to SOURCE_FILE to be dumped
758876 by a subsequent call to dump_ada_nodes. */
@@ -763 +880 @@collect_ada_nodes (tree t, const char *source_file)
763880 tree n;
764881 int i = to_dump_count;
765882
766Removed line. /* Count the likely relevant nodes: do not dump builtins (they are irrelevant
767Removed line. in the context of bindings) and namespaces (we do not handle them properly
768Removed line. yet). */
883Added line. /* Count the likely relevant nodes. Namespace declarations themselves are
884Added line. represented by packages around their collected children. */
769885 for (n = t; n; n = TREE_CHAIN (n))
770886 if (!DECL_IS_UNDECLARED_BUILTIN (n)
771887 && TREE_CODE (n) != NAMESPACE_DECL
@@ -877 +993 @@dump_ada_nodes (pretty_printer *pp, const char *source_file)
877993 {
878994 current_source_file = source_file;
879995
880Removed line. if (dump_ada_declaration (pp, to_dump[i++], NULL_TREE,
881Removed line. INDENT_INCR))
996Added line. tree decl = to_dump[i++];
997Added line. tree child = direct_namespace_child (NULL_TREE, decl);
998Added line. if (child)
999Added line. {
1000Added line. if (!namespace_child_seen (NULL_TREE, child, i - 1))
1001Added line. {
1002Added line. for (int indent = 0; indent < INDENT_INCR; ++indent)
1003Added line. pp_space (pp);
1004Added line. pp_string (pp, "package ");
1005Added line. pp_ada_namespace_name (pp, child);
1006Added line. pp_string (pp, " is");
1007Added line. pp_newline (pp);
1008Added line. pp_newline (pp);
1009Added line. dump_ada_namespace_contents (pp, child,
1010Added line. INDENT_INCR * 2);
1011Added line. for (int indent = 0; indent < INDENT_INCR; ++indent)
1012Added line. pp_space (pp);
1013Added line. pp_string (pp, "end ");
1014Added line. pp_ada_namespace_name (pp, child);
1015Added line. pp_semicolon (pp);
1016Added line. pp_newline (pp);
1017Added line. pp_newline (pp);
1018Added line. }
1019Added line. }
1020Added line. else if (dump_ada_declaration (pp, decl, NULL_TREE,
1021Added line. INDENT_INCR))
8821022 {
8831023 pp_newline (pp);
8841024 pp_newline (pp);
@@ -1370 +1510 @@to_ada_name (const char *name, bool *space_found)
13701510 return s;
13711511}
13721512
1513Added line. /* Dump the Ada package name corresponding to named namespace NS. */
1514Added line.
1515Added line. static void
1516Added line. pp_ada_namespace_name (pretty_printer *pp, tree ns)
1517Added line. {
1518Added line. bool space_found = false;
1519Added line. char *name = to_ada_name (IDENTIFIER_POINTER (DECL_NAME (ns)),
1520Added line. &space_found);
1521Added line. pp_string (pp, name);
1522Added line. free (name);
1523Added line. }
1524Added line.
1525Added line. /* Dump the complete nested Ada package path containing DECL, unless DECL is
1526Added line. already in the namespace package currently being emitted. */
1527Added line.
1528Added line. static void
1529Added line. pp_ada_namespace_path (pretty_printer *pp, tree ns)
1530Added line. {
1531Added line. if (!ns)
1532Added line. return;
1533Added line.
1534Added line. tree parent = parent_named_namespace (ns);
1535Added line. if (parent)
1536Added line. pp_ada_namespace_path (pp, parent);
1537Added line. pp_ada_namespace_name (pp, ns);
1538Added line. pp_dot (pp);
1539Added line. }
1540Added line.
1541Added line. static void
1542Added line. pp_ada_namespace_prefix (pretty_printer *pp, tree decl)
1543Added line. {
1544Added line. tree ns = named_namespace_context (decl);
1545Added line. if (ns && ns != current_namespace)
1546Added line. pp_ada_namespace_path (pp, ns);
1547Added line. }
1548Added line.
13731549/* Return true if DECL refers to a C++ class type for which a
13741550 separate enclosing package has been or should be generated. */
13751551
@@ -1397 +1573 @@pp_ada_tree_identifier (pretty_printer *pp, tree node, tree type,
13971573 char *s = to_ada_name (name, &space_found);
13981574 tree decl = get_underlying_decl (type);
13991575
1576Added line. bool external_decl = false;
14001577 if (decl)
14011578 {
14021579 /* If the entity comes from another file, generate a package prefix. */
@@ -1404 +1581 @@pp_ada_tree_identifier (pretty_printer *pp, tree node, tree type,
14041581
14051582 if (xloc.line && xloc.file && xloc.file != current_source_file)
14061583 {
1584Added line. external_decl = true;
14071585 switch (TREE_CODE (type))
14081586 {
14091587 case ENUMERAL_TYPE:
@@ -1430 +1608 @@pp_ada_tree_identifier (pretty_printer *pp, tree node, tree type,
14301608 break;
14311609 }
14321610
1433Removed line. /* Generate the additional package prefix for C++ classes. */
1434Removed line. if (separate_class_package (decl))
1435Removed line. {
1436Removed line. pp_string (pp, "Class_");
1437Removed line. pp_string (pp, s);
1438Removed line. pp_dot (pp);
1439Removed line. }
1611Added line. }
1612Added line.
1613Added line. pp_ada_namespace_prefix (pp, decl);
1614Added line.
1615Added line. /* Generate the additional package prefix for C++ classes when the
1616Added line. declaration is outside the namespace package currently being emitted. */
1617Added line. if (separate_class_package (decl)
1618Added line. && (external_decl
1619Added line. || named_namespace_context (decl) != current_namespace))
1620Added line. {
1621Added line. pp_string (pp, "Class_");
1622Added line. pp_string (pp, s);
1623Added line. pp_dot (pp);
14401624 }
14411625 }
14421626
gcc/testsuite/g++.dg/ada-spec/namespace-identity.C +60−0new file
Unified diff for gcc/testsuite/g++.dg/ada-spec/namespace-identity.C: original line, patched line, change, source
@@ -0 +1 @@
1Added line. /* { dg-do compile } */
2Added line. /* { dg-options "-fdump-ada-spec-slim" } */
3Added line. /* { dg-final { scan-file namespace_identity_c.ads "package first is" } } */
4Added line. /* { dg-final { scan-file namespace_identity_c.ads "package inner is" } } */
5Added line. /* { dg-final { scan-file namespace_identity_c.ads "function transform \(value : Item\) return Item" } } */
6Added line. /* { dg-final { scan-file namespace_identity_c.ads "package Class_Object is" } } */
7Added line. /* { dg-final { scan-file namespace_identity_c.ads "package a_b is" } } */
8Added line. /* { dg-final { scan-file namespace_identity_c.ads "package a is" } } */
9Added line. /* { dg-final { scan-file namespace_identity_c.ads "type Again is record" } } */
10Added line. /* { dg-final { scan-file-not namespace_identity_c.ads "package :: is" } } */
11Added line.
12Added line. namespace first::inner
13Added line. {
14Added line. struct Item { int value; };
15Added line. Item transform (Item value) { value.value += 1; return value; }
16Added line.
17Added line. class Object
18Added line. {
19Added line. public:
20Added line. int get () const;
21Added line. private:
22Added line. int value_;
23Added line. };
24Added line. }
25Added line.
26Added line. namespace second::inner
27Added line. {
28Added line. struct Item { double value; };
29Added line. Item transform (Item value) { value.value += 2.0; return value; }
30Added line.
31Added line. class Object
32Added line. {
33Added line. public:
34Added line. int get () const;
35Added line. private:
36Added line. double value_;
37Added line. };
38Added line. }
39Added line.
40Added line. namespace a_b
41Added line. {
42Added line. struct Marker { int value; };
43Added line. }
44Added line.
45Added line. namespace a::b
46Added line. {
47Added line. struct Marker { double value; };
48Added line. }
49Added line.
50Added line. namespace first::inner
51Added line. {
52Added line. struct Again { long value; };
53Added line. }
54Added line.
55Added line. using First_Item = first::inner::Item;
56Added line. using Second_Item = second::inner::Item;
57Added line.
58Added line. extern "C" int namespace_identity_oracle () { return 73; }
59Added line.
60Added line. /* { dg-final { cleanup-ada-spec } } */
61

Tests.

namespace-identity.C C++ · 60 lines
/* { 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 } } */

Download · View in repository

namespace_identity_consumer.adb Ada · 21 lines
with Namespace_Identity_C;
with Interfaces.C; use Interfaces.C;

procedure Namespace_Identity_Consumer is
   package Bindings renames Namespace_Identity_C;
   First : Bindings.first.inner.Item := (value => 11);
   Second : Bindings.second.inner.Item := (value => 13.0);
   Flat : Bindings.a_b.Marker := (value => 17);
   Nested : Bindings.a.b.Marker := (value => 19.0);
   Reopened : Bindings.first.inner.Again := (value => 23);
begin
   if Bindings.namespace_identity_oracle /= 73
     or else First.value /= 11
     or else Second.value /= 13.0
     or else Flat.value /= 17
     or else Nested.value /= 19.0
     or else Reopened.value /= 23
   then
      raise Program_Error with "nested namespace package mapping failed";
   end if;
end Namespace_Identity_Consumer;

Download · View in repository

run-test.sh shell · 82 lines
#!/usr/bin/env bash
set -euo pipefail

if [[ $# -ne 3 ]]; then
  echo "usage: $0 TOOLCHAIN_ROOT GCC_VERSION unpatched|patched" >&2
  exit 2
fi

root=$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)
source "$root/scripts/regression-common.sh"
resolve_regression_toolchain "$1"
version=$2
state=$3
[[ "$state" == unpatched || "$state" == patched ]] || {
  echo "error: state must be unpatched or patched" >&2
  exit 2
}

gxx="$REGRESSION_TOOLCHAIN/bin/g++"
[[ -x "$gxx" ]] || {
  echo "error: no g++ in $REGRESSION_TOOLCHAIN" >&2
  exit 1
}

cxx_fixture="$root/bundles/cxx-ada-namespace-identity/tests/namespace-identity.C"
ada_fixture="$root/bundles/cxx-ada-namespace-identity/tests/namespace_identity_consumer.adb"
work=$(mktemp -d "${TMPDIR:-/tmp}/gnat-cxx-ada-namespace-test.XXXXXX")
trap 'rm -rf "$work"' EXIT

for optimization in 0 2; do
  case_dir="$work/O$optimization"
  mkdir -p "$case_dir"
  cp "$cxx_fixture" "$ada_fixture" "$case_dir/"
  (
    cd "$case_dir"
    "${REGRESSION_ENV[@]}" "$gxx" -c "-O$optimization" \
      -fdump-ada-spec-slim namespace-identity.C
  )

  spec="$case_dir/namespace_identity_c.ads"
  set +e
  (
    cd "$case_dir"
    "${REGRESSION_ENV[@]}" "$REGRESSION_GNATMAKE" -q -f \
      "-O$optimization" namespace_identity_consumer.adb \
      -largs namespace-identity.o -lstdc++
    "${REGRESSION_ENV[@]}" ./namespace_identity_consumer
  ) >"$case_dir/build.log" 2>&1
  build_status=$?
  set -e

  if [[ "$state" == unpatched ]]; then
    [[ $build_status -ne 0 ]] || {
      echo "error: unpatched namespace regression unexpectedly compiled" >&2
      exit 1
    }
    grep -Eiq 'conflicts with declaration|duplicate|already declared' \
      "$case_dir/build.log" || {
      cat "$case_dir/build.log"
      exit 1
    }
    echo "cxx-ada-namespace-identity -O$optimization: expected collision (GCC $version)"
    continue
  fi

  [[ $build_status -eq 0 ]] || {
    cat "$case_dir/build.log"
    exit 1
  }
  grep -F "package first is" "$spec"
  grep -F "package inner is" "$spec"
  grep -F "function transform (value : Item) return Item" "$spec"
  grep -F "package Class_Object is" "$spec"
  grep -F "package a_b is" "$spec"
  grep -F "package a is" "$spec"
  grep -F "type Again is record" "$spec"
  if grep -Fq "package :: is" "$spec"; then
    echo "error: global C++ namespace was emitted as an Ada package" >&2
    exit 1
  fi
  echo "cxx-ada-namespace-identity -O$optimization: patched (GCC $version)"
done

Download · View in repository

Commands.

Apply the patch
patch --fuzz=0 -p1 -i bundles/cxx-ada-namespace-identity/patches/VARIANT.patch
Build the compiler
PATH=/path/to/bootstrap/bin:$PATH ./scripts/build-gnat.sh SOURCE BUILD INSTALL
Run the regression
./scripts/run-regressions.sh INSTALL 1.2.0 GCC_MAJOR patched

Metadata.