cxx-ada-casefold-identity

C++ Ada casefold identity

The C++ Ada spec dumper emits case-distinct C++ identifiers as duplicate Ada identifiers.

AcceptedApplies in patchset orderSince 1.2.0

Where it applies.

How each patchset treats this bundle on each exact GCC target
PatchsetGCC 1313.2.0GCC 1414.2.0GCC 1515.3.0GCC 1616.1.0GCC 1616.2.0
1.2.0 (latest)Patchedgcc-13-1413.2.0Patchedgcc-13-1414.2.0Patchedgcc-15-1615.3.0Not coveredPatchedgcc-15-1616.2.0
1.1.1Not applicable13.2.0Not applicable14.2.0Not applicable15.3.0Not applicable16.1.0Not applicable16.2.0
1.1.0Not applicable13.2.0Not applicable14.2.0Not applicable15.3.0Not coveredNot applicable16.2.0
1.0.1Not applicable13.2.0Not applicable14.2.0Not applicable15.3.0Not applicable16.1.0Not covered
1.0.0Not applicable13.2.0Not applicable14.2.0Not applicable15.3.0Not applicable16.1.0Not covered

Explanation.

Ada identifiers are case-insensitive, while C++ identifiers are case-sensitive. The mapper previously copied C++ casing without detecting collisions in the generated Ada scope.

For example:

struct Item { int value; };
struct ITEM { double value; };
int measure(Item);
int MEASURE(ITEM);

The unpatched output preserves spelling but loses identity in Ada:

type Item is record ... end record;
type ITEM is record ... end record;
function measure (arg1 : Item) return int;
function MEASURE (arg1 : ITEM) return int;

Both pairs are duplicate Ada identifiers. The corrected output assigns a stable, scope-local suffix to the later case variant and uses it in every reference:

type Item is record ... end record;
type ITEM_Case_2 is record ... end record;
function measure (arg1 : Item) return int;
function MEASURE_Case_2 (arg1 : ITEM_Case_2) return int;

The same rule covers records, functions, aliases, and fields. Identical names in different C++ scopes remain unchanged. The executable regression compiles the corrected Ada and calls both case-distinct C++ functions at -O0 and -O2.

Patch.

Variant gcc-13-14

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

+200 −4 2 files

Download the patch

