summaryrefslogtreecommitdiffstats
path: root/test/CodeGenCXX/eh.cpp
blob: d03dc9171539e6f5116effdb1e6a56d8214c1e64 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
// RUN: %clang_cc1 -fexceptions -triple x86_64-apple-darwin -std=c++0x -emit-llvm %s -o %t.ll
// RUN: FileCheck --input-file=%t.ll %s

struct test1_D {
  double d;
} d1;

void test1() {
  throw d1;
}

// CHECK:     define void @_Z5test1v()
// CHECK:       [[FREEVAR:%.*]] = alloca i1
// CHECK-NEXT:  [[EXNOBJVAR:%.*]] = alloca i8*
// CHECK-NEXT:  store i1 false, i1* [[FREEVAR]]
// CHECK-NEXT:  [[EXNOBJ:%.*]] = call i8* @__cxa_allocate_exception(i64 8)
// CHECK-NEXT:  store i8* [[EXNOBJ]], i8** [[EXNOBJVAR]]
// CHECK-NEXT:  store i1 true, i1* [[FREEVAR]]
// CHECK-NEXT:  [[EXN:%.*]] = bitcast i8* [[EXNOBJ]] to [[DSTAR:%[^*]*\*]]
// CHECK-NEXT:  [[EXN2:%.*]] = bitcast [[DSTAR]] [[EXN]] to i8*
// CHECK-NEXT:  call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[EXN2]], i8* bitcast ([[DSTAR]] @d1 to i8*), i64 8, i32 8, i1 false)
// CHECK-NEXT:  store i1 false, i1* [[FREEVAR]]
// CHECK-NEXT:  call void @__cxa_throw(i8* [[EXNOBJ]], i8* bitcast (%0* @_ZTI7test1_D to i8*), i8* null) noreturn
// CHECK-NEXT:  unreachable


struct test2_D {
  test2_D(const test2_D&o);
  test2_D();
  virtual void bar() { }
  int i; int j;
} d2;

void test2() {
  throw d2;
}

// CHECK:     define void @_Z5test2v()
// CHECK:       [[FREEVAR:%.*]] = alloca i1
// CHECK-NEXT:  [[EXNOBJVAR:%.*]] = alloca i8*
// CHECK-NEXT:  [[EXNSLOTVAR:%.*]] = alloca i8*
// CHECK-NEXT:  store i1 false, i1* [[FREEVAR]]
// CHECK-NEXT:  [[EXNOBJ:%.*]] = call i8* @__cxa_allocate_exception(i64 16)
// CHECK-NEXT:  store i8* [[EXNOBJ]], i8** [[EXNOBJVAR]]
// CHECK-NEXT:  store i1 true, i1* [[FREEVAR]]
// CHECK-NEXT:  [[EXN:%.*]] = bitcast i8* [[EXNOBJ]] to [[DSTAR:%[^*]*\*]]
// CHECK-NEXT:  invoke void @_ZN7test2_DC1ERKS_([[DSTAR]] [[EXN]], [[DSTAR]] @d2)
// CHECK-NEXT:     to label %[[CONT:.*]] unwind label %{{.*}}
//      :     [[CONT]]:   (can't check this in Release-Asserts builds)
// CHECK:       store i1 false, i1* [[FREEVAR]]
// CHECK-NEXT:  call void @__cxa_throw(i8* [[EXNOBJ]], i8* bitcast (%{{.*}}* @_ZTI7test2_D to i8*), i8* null) noreturn
// CHECK-NEXT:  unreachable


struct test3_D {
  test3_D() { }
  test3_D(volatile test3_D&o);
  virtual void bar();
};

void test3() {
  throw (volatile test3_D *)0;
}

// CHECK:     define void @_Z5test3v()
// CHECK:       [[FREEVAR:%.*]] = alloca i1
// CHECK-NEXT:  [[EXNOBJVAR:%.*]] = alloca i8*
// CHECK-NEXT:  store i1 false, i1* [[FREEVAR]]
// CHECK-NEXT:  [[EXNOBJ:%.*]] = call i8* @__cxa_allocate_exception(i64 8)
// CHECK-NEXT:  store i8* [[EXNOBJ]], i8** [[EXNOBJVAR]]
// CHECK-NEXT:  store i1 true, i1* [[FREEVAR]]
// CHECK-NEXT:  [[EXN:%.*]] = bitcast i8* [[EXNOBJ]] to [[DSS:%[^*]*\*]]*
// CHECK-NEXT:  store [[DSS]] null, [[DSS]]* [[EXN]]
// CHECK-NEXT:  store i1 false, i1* [[FREEVAR]]
// CHECK-NEXT:  call void @__cxa_throw(i8* [[EXNOBJ]], i8* bitcast (%1* @_ZTIPV7test3_D to i8*), i8* null) noreturn
// CHECK-NEXT:  unreachable


void test4() {
  throw;
}

// CHECK:     define void @_Z5test4v()
// CHECK:        call void @__cxa_rethrow() noreturn
// CHECK-NEXT:   unreachable


// rdar://problem/7696549
namespace test5 {
  struct A {
    A();
    A(const A&);
    ~A();
  };

