// 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);