gcc/c-family/c-ada-spec.cc +166−4modified
Unified diff for gcc/c-family/c-ada-spec.cc: original line, patched line, change, source
@@ -701 +701 @@static tree *to_dump = NULL;
701701static int to_dump_count = 0;
702702static tree current_namespace = NULL_TREE;
703703
704Added line. enum ada_name_role
705Added line. {
706Added line. ADA_NAME_SOURCE,
707Added line. ADA_NAME_QUALIFIED_METHOD,
708Added line. ADA_NAME_RENAMED_METHOD,
709Added line. ADA_NAME_TEMPLATE_INSTANCE,
710Added line. ADA_NAME_AS_BASE,
711Added line. ADA_NAME_SYNTHETIC_FIELD,
712Added line. ADA_NAME_FORMAL
713Added line. };
714Added line.
715Added line. static const char *allocate_ada_name (const char *, tree, ada_name_role,
716Added line. tree, const char *, const char *);
717Added line.
704718static void pp_ada_namespace_name (pretty_printer *, tree);
705719
706720/* Return the innermost named C++ namespace containing NODE. Anonymous
@@ -1459 +1473 @@pp_ada_namespace_name (pretty_printer *pp, tree ns)
14591473 bool space_found = false;
14601474 char *name = to_ada_name (IDENTIFIER_POINTER (DECL_NAME (ns)),
14611475 &space_found);
1462Removed line. pp_string (pp, name);
1476Added line. const char *allocated
1477Added line. = allocate_ada_name (name, DECL_NAME (ns), ADA_NAME_SOURCE,
1478Added line. DECL_CONTEXT (ns),
1479Added line. LOCATION_FILE (decl_sloc (ns, false)), "_Case_");
1480Added line. pp_string (pp, allocated);
14631481 free (name);
14641482}
14651483
@@ -1501 +1519 @@static bool package_prefix = true;
15011519static tree current_template = NULL_TREE;
15021520static tree current_template_instance = NULL_TREE;
15031521
1522Added line. struct allocated_ada_name
1523Added line. {
1524Added line. hashval_t hash;
1525Added line. tree identity;
1526Added line. tree scope;
1527Added line. const char *file;
1528Added line. ada_name_role role;
1529Added line. char *name;
1530Added line.
1531Added line. ~allocated_ada_name () { free (name); }
1532Added line. };
1533Added line.
1534Added line. struct allocated_ada_name_hasher : delete_ptr_hash<allocated_ada_name>
1535Added line. {
1536Added line. static inline hashval_t hash (allocated_ada_name *entry)
1537Added line. { return entry->hash; }
1538Added line. static inline bool equal (allocated_ada_name *a, allocated_ada_name *b)
1539Added line. {
1540Added line. return (a->identity == b->identity && a->scope == b->scope
1541Added line. && a->file == b->file
1542Added line. && a->role == b->role);
1543Added line. }
1544Added line. };
1545Added line.
1546Added line. struct occupied_ada_name
1547Added line. {
1548Added line. hashval_t hash;
1549Added line. tree scope;
1550Added line. const char *file;
1551Added line. char *name;
1552Added line.
1553Added line. ~occupied_ada_name () { free (name); }
1554Added line. };
1555Added line.
1556Added line. struct occupied_ada_name_hasher : delete_ptr_hash<occupied_ada_name>
1557Added line. {
1558Added line. static inline hashval_t hash (occupied_ada_name *entry)
1559Added line. { return entry->hash; }
1560Added line. static inline bool equal (occupied_ada_name *a, occupied_ada_name *b)
1561Added line. {
1562Added line. return (a->scope == b->scope && a->file == b->file
1563Added line. && !strcmp (a->name, b->name));
1564Added line. }
1565Added line. };
1566Added line.
1567Added line. typedef hash_table<allocated_ada_name_hasher> allocated_ada_name_table;
1568Added line. typedef hash_table<occupied_ada_name_hasher> occupied_ada_name_table;
1569Added line. static allocated_ada_name_table *allocated_ada_names;
1570Added line. static occupied_ada_name_table *occupied_ada_names;
1571Added line.
1572Added line. /* Return a lower-case copy of NAME for Ada-insensitive comparison. */
1573Added line.
1574Added line. static char *
1575Added line. fold_ada_name (const char *name)
1576Added line. {
1577Added line. char *folded = xstrdup (name);
1578Added line. for (char *p = folded; *p; ++p)
1579Added line. *p = TOLOWER (*p);
1580Added line. return folded;
1581Added line. }
1582Added line.
1583Added line. /* Allocate a stable Ada name for IDENTITY and ROLE in SCOPE. PREFERRED is
1584Added line. retained when it is unique. Only an actual collision receives SUFFIX and
1585Added line. a deterministic ordinal. */
1586Added line.
1587Added line. static const char *
1588Added line. allocate_ada_name (const char *preferred, tree identity, ada_name_role role,
1589Added line. tree scope, const char *file, const char *suffix)
1590Added line. {
1591Added line. allocated_ada_name query;
1592Added line. query.identity = identity;
1593Added line. query.scope = scope;
1594Added line. query.file = file;
1595Added line. query.role = role;
1596Added line. query.name = NULL;
1597Added line. query.hash = (htab_hash_pointer (identity) ^ htab_hash_pointer (scope)
1598Added line. ^ htab_hash_pointer (file) ^ (hashval_t) role);
1599Added line. allocated_ada_name *existing
1600Added line. = allocated_ada_names->find_with_hash (&query, query.hash);
1601Added line. if (existing)
1602Added line. return existing->name;
1603Added line.
1604Added line. char *candidate = xstrdup (preferred);
1605Added line. unsigned int ordinal = 1;
1606Added line. while (true)
1607Added line. {
1608Added line. char *folded = fold_ada_name (candidate);
1609Added line. occupied_ada_name occupied_query;
1610Added line. occupied_query.scope = scope;
1611Added line. occupied_query.file = file;
1612Added line. occupied_query.name = folded;
1613Added line. occupied_query.hash = (htab_hash_string (folded)
1614Added line. ^ htab_hash_pointer (scope)
1615Added line. ^ htab_hash_pointer (file));
1616Added line. occupied_ada_name *occupied_existing
1617Added line. = occupied_ada_names->find_with_hash (&occupied_query,
1618Added line. occupied_query.hash);
1619Added line. if (!occupied_existing)
1620Added line. {
1621Added line. occupied_ada_name **occupied_slot
1622Added line. = occupied_ada_names->find_slot_with_hash (&occupied_query,
1623Added line. occupied_query.hash, INSERT);
1624Added line. occupied_query.name = NULL;
1625Added line. occupied_ada_name *occupied = new occupied_ada_name;
1626Added line. occupied->hash = occupied_query.hash;
1627Added line. occupied->scope = scope;
1628Added line. occupied->file = file;
1629Added line. occupied->name = folded;
1630Added line. *occupied_slot = occupied;
1631Added line. break;
1632Added line. }
1633Added line.
1634Added line. occupied_query.name = NULL;
1635Added line. free (folded);
1636Added line. free (candidate);
1637Added line. ++ordinal;
1638Added line. const size_t length = strlen (preferred) + strlen (suffix) + 24;
1639Added line. candidate = XNEWVEC (char, length);
1640Added line. snprintf (candidate, length, "%s%s%u", preferred, suffix, ordinal);
1641Added line. }
1642Added line.
1643Added line. allocated_ada_name **slot
1644Added line. = allocated_ada_names->find_slot_with_hash (&query, query.hash, INSERT);
1645Added line. allocated_ada_name *allocated = new allocated_ada_name;
1646Added line. allocated->hash = query.hash;
1647Added line. allocated->identity = identity;
1648Added line. allocated->scope = scope;
1649Added line. allocated->file = file;
1650Added line. allocated->role = role;
1651Added line. allocated->name = candidate;
1652Added line. *slot = allocated;
1653Added line. return allocated->name;
1654Added line. }
1655Added line.
15041656/* Dump in BUFFER the name of an identifier NODE of type TYPE, following Ada
15051657 syntax. LIMITED_ACCESS indicates whether NODE can be accessed through a
15061658 limited 'with' clause rather than a regular 'with' clause. */
@@ -1513 +1665 @@pp_ada_tree_identifier (pretty_printer *buffer, tree node, tree type,
15131665 bool space_found = false;
15141666 char *s = to_ada_name (name, &space_found);
15151667 tree decl = get_underlying_decl (type);
1668Added line. const char *allocated = s;
1669Added line. if (cpp_check && decl)
1670Added line. allocated = allocate_ada_name (s, node, ADA_NAME_SOURCE,
1671Added line. DECL_CONTEXT (decl),
1672Added line. LOCATION_FILE (decl_sloc (decl, false)),
1673Added line. "_Case_");
15161674
15171675 bool external_decl = false;
15181676 if (decl)
@@ -1560 +1718 @@pp_ada_tree_identifier (pretty_printer *buffer, tree node, tree type,
15601718 || named_namespace_context (decl) != current_namespace))
15611719 {
15621720 pp_string (buffer, "Class_");
1563Removed line. pp_string (buffer, s);
1721Added line. pp_string (buffer, allocated);
15641722 pp_dot (buffer);
15651723 }
15661724 }
@@ -1589 +1747 @@pp_ada_tree_identifier (pretty_printer *buffer, tree node, tree type,
15891747 pp_string (buffer, "unsigned_long_long");
15901748 }
15911749 else
1592Removed line. pp_string(buffer, s);
1750Added line. pp_string(buffer, allocated);
15931751 else
15941752 if (!strcmp (s, "u_Bool") || !strcmp (s, "bool"))
15951753 {
@@ -1602 +1760 @@pp_ada_tree_identifier (pretty_printer *buffer, tree node, tree type,
16021760 pp_string (buffer, "bool");
16031761 }
16041762 else
1605Removed line. pp_string(buffer, s);
1763Added line. pp_string(buffer, allocated);
16061764
16071765 free (s);
16081766}
@@ -3873 +4031 @@dump_ada_specs (void (*collect_all_refs)(const char *),
38734031 bitmap_obstack_initialize (NULL);
38744032
38754033 overloaded_names = init_overloaded_names ();
4034Added line. allocated_ada_names = new allocated_ada_name_table (64);
4035Added line. occupied_ada_names = new occupied_ada_name_table (64);
38764036
38774037 /* Iterate over the list of files to dump specs for. */
38784038 for (int i = 0; i < source_refs_used; i++)
@@ -3885 +4045 @@dump_ada_specs (void (*collect_all_refs)(const char *),
38854045 /* Free various tables. */
38864046 free (source_refs);
38874047 delete overloaded_names;
4048Added line. delete allocated_ada_names;
4049Added line. delete occupied_ada_names;
38884050
38894051 bitmap_obstack_release (NULL);
38904052}
gcc/testsuite/g++.dg/ada-spec/casefold-identity.C +34−0new file
Unified diff for gcc/testsuite/g++.dg/ada-spec/casefold-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 casefold_identity_c.ads "type ITEM_Case_2" } } */
4Added line. /* { dg-final { scan-file casefold_identity_c.ads "subtype ALIAS_Case_2" } } */
5Added line. /* { dg-final { scan-file casefold_identity_c.ads "VALUE_Case_2" } } */
6Added line. /* { dg-final { scan-file casefold_identity_c.ads "VaLuE_Case_3" } } */
7Added line. /* { dg-final { scan-file casefold_identity_c.ads "function MEASURE_Case_2" } } */
8Added line.
9Added line. struct Item
10Added line. {
11Added line. int value;
12Added line. };
13Added line.
14Added line. struct ITEM
15Added line. {
16Added line. double value;
17Added line. };
18Added line.
19Added line. using Alias = Item;
20Added line. using ALIAS = ITEM;
21Added line.
22Added line. struct Fields
23Added line. {
24Added line. int value;
25Added line. int VALUE;
26Added line. int VaLuE;
27Added line. };
28Added line.
29Added line. int measure (Item item) { return item.value; }
30Added line. int MEASURE (ITEM item) { return static_cast<int> (item.value); }
31Added line. int combine (Fields fields)
32Added line. { return fields.value + fields.VALUE + fields.VaLuE; }
33Added line.
34Added line. /* { dg-final { cleanup-ada-spec } } */
35

