|  | // 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 noundef 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 noundef 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 noundef 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 noundef zeroext i1 @_ZN1XcvbEv | 
|  | // CHECK-NEXT: br i1 [[COND]] | 
|  |  | 
|  | // Loop-exit staging block. | 
|  | // CHECK: store i32 3, ptr [[CLEANUPDEST]] | 
|  | // CHECK-NEXT: br | 
|  |  | 
|  | // While body. | 
|  | // CHECK: store i32 21, ptr [[Z]] | 
|  | // CHECK: store i32 0, ptr [[CLEANUPDEST]] | 
|  | // CHECK-NEXT: br | 
|  | z = 21; | 
|  |  | 
|  | // Cleanup. | 
|  | // CHECK: call void @_ZN1XD1Ev | 
|  | // CHECK-NEXT: [[DEST:%.*]] = load i32, ptr [[CLEANUPDEST]] | 
|  | // CHECK-NEXT: switch i32 [[DEST]] | 
|  | } | 
|  |  | 
|  | // CHECK: store i32 22, ptr [[Z]] | 
|  | z = 22; | 
|  |  | 
|  | // CHECK: call void @_Z4getXv | 
|  | // CHECK-NEXT: call noundef zeroext i1 @_ZN1XcvbEv | 
|  | // CHECK-NEXT: call void @_ZN1XD1Ev | 
|  | // CHECK-NEXT: br | 
|  | while(getX()) { } | 
|  |  | 
|  | // CHECK: store i32 25, ptr [[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 noundef zeroext i1 @_ZN1XcvbEv( | 
|  | // CHECK-NEXT: br i1 [[COND]] | 
|  | // -> %for.body, %for.cond.cleanup | 
|  |  | 
|  | // %for.cond.cleanup: Exit cleanup staging. | 
|  | // CHECK: store i32 2, ptr [[CLEANUPDEST]] | 
|  | // CHECK-NEXT: br | 
|  | // -> %cleanup | 
|  |  | 
|  | // %for.body: | 
|  | // CHECK: store i32 23, ptr [[Z]] | 
|  | // CHECK-NEXT: br | 
|  | // -> %for.inc | 
|  | z = 23; | 
|  |  | 
|  | // %for.inc: | 
|  | // CHECK: [[TMP:%.*]] = load i32, ptr [[Z]] | 
|  | // CHECK-NEXT: [[INC:%.*]] = add nsw i32 [[TMP]], 1 | 
|  | // CHECK-NEXT: store i32 [[INC]], ptr [[Z]] | 
|  | // CHECK-NEXT: store i32 0, ptr [[CLEANUPDEST]] | 
|  | // CHECK-NEXT: br | 
|  | // -> %cleanup | 
|  |  | 
|  | // %cleanup:  Destroys X. | 
|  | // CHECK: call void @_ZN1XD1Ev | 
|  | // CHECK-NEXT: [[YDESTTMP:%.*]] = load i32, ptr [[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, ptr [[I]] | 
|  | // CHECK-NEXT: br | 
|  | // -> %for.cond6 | 
|  |  | 
|  | // %for.cond6: | 
|  | // CHECK: call void @_Z4getXv | 
|  | // CHECK-NEXT: call noundef 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, ptr [[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 noundef 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 noundef 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 noundef 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 noundef i32 @_Z1f1X | 
|  | // CHECK: call void @_ZN1XD1Ev | 
|  | // CHECK: br | 
|  | // CHECK: store i32 6 | 
|  | // CHECK: br | 
|  | // CHECK: call void @_ZN1XC1ERKS_ | 
|  | // CHECK: call noundef 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 noundef 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 noundef i32 @_Z1f1X | 
|  | // CHECK: call void @_ZN1XD1Ev | 
|  | // CHECK: br | 
|  | do { | 
|  | result = 9; | 
|  | } while (f(x)); | 
|  |  | 
|  | // CHECK: store i32 10 | 
|  | // CHECK: call void @_ZN1XC1ERKS_ | 
|  | // CHECK: call noundef zeroext i1 @_ZN1XcvbEv | 
|  | // CHECK: call void @_ZN1XD1Ev | 
|  | // CHECK: br | 
|  | do { | 
|  | result = 10; | 
|  | } while (X(x)); | 
|  |  | 
|  | // CHECK: ret i32 | 
|  | return result; | 
|  | } | 
|  |  | 
|  | template int instantiated(X); |