1 // Check that destructors of memcpy-able struct members are called properly 2 // during stack unwinding after an exception. 3 // 4 // Check that destructor's argument (address of member to be destroyed) is 5 // obtained by taking offset from struct, not by bitcasting pointers. 6 // 7 // RUN: %clang_cc1 -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -O0 -fno-elide-constructors -emit-llvm %s -o - | FileCheck %s 8 9 struct ImplicitCopy { 10 int id; ImplicitCopyImplicitCopy11 ImplicitCopy() { id = 10; } ~ImplicitCopyImplicitCopy12 ~ImplicitCopy() { id = 20; } 13 }; 14 15 struct ThrowCopy { 16 int id; ThrowCopyThrowCopy17 ThrowCopy() { id = 15; } ThrowCopyThrowCopy18 ThrowCopy(const ThrowCopy &x) { 19 id = 25; 20 throw 1; 21 } ~ThrowCopyThrowCopy22 ~ThrowCopy() { id = 35; } 23 }; 24 25 struct Container { 26 int id; 27 ImplicitCopy o1; 28 ThrowCopy o2; 29 ContainerContainer30 Container() { id = 1000; } ~ContainerContainer31 ~Container() { id = 2000; } 32 }; 33 main()34int main() { 35 try { 36 Container c1; 37 // CHECK-LABEL: main 38 // CHECK: %{{.+}} = getelementptr inbounds %struct.Container, %struct.Container* %{{.+}}, i32 0, i32 1 39 // CHECK-NOT: %{{.+}} = bitcast %struct.Container* %{{.+}} to %struct.ImplicitCopy* 40 Container c2(c1); 41 42 return 2; 43 } catch (...) { 44 return 1; 45 } 46 return 0; 47 } 48