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++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 #include "test_macros.h"
21 
22 int count = 0;
23 
24 struct Explicit {
25   Explicit() = default;
26   explicit Explicit(int) {}
27 };
28 
29 struct Implicit {
30   Implicit() = default;
31   Implicit(int) {}
32 };
33 
34 template<class T>
35 struct Derived : std::tuple<T> {
36   using std::tuple<T>::tuple;
37   template<class U>
38   operator std::tuple<U>() && { ++count; return {}; }
39 };
40 
41 
42 template<class T>
43 struct ExplicitDerived : std::tuple<T> {
44   using std::tuple<T>::tuple;
45   template<class U>
46   explicit operator std::tuple<U>() && { ++count; return {}; }
47 };
48 
49 int main(int, char**) {
50   {
51     std::tuple<Explicit> foo = Derived<int>{42}; ((void)foo);
52     assert(count == 1);
53     std::tuple<Explicit> bar(Derived<int>{42}); ((void)bar);
54     assert(count == 2);
55   }
56   count = 0;
57   {
58     std::tuple<Implicit> foo = Derived<int>{42}; ((void)foo);
59     assert(count == 1);
60     std::tuple<Implicit> bar(Derived<int>{42}); ((void)bar);
61     assert(count == 2);
62   }
63   count = 0;
64   {
65     static_assert(!std::is_convertible<
66         ExplicitDerived<int>, std::tuple<Explicit>>::value, "");
67     std::tuple<Explicit> bar(ExplicitDerived<int>{42}); ((void)bar);
68     assert(count == 1);
69   }
70   count = 0;
71   {
72     // FIXME: Libc++ incorrectly rejects this code.
73 #ifndef _LIBCPP_VERSION
74     std::tuple<Implicit> foo = ExplicitDerived<int>{42}; ((void)foo);
75     static_assert(std::is_convertible<
76         ExplicitDerived<int>, std::tuple<Implicit>>::value,
77         "correct STLs accept this");
78 #else
79     static_assert(!std::is_convertible<
80         ExplicitDerived<int>, std::tuple<Implicit>>::value,
81         "libc++ incorrectly rejects this");
82 #endif
83     assert(count == 0);
84     std::tuple<Implicit> bar(ExplicitDerived<int>{42}); ((void)bar);
85     assert(count == 1);
86   }
87   count = 0;
88 
89 
90   return 0;
91 }
92