Variant gcc-15-16

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

+199 −4 2 files

Download the patch

gcc/c-family/c-ada-spec.cc +165−4modified
Unified diff for gcc/c-family/c-ada-spec.cc: original line, patched line, change, source
@@ -755 +755 @@static bool bitfield_used = false;
755755static bool packed_layout = false;
756756static tree current_namespace = NULL_TREE;
757757
758Added line. enum ada_name_role
759Added line. {
760Added line. ADA_NAME_SOURCE,
761Added line. ADA_NAME_QUALIFIED_METHOD,
762Added line. ADA_NAME_RENAMED_METHOD,
763Added line. ADA_NAME_TEMPLATE_INSTANCE,
764Added line. ADA_NAME_AS_BASE,
765Added line. ADA_NAME_SYNTHETIC_FIELD,
766Added line. ADA_NAME_FORMAL
767Added line. };
768Added line.
769Added line. static const char *allocate_ada_name (const char *, tree, ada_name_role,
770Added line. tree, const char *, const char *);
758771static void pp_ada_namespace_name (pretty_printer *, tree);
759772
760773/* Return the innermost named C++ namespace containing NODE. Anonymous
@@ -1513 +1526 @@pp_ada_namespace_name (pretty_printer *pp, tree ns)
15131526 bool space_found = false;
15141527 char *name = to_ada_name (IDENTIFIER_POINTER (DECL_NAME (ns)),
15151528 &space_found);
1516Removed line. pp_string (pp, name);
1529Added line. const char *allocated
1530Added line. = allocate_ada_name (name, DECL_NAME (ns), ADA_NAME_SOURCE,
1531Added line. DECL_CONTEXT (ns),
1532Added line. LOCATION_FILE (decl_sloc (ns, false)), "_Case_");
1533Added line. pp_string (pp, allocated);
15171534 free (name);
15181535}
15191536
@@ -1555 +1572 @@static bool package_prefix = true;
15551572static tree current_template = NULL_TREE;
15561573static tree current_template_instance = NULL_TREE;
15571574
1575Added line. struct allocated_ada_name
1576Added line. {
1577Added line. hashval_t hash;
1578Added line. tree identity;
1579Added line. tree scope;
1580Added line. const char *file;
1581Added line. ada_name_role role;
1582Added line. char *name;
1583Added line.
1584Added line. ~allocated_ada_name () { free (name); }
1585Added line. };
1586Added line.
1587Added line. struct allocated_ada_name_hasher : delete_ptr_hash<allocated_ada_name>
1588Added line. {
1589Added line. static inline hashval_t hash (allocated_ada_name *entry)
1590Added line. { return entry->hash; }
1591Added line. static inline bool equal (allocated_ada_name *a, allocated_ada_name *b)
1592Added line. {
1593Added line. return (a->identity == b->identity && a->scope == b->scope
1594Added line. && a->file == b->file
1595Added line. && a->role == b->role);
1596Added line. }
1597Added line. };
1598Added line.
1599Added line. struct occupied_ada_name
1600Added line. {
1601Added line. hashval_t hash;
1602Added line. tree scope;
1603Added line. const char *file;
1604Added line. char *name;
1605Added line.
1606Added line. ~occupied_ada_name () { free (name); }
1607Added line. };
1608Added line.
1609Added line. struct occupied_ada_name_hasher : delete_ptr_hash<occupied_ada_name>
1610Added line. {
1611Added line. static inline hashval_t hash (occupied_ada_name *entry)
1612Added line. { return entry->hash; }
1613Added line. static inline bool equal (occupied_ada_name *a, occupied_ada_name *b)
1614Added line. {
1615Added line. return (a->scope == b->scope && a->file == b->file
1616Added line. && !strcmp (a->name, b->name));
1617Added line. }
1618Added line. };
1619Added line.
1620Added line. typedef hash_table<allocated_ada_name_hasher> allocated_ada_name_table;
1621Added line. typedef hash_table<occupied_ada_name_hasher> occupied_ada_name_table;
1622Added line. static allocated_ada_name_table *allocated_ada_names;
1623Added line. static occupied_ada_name_table *occupied_ada_names;
1624Added line.
1625Added line. /* Return a lower-case copy of NAME for Ada-insensitive comparison. */
1626Added line.
1627Added line. static char *
1628Added line. fold_ada_name (const char *name)
1629Added line. {
1630Added line. char *folded = xstrdup (name);
1631Added line. for (char *p = folded; *p; ++p)
1632Added line. *p = TOLOWER (*p);
1633Added line. return folded;
1634Added line. }
1635Added line.
1636Added line. /* Allocate a stable Ada name for IDENTITY and ROLE in SCOPE. PREFERRED is
1637Added line. retained when it is unique. Only an actual collision receives SUFFIX and
1638Added line. a deterministic ordinal. */
1639Added line.
1640Added line. static const char *
1641Added line. allocate_ada_name (const char *preferred, tree identity, ada_name_role role,
1642Added line. tree scope, const char *file, const char *suffix)
1643Added line. {
1644Added line. allocated_ada_name query;
1645Added line. query.identity = identity;
1646Added line. query.scope = scope;
1647Added line. query.file = file;
1648Added line. query.role = role;
1649Added line. query.name = NULL;
1650Added line. query.hash = (htab_hash_pointer (identity) ^ htab_hash_pointer (scope)
1651Added line. ^ htab_hash_pointer (file) ^ (hashval_t) role);
1652Added line. allocated_ada_name *existing
1653Added line. = allocated_ada_names->find_with_hash (&query, query.hash);
1654Added line. if (existing)
1655Added line. return existing->name;
1656Added line.
1657Added line. char *candidate = xstrdup (preferred);
1658Added line. unsigned int ordinal = 1;
1659Added line. while (true)
1660Added line. {
1661Added line. char *folded = fold_ada_name (candidate);
1662Added line. occupied_ada_name occupied_query;
1663Added line. occupied_query.scope = scope;
1664Added line. occupied_query.file = file;
1665Added line. occupied_query.name = folded;
1666Added line. occupied_query.hash = (htab_hash_string (folded)
1667Added line. ^ htab_hash_pointer (scope)
1668Added line. ^ htab_hash_pointer (file));
1669Added line. occupied_ada_name *occupied_existing
1670Added line. = occupied_ada_names->find_with_hash (&occupied_query,
1671Added line. occupied_query.hash);
1672Added line. if (!occupied_existing)
1673Added line. {
1674Added line. occupied_ada_name **occupied_slot
1675Added line. = occupied_ada_names->find_slot_with_hash (&occupied_query,
1676Added line. occupied_query.hash, INSERT);
1677Added line. occupied_query.name = NULL;
1678Added line. occupied_ada_name *occupied = new occupied_ada_name;
1679Added line. occupied->hash = occupied_query.hash;
1680Added line. occupied->scope = scope;
1681Added line. occupied->file = file;
1682Added line. occupied->name = folded;
1683Added line. *occupied_slot = occupied;
1684Added line. break;
1685Added line. }
1686Added line.
1687Added line. occupied_query.name = NULL;
1688Added line. free (folded);
1689Added line. free (candidate);
1690Added line. ++ordinal;
1691Added line. const size_t length = strlen (preferred) + strlen (suffix) + 24;
1692Added line. candidate = XNEWVEC (char, length);
1693Added line. snprintf (candidate, length, "%s%s%u", preferred, suffix, ordinal);
1694Added line. }
1695Added line.
1696Added line. allocated_ada_name **slot
1697Added line. = allocated_ada_names->find_slot_with_hash (&query, query.hash, INSERT);
1698Added line. allocated_ada_name *allocated = new allocated_ada_name;
1699Added line. allocated->hash = query.hash;
1700Added line. allocated->identity = identity;
1701Added line. allocated->scope = scope;
1702Added line. allocated->file = file;
1703Added line. allocated->role = role;
1704Added line. allocated->name = candidate;
1705Added line. *slot = allocated;
1706Added line. return allocated->name;
1707Added line. }
1708Added line.
15581709/* Dump in PP the name of an identifier NODE of type TYPE, following Ada
15591710 syntax. LIMITED_ACCESS indicates whether NODE can be accessed through a
15601711 limited 'with' clause rather than a regular 'with' clause. */
@@ -1567 +1718 @@pp_ada_tree_identifier (pretty_printer *pp, tree node, tree type,
15671718 bool space_found = false;
15681719 char *s = to_ada_name (name, &space_found);
15691720 tree decl = get_underlying_decl (type);
1721Added line. const char *allocated = s;
1722Added line. if (cpp_check && decl)
1723Added line. allocated = allocate_ada_name (s, node, ADA_NAME_SOURCE,
1724Added line. DECL_CONTEXT (decl),
1725Added line. LOCATION_FILE (decl_sloc (decl, false)),
1726Added line. "_Case_");
15701727
15711728 bool external_decl = false;
15721729 if (decl)
@@ -1614 +1771 @@pp_ada_tree_identifier (pretty_printer *pp, tree node, tree type,
16141771 || named_namespace_context (decl) != current_namespace))
16151772 {
16161773 pp_string (pp, "Class_");
1617Removed line. pp_string (pp, s);
1774Added line. pp_string (pp, allocated);
16181775 pp_dot (pp);
16191776 }
16201777 }
@@ -1643 +1800 @@pp_ada_tree_identifier (pretty_printer *pp, tree node, tree type,
16431800 pp_string (pp, "unsigned_long_long");
16441801 }
16451802 else
1646Removed line. pp_string (pp, s);
1803Added line. pp_string (pp, allocated);
16471804 else
16481805 if (!strcmp (s, "u_Bool") || !strcmp (s, "bool"))
16491806 {
@@ -1656 +1813 @@pp_ada_tree_identifier (pretty_printer *pp, tree node, tree type,
16561813 pp_string (pp, "bool");
16571814 }
16581815 else
1659Removed line. pp_string (pp, s);
1816Added line. pp_string (pp, allocated);
16601817
16611818 free (s);
16621819}
@@ -3960 +4117 @@dump_ada_specs (void (*collect_all_refs)(const char *),
39604117 bitmap_obstack_initialize (NULL);
39614118
39624119 overloaded_names = init_overloaded_names ();
4120Added line. allocated_ada_names = new allocated_ada_name_table (64);
4121Added line. occupied_ada_names = new occupied_ada_name_table (64);
39634122
39644123 /* Iterate over the list of files to dump specs for. */
39654124 for (int i = 0; i < source_refs_used; i++)
@@ -3972 +4131 @@dump_ada_specs (void (*collect_all_refs)(const char *),
39724131 /* Free various tables. */
39734132 free (source_refs);
39744133 delete overloaded_names;
4134Added line. delete allocated_ada_names;
4135Added line. delete occupied_ada_names;
39754136
39764137 bitmap_obstack_release (NULL);
39774138}
gcc/testsuite/g++.dg/ada-spec/casefold-identity.C +34−0new file
Unified diff for gcc/testsuite/g++.dg/ada-spec/casefold-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 casefold_identity_c.ads "type ITEM_Case_2" } } */
4Added line. /* { dg-final { scan-file casefold_identity_c.ads "subtype ALIAS_Case_2" } } */
5Added line. /* { dg-final { scan-file casefold_identity_c.ads "VALUE_Case_2" } } */
6Added line. /* { dg-final { scan-file casefold_identity_c.ads "VaLuE_Case_3" } } */
7Added line. /* { dg-final { scan-file casefold_identity_c.ads "function MEASURE_Case_2" } } */
8Added line.
9Added line. struct Item
10Added line. {
11Added line. int value;
12Added line. };
13Added line.
14Added line. struct ITEM
15Added line. {
16Added line. double value;
17Added line. };
18Added line.
19Added line. using Alias = Item;
20Added line. using ALIAS = ITEM;
21Added line.
22Added line. struct Fields
23Added line. {
24Added line. int value;
25Added line. int VALUE;
26Added line. int VaLuE;
27Added line. };
28Added line.
29Added line. int measure (Item item) { return item.value; }
30Added line. int MEASURE (ITEM item) { return static_cast<int> (item.value); }
31Added line. int combine (Fields fields)
32Added line. { return fields.value + fields.VALUE + fields.VaLuE; }
33Added line.
34Added line. /* { dg-final { cleanup-ada-spec } } */
35

