libstdc++: Work around C++20 tuple<tuple<any>> constraint recursion [PR116440]
The type tuple<tuple<any>> is clearly copy/move constructible, but for
reasons that are not yet completely understood checking this triggers
constraint recursion with our C++20 tuple implementation (but not the
C++17 implementation).
It turns out this recursion stems from considering the non-template
tuple(const _Elements&) constructor during the copy/move constructibility
check. Considering this constructor is ultimately redundant, since the
defaulted copy/move constructors are better matches.
GCC has a non-standard "perfect candidate" optimization[1] that causes
overload resolution to shortcut considering template candidates if we
find a (non-template) perfect candidate. So to work around this issue
(and as a general compile-time optimization) this patch turns the
problematic constructor into a template so that GCC doesn't consider it
when checking for copy/move constructibility of this tuple type.
Changing the template-ness of a constructor can affect overload
resolution (since template-ness is a tiebreaker) so there's a risk this
change could e.g. introduce overload resolution ambiguities. But the
original C++17 implementation has long defined this constructor as a
template (in order to constrain it etc), so doing the same thing in the
C++20 mode should naturally be quite safe.
The testcase still fails with Clang (in C++20 mode) since it doesn't
implement said optimization.
[1]: See
r11-7287-g187d0d5871b1fa and
https://isocpp.org/files/papers/P3606R0.html
PR libstdc++/116440
libstdc++-v3/ChangeLog:
* include/std/tuple (tuple::tuple(const _Elements&...))
[C++20]: Turn into a template.
* testsuite/20_util/tuple/116440.C: New test.
Reviewed-by: Jonathan Wakely <jwakely@redhat.com>
(cherry picked from commit
6570fa6f2612a4e4ddd2fcfc119369a1a48656e4)