Home / Bundles / C++ Ada template record termination
cxx-ada-template-record-termination
C++ Ada template record termination
The C++ Ada spec dumper omits the terminating semicolon from trivial record declarations emitted for concrete class-template instances.
Accepted Applies standalone Since 1.2.0
Explanation.
dump_ada_template writes concrete class-template instances inside nested Ada
packages. For trivial records, dump_ada_structure deliberately leaves the
terminating semicolon to its caller, but the template caller did not add it.
The resulting aspect ends at C_Pass_By_Copy and GNAT rejects the generated
specification.
A minimal offending declaration is a trivial concrete template instance:
template < typename T>
struct Plain { T value; };
template struct Plain< int > ;The unpatched mapper produces an unterminated record declaration:
package Plain_int is
type Plain is limited record
value : aliased int;
end record
with Convention => C_Pass_By_Copy
end ;The corrected output terminates the representation aspect before the package
continues:
package Plain_int is
type Plain is limited record
value : aliased int;
end record
with Convention => C_Pass_By_Copy;
end ;The patch terminates records only when the structure printer did not already
do so while emitting methods or static fields. The executable regression
covers the shared path with primary, partial-specialization,
full-specialization, nested, constrained, and template-template instances.
Run it against an unpatched or patched compiler root:
./bundles/cxx-ada-template-record-termination/run-test.sh \
TOOLCHAIN_ROOT GCC_VERSION unpatched
./bundles/cxx-ada-template-record-termination/run-test.sh \
TOOLCHAIN_ROOT GCC_VERSION patched
Patch.
SHA-256 d3e4f3784943166957eb53b8ec5031f91eedc4946b272e6122149625cf06a8ae
Patch bundles/cxx-ada-template-record-termination/patches/gcc-13-14.patch
Download the patch
gcc/c-family/c-ada-spec.cc
+2 −0 modified
gcc/testsuite/g++.dg/ada-spec/template-record-termination.C
+75 −0 new file
SHA-256 410ff115e39d1b6f9e3f5c31c3bebec41e2f10cf2d2641b0e78b1e2f0ba31ef7
Patch bundles/cxx-ada-template-record-termination/patches/gcc-15-16.patch
Download the patch
gcc/c-family/c-ada-spec.cc
+2 −0 modified
gcc/testsuite/g++.dg/ada-spec/template-record-termination.C
+75 −0 new file
Tests.
Before the patch GNAT rejects the generated Ada specification at the unterminated C_Pass_By_Copy aspect.
After the patch Every generated template record is terminated and the Ada consumer compiles at -O0 and -O2.
template-record-termination.C
C++ · 75 lines
template < typename T>
struct Plain
{
T value;
};
template struct Plain< int > ;
template < typename T, bool Select>
struct Choice;
template < typename T>
struct Choice< T, false >
{
T value;
};
template struct Choice< int , false > ;
template < typename T>
struct Specialized
{
T value;
};
template < >
struct Specialized< bool >
{
unsigned value;
};
using Bool_Specialized = Specialized< bool > ;
template < typename T>
struct Outer
{
template < typename U>
struct Inner
{
U value;
};
};
template struct Outer< int > ;
template < typename T>
concept Integral_Sized = sizeof (T) >= sizeof (int );
template < Integral_Sized T>
struct Constrained
{
T value;
};
template struct Constrained< int > ;
template < typename T>
struct Item
{
T value;
};
template < template < typename > class Container, typename T>
struct Wrapper
{
Container< T> item;
};
template struct Wrapper< Item, int > ;
Download · View in repository
template_record_termination_consumer.adb
Ada · 6 lines
with Template_Record_Termination_C;
procedure Template_Record_Termination_Consumer is
begin
null ;
end Template_Record_Termination_Consumer;
Download · View in repository
run-test.sh
shell · 78 lines
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-template-record-termination/tests/template-record-termination.C"
ada_fixture="$root/bundles/cxx-ada-template-record-termination/tests/template_record_termination_consumer.adb"
work=$(mktemp -d "${TMPDIR:-/tmp}/gnat-cxx-ada-template-record-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" -std=gnu++20 -c "-O$optimization" \
-fdump-ada-spec-slim template-record-termination.C
)
spec="$case_dir/template_record_termination_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" -c template_record_termination_consumer.adb
) > "$case_dir/build.log" 2 > & 1
build_status=$?
set -e
if [[ "$state" == unpatched ]]; then
[[ $build_status -ne 0 ]] || {
echo "error: unpatched template record regression unexpectedly compiled at -O$optimization" > & 2
exit 1
}
grep -Eiq 'missing.*;|aspect.*requires|declaration expected' "$case_dir/build.log" || {
cat "$case_dir/build.log"
exit 1
}
echo "cxx-ada-template-record-termination -O$optimization: expected rejection (GCC $version)"
continue
fi
[[ $build_status -eq 0 ]] || {
cat "$case_dir/build.log"
exit 1
}
count=$(grep -Fc "with Convention => C_Pass_By_Copy;" "$spec" )
[[ $count -eq 7 ]] || {
echo "error: expected 7 terminated template records, found $count" > & 2
exit 1
}
echo "cxx-ada-template-record-termination -O$optimization: patched (GCC $version)"
done
Download · View in repository
Commands.
Apply the patch
patch --fuzz=0 -p1 -i bundles/cxx-ada-template-record-termination/patches/VARIANT.patchBuild the compiler
PATH=/path/to/bootstrap/bin:$PATH ./scripts/build-gnat.sh SOURCE BUILD INSTALLRun the regression
./scripts/run-regressions.sh INSTALL 1 .2 .0 GCC_MAJOR patched
Affected releases 13.2.014.2.015.3.016.1.016.2.0Files modified gcc/c-family/c-ada-spec.ccgcc/testsuite/g++.dg/ada-spec/template-record-termination.CRegression tests gcc/testsuite/g++.dg/ada-spec/template-record-termination.C
Before the patch GNAT rejects the generated Ada specification at the unterminated C_Pass_By_Copy aspect.
After the patch Every generated template record is terminated and the Ada consumer compiles at -O0 and -O2.
Upstream issue Pending GCC Bugzilla filing.
Upstream submission Not yet filed or submitted upstream.
Provenance Repository-authored GCC patch and executable regression; exact application verified locally against the pinned Darwin release identities. Pinned FSF release application is required by Linux CI.
Licensing GCC-derived compiler hunks remain GPL-3.0-or-later. The new test is proposed for the GCC testsuite under GCC project terms.
Repository fixture bundles/cxx-ada-template-record-termination/tests/template-record-termination.C
Fixture SHA-256 c8497f40d88ee08980eb6d7414f8a01c95e81161974093fee81d2adc6dde4f13
Test runner bundles/cxx-ada-template-record-termination/run-test.sh