1 // RUN: %clang_cc1 -emit-llvm %s -std=c++2a -triple x86_64-unknown-linux-gnu -o %t.ll 2 // RUN: FileCheck -check-prefix=EVAL -input-file=%t.ll %s 3 // RUN: FileCheck -check-prefix=EVAL-STATIC -input-file=%t.ll %s 4 // RUN: FileCheck -check-prefix=EVAL-FN -input-file=%t.ll %s 5 // 6 // RUN: %clang_cc1 -emit-llvm %s -Dconsteval="" -std=c++2a -triple x86_64-unknown-linux-gnu -o %t.ll 7 // RUN: FileCheck -check-prefix=EXPR -input-file=%t.ll %s 8 9 // RUN: %clang_cc1 -emit-llvm %s -std=c++2a -triple x86_64-unknown-linux-gnu -o %t.ll -fexperimental-new-constant-interpreter 10 // RUN: FileCheck -check-prefix=EVAL -input-file=%t.ll %s 11 // RUN: FileCheck -check-prefix=EVAL-STATIC -input-file=%t.ll %s 12 // RUN: FileCheck -check-prefix=EVAL-FN -input-file=%t.ll %s 13 // 14 // RUN: %clang_cc1 -emit-llvm %s -Dconsteval="" -std=c++2a -triple x86_64-unknown-linux-gnu -o %t.ll -fexperimental-new-constant-interpreter 15 // RUN: FileCheck -check-prefix=EXPR -input-file=%t.ll %s 16 17 // there is two version of symbol checks to ensure 18 // that the symbol we are looking for are correct 19 // EVAL-NOT: @__cxx_global_var_init() 20 // EXPR: @__cxx_global_var_init() 21 22 // EVAL-NOT: @_Z4ret7v() 23 // EXPR: @_Z4ret7v() 24 consteval int ret7() { 25 return 7; 26 } 27 28 // EVAL-FN-LABEL: @_Z9test_ret7v( 29 // EVAL-FN-NEXT: entry: 30 // EVAL-FN-NEXT: [[I:%.*]] = alloca i32, align 4 31 // EVAL-FN-NEXT: store i32 7, ptr [[I]], align 4 32 // EVAL-FN-NEXT: [[TMP0:%.*]] = load i32, ptr [[I]], align 4 33 // EVAL-FN-NEXT: ret i32 [[TMP0]] 34 // 35 int test_ret7() { 36 int i = ret7(); 37 return i; 38 } 39 40 int global_i = ret7(); 41 42 constexpr int i_const = 5; 43 44 // EVAL-NOT: @_Z4retIv() 45 // EXPR: @_Z4retIv() 46 consteval const int &retI() { 47 return i_const; 48 } 49 50 // EVAL-FN-LABEL: @_Z12test_retRefIv( 51 // EVAL-FN-NEXT: entry: 52 // EVAL-FN-NEXT: ret ptr @_ZL7i_const 53 // 54 const int &test_retRefI() { 55 return retI(); 56 } 57 58 // EVAL-FN-LABEL: @_Z9test_retIv( 59 // EVAL-FN-NEXT: entry: 60 // EVAL-FN-NEXT: [[TMP0:%.*]] = load i32, ptr @_ZL7i_const, align 4 61 // EVAL-FN-NEXT: ret i32 [[TMP0]] 62 // 63 int test_retI() { 64 return retI(); 65 } 66 67 // EVAL-NOT: @_Z4retIv() 68 // EXPR: @_Z4retIv() 69 consteval const int *retIPtr() { 70 return &i_const; 71 } 72 73 // EVAL-FN-LABEL: @_Z12test_retIPtrv( 74 // EVAL-FN-NEXT: entry: 75 // EVAL-FN-NEXT: [[TMP0:%.*]] = load i32, ptr @_ZL7i_const, align 4 76 // EVAL-FN-NEXT: ret i32 [[TMP0]] 77 // 78 int test_retIPtr() { 79 return *retIPtr(); 80 } 81 82 // EVAL-FN-LABEL: @_Z13test_retPIPtrv( 83 // EVAL-FN-NEXT: entry: 84 // EVAL-FN-NEXT: ret ptr @_ZL7i_const 85 // 86 const int *test_retPIPtr() { 87 return retIPtr(); 88 } 89 90 // EVAL-NOT: @_Z4retIv() 91 // EXPR: @_Z4retIv() 92 consteval const int &&retIRRef() { 93 return static_cast<const int &&>(i_const); 94 } 95 96 // EVAL-FN-LABEL: @_Z13test_retIRRefv( 97 // EVAL-FN-NEXT: entry: 98 // EVAL-FN-NEXT: ret ptr @_ZL7i_const 99 // 100 const int &&test_retIRRef() { 101 return static_cast<const int &&>(retIRRef()); 102 } 103 104 // EVAL-FN-LABEL: @_Z14test_retIRRefIv( 105 // EVAL-FN-NEXT: entry: 106 // EVAL-FN-NEXT: [[TMP0:%.*]] = load i32, ptr @_ZL7i_const, align 4 107 // EVAL-FN-NEXT: ret i32 [[TMP0]] 108 // 109 int test_retIRRefI() { 110 return retIRRef(); 111 } 112 113 struct Agg { 114 int a; 115 long b; 116 }; 117 118 // EVAL-NOT: @_Z6retAggv() 119 // EXPR: @_Z6retAggv() 120 consteval Agg retAgg() { 121 return {13, 17}; 122 } 123 124 // EVAL-FN-LABEL: @_Z11test_retAggv( 125 // EVAL-FN-NEXT: entry: 126 // EVAL-FN-NEXT: [[B:%.*]] = alloca i64, align 8 127 // EVAL-FN-NEXT: [[REF_TMP:%.*]] = alloca [[STRUCT_AGG:%.*]], align 8 128 // EVAL-FN-NEXT: [[TMP0:%.*]] = getelementptr inbounds nuw [[STRUCT_AGG]], ptr [[REF_TMP]], i32 0, i32 0 129 // EVAL-FN-NEXT: store i32 13, ptr [[TMP0]], align 8 130 // EVAL-FN-NEXT: [[TMP1:%.*]] = getelementptr inbounds nuw [[STRUCT_AGG]], ptr [[REF_TMP]], i32 0, i32 1 131 // EVAL-FN-NEXT: store i64 17, ptr [[TMP1]], align 8 132 // EVAL-FN-NEXT: store i64 17, ptr [[B]], align 8 133 // EVAL-FN-NEXT: [[TMP2:%.*]] = load i64, ptr [[B]], align 8 134 // EVAL-FN-NEXT: ret i64 [[TMP2]] 135 // 136 long test_retAgg() { 137 long b = retAgg().b; 138 return b; 139 } 140 141 // EVAL-STATIC: @A ={{.*}} global %struct.Agg { i32 13, i64 17 }, align 8 142 Agg A = retAgg(); 143 144 // EVAL-NOT: @_Z9retRefAggv() 145 // EXPR: @_Z9retRefAggv() 146 consteval const Agg &retRefAgg() { 147 const Agg &tmp = A; 148 return A; 149 } 150 151 // EVAL-FN-LABEL: @_Z14test_retRefAggv( 152 // EVAL-FN-NEXT: entry: 153 // EVAL-FN-NEXT: [[B:%.*]] = alloca i64, align 8 154 // EVAL-FN-NEXT: [[REF_TMP:%.*]] = alloca [[STRUCT_AGG:%.*]], align 8 155 // EVAL-FN-NEXT: [[TMP0:%.*]] = getelementptr inbounds nuw [[STRUCT_AGG]], ptr [[REF_TMP]], i32 0, i32 0 156 // EVAL-FN-NEXT: store i32 13, ptr [[TMP0]], align 8 157 // EVAL-FN-NEXT: [[TMP1:%.*]] = getelementptr inbounds nuw [[STRUCT_AGG]], ptr [[REF_TMP]], i32 0, i32 1 158 // EVAL-FN-NEXT: store i64 17, ptr [[TMP1]], align 8 159 // EVAL-FN-NEXT: store i64 17, ptr [[B]], align 8 160 // EVAL-FN-NEXT: [[TMP2:%.*]] = load i64, ptr [[B]], align 8 161 // EVAL-FN-NEXT: ret i64 [[TMP2]] 162 // 163 long test_retRefAgg() { 164 long b = retAgg().b; 165 return b; 166 } 167 168 // EVAL-NOT: @_Z8is_constv() 169 // EXPR: @_Z8is_constv() 170 consteval Agg is_const() { 171 return {5, 19 * __builtin_is_constant_evaluated()}; 172 } 173 174 // EVAL-FN-LABEL: @_Z13test_is_constv( 175 // EVAL-FN-NEXT: entry: 176 // EVAL-FN-NEXT: [[B:%.*]] = alloca i64, align 8 177 // EVAL-FN-NEXT: [[REF_TMP:%.*]] = alloca [[STRUCT_AGG:%.*]], align 8 178 // EVAL-FN-NEXT: [[TMP0:%.*]] = getelementptr inbounds nuw [[STRUCT_AGG]], ptr [[REF_TMP]], i32 0, i32 0 179 // EVAL-FN-NEXT: store i32 5, ptr [[TMP0]], align 8 180 // EVAL-FN-NEXT: [[TMP1:%.*]] = getelementptr inbounds nuw [[STRUCT_AGG]], ptr [[REF_TMP]], i32 0, i32 1 181 // EVAL-FN-NEXT: store i64 19, ptr [[TMP1]], align 8 182 // EVAL-FN-NEXT: store i64 19, ptr [[B]], align 8 183 // EVAL-FN-NEXT: [[TMP2:%.*]] = load i64, ptr [[B]], align 8 184 // EVAL-FN-NEXT: ret i64 [[TMP2]] 185 // 186 long test_is_const() { 187 long b = is_const().b; 188 return b; 189 } 190 191 // EVAL-NOT: @_ZN7AggCtorC 192 // EXPR: @_ZN7AggCtorC 193 struct AggCtor { 194 consteval AggCtor(int a = 3, long b = 5) : a(a * a), b(a * b) {} 195 int a; 196 long b; 197 }; 198 199 // EVAL-FN-LABEL: @_Z12test_AggCtorv( 200 // EVAL-FN-NEXT: entry: 201 // EVAL-FN-NEXT: [[I:%.*]] = alloca i32, align 4 202 // EVAL-FN-NEXT: [[C:%.*]] = alloca [[STRUCT_AGGCTOR:%.*]], align 8 203 // EVAL-FN-NEXT: store i32 2, ptr [[I]], align 4 204 // EVAL-FN-NEXT: [[TMP0:%.*]] = getelementptr inbounds nuw [[STRUCT_AGGCTOR]], ptr [[C]], i32 0, i32 0 205 // EVAL-FN-NEXT: store i32 4, ptr [[TMP0]], align 8 206 // EVAL-FN-NEXT: [[TMP1:%.*]] = getelementptr inbounds nuw [[STRUCT_AGGCTOR]], ptr [[C]], i32 0, i32 1 207 // EVAL-FN-NEXT: store i64 10, ptr [[TMP1]], align 8 208 // EVAL-FN-NEXT: [[A:%.*]] = getelementptr inbounds nuw [[STRUCT_AGGCTOR]], ptr [[C]], i32 0, i32 0 209 // EVAL-FN-NEXT: [[TMP2:%.*]] = load i32, ptr [[A]], align 8 210 // EVAL-FN-NEXT: [[CONV:%.*]] = sext i32 [[TMP2]] to i64 211 // EVAL-FN-NEXT: [[B:%.*]] = getelementptr inbounds nuw [[STRUCT_AGGCTOR]], ptr [[C]], i32 0, i32 1 212 // EVAL-FN-NEXT: [[TMP3:%.*]] = load i64, ptr [[B]], align 8 213 // EVAL-FN-NEXT: [[ADD:%.*]] = add nsw i64 [[CONV]], [[TMP3]] 214 // EVAL-FN-NEXT: ret i64 [[ADD]] 215 // 216 long test_AggCtor() { 217 const int i = 2; 218 AggCtor C(i); 219 return C.a + C.b; 220 } 221 222 struct UserConv { 223 consteval operator int() const noexcept { return 42; } 224 }; 225 226 // EVAL-FN-LABEL: @_Z13test_UserConvv( 227 // EVAL-FN-NEXT: entry: 228 // EVAL-FN-NEXT: ret i32 42 229 // 230 int test_UserConv() { 231 return UserConv(); 232 } 233 234 // EVAL-FN-LABEL: @_Z28test_UserConvOverload_helperi( 235 // EVAL-FN-NEXT: entry: 236 // EVAL-FN-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4 237 // EVAL-FN-NEXT: store i32 [[A:%.*]], ptr [[A_ADDR]], align 4 238 // EVAL-FN-NEXT: [[TMP0:%.*]] = load i32, ptr [[A_ADDR]], align 4 239 // EVAL-FN-NEXT: ret i32 [[TMP0]] 240 // 241 int test_UserConvOverload_helper(int a) { return a; } 242 243 // EVAL-FN-LABEL: @_Z21test_UserConvOverloadv( 244 // EVAL-FN-NEXT: entry: 245 // EVAL-FN-NEXT: [[CALL:%.*]] = call noundef i32 @_Z28test_UserConvOverload_helperi(i32 noundef 42) 246 // EVAL-FN-NEXT: ret i32 [[CALL]] 247 // 248 int test_UserConvOverload() { 249 return test_UserConvOverload_helper(UserConv()); 250 } 251 252 consteval int test_UserConvOverload_helper_ceval(int a) { return a; } 253 254 // EVAL-FN-LABEL: @_Z27test_UserConvOverload_cevalv( 255 // EVAL-FN-NEXT: entry: 256 // EVAL-FN-NEXT: ret i32 42 257 // 258 int test_UserConvOverload_ceval() { 259 return test_UserConvOverload_helper_ceval(UserConv()); 260 } 261 262 consteval void void_test() {} 263 void void_call() { // EVAL-FN-LABEL: define {{.*}} @_Z9void_call 264 // EVAL-FN-NOT: call 265 void_test(); 266 // EVAL-FN: {{^}}} 267 } 268 269 270 namespace GH82154 { 271 struct S1 { consteval S1(int) {} }; 272 struct S3 { constexpr S3(int) {} }; 273 274 void f() { 275 struct S2 { 276 S1 s = 0; 277 S3 s2 = 0; 278 }; 279 S2 s; 280 // EVAL-FN-LABEL: define {{.*}} void @_ZZN7GH821541fEvEN2S2C2Ev 281 // EVAL-FN-NOT: call void @_ZN7GH821542S1C2Ei 282 // EVAL-FN: call void @_ZN7GH821542S3C2Ei 283 } 284 } 285 286 namespace GH93040 { 287 struct C { char c = 1; }; 288 struct Empty { consteval Empty() {} }; 289 struct Empty2 { consteval Empty2() {} }; 290 struct Test : C, Empty { 291 [[no_unique_address]] Empty2 e; 292 }; 293 static_assert(sizeof(Test) == 1); 294 void f() { 295 Test test; 296 297 // Make sure we don't overwrite the initialization of c. 298 299 // EVAL-FN-LABEL: define {{.*}} void @_ZN7GH930404TestC2Ev 300 // EVAL-FN: entry: 301 // EVAL-FN-NEXT: [[THIS_ADDR:%.*]] = alloca ptr, align 8 302 // EVAL-FN-NEXT: store ptr {{.*}}, ptr [[THIS_ADDR]], align 8 303 // EVAL-FN-NEXT: [[THIS:%.*]] = load ptr, ptr [[THIS_ADDR]], align 8 304 // EVAL-FN-NEXT: call void @_ZN7GH930401CC2Ev(ptr noundef nonnull align 1 dereferenceable(1) [[THIS]]) 305 // EVAL-FN-NEXT: ret void 306 } 307 } 308