1// { dg-do run  }
2//
3// Purpose: Check the lifetime of the temporaries.
4//
5// Lifetime of temporaries:
6// egcs 2.92 performs cleanup for temporaries inside new expressions
7// after the new is complete, not at the end of the full expression.
8//
9// In GCC, the operands are computed first.  If no exception is raised, then
10// the result should be "ctor, new, func, dtor".  If the new operator throws
11// the exception, then the result should be "ctor, new, dtor".  If the
12// constructor of the temporary throws the exception, then the result should
13// be "ctor".
14//
15// In Clang, the new operator is called first.  If no exception is raised,
16// then the result should be "new, ctor, func, dtor".  If the new operator
17// throws the exception, then the result should be "new".  If the constructor
18// of the temporary throws the exception, then the result should be
19// "new, ctor, delete".
20//
21// Both of them are allowed by the C++ language specification, so we are using
22// #ifdef for different compilers.
23
24#include <new>
25#include <cstdlib>
26#include <cstdio>
27
28bool new_throws;
29bool ctor_throws;
30
31int new_done;
32int ctor_done;
33int func_done;
34int dtor_done;
35int delete_done;
36
37int count;
38
39void init()
40{
41  new_throws = ctor_throws = false;
42  new_done = ctor_done = func_done = dtor_done = delete_done = count = 0;
43}
44
45struct line_error{
46  int line;
47  line_error(int i):line(i){}
48};
49
50#define CHECK(cond)  if(!(cond))throw line_error(__LINE__);
51
52struct A{
53  A(int){
54    ctor_done = ++count;
55    if(ctor_throws)
56      throw 1;
57  }
58  A(const A&){
59    CHECK(false); //no copy constructors in this code
60  }
61  ~A(){
62    dtor_done = ++count;
63  }
64  A* addr(){return this;}
65};
66
67struct B{
68  B(A*){}
69  void* operator new(size_t s){
70    new_done = ++count;
71    if(new_throws)
72      throw 1;
73    return malloc(s);
74  }
75  void operator delete(void *){
76    delete_done = ++count;
77  }
78};
79
80void func(B* )
81{
82  func_done = ++count;
83}
84
85void test1()
86{
87  init();
88  try{
89    func(new B(A(10).addr()));
90  }catch(int){
91  }
92#if defined(__clang__)
93  CHECK(new_done==1);
94  CHECK(ctor_done==2);
95  CHECK(func_done==3);
96  CHECK(dtor_done==4);
97  CHECK(delete_done==0);
98#elif defined(__GNUC__)
99  CHECK(ctor_done==1);
100  CHECK(new_done==2);
101  CHECK(func_done==3);
102  CHECK(dtor_done==4);
103  CHECK(delete_done==0);
104#else
105#error "Unknown compiler"
106#endif
107}
108
109void test2()
110{
111  init();
112  new_throws = true;
113  try{
114    func(new B(A(10).addr()));
115  }catch(int){
116  }
117#if defined(__clang__)
118  CHECK(new_done==1);
119  CHECK(ctor_done==0);
120  CHECK(func_done==0);
121  CHECK(dtor_done==0);
122  CHECK(delete_done==0);
123#elif defined(__GNUC__)
124  CHECK(ctor_done==1);
125  CHECK(new_done==2);
126  CHECK(func_done==0);
127  CHECK(dtor_done==3);
128  CHECK(delete_done==0);
129#else
130#error "Unknown compiler"
131#endif
132}
133
134void test3()
135{
136  init();
137  ctor_throws = true;
138  try{
139    func(new B(A(10).addr()));
140  }catch(int){
141  }
142#if defined(__clang__)
143  CHECK(new_done==1);
144  CHECK(ctor_done==2);
145  CHECK(func_done==0);
146  CHECK(dtor_done==0);
147  CHECK(delete_done==3);
148#elif defined(__GNUC__)
149  CHECK(new_done==0);
150  CHECK(ctor_done==1);
151  CHECK(func_done==0);
152  CHECK(dtor_done==0);
153  CHECK(delete_done==0);
154#else
155#error "Unknown compiler"
156#endif
157}
158
159int main()
160{
161  try{
162    test1();
163    test2();
164    test3();
165  }catch(line_error e){
166    printf("Got error in line %d\n",e.line);
167    return 1;
168  }
169  return 0;
170}
171