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