// { dg-do run } // // Purpose: Check the lifetime of the temporaries. // // Lifetime of temporaries: // egcs 2.92 performs cleanup for temporaries inside new expressions // after the new is complete, not at the end of the full expression. // // In GCC, the operands are computed first. If no exception is raised, then // the result should be "ctor, new, func, dtor". If the new operator throws // the exception, then the result should be "ctor, new, dtor". If the // constructor of the temporary throws the exception, then the result should // be "ctor". // // In Clang, the new operator is called first. If no exception is raised, // then the result should be "new, ctor, func, dtor". If the new operator // throws the exception, then the result should be "new". If the constructor // of the temporary throws the exception, then the result should be // "new, ctor, delete". // // Both of them are allowed by the C++ language specification, so we are using // #ifdef for different compilers. #include <new> #include <cstdlib> #include <cstdio> bool new_throws; bool ctor_throws; int new_done; int ctor_done; int func_done; int dtor_done; int delete_done; int count; void init() { new_throws = ctor_throws = false; new_done = ctor_done = func_done = dtor_done = delete_done = count = 0; } struct line_error{ int line; line_error(int i):line(i){} }; #define CHECK(cond) if(!(cond))throw line_error(__LINE__); struct A{ A(int){ ctor_done = ++count; if(ctor_throws) throw 1; } A(const A&){ CHECK(false); //no copy constructors in this code } ~A(){ dtor_done = ++count; } A* addr(){return this;} }; struct B{ B(A*){} void* operator new(size_t s){ new_done = ++count; if(new_throws) throw 1; return malloc(s); } void operator delete(void *){ delete_done = ++count; } }; void func(B* ) { func_done = ++count; } void test1() { init(); try{ func(new B(A(10).addr())); }catch(int){ } #if defined(__clang__) CHECK(new_done==1); CHECK(ctor_done==2); CHECK(func_done==3); CHECK(dtor_done==4); CHECK(delete_done==0); #elif defined(__GNUC__) CHECK(ctor_done==1); CHECK(new_done==2); CHECK(func_done==3); CHECK(dtor_done==4); CHECK(delete_done==0); #else #error "Unknown compiler" #endif } void test2() { init(); new_throws = true; try{ func(new B(A(10).addr())); }catch(int){ } #if defined(__clang__) CHECK(new_done==1); CHECK(ctor_done==0); CHECK(func_done==0); CHECK(dtor_done==0); CHECK(delete_done==0); #elif defined(__GNUC__) CHECK(ctor_done==1); CHECK(new_done==2); CHECK(func_done==0); CHECK(dtor_done==3); CHECK(delete_done==0); #else #error "Unknown compiler" #endif } void test3() { init(); ctor_throws = true; try{ func(new B(A(10).addr())); }catch(int){ } #if defined(__clang__) CHECK(new_done==1); CHECK(ctor_done==2); CHECK(func_done==0); CHECK(dtor_done==0); CHECK(delete_done==3); #elif defined(__GNUC__) CHECK(new_done==0); CHECK(ctor_done==1); CHECK(func_done==0); CHECK(dtor_done==0); CHECK(delete_done==0); #else #error "Unknown compiler" #endif } int main() { try{ test1(); test2(); test3(); }catch(line_error e){ printf("Got error in line %d\n",e.line); return 1; } return 0; }