1 // RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm %s -std=c++2a -o %t.ll 2 // RUN: FileCheck -check-prefix=CHECK-FN-CG -input-file=%t.ll %s 3 // RUN: FileCheck -check-prefix=CHECK-STATIC -input-file=%t.ll %s 4 // RUN: FileCheck -check-prefix=CHECK-DYN -input-file=%t.ll %s 5 // RUN: FileCheck -check-prefix=CHECK-ARR -input-file=%t.ll %s 6 // RUN: FileCheck -check-prefix=CHECK-FOLD -input-file=%t.ll %s 7 // RUN: FileCheck -check-prefix=CHECK-DTOR -input-file=%t.ll %s 8 9 using size_t = decltype(sizeof(int)); 10 11 #define CONSTINIT __attribute__((require_constant_initialization)) 12 13 extern "C" [[noreturn]] void BOOM(); 14 extern "C" void OK(); 15 extern "C" size_t RANDU(); 16 17 namespace std { 18 inline constexpr bool is_constant_evaluated() noexcept { 19 return __builtin_is_constant_evaluated(); 20 } 21 } // namespace std 22 23 // CHECK-FN-CG-LABEL: define{{.*}} zeroext i1 @_Z3foov() 24 // CHECK-FN-CG: ret i1 false 25 bool foo() { 26 return __builtin_is_constant_evaluated(); 27 } 28 29 // CHECK-FN-CG-LABEL: define linkonce_odr noundef i32 @_Z1fv() 30 constexpr int f() { 31 // CHECK-FN-CG: store i32 13, i32* %n, align 4 32 // CHECK-FN-CG: store i32 17, i32* %m, align 4 33 // CHECK-FN-CG: %1 = load i32, i32* %m, align 4 34 // CHECK-FN-CG: %add = add nsw i32 %1, 13 35 // CHECK-FN-CG: ret i32 %add 36 const int n = __builtin_is_constant_evaluated() && std::is_constant_evaluated() ? 13 : 17; // n == 13 37 int m = __builtin_is_constant_evaluated() ? 13 : 17; // m might be 13 or 17 (see below) 38 char arr[n] = {}; // char[13] 39 return m + int(sizeof(arr)); 40 } 41 42 // CHECK-STATIC-DAG: @p ={{.*}} global i32 26, 43 CONSTINIT int p = f(); // f().m == 13; initialized to 26 44 // CHECK-STATIC-DAG: @p2 ={{.*}} global i32 26, 45 int p2 = f(); // same result without CONSTINIT 46 47 // CHECK-DYN-LABEL: define internal void @__cxx_global_var_init() 48 // CHECK-DYN: %0 = load i32, i32* @p, align 4 49 // CHECK-DYN-NEXT: %call = call noundef i32 @_Z1fv() 50 // CHECK-DYN-NEXT: %add = add nsw i32 %0, %call 51 // CHECK-DYN-NEXT: store i32 %add, i32* @q, align 4 52 // CHECK-DYN-NEXT: ret void 53 int q = p + f(); // m == 17 for this call; initialized to 56 54 55 int y; 56 57 // CHECK-STATIC-DAG: @b ={{.*}} global i32 2, 58 CONSTINIT int b = __builtin_is_constant_evaluated() ? 2 : y; // static initialization to 2 59 60 // CHECK-DYN-LABEL: define internal void @__cxx_global_var_init.1() 61 // CHECK-DYN: %0 = load i32, i32* @y, align 4 62 // CHECK-DYN: %1 = load i32, i32* @y, align 4 63 // CHECK-DYN-NEXT: %add = add 64 // CHECK-DYN-NEXT: store i32 %add, i32* @c, 65 int c = y + (__builtin_is_constant_evaluated() ? 2 : y); // dynamic initialization to y+y 66 67 // This is dynamic initialization that we can convert to static initialization 68 // during lowering. When doing so, the dynamic initializer value is preserved. 69 // CHECK-STATIC-DAG: @_ZL1a = internal constant i32 1 70 const int a = __builtin_is_constant_evaluated() ? y : 1; // dynamic initialization to 1 71 const int *a_sink = &a; 72 73 // CHECK-ARR-LABEL: define{{.*}} void @_Z13test_arr_exprv 74 void test_arr_expr() { 75 // CHECK-ARR: %x1 = alloca [101 x i8], 76 char x1[std::is_constant_evaluated() && __builtin_is_constant_evaluated() ? 101 : 1]; 77 78 // CHECK-ARR: %x2 = alloca [42 x i8], 79 char x2[std::is_constant_evaluated() && __builtin_is_constant_evaluated() ? 42 : RANDU()]; 80 81 // CHECK-ARR: call i8* @llvm.stacksave() 82 // CHECK-ARR: %vla = alloca i8, i64 13, 83 char x3[std::is_constant_evaluated() || __builtin_is_constant_evaluated() ? RANDU() : 13]; 84 } 85 86 // CHECK-ARR-LABEL: define{{.*}} void @_Z17test_new_arr_exprv 87 void test_new_arr_expr() { 88 // CHECK-ARR: call noalias noundef nonnull i8* @_Znam(i64 noundef 17) 89 new char[std::is_constant_evaluated() || __builtin_is_constant_evaluated() ? 1 : 17]; 90 } 91 92 // CHECK-FOLD-LABEL: @_Z31test_constant_initialized_locali( 93 bool test_constant_initialized_local(int k) { 94 // CHECK-FOLD: store i8 1, i8* %n, 95 // CHECK-FOLD: store volatile i8* %n, i8** %p, 96 const bool n = __builtin_is_constant_evaluated() && std::is_constant_evaluated(); 97 const bool *volatile p = &n; 98 return *p; 99 } 100 101 // CHECK-FOLD-LABEL: define{{.*}} void @_Z21test_ir_constant_foldv() 102 void test_ir_constant_fold() { 103 // CHECK-FOLD-NEXT: entry: 104 // CHECK-FOLD-NEXT: call void @OK() 105 // CHECK-FOLD-NEXT: call void @OK() 106 // CHECK-FOLD-NEXT: ret void 107 if (std::is_constant_evaluated()) { 108 BOOM(); 109 } else { 110 OK(); 111 } 112 std::is_constant_evaluated() ? BOOM() : OK(); 113 } 114 115 // CHECK-STATIC-DAG: @ir ={{.*}} constant i32* @i_constant, 116 int i_constant; 117 int i_not_constant; 118 int &ir = __builtin_is_constant_evaluated() ? i_constant : i_not_constant; 119 120 // CHECK-FOLD-LABEL: @_Z35test_ref_initialization_local_scopev() 121 void test_ref_initialization_local_scope() { 122 const int i_constant = 42; 123 const int i_non_constant = 101; 124 // CHECK-FOLD: store i32* %i_non_constant, i32** %r, 125 const int &r = __builtin_is_constant_evaluated() ? i_constant : i_non_constant; 126 } 127 128 // CHECK-FOLD-LABEL: @_Z22test_ref_to_static_varv() 129 void test_ref_to_static_var() { 130 static int i_constant = 42; 131 static int i_non_constant = 101; 132 // CHECK-FOLD: store i32* @_ZZ22test_ref_to_static_varvE10i_constant, i32** %r, 133 int &r = __builtin_is_constant_evaluated() ? i_constant : i_non_constant; 134 } 135 136 int not_constexpr; 137 138 // __builtin_is_constant_evaluated() should never evaluate to true during 139 // destruction if it would not have done so during construction. 140 // 141 // FIXME: The standard doesn't say that it should ever return true when 142 // evaluating a destructor call, even for a constexpr variable. That seems 143 // obviously wrong. 144 struct DestructorBCE { 145 int n; 146 constexpr DestructorBCE(int n) : n(n) {} 147 constexpr ~DestructorBCE() { 148 if (!__builtin_is_constant_evaluated()) 149 not_constexpr = 1; 150 } 151 }; 152 153 // CHECK-DTOR-NOT: @_ZN13DestructorBCED{{.*}}@global_dtor_bce_1 154 DestructorBCE global_dtor_bce_1(101); 155 156 // CHECK-DTOR: load i32, i32* @not_constexpr 157 // CHECK-DTOR: call {{.*}} @_ZN13DestructorBCEC1Ei({{.*}} @global_dtor_bce_2, i32 158 // CHECK-DTOR: atexit{{.*}} @_ZN13DestructorBCED{{.*}} @global_dtor_bce_2 159 // CHECK-DTOR: } 160 DestructorBCE global_dtor_bce_2(not_constexpr); 161 162 // CHECK-DTOR-NOT: @_ZN13DestructorBCED{{.*}}@global_dtor_bce_3 163 constexpr DestructorBCE global_dtor_bce_3(103); 164 165 // CHECK-DTOR-LABEL: define {{.*}} @_Z15test_dtor_bce_1v( 166 void test_dtor_bce_1() { 167 // Variable is neither constant initialized (because it has automatic storage 168 // duration) nor usable in constant expressions, so BCE should not return 169 // true during destruction. It would be OK if we replaced the constructor 170 // call with a direct store, but we should emit the destructor call. 171 172 // CHECK-DTOR: call {{.*}} @_ZN13DestructorBCEC1Ei({{.*}}, i32 noundef 201) 173 DestructorBCE local(201); 174 // CHECK-DTOR: call {{.*}} @_ZN13DestructorBCED 175 // CHECK-DTOR: } 176 } 177 178 // CHECK-DTOR-LABEL: define {{.*}} @_Z15test_dtor_bce_2v( 179 void test_dtor_bce_2() { 180 // Non-constant init => BCE is false in destructor. 181 182 // CHECK-DTOR: call {{.*}} @_ZN13DestructorBCEC1Ei({{.*}} 183 DestructorBCE local(not_constexpr); 184 // CHECK-DTOR: call {{.*}} @_ZN13DestructorBCED 185 // CHECK-DTOR: } 186 } 187 188 // CHECK-DTOR-LABEL: define {{.*}} @_Z15test_dtor_bce_3v( 189 void test_dtor_bce_3() { 190 // Should never call dtor for a constexpr variable. 191 192 // CHECK-DTOR-NOT: call {{.*}} @_ZN13DestructorBCEC1Ei( 193 constexpr DestructorBCE local(203); 194 // CHECK-DTOR-NOT: @_ZN13DestructorBCED 195 // CHECK-DTOR: } 196 } 197 198 // CHECK-DTOR-LABEL: define {{.*}} @_Z22test_dtor_bce_static_1v( 199 void test_dtor_bce_static_1() { 200 // Variable is constant initialized, so BCE returns true during constant 201 // destruction. 202 203 // CHECK: store i32 301 204 // CHECK-DTOR-NOT: @_ZN13DestructorBCEC1Ei({{.*}} 205 static DestructorBCE local(301); 206 // CHECK-DTOR-NOT: @_ZN13DestructorBCED 207 // CHECK-DTOR: } 208 } 209 210 // CHECK-DTOR-LABEL: define {{.*}} @_Z22test_dtor_bce_static_2v( 211 void test_dtor_bce_static_2() { 212 // CHECK-DTOR: call {{.*}} @_ZN13DestructorBCEC1Ei({{.*}} 213 static DestructorBCE local(not_constexpr); 214 // CHECK-DTOR: call {{.*}}atexit{{.*}} @_ZN13DestructorBCED 215 // CHECK-DTOR: } 216 } 217 218 // CHECK-DTOR-LABEL: define {{.*}} @_Z22test_dtor_bce_static_3v( 219 void test_dtor_bce_static_3() { 220 // CHECK: store i32 303 221 // CHECK-DTOR-NOT: @_ZN13DestructorBCEC1Ei({{.*}} 222 static constexpr DestructorBCE local(303); 223 // CHECK-DTOR-NOT: @_ZN13DestructorBCED 224 // CHECK-DTOR: } 225 } 226