Tests.

casefold-identity.C C++ · 34 lines
/* { dg-do compile } */
/* { dg-options "-fdump-ada-spec-slim" } */
/* { dg-final { scan-file casefold_identity_c.ads "type ITEM_Case_2" } } */
/* { dg-final { scan-file casefold_identity_c.ads "subtype ALIAS_Case_2" } } */
/* { dg-final { scan-file casefold_identity_c.ads "VALUE_Case_2" } } */
/* { dg-final { scan-file casefold_identity_c.ads "VaLuE_Case_3" } } */
/* { dg-final { scan-file casefold_identity_c.ads "function MEASURE_Case_2" } } */

struct Item
{
  int value;
};

struct ITEM
{
  double value;
};

using Alias = Item;
using ALIAS = ITEM;

struct Fields
{
  int value;
  int VALUE;
  int VaLuE;
};

int measure (Item item) { return item.value; }
int MEASURE (ITEM item) { return static_cast<int> (item.value); }
int combine (Fields fields)
{ return fields.value + fields.VALUE + fields.VaLuE; }

/* { dg-final { cleanup-ada-spec } } */

Download · View in repository

casefold_identity_consumer.adb Ada · 18 lines
with Interfaces.C; use Interfaces.C;
with Casefold_Identity_C;

procedure Casefold_Identity_Consumer is
   package Bindings renames Casefold_Identity_C;

   First : Bindings.Item := (value => 7);
   Second : Bindings.ITEM_Case_2 := (value => 8.0);
   Pair : Bindings.Fields :=
     (value => 11, VALUE_Case_2 => 13, VaLuE_Case_3 => 17);
