cxx-ada-explicit-alignment

C++ Ada explicit alignment

The C++ Ada spec dumper omits user-specified record alignment unless the layout is also packed or contains bit fields.

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 mapper preserves packed/bit-field alignment because those paths already emit Ada representation aspects, but it drops an otherwise ordinary C++ type's explicit alignas requirement.

For example:

struct alignas(32) Aligned
{
  int value;
};

The unpatched output keeps only the convention, so GNAT gives the record its natural alignment:

type Aligned is record
   value : aliased int;
end record
with Convention => C_Pass_By_Copy;

The corrected output carries the C++ alignment into the Ada view:

type Aligned is record
   value : aliased int;
end record
with Convention => C_Pass_By_Copy,
     Alignment => 32;

The patch keeps Pack limited to packed or bit-field layouts and emits Alignment independently when GCC records a user-specified type alignment. The executable regression links C++ and Ada at -O0 and -O2 and compares sizeof, alignof, Ada Object_Size, and Ada Alignment.

Patch.

Variant gcc-13-14

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

+25 −2 2 files

Download the patch

gcc/c-family/c-ada-spec.cc +12−2modified
Unified diff for gcc/c-family/c-ada-spec.cc: original line, patched line, change, source
@@ -3440 +3440 @@dump_ada_structure (pretty_printer *buffer, tree node, tree type, bool nested,
34403440 pp_string (buffer, "Unchecked_Union => True");
34413441 }
34423442
3443Removed line. if (bitfield_used || packed_layout)
3443Added line. const bool needs_pack = bitfield_used || packed_layout;
3444Added line.
3445Added line. if (needs_pack)
34443446 {
3445Removed line. char buf[32];
34463447 pp_comma (buffer);
34473448 newline_and_indent (buffer, spc + 5);
34483449 pp_string (buffer, "Pack => True");
3450Added line. }
3451Added line.
3452Added line. if (needs_pack || TYPE_USER_ALIGN (node))
3453Added line. {
3454Added line. char buf[32];
34493455 pp_comma (buffer);
34503456 newline_and_indent (buffer, spc + 5);
34513457 sprintf (buf, "Alignment => %d", TYPE_ALIGN (node) / BITS_PER_UNIT);
34523458 pp_string (buffer, buf);
3459Added line. }
3460Added line.
3461Added line. if (needs_pack)
3462Added line. {
34533463 bitfield_used = false;
34543464 packed_layout = false;
34553465 }
gcc/testsuite/g++.dg/ada-spec/explicit-alignment.C +13−0new file
Unified diff for gcc/testsuite/g++.dg/ada-spec/explicit-alignment.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 explicit_alignment_c.ads "Alignment => 32" } } */
4Added line.
5Added line. struct alignas(32) Aligned
6Added line. {
7Added line. int value;
8Added line. };
9Added line.
10Added line. extern "C" unsigned long cpp_size () { return sizeof (Aligned); }
11Added line. extern "C" unsigned long cpp_alignment () { return alignof (Aligned); }
12Added line.
13Added line. /* { dg-final { cleanup-ada-spec } } */
14

Variant gcc-15-16

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

+25 −2 2 files

Download the patch

