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 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.

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.