]> git.feebdaed.xyz Git - 0xmirror/gcc.git/commit
libstdc++: Use union to store non-trivially destructible types in C++17 mode [PR112591]
authorTomasz Kamiński <tkaminsk@redhat.com>
Thu, 11 Dec 2025 09:43:44 +0000 (10:43 +0100)
committerTomasz Kamiński <tkaminsk@redhat.com>
Fri, 19 Dec 2025 21:50:38 +0000 (22:50 +0100)
commitb3c167b61fd75fe9820636d9f7fff7920ca9b084
tree9216b675dc96f1b158262fdb9f0c5243fe76c179
parent05f9824f44f088f4afa02f03063d638c787162c5
libstdc++: Use union to store non-trivially destructible types in C++17 mode [PR112591]

This patch disables use of specialization _Uninitialized<_Type, false> for
non-trivially destructible types by default in C++17, and fallbacks to
the  primary template, that stores the type in union directly. This makes the
ABI consistent between C++17 and C++20 (or later). This partial specialization
is no longer required after the changes introduced in r16-5961-g09bece00d0ec98.

This fixes non-conformance in C++17 mode where global variables of a variant
specialization type, were not statically-initialized for non-trivially
destructible types, even if initialization of the selected alternative could
be performed at compile time. For illustration, the following global variable
will be statically initialized after this change:
  std::variant<std::unique_ptr<T>, std::unique_ptr<U>> ptr;

This constitutes an ABI break, and changes the layout of the types, that uses
the same non-trivially copyable both as the base class, as alternative of the
variant object that is first member:
  struct EmptyNonTrivial { ~EmptyNonTrivial(); };
  struct Affected : EmptyNonTrivial {
    std::variant<EmptyNonTrivial, char> mem; // mem was at offset zero,
                                             // will use non-zero offset now
  };
After changes the layout of such types consistent with one used for empty types
with trivial destructor, or one used for any empty type in C++20 or later.

For programs affected by this change, it can be reverted in C++17 mode, by
defining _GLIBCXX_USE_VARIANT_CXX17_OLD_ABI. However, presence of this macro
has no effect in C++20 or later modes.

PR libstdc++/112591

libstdc++-v3/ChangeLog:

* include/std/variant (_Uninitialized::_M_get, __get_n)
(_Uninitialized<_Type, false>): Add _GLIBCXX_USE_VARIANT_CXX17_OLD_ABI
check to preprocessor guard.
* testsuite/20_util/variant/112591.cc: Updated tests.
* testsuite/20_util/variant/112591_compat.cc: New test.
* testsuite/20_util/variant/constinit.cc: New test.
* testsuite/20_util/variant/constinit_compat.cc: New test.

Reviewed-by: Jonathan Wakely <jwakely@redhat.com>
Signed-off-by: Tomasz Kamiński <tkaminsk@redhat.com>
libstdc++-v3/include/std/variant
libstdc++-v3/testsuite/20_util/variant/112591.cc
libstdc++-v3/testsuite/20_util/variant/112591_compat.cc [new file with mode: 0644]
libstdc++-v3/testsuite/20_util/variant/constinit.cc [new file with mode: 0644]
libstdc++-v3/testsuite/20_util/variant/constinit_compat.cc [new file with mode: 0644]