Bug 102301

Summary: make_from_tuple can not work with subrange
Product: gcc Reporter: 康桓瑋 <hewillk>
Component: libstdc++Assignee: Jonathan Wakely <redi>
Status: ASSIGNED ---    
Severity: normal CC: de34, webrown.cpp
Priority: P3    
Version: 12.0   
Target Milestone: ---   
Host: Target:
Build: Known to work:
Known to fail: Last reconfirmed: 2021-09-13 00:00:00

Description 康桓瑋 2021-09-13 03:54:25 UTC
I don't know if it is a bug, because the standard does not specify whether make_from_tuple can be applied to subrange even if it looks well-formed, so this may only be regarded as a feature request. 

Given that MSVC-STL already supports it, I think it should have some value.

#include <ranges>
#include <vector>

int main() {
  auto v = std::make_from_tuple<std::vector<int>>(std::ranges::subrange(std::views::iota(0, 5)));
}

https://godbolt.org/z/Ebx83z4s1
Comment 1 Andrew Pinski 2021-09-13 04:04:29 UTC
Even LLVM's libc++ does not support this ...
Comment 2 康桓瑋 2021-09-13 04:22:31 UTC
(In reply to Andrew Pinski from comment #1)
> Even LLVM's libc++ does not support this ...

I think you are right, but I want to know what libstdc++ thinks about this issue.
Comment 3 Jonathan Wakely 2021-09-13 09:24:26 UTC
(In reply to Andrew Pinski from comment #1)
> Even LLVM's libc++ does not support this ...

Does libc++ even define subrange yet?

It looks like we don't define the tuple_size and tuple_element specializations for subrange, probably because I didn't realise they were needed.
Comment 4 Jonathan Wakely 2021-09-13 09:28:03 UTC
Oh no, Patrick added them in r10-6508, and after PR 97512 it should work. Hmm.
Comment 5 康桓瑋 2021-09-13 10:16:27 UTC
(In reply to Jonathan Wakely from comment #4)
> Oh no, Patrick added them in r10-6508, and after PR 97512 it should work.
> Hmm.

I think it should not work because make_from_tuple uses std::get inside and is defined before using ranges::get, this will cause some namespace and ADL mechanisms to prevent it from being selected.
Comment 6 Jonathan Wakely 2021-09-13 10:18:01 UTC
Ugh, std::get is such a fragile and horrible API.
Comment 7 康桓瑋 2021-09-13 10:29:04 UTC
(In reply to Jonathan Wakely from comment #6)
> Ugh, std::get is such a fragile and horrible API.

Agreed, BTW PR 97512 was the first libstdc++ bug I reported, thank you for letting me back to the old days.
Comment 8 Jiang An 2022-04-06 03:07:04 UTC
I've submitted an LWG issue for this.

BTW, it's unfortunate that the standard library has both tuple-like and variant-like std::get overloads, and they are not clearly distinguished in the specification...
Comment 9 Jonathan Wakely 2022-04-13 07:20:39 UTC
https://cplusplus.github.io/LWG/issue3690
Comment 10 Jakub Jelinek 2022-06-28 10:46:21 UTC
GCC 10.4 is being released, retargeting bugs to GCC 10.5.
Comment 11 Jiang An 2022-07-28 07:34:54 UTC
I think the P2165R4 has clarifed that std::make_from_tuple etc. need to be applicable to std::ranges::subrange. And a large part of LWG3690 becomes NAD in C++23 - tuple-like utilities no longer touch std::variant or classes derived from tuple-like types.

But the standard wording does not yet guarantee that std::get overloads must be found.
Comment 12 GCC Commits 2023-01-24 23:51:37 UTC
The master branch has been updated by Jonathan Wakely <redi@gcc.gnu.org>:

https://gcc.gnu.org/g:33ed11085837e9492c6ed512931f5b6375c68ee7

commit r13-5338-g33ed11085837e9492c6ed512931f5b6375c68ee7
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Mon Jan 23 12:25:36 2023 +0000

    libstdc++: Include std::ranges::subrange definition in <tuple> [PR102301]
    
    In order for std::make_from_tuple to work with tuple-like types, the
    overloads of std::get for those types must have been declared before the
    definition of std::make_from_tuple. That means we need to include the
    definition of std::ranges::subrange in <tuple>.
    
    The definitions of std::pair and its overloads of std::get are already
    included in <tuple>. We provide forward declarations of std::array and
    its std::get overloads in <tuple>. We could just declare subrange
    without defining it, and give ranges::get a non-deduced return type,
    like so:
    
      namespace ranges
      {
        enum class subrange_kind : bool { unsized, sized};
    
        template<input_or_output_iterator I, sentinel_for<I> S,
                 subrange_kind K>
          requires (K == subrange_kind::sized || !sized_sentinel_for<S, I>)
          class subrange;
    
        template<size_t _Num, class _It, class _Sent, subrange_kind _Kind>
          requires (_Num < 2)
          constexpr __conditional_t<_Num == 0, _It, _Sent>
          get(const subrange<_It, _Sent, _Kind>& __r);
    
        template<size_t _Num, class _It, class _Sent, subrange_kind _Kind>
          requires (_Num < 2)
          constexpr __conditional_t<_Num == 0, _It, _Sent>
          get(subrange<_It, _Sent, _Kind>&& __r)
      }
      using ranges::get;
    
    It is a bit late in the GCC 13 dev cycle to do this, so just include the
    right headers for now.
    
    Also add the dangling check to std::make_from_tuple added by P2255.
    
    libstdc++-v3/ChangeLog:
    
            PR libstdc++/102301
            * include/bits/ranges_base.h: Include <bits/stl_iterator.h> for
            std::make_reverse_iterator.
            * include/std/tuple: Include <bits/ranges_util.h> for subrange.
            (make_from_tuple): Add static assertion from P2255 to diagnose
            dangling references.
            * testsuite/20_util/tuple/make_from_tuple/dangling_ref.cc: New test.
            * testsuite/20_util/tuple/make_from_tuple/tuple_like.cc: New test.