1//===----------------------------------------------------------------------===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is dual licensed under the MIT and the University of Illinois Open
6// Source Licenses. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10// <tuple>
11
12// template <class... Types> class tuple;
13
14// template <class Alloc, class... UTypes>
15//   tuple(allocator_arg_t, const Alloc& a, UTypes&&...);
16
17// UNSUPPORTED: c++98, c++03
18
19#include <tuple>
20#include <cassert>
21
22#include "MoveOnly.h"
23#include "allocators.h"
24#include "../alloc_first.h"
25#include "../alloc_last.h"
26
27template <class T = void>
28struct DefaultCtorBlowsUp {
29  constexpr DefaultCtorBlowsUp() {
30      static_assert(!std::is_same<T, T>::value, "Default Ctor instantiated");
31  }
32
33  explicit constexpr DefaultCtorBlowsUp(int x) : value(x) {}
34
35  int value;
36};
37
38
39struct DerivedFromAllocArgT : std::allocator_arg_t {};
40
41
42// Make sure the _Up... constructor SFINAEs out when the number of initializers
43// is less that the number of elements in the tuple. Previously libc++ would
44// offer these constructers as an extension but they broke conforming code.
45void test_uses_allocator_sfinae_evaluation()
46{
47     using BadDefault = DefaultCtorBlowsUp<>;
48    {
49        typedef std::tuple<MoveOnly, MoveOnly, BadDefault> Tuple;
50
51        static_assert(!std::is_constructible<
52            Tuple,
53            std::allocator_arg_t, A1<int>, MoveOnly
54        >::value, "");
55
56        static_assert(std::is_constructible<
57            Tuple,
58            std::allocator_arg_t, A1<int>, MoveOnly, MoveOnly, BadDefault
59        >::value, "");
60    }
61    {
62        typedef std::tuple<MoveOnly, MoveOnly, BadDefault, BadDefault> Tuple;
63
64        static_assert(!std::is_constructible<
65            Tuple,
66            std::allocator_arg_t, A1<int>, MoveOnly, MoveOnly
67        >::value, "");
68
69        static_assert(std::is_constructible<
70            Tuple,
71            std::allocator_arg_t, A1<int>, MoveOnly, MoveOnly, BadDefault, BadDefault
72        >::value, "");
73    }
74}
75
76struct Explicit {
77  int value;
78  explicit Explicit(int x) : value(x) {}
79};
80
81int main()
82{
83    {
84        std::tuple<Explicit> t{std::allocator_arg, std::allocator<void>{}, 42};
85        assert(std::get<0>(t).value == 42);
86    }
87    {
88        std::tuple<MoveOnly> t(std::allocator_arg, A1<int>(), MoveOnly(0));
89        assert(std::get<0>(t) == 0);
90    }
91    {
92        using T = DefaultCtorBlowsUp<>;
93        std::tuple<T> t(std::allocator_arg, A1<int>(), T(42));
94        assert(std::get<0>(t).value == 42);
95    }
96    {
97        std::tuple<MoveOnly, MoveOnly> t(std::allocator_arg, A1<int>(),
98                                         MoveOnly(0), MoveOnly(1));
99        assert(std::get<0>(t) == 0);
100        assert(std::get<1>(t) == 1);
101    }
102    {
103        using T = DefaultCtorBlowsUp<>;
104        std::tuple<T, T> t(std::allocator_arg, A1<int>(), T(42), T(43));
105        assert(std::get<0>(t).value == 42);
106        assert(std::get<1>(t).value == 43);
107    }
108    {
109        std::tuple<MoveOnly, MoveOnly, MoveOnly> t(std::allocator_arg, A1<int>(),
110                                                   MoveOnly(0),
111                                                   1, 2);
112        assert(std::get<0>(t) == 0);
113        assert(std::get<1>(t) == 1);
114        assert(std::get<2>(t) == 2);
115    }
116    {
117        using T = DefaultCtorBlowsUp<>;
118        std::tuple<T, T, T> t(std::allocator_arg, A1<int>(), T(1), T(2), T(3));
119        assert(std::get<0>(t).value == 1);
120        assert(std::get<1>(t).value == 2);
121        assert(std::get<2>(t).value == 3);
122    }
123    {
124        alloc_first::allocator_constructed = false;
125        alloc_last::allocator_constructed = false;
126        std::tuple<int, alloc_first, alloc_last> t(std::allocator_arg,
127                                                   A1<int>(5), 1, 2, 3);
128        assert(std::get<0>(t) == 1);
129        assert(alloc_first::allocator_constructed);
130        assert(std::get<1>(t) == alloc_first(2));
131        assert(alloc_last::allocator_constructed);
132        assert(std::get<2>(t) == alloc_last(3));
133    }
134    {
135        // Check that uses-allocator construction is still selected when
136        // given a tag type that derives from allocator_arg_t.
137        DerivedFromAllocArgT tag;
138        alloc_first::allocator_constructed = false;
139        alloc_last::allocator_constructed = false;
140        std::tuple<int, alloc_first, alloc_last> t(tag,
141                                                   A1<int>(5), 1, 2, 3);
142        assert(std::get<0>(t) == 1);
143        assert(alloc_first::allocator_constructed);
144        assert(std::get<1>(t) == alloc_first(2));
145        assert(alloc_last::allocator_constructed);
146        assert(std::get<2>(t) == alloc_last(3));
147    }
148    // Stress test the SFINAE on the uses-allocator constructors and
149    // ensure that the "reduced-arity-initialization" extension is not offered
150    // for these constructors.
151    test_uses_allocator_sfinae_evaluation();
152}
153