318 lines
6.6 KiB
C++
318 lines
6.6 KiB
C++
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s
|
|
void *f();
|
|
|
|
template <typename T> T* g() {
|
|
if (T* t = f())
|
|
return t;
|
|
|
|
return 0;
|
|
}
|
|
|
|
void h() {
|
|
void *a = g<void>();
|
|
}
|
|
|
|
struct X {
|
|
X();
|
|
X(const X&);
|
|
~X();
|
|
operator bool();
|
|
};
|
|
|
|
struct Y {
|
|
Y();
|
|
~Y();
|
|
};
|
|
|
|
X getX();
|
|
|
|
// CHECK-LABEL: define{{.*}} void @_Z11if_destructi(
|
|
void if_destruct(int z) {
|
|
// Verify that the condition variable is destroyed at the end of the
|
|
// "if" statement.
|
|
// CHECK: call void @_ZN1XC1Ev
|
|
// CHECK: call zeroext i1 @_ZN1XcvbEv
|
|
if (X x = X()) {
|
|
// CHECK: store i32 18
|
|
z = 18;
|
|
}
|
|
// CHECK: call void @_ZN1XD1Ev
|
|
// CHECK: store i32 17
|
|
z = 17;
|
|
|
|
// CHECK: call void @_ZN1XC1Ev
|
|
if (X x = X())
|
|
Y y;
|
|
// CHECK: br
|
|
// CHECK: call void @_ZN1YC1Ev
|
|
// CHECK: call void @_ZN1YD1Ev
|
|
// CHECK: br
|
|
// CHECK: call void @_ZN1XD1Ev
|
|
|
|
// CHECK: call void @_Z4getXv
|
|
// CHECK: call zeroext i1 @_ZN1XcvbEv
|
|
// CHECK: call void @_ZN1XD1Ev
|
|
// CHECK: br
|
|
if (getX()) { }
|
|
|
|
// CHECK: ret
|
|
}
|
|
|
|
struct ConvertibleToInt {
|
|
ConvertibleToInt();
|
|
~ConvertibleToInt();
|
|
operator int();
|
|
};
|
|
|
|
ConvertibleToInt getConvToInt();
|
|
|
|
void switch_destruct(int z) {
|
|
// CHECK: call void @_ZN16ConvertibleToIntC1Ev
|
|
switch (ConvertibleToInt conv = ConvertibleToInt()) {
|
|
case 0:
|
|
break;
|
|
|
|
default:
|
|
// CHECK: store i32 19
|
|
z = 19;
|
|
break;
|
|
}
|
|
// CHECK: call void @_ZN16ConvertibleToIntD1Ev
|
|
// CHECK: store i32 20
|
|
z = 20;
|
|
|
|
// CHECK: call void @_Z12getConvToIntv
|
|
// CHECK: call i32 @_ZN16ConvertibleToIntcviEv
|
|
// CHECK: call void @_ZN16ConvertibleToIntD1Ev
|
|
switch(getConvToInt()) {
|
|
case 0:
|
|
break;
|
|
}
|
|
// CHECK: store i32 27
|
|
z = 27;
|
|
// CHECK: ret
|
|
}
|
|
|
|
int foo();
|
|
|
|
// CHECK-LABEL: define{{.*}} void @_Z14while_destructi
|
|
void while_destruct(int z) {
|
|
// CHECK: [[Z:%.*]] = alloca i32
|
|
// CHECK: [[CLEANUPDEST:%.*]] = alloca i32
|
|
while (X x = X()) {
|
|
// CHECK: call void @_ZN1XC1Ev
|
|
// CHECK-NEXT: [[COND:%.*]] = call zeroext i1 @_ZN1XcvbEv
|
|
// CHECK-NEXT: br i1 [[COND]]
|
|
|
|
// Loop-exit staging block.
|
|
// CHECK: store i32 3, i32* [[CLEANUPDEST]]
|
|
// CHECK-NEXT: br
|
|
|
|
// While body.
|
|
// CHECK: store i32 21, i32* [[Z]]
|
|
// CHECK: store i32 0, i32* [[CLEANUPDEST]]
|
|
// CHECK-NEXT: br
|
|
z = 21;
|
|
|
|
// Cleanup.
|
|
// CHECK: call void @_ZN1XD1Ev
|
|
// CHECK-NEXT: [[DEST:%.*]] = load i32, i32* [[CLEANUPDEST]]
|
|
// CHECK-NEXT: switch i32 [[DEST]]
|
|
}
|
|
|
|
// CHECK: store i32 22, i32* [[Z]]
|
|
z = 22;
|
|
|
|
// CHECK: call void @_Z4getXv
|
|
// CHECK-NEXT: call zeroext i1 @_ZN1XcvbEv
|
|
// CHECK-NEXT: call void @_ZN1XD1Ev
|
|
// CHECK-NEXT: br
|
|
while(getX()) { }
|
|
|
|
// CHECK: store i32 25, i32* [[Z]]
|
|
z = 25;
|
|
|
|
// CHECK: ret
|
|
}
|
|
|
|
// CHECK-LABEL: define{{.*}} void @_Z12for_destructi(
|
|
void for_destruct(int z) {
|
|
// CHECK: [[Z:%.*]] = alloca i32
|
|
// CHECK: [[CLEANUPDEST:%.*]] = alloca i32
|
|
// CHECK: [[I:%.*]] = alloca i32
|
|
// CHECK: call void @_ZN1YC1Ev
|
|
// CHECK-NEXT: br
|
|
// -> %for.cond
|
|
|
|
for(Y y = Y(); X x = X(); ++z) {
|
|
// %for.cond: The loop condition.
|
|
// CHECK: call void @_ZN1XC1Ev
|
|
// CHECK-NEXT: [[COND:%.*]] = call zeroext i1 @_ZN1XcvbEv(
|
|
// CHECK-NEXT: br i1 [[COND]]
|
|
// -> %for.body, %for.cond.cleanup
|
|
|
|
// %for.cond.cleanup: Exit cleanup staging.
|
|
// CHECK: store i32 2, i32* [[CLEANUPDEST]]
|
|
// CHECK-NEXT: br
|
|
// -> %cleanup
|
|
|
|
// %for.body:
|
|
// CHECK: store i32 23, i32* [[Z]]
|
|
// CHECK-NEXT: br
|
|
// -> %for.inc
|
|
z = 23;
|
|
|
|
// %for.inc:
|
|
// CHECK: [[TMP:%.*]] = load i32, i32* [[Z]]
|
|
// CHECK-NEXT: [[INC:%.*]] = add nsw i32 [[TMP]], 1
|
|
// CHECK-NEXT: store i32 [[INC]], i32* [[Z]]
|
|
// CHECK-NEXT: store i32 0, i32* [[CLEANUPDEST]]
|
|
// CHECK-NEXT: br
|
|
// -> %cleanup
|
|
|
|
// %cleanup: Destroys X.
|
|
// CHECK: call void @_ZN1XD1Ev
|
|
// CHECK-NEXT: [[YDESTTMP:%.*]] = load i32, i32* [[CLEANUPDEST]]
|
|
// CHECK-NEXT: switch i32 [[YDESTTMP]]
|
|
// 0 -> %cleanup.cont, default -> %cleanup1
|
|
|
|
// %cleanup.cont: (eliminable)
|
|
// CHECK: br
|
|
// -> %for.cond
|
|
|
|
// %cleanup1: Destroys Y.
|
|
// CHECK: call void @_ZN1YD1Ev(
|
|
// CHECK-NEXT: br
|
|
// -> %for.end
|
|
}
|
|
|
|
// %for.end:
|
|
// CHECK: store i32 24
|
|
z = 24;
|
|
|
|
// CHECK-NEXT: store i32 0, i32* [[I]]
|
|
// CHECK-NEXT: br
|
|
// -> %for.cond6
|
|
|
|
// %for.cond6:
|
|
// CHECK: call void @_Z4getXv
|
|
// CHECK-NEXT: call zeroext i1 @_ZN1XcvbEv
|
|
// CHECK-NEXT: call void @_ZN1XD1Ev
|
|
// CHECK-NEXT: br
|
|
// -> %for.body10, %for.end16
|
|
|
|
// %for.body10:
|
|
// CHECK: br
|
|
// -> %for.inc11
|
|
|
|
// %for.inc11:
|
|
// CHECK: call void @_Z4getXv
|
|
// CHECK-NEXT: load i32, i32* [[I]]
|
|
// CHECK-NEXT: add
|
|
// CHECK-NEXT: store
|
|
// CHECK-NEXT: call void @_ZN1XD1Ev
|
|
// CHECK-NEXT: br
|
|
// -> %for.cond6
|
|
int i = 0;
|
|
for(; getX(); getX(), ++i) { }
|
|
|
|
// %for.end16
|
|
// CHECK: store i32 26
|
|
z = 26;
|
|
|
|
// CHECK-NEXT: ret void
|
|
}
|
|
|
|
void do_destruct(int z) {
|
|
// CHECK-LABEL: define{{.*}} void @_Z11do_destruct
|
|
do {
|
|
// CHECK: store i32 77
|
|
z = 77;
|
|
// CHECK: call void @_Z4getXv
|
|
// CHECK: call zeroext i1 @_ZN1XcvbEv
|
|
// CHECK: call void @_ZN1XD1Ev
|
|
// CHECK: br
|
|
} while (getX());
|
|
// CHECK: store i32 99
|
|
z = 99;
|
|
// CHECK: ret
|
|
}
|
|
|
|
int f(X);
|
|
|
|
template<typename T>
|
|
int instantiated(T x) {
|
|
int result;
|
|
|
|
// CHECK: call void @_ZN1XC1ERKS_
|
|
// CHECK: call i32 @_Z1f1X
|
|
// CHECK: call void @_ZN1XD1Ev
|
|
// CHECK: br
|
|
// CHECK: store i32 2
|
|
// CHECK: br
|
|
// CHECK: store i32 3
|
|
if (f(x)) { result = 2; } else { result = 3; }
|
|
|
|
// CHECK: call void @_ZN1XC1ERKS_
|
|
// CHECK: call i32 @_Z1f1X
|
|
// CHECK: call void @_ZN1XD1Ev
|
|
// CHECK: br
|
|
// CHECK: store i32 4
|
|
// CHECK: br
|
|
while (f(x)) { result = 4; }
|
|
|
|
// CHECK: call void @_ZN1XC1ERKS_
|
|
// CHECK: call i32 @_Z1f1X
|
|
// CHECK: call void @_ZN1XD1Ev
|
|
// CHECK: br
|
|
// CHECK: store i32 6
|
|
// CHECK: br
|
|
// CHECK: call void @_ZN1XC1ERKS_
|
|
// CHECK: call i32 @_Z1f1X
|
|
// CHECK: store i32 5
|
|
// CHECK: call void @_ZN1XD1Ev
|
|
// CHECK: br
|
|
for (; f(x); f(x), result = 5) {
|
|
result = 6;
|
|
}
|
|
|
|
// CHECK: call void @_ZN1XC1ERKS_
|
|
// CHECK: call i32 @_Z1f1X
|
|
// CHECK: call void @_ZN1XD1Ev
|
|
// CHECK: switch i32
|
|
// CHECK: store i32 7
|
|
// CHECK: store i32 8
|
|
switch (f(x)) {
|
|
case 0:
|
|
result = 7;
|
|
break;
|
|
|
|
case 1:
|
|
result = 8;
|
|
}
|
|
|
|
// CHECK: store i32 9
|
|
// CHECK: br
|
|
// CHECK: call void @_ZN1XC1ERKS_
|
|
// CHECK: call i32 @_Z1f1X
|
|
// CHECK: call void @_ZN1XD1Ev
|
|
// CHECK: br
|
|
do {
|
|
result = 9;
|
|
} while (f(x));
|
|
|
|
// CHECK: store i32 10
|
|
// CHECK: call void @_ZN1XC1ERKS_
|
|
// CHECK: call zeroext i1 @_ZN1XcvbEv
|
|
// CHECK: call void @_ZN1XD1Ev
|
|
// CHECK: br
|
|
do {
|
|
result = 10;
|
|
} while (X(x));
|
|
|
|
// CHECK: ret i32
|
|
return result;
|
|
}
|
|
|
|
template int instantiated(X);
|