| author | |
| committer | |
| log | ccfa16828445ebf3634c2a0f27ec359af1628efc |
| tree | 0d73a532885fca9b9e6db9fdceb8f1e014cf495f |
| parent | c822a0b59fe123ff67bcb188f20290d818467be7 |
| parent | d41a5105cd6222564dfe6bad9cff2c445847c6b3 |
| signature |
Stage2: implement comptime variables5 files changed, 223 insertions(+), 7 deletions(-)
src/AstGen.zig+1-1| ... | ... | @@ -2357,7 +2357,7 @@ fn varDecl( |
| 2357 | 2357 | return &sub_scope.base; |
| 2358 | 2358 | }, |
| 2359 | 2359 | .keyword_var => { |
| 2360 | const is_comptime = var_decl.comptime_token != null; | |
| 2360 | const is_comptime = var_decl.comptime_token != null or gz.force_comptime; | |
| 2361 | 2361 | var resolve_inferred_alloc: Zir.Inst.Ref = .none; |
| 2362 | 2362 | const var_data: struct { |
| 2363 | 2363 | result_loc: ResultLoc, |
src/Module.zig+10| ... | ... | @@ -1139,6 +1139,13 @@ pub const Scope = struct { |
| 1139 | 1139 | instructions: ArrayListUnmanaged(*ir.Inst), |
| 1140 | 1140 | label: ?*Label = null, |
| 1141 | 1141 | inlining: ?*Inlining, |
| 1142 | /// If runtime_index is not 0 then one of these is guaranteed to be non null. | |
| 1143 | runtime_cond: ?LazySrcLoc = null, | |
| 1144 | runtime_loop: ?LazySrcLoc = null, | |
| 1145 | /// Non zero if a non-inline loop or a runtime conditional have been encountered. | |
| 1146 | /// Stores to to comptime variables are only allowed when var.runtime_index <= runtime_index. | |
| 1147 | runtime_index: u32 = 0, | |
| 1148 | ||
| 1142 | 1149 | is_comptime: bool, |
| 1143 | 1150 | |
| 1144 | 1151 | /// This `Block` maps a block ZIR instruction to the corresponding |
| ... | ... | @@ -1182,6 +1189,9 @@ pub const Scope = struct { |
| 1182 | 1189 | .label = null, |
| 1183 | 1190 | .inlining = parent.inlining, |
| 1184 | 1191 | .is_comptime = parent.is_comptime, |
| 1192 | .runtime_cond = parent.runtime_cond, | |
| 1193 | .runtime_loop = parent.runtime_loop, | |
| 1194 | .runtime_index = parent.runtime_index, | |
| 1185 | 1195 | }; |
| 1186 | 1196 | } |
| 1187 | 1197 |
src/Sema.zig+83-6| ... | ... | @@ -147,7 +147,7 @@ pub fn analyzeBody( |
| 147 | 147 | // directly jump to the next one, rather than detouring through the loop |
| 148 | 148 | // continue expression. Related: https://github.com/ziglang/zig/issues/8220 |
| 149 | 149 | var i: usize = 0; |
| 150 | while (true) : (i += 1) { | |
| 150 | while (true) { | |
| 151 | 151 | const inst = body[i]; |
| 152 | 152 | const air_inst = switch (tags[inst]) { |
| 153 | 153 | // zig fmt: off |
| ... | ... | @@ -394,78 +394,97 @@ pub fn analyzeBody( |
| 394 | 394 | // putting them into the map. |
| 395 | 395 | .breakpoint => { |
| 396 | 396 | try sema.zirBreakpoint(block, inst); |
| 397 | i += 1; | |
| 397 | 398 | continue; |
| 398 | 399 | }, |
| 399 | 400 | .fence => { |
| 400 | 401 | try sema.zirFence(block, inst); |
| 402 | i += 1; | |
| 401 | 403 | continue; |
| 402 | 404 | }, |
| 403 | 405 | .dbg_stmt => { |
| 404 | 406 | try sema.zirDbgStmt(block, inst); |
| 407 | i += 1; | |
| 405 | 408 | continue; |
| 406 | 409 | }, |
| 407 | 410 | .ensure_err_payload_void => { |
| 408 | 411 | try sema.zirEnsureErrPayloadVoid(block, inst); |
| 412 | i += 1; | |
| 409 | 413 | continue; |
| 410 | 414 | }, |
| 411 | 415 | .ensure_result_non_error => { |
| 412 | 416 | try sema.zirEnsureResultNonError(block, inst); |
| 417 | i += 1; | |
| 413 | 418 | continue; |
| 414 | 419 | }, |
| 415 | 420 | .ensure_result_used => { |
| 416 | 421 | try sema.zirEnsureResultUsed(block, inst); |
| 422 | i += 1; | |
| 417 | 423 | continue; |
| 418 | 424 | }, |
| 419 | 425 | .set_eval_branch_quota => { |
| 420 | 426 | try sema.zirSetEvalBranchQuota(block, inst); |
| 427 | i += 1; | |
| 421 | 428 | continue; |
| 422 | 429 | }, |
| 423 | 430 | .store => { |
| 424 | 431 | try sema.zirStore(block, inst); |
| 432 | i += 1; | |
| 425 | 433 | continue; |
| 426 | 434 | }, |
| 427 | 435 | .store_node => { |
| 428 | 436 | try sema.zirStoreNode(block, inst); |
| 437 | i += 1; | |
| 429 | 438 | continue; |
| 430 | 439 | }, |
| 431 | 440 | .store_to_block_ptr => { |
| 432 | 441 | try sema.zirStoreToBlockPtr(block, inst); |
| 442 | i += 1; | |
| 433 | 443 | continue; |
| 434 | 444 | }, |
| 435 | 445 | .store_to_inferred_ptr => { |
| 436 | 446 | try sema.zirStoreToInferredPtr(block, inst); |
| 447 | i += 1; | |
| 437 | 448 | continue; |
| 438 | 449 | }, |
| 439 | 450 | .resolve_inferred_alloc => { |
| 440 | 451 | try sema.zirResolveInferredAlloc(block, inst); |
| 452 | i += 1; | |
| 441 | 453 | continue; |
| 442 | 454 | }, |
| 443 | 455 | .validate_struct_init_ptr => { |
| 444 | 456 | try sema.zirValidateStructInitPtr(block, inst); |
| 457 | i += 1; | |
| 445 | 458 | continue; |
| 446 | 459 | }, |
| 447 | 460 | .validate_array_init_ptr => { |
| 448 | 461 | try sema.zirValidateArrayInitPtr(block, inst); |
| 462 | i += 1; | |
| 449 | 463 | continue; |
| 450 | 464 | }, |
| 451 | 465 | .@"export" => { |
| 452 | 466 | try sema.zirExport(block, inst); |
| 467 | i += 1; | |
| 453 | 468 | continue; |
| 454 | 469 | }, |
| 455 | 470 | .set_align_stack => { |
| 456 | 471 | try sema.zirSetAlignStack(block, inst); |
| 472 | i += 1; | |
| 457 | 473 | continue; |
| 458 | 474 | }, |
| 459 | 475 | .set_cold => { |
| 460 | 476 | try sema.zirSetAlignStack(block, inst); |
| 477 | i += 1; | |
| 461 | 478 | continue; |
| 462 | 479 | }, |
| 463 | 480 | .set_float_mode => { |
| 464 | 481 | try sema.zirSetFloatMode(block, inst); |
| 482 | i += 1; | |
| 465 | 483 | continue; |
| 466 | 484 | }, |
| 467 | 485 | .set_runtime_safety => { |
| 468 | 486 | try sema.zirSetRuntimeSafety(block, inst); |
| 487 | i += 1; | |
| 469 | 488 | continue; |
| 470 | 489 | }, |
| 471 | 490 | |
| ... | ... | @@ -509,7 +528,8 @@ pub fn analyzeBody( |
| 509 | 528 | }; |
| 510 | 529 | if (air_inst.ty.isNoReturn()) |
| 511 | 530 | return always_noreturn; |
| 512 | try map.putNoClobber(sema.gpa, inst, air_inst); | |
| 531 | try map.put(sema.gpa, inst, air_inst); | |
| 532 | i += 1; | |
| 513 | 533 | } |
| 514 | 534 | } |
| 515 | 535 | |
| ... | ... | @@ -1238,9 +1258,26 @@ fn zirAllocExtended( |
| 1238 | 1258 | } |
| 1239 | 1259 | |
| 1240 | 1260 | fn zirAllocComptime(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { |
| 1261 | const tracy = trace(@src()); | |
| 1262 | defer tracy.end(); | |
| 1263 | ||
| 1241 | 1264 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 1242 | 1265 | const src = inst_data.src(); |
| 1243 | return sema.mod.fail(&block.base, src, "TODO implement Sema.zirAllocComptime", .{}); | |
| 1266 | const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = inst_data.src_node }; | |
| 1267 | const var_type = try sema.resolveType(block, ty_src, inst_data.operand); | |
| 1268 | const ptr_type = try sema.mod.simplePtrType(sema.arena, var_type, true, .One); | |
| 1269 | ||
| 1270 | const val_payload = try sema.arena.create(Value.Payload.ComptimeAlloc); | |
| 1271 | val_payload.* = .{ | |
| 1272 | .data = .{ | |
| 1273 | .runtime_index = block.runtime_index, | |
| 1274 | .val = undefined, // astgen guarantees there will be a store before the first load | |
| 1275 | }, | |
| 1276 | }; | |
| 1277 | return sema.mod.constInst(sema.arena, src, .{ | |
| 1278 | .ty = ptr_type, | |
| 1279 | .val = Value.initPayload(&val_payload.base), | |
| 1280 | }); | |
| 1244 | 1281 | } |
| 1245 | 1282 | |
| 1246 | 1283 | fn zirAllocInferredComptime(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { |
| ... | ... | @@ -1742,6 +1779,9 @@ fn zirLoop(sema: *Sema, parent_block: *Scope.Block, inst: Zir.Inst.Index) InnerE |
| 1742 | 1779 | }; |
| 1743 | 1780 | var child_block = parent_block.makeSubBlock(); |
| 1744 | 1781 | child_block.label = &label; |
| 1782 | child_block.runtime_cond = null; | |
| 1783 | child_block.runtime_loop = src; | |
| 1784 | child_block.runtime_index += 1; | |
| 1745 | 1785 | const merges = &child_block.label.?.merges; |
| 1746 | 1786 | |
| 1747 | 1787 | defer child_block.instructions.deinit(sema.gpa); |
| ... | ... | @@ -4066,6 +4106,9 @@ fn analyzeSwitch( |
| 4066 | 4106 | const cases = try sema.arena.alloc(Inst.SwitchBr.Case, scalar_cases_len); |
| 4067 | 4107 | |
| 4068 | 4108 | var case_block = child_block.makeSubBlock(); |
| 4109 | case_block.runtime_loop = null; | |
| 4110 | case_block.runtime_cond = operand.src; | |
| 4111 | case_block.runtime_index += 1; | |
| 4069 | 4112 | defer case_block.instructions.deinit(gpa); |
| 4070 | 4113 | |
| 4071 | 4114 | var extra_index: usize = special.end; |
| ... | ... | @@ -4584,14 +4627,14 @@ fn zirArithmetic(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerEr |
| 4584 | 4627 | |
| 4585 | 4628 | const tag_override = block.sema.code.instructions.items(.tag)[inst]; |
| 4586 | 4629 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 4587 | const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node }; | |
| 4630 | sema.src = .{ .node_offset_bin_op = inst_data.src_node }; | |
| 4588 | 4631 | const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node }; |
| 4589 | 4632 | const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node }; |
| 4590 | 4633 | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; |
| 4591 | 4634 | const lhs = try sema.resolveInst(extra.lhs); |
| 4592 | 4635 | const rhs = try sema.resolveInst(extra.rhs); |
| 4593 | 4636 | |
| 4594 | return sema.analyzeArithmetic(block, tag_override, lhs, rhs, src, lhs_src, rhs_src); | |
| 4637 | return sema.analyzeArithmetic(block, tag_override, lhs, rhs, sema.src, lhs_src, rhs_src); | |
| 4595 | 4638 | } |
| 4596 | 4639 | |
| 4597 | 4640 | fn zirOverflowArithmetic( |
| ... | ... | @@ -5150,6 +5193,9 @@ fn zirBoolBr( |
| 5150 | 5193 | }; |
| 5151 | 5194 | |
| 5152 | 5195 | var child_block = parent_block.makeSubBlock(); |
| 5196 | child_block.runtime_loop = null; | |
| 5197 | child_block.runtime_cond = lhs.src; | |
| 5198 | child_block.runtime_index += 1; | |
| 5153 | 5199 | defer child_block.instructions.deinit(sema.gpa); |
| 5154 | 5200 | |
| 5155 | 5201 | var then_block = child_block.makeSubBlock(); |
| ... | ... | @@ -5258,6 +5304,9 @@ fn zirCondbr( |
| 5258 | 5304 | } |
| 5259 | 5305 | |
| 5260 | 5306 | var sub_block = parent_block.makeSubBlock(); |
| 5307 | sub_block.runtime_loop = null; | |
| 5308 | sub_block.runtime_cond = cond.src; | |
| 5309 | sub_block.runtime_index += 1; | |
| 5261 | 5310 | defer sub_block.instructions.deinit(sema.gpa); |
| 5262 | 5311 | |
| 5263 | 5312 | _ = try sema.analyzeBody(&sub_block, then_body); |
| ... | ... | @@ -6753,7 +6802,35 @@ fn storePtr( |
| 6753 | 6802 | if ((try sema.typeHasOnePossibleValue(block, src, elem_ty)) != null) |
| 6754 | 6803 | return; |
| 6755 | 6804 | |
| 6756 | // TODO handle comptime pointer writes | |
| 6805 | if (try sema.resolvePossiblyUndefinedValue(block, src, ptr)) |ptr_val| { | |
| 6806 | const const_val = (try sema.resolvePossiblyUndefinedValue(block, src, value)) orelse | |
| 6807 | return sema.mod.fail(&block.base, src, "cannot store runtime value in compile time variable", .{}); | |
| 6808 | ||
| 6809 | const comptime_alloc = ptr_val.castTag(.comptime_alloc).?; | |
| 6810 | if (comptime_alloc.data.runtime_index < block.runtime_index) { | |
| 6811 | if (block.runtime_cond) |cond_src| { | |
| 6812 | const msg = msg: { | |
| 6813 | const msg = try sema.mod.errMsg(&block.base, src, "store to comptime variable depends on runtime condition", .{}); | |
| 6814 | errdefer msg.destroy(sema.gpa); | |
| 6815 | try sema.mod.errNote(&block.base, cond_src, msg, "runtime condition here", .{}); | |
| 6816 | break :msg msg; | |
| 6817 | }; | |
| 6818 | return sema.mod.failWithOwnedErrorMsg(&block.base, msg); | |
| 6819 | } | |
| 6820 | if (block.runtime_loop) |loop_src| { | |
| 6821 | const msg = msg: { | |
| 6822 | const msg = try sema.mod.errMsg(&block.base, src, "cannot store to comptime variable in non-inline loop", .{}); | |
| 6823 | errdefer msg.destroy(sema.gpa); | |
| 6824 | try sema.mod.errNote(&block.base, loop_src, msg, "non-inline loop here", .{}); | |
| 6825 | break :msg msg; | |
| 6826 | }; | |
| 6827 | return sema.mod.failWithOwnedErrorMsg(&block.base, msg); | |
| 6828 | } | |
| 6829 | unreachable; | |
| 6830 | } | |
| 6831 | comptime_alloc.data.val = const_val; | |
| 6832 | return; | |
| 6833 | } | |
| 6757 | 6834 | // TODO handle if the element type requires comptime |
| 6758 | 6835 | |
| 6759 | 6836 | try sema.requireRuntimeBlock(block, src); |
src/value.zig+26| ... | ... | @@ -101,6 +101,8 @@ pub const Value = extern union { |
| 101 | 101 | variable, |
| 102 | 102 | /// Represents a pointer to another immutable value. |
| 103 | 103 | ref_val, |
| 104 | /// Represents a comptime variables storage. | |
| 105 | comptime_alloc, | |
| 104 | 106 | /// Represents a pointer to a decl, not the value of the decl. |
| 105 | 107 | decl_ref, |
| 106 | 108 | elem_ptr, |
| ... | ... | @@ -223,6 +225,7 @@ pub const Value = extern union { |
| 223 | 225 | .int_i64 => Payload.I64, |
| 224 | 226 | .function => Payload.Function, |
| 225 | 227 | .variable => Payload.Variable, |
| 228 | .comptime_alloc => Payload.ComptimeAlloc, | |
| 226 | 229 | .elem_ptr => Payload.ElemPtr, |
| 227 | 230 | .field_ptr => Payload.FieldPtr, |
| 228 | 231 | .float_16 => Payload.Float_16, |
| ... | ... | @@ -403,6 +406,7 @@ pub const Value = extern union { |
| 403 | 406 | }; |
| 404 | 407 | return Value{ .ptr_otherwise = &new_payload.base }; |
| 405 | 408 | }, |
| 409 | .comptime_alloc => return self.copyPayloadShallow(allocator, Payload.ComptimeAlloc), | |
| 406 | 410 | .decl_ref => return self.copyPayloadShallow(allocator, Payload.Decl), |
| 407 | 411 | .elem_ptr => { |
| 408 | 412 | const payload = self.castTag(.elem_ptr).?; |
| ... | ... | @@ -577,6 +581,11 @@ pub const Value = extern union { |
| 577 | 581 | try out_stream.writeAll("&const "); |
| 578 | 582 | val = ref_val; |
| 579 | 583 | }, |
| 584 | .comptime_alloc => { | |
| 585 | const ref_val = val.castTag(.comptime_alloc).?.data.val; | |
| 586 | try out_stream.writeAll("&"); | |
| 587 | val = ref_val; | |
| 588 | }, | |
| 580 | 589 | .decl_ref => return out_stream.writeAll("(decl ref)"), |
| 581 | 590 | .elem_ptr => { |
| 582 | 591 | const elem_ptr = val.castTag(.elem_ptr).?.data; |
| ... | ... | @@ -713,6 +722,7 @@ pub const Value = extern union { |
| 713 | 722 | .extern_fn, |
| 714 | 723 | .variable, |
| 715 | 724 | .ref_val, |
| 725 | .comptime_alloc, | |
| 716 | 726 | .decl_ref, |
| 717 | 727 | .elem_ptr, |
| 718 | 728 | .field_ptr, |
| ... | ... | @@ -1186,6 +1196,10 @@ pub const Value = extern union { |
| 1186 | 1196 | const payload = self.castTag(.ref_val).?; |
| 1187 | 1197 | std.hash.autoHash(&hasher, payload.data.hash()); |
| 1188 | 1198 | }, |
| 1199 | .comptime_alloc => { | |
| 1200 | const payload = self.castTag(.comptime_alloc).?; | |
| 1201 | std.hash.autoHash(&hasher, payload.data.val.hash()); | |
| 1202 | }, | |
| 1189 | 1203 | .int_big_positive, .int_big_negative => { |
| 1190 | 1204 | var space: BigIntSpace = undefined; |
| 1191 | 1205 | const big = self.toBigInt(&space); |
| ... | ... | @@ -1277,6 +1291,7 @@ pub const Value = extern union { |
| 1277 | 1291 | /// Returns error.AnalysisFail if the pointer points to a Decl that failed semantic analysis. |
| 1278 | 1292 | pub fn pointerDeref(self: Value, allocator: *Allocator) error{ AnalysisFail, OutOfMemory }!Value { |
| 1279 | 1293 | return switch (self.tag()) { |
| 1294 | .comptime_alloc => self.castTag(.comptime_alloc).?.data.val, | |
| 1280 | 1295 | .ref_val => self.castTag(.ref_val).?.data, |
| 1281 | 1296 | .decl_ref => self.castTag(.decl_ref).?.data.value(), |
| 1282 | 1297 | .elem_ptr => { |
| ... | ... | @@ -1462,6 +1477,7 @@ pub const Value = extern union { |
| 1462 | 1477 | .int_big_positive, |
| 1463 | 1478 | .int_big_negative, |
| 1464 | 1479 | .ref_val, |
| 1480 | .comptime_alloc, | |
| 1465 | 1481 | .decl_ref, |
| 1466 | 1482 | .elem_ptr, |
| 1467 | 1483 | .field_ptr, |
| ... | ... | @@ -1542,6 +1558,16 @@ pub const Value = extern union { |
| 1542 | 1558 | data: Value, |
| 1543 | 1559 | }; |
| 1544 | 1560 | |
| 1561 | pub const ComptimeAlloc = struct { | |
| 1562 | pub const base_tag = Tag.comptime_alloc; | |
| 1563 | ||
| 1564 | base: Payload = Payload{ .tag = base_tag }, | |
| 1565 | data: struct { | |
| 1566 | val: Value, | |
| 1567 | runtime_index: u32, | |
| 1568 | }, | |
| 1569 | }; | |
| 1570 | ||
| 1545 | 1571 | pub const ElemPtr = struct { |
| 1546 | 1572 | pub const base_tag = Tag.elem_ptr; |
| 1547 | 1573 |
test/stage2/test.zig+103| ... | ... | @@ -1420,4 +1420,107 @@ pub fn addCases(ctx: *TestContext) !void { |
| 1420 | 1420 | \\} |
| 1421 | 1421 | , &[_][]const u8{":4:27: error: expected type, found comptime_int"}); |
| 1422 | 1422 | } |
| 1423 | { | |
| 1424 | var case = ctx.exe("comptime var", linux_x64); | |
| 1425 | ||
| 1426 | case.addError( | |
| 1427 | \\pub fn main() void { | |
| 1428 | \\ var a: u32 = 0; | |
| 1429 | \\ comptime var b: u32 = 0; | |
| 1430 | \\ if (a == 0) b = 3; | |
| 1431 | \\} | |
| 1432 | , &.{ | |
| 1433 | ":4:21: error: store to comptime variable depends on runtime condition", | |
| 1434 | ":4:11: note: runtime condition here", | |
| 1435 | }); | |
| 1436 | ||
| 1437 | case.addError( | |
| 1438 | \\pub fn main() void { | |
| 1439 | \\ var a: u32 = 0; | |
| 1440 | \\ comptime var b: u32 = 0; | |
| 1441 | \\ switch (a) { | |
| 1442 | \\ 0 => {}, | |
| 1443 | \\ else => b = 3, | |
| 1444 | \\ } | |
| 1445 | \\} | |
| 1446 | , &.{ | |
| 1447 | ":6:21: error: store to comptime variable depends on runtime condition", | |
| 1448 | ":4:13: note: runtime condition here", | |
| 1449 | }); | |
| 1450 | ||
| 1451 | case.addCompareOutput( | |
| 1452 | \\pub fn main() void { | |
| 1453 | \\ comptime var len: u32 = 5; | |
| 1454 | \\ print(len); | |
| 1455 | \\ len += 9; | |
| 1456 | \\ print(len); | |
| 1457 | \\} | |
| 1458 | \\ | |
| 1459 | \\fn print(len: usize) void { | |
| 1460 | \\ asm volatile ("syscall" | |
| 1461 | \\ : | |
| 1462 | \\ : [number] "{rax}" (1), | |
| 1463 | \\ [arg1] "{rdi}" (1), | |
| 1464 | \\ [arg2] "{rsi}" (@ptrToInt("Hello, World!\n")), | |
| 1465 | \\ [arg3] "{rdx}" (len) | |
| 1466 | \\ : "rcx", "r11", "memory" | |
| 1467 | \\ ); | |
| 1468 | \\ return; | |
| 1469 | \\} | |
| 1470 | , "HelloHello, World!\n"); | |
| 1471 | ||
| 1472 | case.addError( | |
| 1473 | \\comptime { | |
| 1474 | \\ var x: i32 = 1; | |
| 1475 | \\ x += 1; | |
| 1476 | \\ if (x != 1) unreachable; | |
| 1477 | \\} | |
| 1478 | \\pub fn main() void {} | |
| 1479 | , &.{":4:17: error: unable to resolve comptime value"}); | |
| 1480 | ||
| 1481 | case.addError( | |
| 1482 | \\pub fn main() void { | |
| 1483 | \\ comptime var i: u64 = 0; | |
| 1484 | \\ while (i < 5) : (i += 1) {} | |
| 1485 | \\} | |
| 1486 | , &.{ | |
| 1487 | ":3:24: error: cannot store to comptime variable in non-inline loop", | |
| 1488 | ":3:5: note: non-inline loop here", | |
| 1489 | }); | |
| 1490 | ||
| 1491 | case.addCompareOutput( | |
| 1492 | \\pub fn main() void { | |
| 1493 | \\ var a: u32 = 0; | |
| 1494 | \\ if (a == 0) { | |
| 1495 | \\ comptime var b: u32 = 0; | |
| 1496 | \\ b = 1; | |
| 1497 | \\ } | |
| 1498 | \\} | |
| 1499 | \\comptime { | |
| 1500 | \\ var x: i32 = 1; | |
| 1501 | \\ x += 1; | |
| 1502 | \\ if (x != 2) unreachable; | |
| 1503 | \\} | |
| 1504 | , ""); | |
| 1505 | ||
| 1506 | case.addCompareOutput( | |
| 1507 | \\pub fn main() void { | |
| 1508 | \\ comptime var i: u64 = 2; | |
| 1509 | \\ inline while (i < 6) : (i+=1) { | |
| 1510 | \\ print(i); | |
| 1511 | \\ } | |
| 1512 | \\} | |
| 1513 | \\fn print(len: usize) void { | |
| 1514 | \\ asm volatile ("syscall" | |
| 1515 | \\ : | |
| 1516 | \\ : [number] "{rax}" (1), | |
| 1517 | \\ [arg1] "{rdi}" (1), | |
| 1518 | \\ [arg2] "{rsi}" (@ptrToInt("Hello")), | |
| 1519 | \\ [arg3] "{rdx}" (len) | |
| 1520 | \\ : "rcx", "r11", "memory" | |
| 1521 | \\ ); | |
| 1522 | \\ return; | |
| 1523 | \\} | |
| 1524 | , "HeHelHellHello"); | |
| 1525 | } | |
| 1423 | 1526 | } |