https://gcc.gnu.org/bugzilla/show_bug.cgi?id=127046
Bug ID: 127046
Summary: Trailing array element loses its initializer when the
constexpr function it's declared in is const-evaluated
Product: gcc
Version: 16.1.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: c++
Assignee: unassigned at gcc dot gnu.org
Reporter: vincenzo.cal.main at gmail dot com
Target Milestone: ---
A regression in r16-3022-gbc42128330c causes a local array of objects with non
trivial destructor to silently lose the initializer of its last element
when the constexpr function it's declared in is const-evaluated anywhere
in the same translation unit.
This bug was initially detected as a failure in the libc++ test suite, in
is the associated issue:
https://github.com/llvm/llvm-project/issues/215497
## Testcase
repro.cpp:
``` cpp
struct T { char padding[4] = {'x'}; constexpr ~T() {} };
constexpr bool test() {
T array[3] = {};
return array[0].padding[0]=='x' && array[1].padding[0]=='x' &&
array[2].padding[0]=='x';
}
int main() { return test() ? 0 : 1; }
```
repro.ii:
```
# 0 "repro.cpp"
# 0 "<built-in>"
# 0 "<command-line>"
# 1
"/nix/store/29isvm6vfq10c528i31igdiy3fnvjcm3-glibc-2.42-67-dev/include/stdc-predef.h"
1 3
# 0 "<command-line>" 2
# 1 "repro.cpp"
struct T { char padding[4] = {'x'}; constexpr ~T() {} };
constexpr bool test() {
T array[3] = {};
return array[0].padding[0]=='x' && array[1].padding[0]=='x' &&
array[2].padding[0]=='x';
}
int main() { return test() ? 0 : 1; }
```
To reproduce:
``` bash
nix shell github:NixOS/nixpkgs/56c02bc00adcf003215cc4bd996d6efaf4cff188#gcc15 \
-c sh -c 'g++ -std=c++23 -O0 repro.cpp -o r15 && ./r15'; echo "15: $?"
nix shell github:NixOS/nixpkgs/56c02bc00adcf003215cc4bd996d6efaf4cff188#gcc16 \
-c sh -c 'g++ -std=c++23 -O0 repro.cpp -o r16 && ./r16'; echo "16: $?"
```
The bug needs no options beyond `-std`. `-O0` is necessary only for this test
case as with `-O1` the test function is inlined in main.
Please check `repro-volatile-fnptr.cpp` in appendix for a test case that
does not require the `-O0` flag .
Godbolt assembly comparison:
https://godbolt.org/z/YPKs3cd17
## Versions
Tested on: x86_64-unknown-linux-gnu (NixOS 26.11, Linux 7.1.3, glibc 2.42)
Known versions to work: 15.1.0, 15.2.0, 15.3.0
Known versions to fail: 16.1.0, 16.2.0
Independently to: -std=[c++20, c++23, c++26]
Bisected by diffing the generated GIMPLE to:
```
bc42128330c0ea70a015b74b655cb8c48b6a8c06
"c++: clobber object on placement new [PR121068]"
Jason Merrill, 2025-08-05
```
## GCC configuration flags
### GCC 16.1.0 (fails)
```
Using built-in specs.
COLLECT_LTO_WRAPPER=/nix/store/r9minpvfk7dgyn3vf5a0lvnmvh2y286k-gcc-16.1.0/libexec/gcc/x86_64-unknown-linux-gnu/16.1.0/lto-wrapper
Target: x86_64-unknown-linux-gnu
Configured with: ../gcc-16.1.0/configure
--prefix=/nix/store/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee-gcc-16.1.0
--with-gmp-include=/nix/store/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee-gmp-with-cxx-6.3.0-dev/include
--with-gmp-lib=/nix/store/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee-gmp-with-cxx-6.3.0/lib
--with-mpfr-include=/nix/store/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee-mpfr-4.2.2-dev/include
--with-mpfr-lib=/nix/store/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee-mpfr-4.2.2/lib
--with-mpc=/nix/store/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee-libmpc-1.4.1
--with-native-system-header-dir=/nix/store/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee-glibc-2.42-67-dev/include
--with-build-sysroot=/
--with-gxx-include-dir=/nix/store/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee-gcc-16.1.0/include/c++/16.1.0/
--program-prefix= --enable-lto --disable-libstdcxx-pch
--without-included-gettext --with-system-zlib --enable-static
--enable-languages=c,c++ --disable-multilib --enable-plugin
--with-isl=/nix/store/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee-isl-0.20
--disable-bootstrap --enable-default-pie --build=x86_64-unknown-linux-gnu
--host=x86_64-unknown-linux-gnu --target=x86_64-unknown-linux-gnu
Thread model: posix
Supported LTO compression algorithms: zlib
gcc version 16.1.0 (GCC)
```
### GCC 15.3.0 (works)
```
Using built-in specs.
COLLECT_LTO_WRAPPER=/nix/store/7sh9061yj9yl20ndc00rqw4d0bd80m1j-gcc-15.3.0/libexec/gcc/x86_64-unknown-linux-gnu/15.3.0/lto-wrapper
Target: x86_64-unknown-linux-gnu
Configured with: ../gcc-15.3.0/configure
--prefix=/nix/store/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee-gcc-15.3.0
--with-gmp-include=/nix/store/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee-gmp-6.3.0-dev/include
--with-gmp-lib=/nix/store/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee-gmp-6.3.0/lib
--with-mpfr-include=/nix/store/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee-mpfr-4.2.2-dev/include
--with-mpfr-lib=/nix/store/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee-mpfr-4.2.2/lib
--with-mpc=/nix/store/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee-libmpc-1.4.1
--with-native-system-header-dir=/nix/store/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee-glibc-2.42-67-dev/include
--with-build-sysroot=/
--with-gxx-include-dir=/nix/store/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee-gcc-15.3.0/include/c++/15.3.0/
--program-prefix= --enable-lto --disable-libstdcxx-pch
--without-included-gettext --with-system-zlib --enable-static
--enable-languages=c,c++ --disable-multilib --enable-plugin --disable-libcc1
--with-isl=/nix/store/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee-isl-0.20
--disable-bootstrap --enable-default-pie --build=x86_64-unknown-linux-gnu
--host=x86_64-unknown-linux-gnu --target=x86_64-unknown-linux-gnu
Thread model: posix
Supported LTO compression algorithms: zlib
gcc version 15.3.0 (GCC)
```
## Test case without opt flags
repro-volatile-fnptr.cpp
``` cpp
struct T { char padding[4] = {'x'}; constexpr ~T() {} };
constexpr bool test() {
T array[3] = {};
return array[0].padding[0]=='x' && array[1].padding[0]=='x' &&
array[2].padding[0]=='x';
}
static_assert(test());
bool (* volatile fp)() = test;
int main() { return fp() ? 0 : 1; }
```
repro-volatile-fnptr.ii
```
# 0 "repro-volatile-fnptr.cpp"
# 0 "<built-in>"
# 0 "<command-line>"
# 1
"/nix/store/29isvm6vfq10c528i31igdiy3fnvjcm3-glibc-2.42-67-dev/include/stdc-predef.h"
1 3
# 0 "<command-line>" 2
# 1 "repro-volatile-fnptr.cpp"
struct T { char padding[4] = {'x'}; constexpr ~T() {} };
constexpr bool test() {
T array[3] = {};
return array[0].padding[0]=='x' && array[1].padding[0]=='x' &&
array[2].padding[0]=='x';
}
static_assert(test());
bool (* volatile fp)() = test;
int main() { return fp() ? 0 : 1; }
```
I would be happy to pick up the bug and develop a patch, if you agree.