The changes the _Variadic_union implementation, in a way that the
_Unitialized<T, false> partial specialization for non-trivial types is not
necessary.

This is simply done by separating the specialization for 
__trivially_destructible
being true and false, and for the later defining an empty destructor (similarly
as it was done using concepts).

We also reduce the number of specialization of _Variadic_union, so 
specialization
(int, int) is reused by (string, int, int) and (int, int). This is done by
initialization __trivially_destructible with conjunction of
is_trivially_destructible_v for remaining components. This is only necessary
for non-trivial (false) specialization, as if both _First and _Rest... are
trivially destructible, then _Rest must also be.

The above change does not regress the fix r14-7259-g2d55d94e5df389 for
template depth, and both before and after the change template depth is 266.
I have added dg-options to the 87619.cc to catch future regressions.

This also add test for PR112591.

        PR libstdc++/112591

libstdc++-v3/ChangeLog:

        * include/std/variant (_Variadic_union): Separate specializations for
        for union of only trivially destructible types (true as first template
        argument). Unconditionally define destructor for _Variadic_union<false,
        _First, _Rest...>.
        * testsuite/20_util/variant/87619.cc: Add limit for the template depth.
        * testsuite/20_util/variant/112591.cc: New test.

Reviewed-by: Jonathan Wakely <[email protected]>
Signed-off-by: Tomasz Kamiński <[email protected]>
---
v2 updated the commit message only:
- add proper changelog
- links to PR112591
- fixes some typos and formatting.

Tested on x86_64-linux. Pushed to trunk.

 libstdc++-v3/include/std/variant              | 34 ++++++++++++++-----
 .../testsuite/20_util/variant/112591.cc       | 32 +++++++++++++++++
 .../testsuite/20_util/variant/87619.cc        |  2 ++
 3 files changed, 59 insertions(+), 9 deletions(-)
 create mode 100644 libstdc++-v3/testsuite/20_util/variant/112591.cc

diff --git a/libstdc++-v3/include/std/variant b/libstdc++-v3/include/std/variant
index 2f44f970028..f2f55837461 100644
--- a/libstdc++-v3/include/std/variant
+++ b/libstdc++-v3/include/std/variant
@@ -393,8 +393,29 @@ namespace __variant
        _Variadic_union(in_place_index_t<_Np>, _Args&&...) = delete;
     };
 
-  template<bool __trivially_destructible, typename _First, typename... _Rest>
-    union _Variadic_union<__trivially_destructible, _First, _Rest...>
+  template<typename _First, typename... _Rest>
+    union _Variadic_union<true, _First, _Rest...>
+    {
+      constexpr _Variadic_union() : _M_rest() { }
+
+      template<typename... _Args>
+       constexpr
+       _Variadic_union(in_place_index_t<0>, _Args&&... __args)
+       : _M_first(in_place_index<0>, std::forward<_Args>(__args)...)
+       { }
+
+      template<size_t _Np, typename... _Args>
+       constexpr
+       _Variadic_union(in_place_index_t<_Np>, _Args&&... __args)
+       : _M_rest(in_place_index<_Np-1>, std::forward<_Args>(__args)...)
+       { }
+
+      _Uninitialized<_First> _M_first;
+      _Variadic_union<true, _Rest...> _M_rest;
+    };
+
+  template<typename _First, typename... _Rest>
+    union _Variadic_union<false, _First, _Rest...>
     {
       constexpr _Variadic_union() : _M_rest() { }
 
@@ -410,24 +431,19 @@ namespace __variant
        : _M_rest(in_place_index<_Np-1>, std::forward<_Args>(__args)...)
        { }
 
-#if __cpp_lib_variant >= 202106L
       _Variadic_union(const _Variadic_union&) = default;
       _Variadic_union(_Variadic_union&&) = default;
       _Variadic_union& operator=(const _Variadic_union&) = default;
       _Variadic_union& operator=(_Variadic_union&&) = default;
 
-      ~_Variadic_union() = default;
-
       // If any alternative type is not trivially destructible then we need a
       // user-provided destructor that does nothing. The active alternative
       // will be destroyed by _Variant_storage::_M_reset() instead of here.
-      constexpr ~_Variadic_union()
-       requires (!__trivially_destructible)
+      _GLIBCXX20_CONSTEXPR ~_Variadic_union()
       { }
-#endif
 
       _Uninitialized<_First> _M_first;
-      _Variadic_union<__trivially_destructible, _Rest...> _M_rest;
+      _Variadic_union<(is_trivially_destructible_v<_Rest> && ...), _Rest...> 
_M_rest;
     };
 
   // _Never_valueless_alt is true for variant alternatives that can
diff --git a/libstdc++-v3/testsuite/20_util/variant/112591.cc 
b/libstdc++-v3/testsuite/20_util/variant/112591.cc
new file mode 100644
index 00000000000..b1b07c4f46e
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/variant/112591.cc
@@ -0,0 +1,32 @@
+// { dg-do run { target c++17 } }
+
+#include <variant>
+#include <testsuite_hooks.h>
+
+struct NonEmpty { int x; };
+struct TrivialEmpty {};
+struct NonTrivialEmpty { ~NonTrivialEmpty() {} };
+
+template<typename T>
+struct Compose : T
+{
+  std::variant<T, int> v;
+};
+
+template<typename T>
+bool testAlias()
+{
+  Compose<T> c;
+  return static_cast<T*>(&c) == &std::get<T>(c.v);
+}
+
+int main()
+{
+  VERIFY( !testAlias<NonEmpty>() );
+  VERIFY( !testAlias<TrivialEmpty>() );
+#if __cplusplus >= 202002L  
+  VERIFY( !testAlias<NonTrivialEmpty>() );
+#else  
+  VERIFY( testAlias<NonTrivialEmpty>() );
+#endif
+}
diff --git a/libstdc++-v3/testsuite/20_util/variant/87619.cc 
b/libstdc++-v3/testsuite/20_util/variant/87619.cc
index d988925532d..ac7dd46e42f 100644
--- a/libstdc++-v3/testsuite/20_util/variant/87619.cc
+++ b/libstdc++-v3/testsuite/20_util/variant/87619.cc
@@ -16,6 +16,7 @@
 // <http://www.gnu.org/licenses/>.
 
 // { dg-do compile { target c++17 } }
+// { dg-options "-ftemplate-depth=270" }
 
 #include <variant>
 #include <utility>
@@ -23,6 +24,7 @@
 
 template<std::size_t I>
 struct S {
+ ~S() {}
 };
 
 template <std::size_t... Is>
-- 
2.52.0

Reply via email to