  void test() {
    try { throw A(); } catch (A &x) {}
  }
// CHECK:      define void @_ZN5test54testEv()
// CHECK:      [[EXNOBJ:%.*]] = call i8* @__cxa_allocate_exception(i64 1)
// CHECK:      [[EXNCAST:%.*]] = bitcast i8* [[EXNOBJ]] to [[A:%[^*]*]]*
// CHECK-NEXT: invoke void @_ZN5test51AC1Ev([[A]]* [[EXNCAST]])
// CHECK:      invoke void @__cxa_throw(i8* [[EXNOBJ]], i8* bitcast ({{%.*}}* @_ZTIN5test51AE to i8*), i8* bitcast (void ([[A]]*)* @_ZN5test51AD1Ev to i8*)) noreturn
// CHECK-NEXT:   to label {{%.*}} unwind label %[[HANDLER:[^ ]*]]
//      :    [[HANDLER]]:  (can't check this in Release-Asserts builds)
// CHECK:      {{%.*}} = call i32 @llvm.eh.typeid.for(i8* bitcast ({{%.*}}* @_ZTIN5test51AE to i8*))
}

namespace test6 {
  template <class T> struct allocator {
    ~allocator() throw() { }
  };

  void foo() {
    allocator<int> a;
  }
}

// PR7127
namespace test7 {
// CHECK:      define i32 @_ZN5test73fooEv() 
  int foo() {
// CHECK:      [[FREEEXNOBJ:%.*]] = alloca i1
// CHECK-NEXT: [[EXNALLOCVAR:%.*]] = alloca i8*
// CHECK-NEXT: [[CAUGHTEXNVAR:%.*]] = alloca i8*
// CHECK-NEXT: [[INTCATCHVAR:%.*]] = alloca i32
// CHECK-NEXT: store i1 false, i1* [[FREEEXNOBJ]]
    try {
      try {
// CHECK-NEXT: [[EXNALLOC:%.*]] = call i8* @__cxa_allocate_exception
// CHECK-NEXT: store i8* [[EXNALLOC]], i8** [[EXNALLOCVAR]]
// CHECK-NEXT: store i1 true, i1* [[FREEEXNOBJ]]
// CHECK-NEXT: bitcast i8* [[EXNALLOC]] to i32*
// CHECK-NEXT: store i32 1, i32*
// CHECK-NEXT: store i1 false, i1* [[FREEEXNOBJ]]
// CHECK-NEXT: invoke void @__cxa_throw(i8* [[EXNALLOC]], i8* bitcast (i8** @_ZTIi to i8*), i8* null
        throw 1;
      }
// This cleanup ends up here for no good reason.  It's actually unused.
// CHECK:      load i8** [[EXNALLOCVAR]]
// CHECK-NEXT: call void @__cxa_free_exception(

// CHECK:      [[CAUGHTEXN:%.*]] = call i8* @llvm.eh.exception()
// CHECK-NEXT: store i8* [[CAUGHTEXN]], i8** [[CAUGHTEXNVAR]]
// CHECK-NEXT: call i32 (i8*, i8*, ...)* @llvm.eh.selector(i8* [[CAUGHTEXN]], i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*), i8* bitcast (i8** @_ZTIi to i8*), i8* null)
// CHECK-NEXT: call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*))
// CHECK-NEXT: icmp eq
// CHECK-NEXT: br i1
// CHECK:      load i8** [[CAUGHTEXNVAR]]
// CHECK-NEXT: call i8* @__cxa_begin_catch
// CHECK:      invoke void @__cxa_rethrow
      catch (int) {
        throw;
      }
    }
// CHECK:      [[CAUGHTEXN:%.*]] = call i8* @llvm.eh.exception()
// CHECK-NEXT: store i8* [[CAUGHTEXN]], i8** [[CAUGHTEXNVAR]]
// CHECK-NEXT: call i32 (i8*, i8*, ...)* @llvm.eh.selector(i8* [[CAUGHTEXN]], i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*), i8* null)
// CHECK-NEXT: call void @__cxa_end_catch()
// CHECK-NEXT: br label
// CHECK:      load i8** [[CAUGHTEXNVAR]]
// CHECK-NEXT: call i8* @__cxa_begin_catch
// CHECK-NEXT: call void @__cxa_end_catch
    catch (...) {
    }
// CHECK:      ret i32 0
    return 0;
  }
}

// Ordering of destructors in a catch handler.
namespace test8 {
  struct A { A(const A&); ~A(); };
  void bar();

  // CHECK: define void @_ZN5test83fooEv()
  void foo() {
    try {
      // CHECK:      invoke void @_ZN5test83barEv()
      bar();
    } catch (A a) {
      // CHECK:      call i8* @__cxa_get_exception_ptr
      // CHECK-NEXT: bitcast
      // CHECK-NEXT: invoke void @_ZN5test81AC1ERKS0_(
      // CHECK:      call i8* @__cxa_begin_catch
      // CHECK-NEXT: invoke void @_ZN5test81AD1Ev(

      // CHECK:      call void @__cxa_end_catch()
      // CHECK-NEXT: load
      // CHECK-NEXT: switch

      // CHECK:      ret void
    }
  }
}

// Constructor function-try-block must rethrow on fallthrough.
// rdar://problem/7696603
namespace test9 {
  void opaque();

  struct A { A(); };

  // CHECK:      define void @_ZN5test91AC1Ev
  // CHECK:      call void @_ZN5test91AC2Ev
  // CHECK-NEXT: ret void

  // CHECK: define void @_ZN5test91AC2Ev(
  A::A() try {
  // CHECK:      invoke void @_ZN5test96opaqueEv()
    opaque();
  } catch (int x) {
  // CHECK:      call i8* @__cxa_begin_catch
  // CHECK:      invoke void @_ZN5test96opaqueEv()
  // CHECK:      invoke void @__cxa_rethrow()
    opaque();
  }

  // landing pad from first call to invoke
  // CHECK:      call i8* @llvm.eh.exception
  // CHECK:      call i32 (i8*, i8*, ...)* @llvm.eh.selector(i8* {{.*}}, i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*), i8* bitcast (i8** @_ZTIi to i8*), i8* null)
}
OpenPOWER on IntegriCloud