1 // -*- C++ -*-
2 //===----------------------------------------------------------------------===//
3 //
4 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5 // See https://llvm.org/LICENSE.txt for license information.
6 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //
8 //===----------------------------------------------------------------------===//
9 
10 // UNSUPPORTED: c++98, c++03
11 
12 // <tuple>
13 
14 // template <class TupleLike> tuple(TupleLike&&); // libc++ extension
15 
16 // See llvm.org/PR31384
17 #include <tuple>
18 #include <cassert>
19 
20 int count = 0;
21 
22 struct Explicit {
23   Explicit() = default;
24   explicit Explicit(int) {}
25 };
26 
27 struct Implicit {
28   Implicit() = default;
29   Implicit(int) {}
30 };
31 
32 template<class T>
33 struct Derived : std::tuple<T> {
34   using std::tuple<T>::tuple;
35   template<class U>
36   operator std::tuple<U>() && { ++count; return {}; }
37 };
38 
39 
40 template<class T>
41 struct ExplicitDerived : std::tuple<T> {
42   using std::tuple<T>::tuple;
43   template<class U>
44   explicit operator std::tuple<U>() && { ++count; return {}; }
45 };
46 
47 int main(int, char**) {
48   {
49     std::tuple<Explicit> foo = Derived<int>{42}; ((void)foo);
50     assert(count == 1);
51     std::tuple<Explicit> bar(Derived<int>{42}); ((void)bar);
52     assert(count == 2);
53   }
54   count = 0;
55   {
56     std::tuple<Implicit> foo = Derived<int>{42}; ((void)foo);
57     assert(count == 1);
58     std::tuple<Implicit> bar(Derived<int>{42}); ((void)bar);
59     assert(count == 2);
60   }
61   count = 0;
62   {
63     static_assert(!std::is_convertible<
64         ExplicitDerived<int>, std::tuple<Explicit>>::value, "");
65     std::tuple<Explicit> bar(ExplicitDerived<int>{42}); ((void)bar);
66     assert(count == 1);
67   }
68   count = 0;
69   {
70     // FIXME: Libc++ incorrectly rejects this code.
71 #ifndef _LIBCPP_VERSION
72     std::tuple<Implicit> foo = ExplicitDerived<int>{42}; ((void)foo);
73     static_assert(std::is_convertible<
74         ExplicitDerived<int>, std::tuple<Implicit>>::value,
75         "correct STLs accept this");
76 #else
77     static_assert(!std::is_convertible<
78         ExplicitDerived<int>, std::tuple<Implicit>>::value,
79         "libc++ incorrectly rejects this");
80 #endif
81     assert(count == 0);
82     std::tuple<Implicit> bar(ExplicitDerived<int>{42}); ((void)bar);
83     assert(count == 1);
84   }
85   count = 0;
86 
87 
88   return 0;
89 }
90