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 28 bool new_throws; 29 bool ctor_throws; 30 31 int new_done; 32 int ctor_done; 33 int func_done; 34 int dtor_done; 35 int delete_done; 36 37 int count; 38 39 void init() 40 { 41 new_throws = ctor_throws = false; 42 new_done = ctor_done = func_done = dtor_done = delete_done = count = 0; 43 } 44 45 struct 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 52 struct 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 67 struct 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 80 void func(B* ) 81 { 82 func_done = ++count; 83 } 84 85 void 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 109 void 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 134 void 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 159 int 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