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// <thread>
11
12// class thread
13
14// template <class F, class ...Args> thread(F&& f, Args&&... args);
15
16#include <thread>
17#include <new>
18#include <cstdlib>
19#include <cassert>
20
21unsigned throw_one = 0xFFFF;
22
23void* operator new(std::size_t s) throw(std::bad_alloc)
24{
25    if (throw_one == 0)
26        throw std::bad_alloc();
27    --throw_one;
28    return std::malloc(s);
29}
30
31void  operator delete(void* p) throw()
32{
33    std::free(p);
34}
35
36bool f_run = false;
37
38void f()
39{
40    f_run = true;
41}
42
43class G
44{
45    int alive_;
46public:
47    static int n_alive;
48    static bool op_run;
49
50    G() : alive_(1) {++n_alive;}
51    G(const G& g) : alive_(g.alive_) {++n_alive;}
52    ~G() {alive_ = 0; --n_alive;}
53
54    void operator()()
55    {
56        assert(alive_ == 1);
57        assert(n_alive >= 1);
58        op_run = true;
59    }
60
61    void operator()(int i, double j)
62    {
63        assert(alive_ == 1);
64        assert(n_alive >= 1);
65        assert(i == 5);
66        assert(j == 5.5);
67        op_run = true;
68    }
69};
70
71int G::n_alive = 0;
72bool G::op_run = false;
73
74#ifndef _LIBCPP_HAS_NO_VARIADICS
75
76class MoveOnly
77{
78    MoveOnly(const MoveOnly&);
79public:
80    MoveOnly() {}
81    MoveOnly(MoveOnly&&) {}
82
83    void operator()(MoveOnly&&)
84    {
85    }
86};
87
88#endif
89
90int main()
91{
92    {
93        std::thread t(f);
94        t.join();
95        assert(f_run == true);
96    }
97    f_run = false;
98    {
99        try
100        {
101            throw_one = 0;
102            std::thread t(f);
103            assert(false);
104        }
105        catch (...)
106        {
107            throw_one = 0xFFFF;
108            assert(!f_run);
109        }
110    }
111    {
112        assert(G::n_alive == 0);
113        assert(!G::op_run);
114        std::thread t((G()));
115        t.join();
116        assert(G::n_alive == 0);
117        assert(G::op_run);
118    }
119    G::op_run = false;
120    {
121        try
122        {
123            throw_one = 0;
124            assert(G::n_alive == 0);
125            assert(!G::op_run);
126            std::thread t((G()));
127            assert(false);
128        }
129        catch (...)
130        {
131            throw_one = 0xFFFF;
132            assert(G::n_alive == 0);
133            assert(!G::op_run);
134        }
135    }
136#ifndef _LIBCPP_HAS_NO_VARIADICS
137    {
138        assert(G::n_alive == 0);
139        assert(!G::op_run);
140        std::thread t(G(), 5, 5.5);
141        t.join();
142        assert(G::n_alive == 0);
143        assert(G::op_run);
144    }
145    {
146        std::thread t = std::thread(MoveOnly(), MoveOnly());
147        t.join();
148    }
149#endif  // _LIBCPP_HAS_NO_VARIADICS
150}
151