begin
   if Bindings.measure (First) /= 7
     or else Bindings.MEASURE_Case_2 (Second) /= 8
     or else Bindings.combine (Pair) /= 41
   then
      raise Program_Error with "case-distinct C++ symbols were conflated";
   end if;
end Casefold_Identity_Consumer;

Download · View in repository

run-test.sh shell · 69 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-casefold-identity/tests/casefold-identity.C"
ada_fixture="$root/bundles/cxx-ada-casefold-identity/tests/casefold_identity_consumer.adb"
work=$(mktemp -d "${TMPDIR:-/tmp}/gnat-cxx-ada-casefold.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 casefold-identity.C
  )

  set +e
  (
    cd "$case_dir"
    "${REGRESSION_ENV[@]}" "$REGRESSION_GNATMAKE" -q -f \
      "-O$optimization" casefold_identity_consumer.adb \
      -largs casefold-identity.o -lstdc++
    "${REGRESSION_ENV[@]}" ./casefold_identity_consumer
  ) >"$case_dir/run.log" 2>&1
  run_status=$?
  set -e

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

  [[ $run_status -eq 0 ]] || {
    cat "$case_dir/run.log"
    exit 1
  }
  echo "cxx-ada-casefold-identity -O$optimization: patched (GCC $version)"
done

Download · View in repository

Commands.

Apply the patch
patch --fuzz=0 -p1 -i bundles/cxx-ada-casefold-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.