On Thu, 11 Jan 2024 at 22:17, Jonathan Wakely wrote: > > I'd like to commit this to trunk for GCC 14. Please take a look. > > -- >8 -- > > This is the last part of PR libstdc++/108822 implementing P2255R2, which > makes it ill-formed to create a std::tuple that would bind a reference > to a temporary. > > The dangling checks are implemented as deleted constructors for C++20 > and higher, and as Debug Mode static assertions in the constructor body > for older standards. This is similar to the r13-6084-g916ce577ad109b > changes for std::pair. > > As part of this change, I've reimplemented most of std::tuple for C++20, > making use of concepts to replace the enable_if constraints, and using > conditional explicit to avoid duplicating most constructors. We could > use conditional explicit for the C++11 implementation too (with pragmas > to disables the -Wc++17-extensions warnings), but that should be done as > a stage 1 change for GCC 15 rather than now. > > The partial specialization for std::tuple<T1, T2> is no longer used for > C++20 (or more precisely, for a C++20 compiler that supports concepts > and conditional explicit). The additional constructors and assignment > operators that take std::pair arguments have been added to the C++20 > implementation of the primary template, with sizeof...(_Elements)==2 > constraints. This avoids reimplementing all the other constructors in > the std::tuple<T1, T2> partial specialization to use concepts. This way > we avoid four implementations of every constructor and only have three! > (The primary template has an implementation of each constructor for > C++11 and another for C++20, and the tuple<T1,T2> specialization has an > implementation of each for C++11, so that's three for each constructor.) > > In order to make the constraints more efficient on the C++20 version of > the default constructor I've also added a variable template for the > __is_implicitly_default_constructible trait, implemented using concepts.
[snip] > +#if __cpp_concepts // >= C++20 > + private: > + template<typename... _UTypes> > + static consteval bool > + __assignable() This causes errors for -std=c++17 -fconcepts-ts because that defines __cpp_concepts=20157L, but does not allow C++20 consteval to be used. I used a different condition for the constructors: #if __cpp_concepts && __cpp_conditional_explicit // >= C++20 The difference is because the assignment ops don't use explicit. The additional check for __cpp_conditional_explicit means it already requires C++20, so doesn't match for -std=c++17 -fconcepts-ts. So that preprocessor group didn't cause problems. N.B. The different conditions means that for a compiler that supports concepts but not conditional explicit we will use concepts for the assignment ops, but not for the constructors. And you'll still get the partial specialization for std::tuple<T1,T2>, and that partial specialization will be missing the C++23 constructors for ranges::zip. I think that's fine - if you don't have a good enough C++20 compiler (i.e. one that defines __cpp_conditional_explicit) then you don't get a complete C++20 std::tuple, let alone a complete C++23 std::tuple. dealwithit.jpg I could just use constexpr instead of consteval for those helper functions, but I think I will add a check for __cpp_consteval. I don't feel comfortable trying to make the new assignment ops work with -std=c++17 -fconcepts-ts as there might be other interactions with C++20 features that will go unnoticed, as we don't routinely test the whole library with C++17 + Concepts TS.