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; |
11 | ImplicitCopy() { id = 10; } |
12 | ~ImplicitCopy() { id = 20; } |
13 | }; |
14 | |
15 | struct ThrowCopy { |
16 | int id; |
17 | ThrowCopy() { id = 15; } |
18 | ThrowCopy(const ThrowCopy &x) { |
19 | id = 25; |
20 | throw 1; |
21 | } |
22 | ~ThrowCopy() { id = 35; } |
23 | }; |
24 | |
25 | struct Container { |
26 | int id; |
27 | ImplicitCopy o1; |
28 | ThrowCopy o2; |
29 | |
30 | Container() { id = 1000; } |
31 | ~Container() { id = 2000; } |
32 | }; |
33 | |
34 | int 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 | |