cxx-ada-int128-types

C++ Ada unsigned __int128 types

GCC 13 and 14 emit the internal C++ name for unsigned __int128 as an undefined Ada identifier.

AcceptedApplies standaloneSince 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.0Known-good control15.3.0Not coveredKnown-good control16.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.

GCC 13 and 14 special-case the internal C++ type name __int128, but compare the complete spelling. That recognizes the signed type and misses the internal unsigned spelling, __int128 unsigned.

The offending C++ is:

using Signed_128 = __int128;
using Unsigned_128 = unsigned __int128;

Signed_128 signed_round_trip (Signed_128);
Unsigned_128 unsigned_round_trip (Unsigned_128);

The GCC 13/14 mapper currently produces one valid subtype and one reference to an Ada identifier that does not exist:

subtype Signed_128 is Extensions.Signed_128;
subtype Unsigned_128 is uu_int128_unsigned;

It should recognize both internal names as 128-bit integer types and produce:

subtype Signed_128 is Extensions.Signed_128;
subtype Unsigned_128 is Extensions.Unsigned_128;

The correction uses the eight-character __int128 prefix comparison already present in GCC 15 and 16. Those releases are known-good controls and receive no code patch. The executable regression passes negative signed and high-bit unsigned values by value from C++ to Ada, back through C++, and into C++ value checkers at -O0 and -O2.

Run it against an unpatched or patched compiler root:

./bundles/cxx-ada-int128-types/run-test.sh \
  TOOLCHAIN_ROOT GCC_VERSION unpatched
./bundles/cxx-ada-int128-types/run-test.sh \
  TOOLCHAIN_ROOT GCC_VERSION patched

Patch.

Variant gcc-13-14

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

+24 −2 2 files

Download the patch

gcc/c-family/c-ada-spec.cc +2−2modified
Unified diff for gcc/c-family/c-ada-spec.cc: original line, patched line, change, source
@@ -2193 +2193 @@dump_ada_node (pretty_printer *buffer, tree node, tree type, int spc,
2193Removed line. && !strcmp (IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (node))),
2194Removed line. "__int128")))
2193Added line. && !strncmp (IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (node))),
2194Added line. "__int128", 8)))
gcc/testsuite/g++.dg/ada-spec/int128-types.C +22−0new file
Unified diff for gcc/testsuite/g++.dg/ada-spec/int128-types.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 int128_types_c.ads "subtype Signed_128 is Extensions.Signed_128" } } */
4Added line. /* { dg-final { scan-file int128_types_c.ads "subtype Unsigned_128 is Extensions.Unsigned_128" } } */
5Added line.
6Added line. using Signed_128 = __int128;
7Added line. using Unsigned_128 = unsigned __int128;
8Added line.
9Added line. static const Signed_128 signed_expected
10Added line. = -((static_cast<Signed_128> (1) << 100) + 12345);
11Added line. static const Unsigned_128 unsigned_expected
12Added line. = (static_cast<Unsigned_128> (1) << 127)
13Added line. | (static_cast<Unsigned_128> (1) << 80) | 67890;
14Added line.
15Added line. Signed_128 signed_seed () { return signed_expected; }
16Added line. Unsigned_128 unsigned_seed () { return unsigned_expected; }
17Added line.
18Added line. Signed_128 signed_round_trip (Signed_128 value) { return value; }
19Added line. Unsigned_128 unsigned_round_trip (Unsigned_128 value) { return value; }
20Added line.
21Added line. int signed_matches (Signed_128 value) { return value == signed_expected; }
22Added line. int unsigned_matches (Unsigned_128 value) { return value == unsigned_expected; }
23

Tests.

int128-types.C C++ · 22 lines
/* { dg-do compile } */
/* { dg-options "-fdump-ada-spec-slim" } */
/* { dg-final { scan-file int128_types_c.ads "subtype Signed_128 is Extensions.Signed_128" } } */
/* { dg-final { scan-file int128_types_c.ads "subtype Unsigned_128 is Extensions.Unsigned_128" } } */

using Signed_128 = __int128;
using Unsigned_128 = unsigned __int128;

static const Signed_128 signed_expected
  = -((static_cast<Signed_128> (1) << 100) + 12345);
static const Unsigned_128 unsigned_expected
  = (static_cast<Unsigned_128> (1) << 127)
    | (static_cast<Unsigned_128> (1) << 80) | 67890;

Signed_128 signed_seed () { return signed_expected; }
Unsigned_128 unsigned_seed () { return unsigned_expected; }

Signed_128 signed_round_trip (Signed_128 value) { return value; }
Unsigned_128 unsigned_round_trip (Unsigned_128 value) { return value; }

int signed_matches (Signed_128 value) { return value == signed_expected; }
int unsigned_matches (Unsigned_128 value) { return value == unsigned_expected; }

Download · View in repository

int128_types_consumer.adb Ada · 15 lines
with Interfaces.C;
with Int128_Types_C;

procedure Int128_Types_Consumer is
   use type Interfaces.C.int;
   use Int128_Types_C;
begin
   if signed_matches (signed_round_trip (signed_seed)) /= 1 then
      raise Program_Error with "signed __int128 round trip failed";
   end if;

   if unsigned_matches (unsigned_round_trip (unsigned_seed)) /= 1 then
      raise Program_Error with "unsigned __int128 round trip failed";
   end if;
end Int128_Types_Consumer;

Download · View in repository

run-test.sh shell · 78 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
major=${version%%.*}
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-int128-types/tests/int128-types.C"
ada_fixture="$root/bundles/cxx-ada-int128-types/tests/int128_types_consumer.adb"
work=$(mktemp -d "${TMPDIR:-/tmp}/gnat-cxx-ada-int128-types.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 int128-types.C
  )

  spec="$case_dir/int128_types_c.ads"
  [[ -f "$spec" ]] || {
    echo "error: g++ did not generate $spec" >&2
    exit 1
  }

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

  if [[ "$state" == unpatched && ( "$major" == 13 || "$major" == 14 ) ]]; then
    [[ $run_status -ne 0 ]] || {
      echo "error: unpatched __int128 regression unexpectedly passed" >&2
      exit 1
    }
    grep -Eiq 'uu_int128_unsigned.*undefined' "$case_dir/run.log" || {
      cat "$case_dir/run.log"
      exit 1
    }
    echo "cxx-ada-int128-types -O$optimization: expected undefined unsigned type (GCC $version)"
    continue
  fi

  [[ $run_status -eq 0 ]] || {
    cat "$case_dir/run.log"
    exit 1
  }
  grep -Eq 'Extensions\.Signed_128' "$spec"
  grep -Eq 'Extensions\.Unsigned_128' "$spec"
  echo "cxx-ada-int128-types -O$optimization: supported (GCC $version, $state)"
done

Download · View in repository

Commands.

Apply the patch
patch --fuzz=0 -p1 -i bundles/cxx-ada-int128-types/patches/gcc-13-14.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.