gcc/c-family/c-ada-spec.cc +12−2modified
Unified diff for gcc/c-family/c-ada-spec.cc: original line, patched line, change, source
@@ -3507 +3507 @@dump_ada_structure (pretty_printer *pp, tree node, tree type, bool nested,
35073507 pp_string (pp, "Unchecked_Union => True");
35083508 }
35093509
3510Removed line. if (bitfield_used || packed_layout)
3510Added line. const bool needs_pack = bitfield_used || packed_layout;
3511Added line.
3512Added line. if (needs_pack)
35113513 {
3512Removed line. char buf[32];
35133514 pp_comma (pp);
35143515 newline_and_indent (pp, spc + 5);
35153516 pp_string (pp, "Pack => True");
3517Added line. }
3518Added line.
3519Added line. if (needs_pack || TYPE_USER_ALIGN (node))
3520Added line. {
3521Added line. char buf[32];
35163522 pp_comma (pp);
35173523 newline_and_indent (pp, spc + 5);
35183524 sprintf (buf, "Alignment => %d", TYPE_ALIGN (node) / BITS_PER_UNIT);
35193525 pp_string (pp, buf);
3526Added line. }
3527Added line.
3528Added line. if (needs_pack)
3529Added line. {
35203530 bitfield_used = false;
35213531 packed_layout = false;
35223532 }
gcc/testsuite/g++.dg/ada-spec/explicit-alignment.C +13−0new file
Unified diff for gcc/testsuite/g++.dg/ada-spec/explicit-alignment.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 explicit_alignment_c.ads "Alignment => 32" } } */
4Added line.
5Added line. struct alignas(32) Aligned
6Added line. {
7Added line. int value;
8Added line. };
9Added line.
10Added line. extern "C" unsigned long cpp_size () { return sizeof (Aligned); }
11Added line. extern "C" unsigned long cpp_alignment () { return alignof (Aligned); }
12Added line.
13Added line. /* { dg-final { cleanup-ada-spec } } */
14

Tests.

explicit-alignment.C C++ · 13 lines
/* { dg-do compile } */
/* { dg-options "-fdump-ada-spec-slim" } */
/* { dg-final { scan-file explicit_alignment_c.ads "Alignment => 32" } } */

struct alignas(32) Aligned
{
  int value;
};

extern "C" unsigned long cpp_size () { return sizeof (Aligned); }
extern "C" unsigned long cpp_alignment () { return alignof (Aligned); }

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

Download · View in repository

explicit_alignment_consumer.adb Ada · 20 lines
with Ada.Text_IO;
with Explicit_Alignment_C;
with Interfaces.C; use Interfaces.C;
with System;

procedure Explicit_Alignment_Consumer is
   package Bindings renames Explicit_Alignment_C;
   Ada_Size : constant unsigned_long :=
     unsigned_long (Bindings.Aligned'Object_Size / System.Storage_Unit);
   Ada_Alignment : constant unsigned_long :=
     unsigned_long (Bindings.Aligned'Alignment);
begin
   if Ada_Size = Bindings.cpp_size
     and then Ada_Alignment = Bindings.cpp_alignment
   then
      Ada.Text_IO.Put_Line ("MATCH C++ Ada explicit alignment");
   else
      Ada.Text_IO.Put_Line ("MISMATCH C++ Ada explicit alignment");
   end if;
end Explicit_Alignment_Consumer;

Download · View in repository

run-test.sh shell · 61 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-explicit-alignment/tests/explicit-alignment.C"
ada_fixture="$root/bundles/cxx-ada-explicit-alignment/tests/explicit_alignment_consumer.adb"
work=$(mktemp -d "${TMPDIR:-/tmp}/gnat-cxx-ada-alignment-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 explicit-alignment.C
    "${REGRESSION_ENV[@]}" "$REGRESSION_GNATMAKE" -q -f \
      "-O$optimization" explicit_alignment_consumer.adb \
      -largs explicit-alignment.o -lstdc++
    "${REGRESSION_ENV[@]}" ./explicit_alignment_consumer
  ) >"$case_dir/output.log" 2>&1 || {
    cat "$case_dir/output.log"
    exit 1
  }

  spec="$case_dir/explicit_alignment_c.ads"
  if [[ "$state" == unpatched ]]; then
    grep -F "MISMATCH C++ Ada explicit alignment" "$case_dir/output.log"
    if grep -Fq "Alignment => 32" "$spec"; then
      echo "error: unpatched mapper unexpectedly preserved explicit alignment" >&2
      exit 1
    fi
    echo "cxx-ada-explicit-alignment -O$optimization: expected mismatch (GCC $version)"
    continue
  fi

  grep -F "Alignment => 32" "$spec"
  grep -F "MATCH C++ Ada explicit alignment" "$case_dir/output.log"
  echo "cxx-ada-explicit-alignment -O$optimization: patched (GCC $version)"
done

Download · View in repository

Commands.

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