| author | |
| committer | |
| log | 078037ab9b410fa13a86eabdfc30918fc83cdcf3 |
| tree | b5e80992e82d015393872fcc57911b03ca7211fd |
| parent | b28b3f6f7b1dd4c3c8a0f3d3a6305a84daed8ead |
* use the real start code for LLVM backend with x86_64-linux
- there is still a check for zig_backend after initializing the TLS
area to skip some stuff.
* introduce new AIR instructions and implement them for the LLVM
backend. They are the same as `call` except with a modifier.
- call_always_tail
- call_never_tail
- call_never_inline
* LLVM backend calls hasRuntimeBitsIgnoringComptime in more places to
avoid unnecessarily depending on comptimeOnly being resolved for some
types.
* LLVM backend: remove duplicate code for setting linkage and value
name. The canonical place for this is in `updateDeclExports`.
* LLVM backend: do some assembly template massaging to make `%%`
rendered as `%`. More hacks will be needed to make inline assembly
catch up with stage1.18 files changed, 190 insertions(+), 70 deletions(-)
lib/std/start.zig+15-1| ... | ... | @@ -22,7 +22,16 @@ comptime { |
| 22 | 22 | // The self-hosted compiler is not fully capable of handling all of this start.zig file. |
| 23 | 23 | // Until then, we have simplified logic here for self-hosted. TODO remove this once |
| 24 | 24 | // self-hosted is capable enough to handle all of the real start.zig logic. |
| 25 | if (builtin.zig_backend != .stage1) { | |
| 25 | if (builtin.zig_backend == .stage2_wasm or | |
| 26 | builtin.zig_backend == .stage2_c or | |
| 27 | builtin.zig_backend == .stage2_x86_64 or | |
| 28 | builtin.zig_backend == .stage2_x86 or | |
| 29 | builtin.zig_backend == .stage2_aarch64 or | |
| 30 | builtin.zig_backend == .stage2_arm or | |
| 31 | builtin.zig_backend == .stage2_riscv64 or | |
| 32 | (builtin.zig_backend == .stage2_llvm and native_os != .linux) or | |
| 33 | (builtin.zig_backend == .stage2_llvm and native_arch != .x86_64)) | |
| 34 | { | |
| 26 | 35 | if (builtin.output_mode == .Exe) { |
| 27 | 36 | if ((builtin.link_libc or builtin.object_format == .c) and @hasDecl(root, "main")) { |
| 28 | 37 | if (@typeInfo(@TypeOf(root.main)).Fn.calling_convention != .C) { |
| ... | ... | @@ -399,6 +408,11 @@ fn posixCallMainAndExit() noreturn { |
| 399 | 408 | // Initialize the TLS area. |
| 400 | 409 | std.os.linux.tls.initStaticTLS(phdrs); |
| 401 | 410 | |
| 411 | if (builtin.zig_backend == .stage2_llvm) { | |
| 412 | root.main(); | |
| 413 | exit2(0); | |
| 414 | } | |
| 415 | ||
| 402 | 416 | // The way Linux executables represent stack size is via the PT_GNU_STACK |
| 403 | 417 | // program header. However the kernel does not recognize it; it always gives 8 MiB. |
| 404 | 418 | // Here we look for the stack size in our program headers and use setrlimit |
src/Air.zig+7-1| ... | ... | @@ -226,6 +226,12 @@ pub const Inst = struct { |
| 226 | 226 | /// Uses the `pl_op` field with the `Call` payload. operand is the callee. |
| 227 | 227 | /// Triggers `resolveTypeLayout` on the return type of the callee. |
| 228 | 228 | call, |
| 229 | /// Same as `call` except with the `always_tail` attribute. | |
| 230 | call_always_tail, | |
| 231 | /// Same as `call` except with the `never_tail` attribute. | |
| 232 | call_never_tail, | |
| 233 | /// Same as `call` except with the `never_inline` attribute. | |
| 234 | call_never_inline, | |
| 229 | 235 | /// Count leading zeroes of an integer according to its representation in twos complement. |
| 230 | 236 | /// Result type will always be an unsigned integer big enough to fit the answer. |
| 231 | 237 | /// Uses the `ty_op` field. |
| ... | ... | @@ -969,7 +975,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type { |
| 969 | 975 | |
| 970 | 976 | .tag_name, .error_name => return Type.initTag(.const_slice_u8_sentinel_0), |
| 971 | 977 | |
| 972 | .call => { | |
| 978 | .call, .call_always_tail, .call_never_tail, .call_never_inline => { | |
| 973 | 979 | const callee_ty = air.typeOf(datas[inst].pl_op.operand); |
| 974 | 980 | switch (callee_ty.zigTypeTag()) { |
| 975 | 981 | .Fn => return callee_ty.fnReturnType(), |
src/Liveness.zig+1-1| ... | ... | @@ -399,7 +399,7 @@ fn analyzeInst( |
| 399 | 399 | return trackOperands(a, new_set, inst, main_tomb, .{ prefetch.ptr, .none, .none }); |
| 400 | 400 | }, |
| 401 | 401 | |
| 402 | .call => { | |
| 402 | .call, .call_always_tail, .call_never_tail, .call_never_inline => { | |
| 403 | 403 | const inst_data = inst_datas[inst].pl_op; |
| 404 | 404 | const callee = inst_data.operand; |
| 405 | 405 | const extra = a.air.extraData(Air.Call, inst_data.payload); |
src/Sema.zig+13-13| ... | ... | @@ -4458,21 +4458,19 @@ fn analyzeCall( |
| 4458 | 4458 | ); |
| 4459 | 4459 | } |
| 4460 | 4460 | |
| 4461 | switch (modifier) { | |
| 4461 | const call_tag: Air.Inst.Tag = switch (modifier) { | |
| 4462 | 4462 | .auto, |
| 4463 | 4463 | .always_inline, |
| 4464 | 4464 | .compile_time, |
| 4465 | 4465 | .no_async, |
| 4466 | => {}, | |
| 4467 | ||
| 4468 | .async_kw, | |
| 4469 | .never_tail, | |
| 4470 | .never_inline, | |
| 4471 | .always_tail, | |
| 4472 | => return sema.fail(block, call_src, "TODO implement call with modifier {}", .{ | |
| 4473 | modifier, | |
| 4474 | }), | |
| 4475 | } | |
| 4466 | => Air.Inst.Tag.call, | |
| 4467 | ||
| 4468 | .never_tail => Air.Inst.Tag.call_never_tail, | |
| 4469 | .never_inline => Air.Inst.Tag.call_never_inline, | |
| 4470 | .always_tail => Air.Inst.Tag.call_always_tail, | |
| 4471 | ||
| 4472 | .async_kw => return sema.fail(block, call_src, "TODO implement async call", .{}), | |
| 4473 | }; | |
| 4476 | 4474 | |
| 4477 | 4475 | const gpa = sema.gpa; |
| 4478 | 4476 | |
| ... | ... | @@ -4490,6 +4488,7 @@ fn analyzeCall( |
| 4490 | 4488 | func_ty_info, |
| 4491 | 4489 | ensure_result_used, |
| 4492 | 4490 | uncasted_args, |
| 4491 | call_tag, | |
| 4493 | 4492 | )) |some| { |
| 4494 | 4493 | return some; |
| 4495 | 4494 | } else |err| switch (err) { |
| ... | ... | @@ -4771,7 +4770,7 @@ fn analyzeCall( |
| 4771 | 4770 | try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Call).Struct.fields.len + |
| 4772 | 4771 | args.len); |
| 4773 | 4772 | const func_inst = try block.addInst(.{ |
| 4774 | .tag = .call, | |
| 4773 | .tag = call_tag, | |
| 4775 | 4774 | .data = .{ .pl_op = .{ |
| 4776 | 4775 | .operand = func, |
| 4777 | 4776 | .payload = sema.addExtraAssumeCapacity(Air.Call{ |
| ... | ... | @@ -4798,6 +4797,7 @@ fn instantiateGenericCall( |
| 4798 | 4797 | func_ty_info: Type.Payload.Function.Data, |
| 4799 | 4798 | ensure_result_used: bool, |
| 4800 | 4799 | uncasted_args: []const Air.Inst.Ref, |
| 4800 | call_tag: Air.Inst.Tag, | |
| 4801 | 4801 | ) CompileError!Air.Inst.Ref { |
| 4802 | 4802 | const mod = sema.mod; |
| 4803 | 4803 | const gpa = sema.gpa; |
| ... | ... | @@ -5107,7 +5107,7 @@ fn instantiateGenericCall( |
| 5107 | 5107 | try sema.air_extra.ensureUnusedCapacity(sema.gpa, @typeInfo(Air.Call).Struct.fields.len + |
| 5108 | 5108 | runtime_args_len); |
| 5109 | 5109 | const func_inst = try block.addInst(.{ |
| 5110 | .tag = .call, | |
| 5110 | .tag = call_tag, | |
| 5111 | 5111 | .data = .{ .pl_op = .{ |
| 5112 | 5112 | .operand = callee_inst, |
| 5113 | 5113 | .payload = sema.addExtraAssumeCapacity(Air.Call{ |
src/arch/aarch64/CodeGen.zig+7-2| ... | ... | @@ -585,7 +585,6 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 585 | 585 | .ret_addr => try self.airRetAddr(inst), |
| 586 | 586 | .frame_addr => try self.airFrameAddress(inst), |
| 587 | 587 | .fence => try self.airFence(), |
| 588 | .call => try self.airCall(inst), | |
| 589 | 588 | .cond_br => try self.airCondBr(inst), |
| 590 | 589 | .dbg_stmt => try self.airDbgStmt(inst), |
| 591 | 590 | .fptrunc => try self.airFptrunc(inst), |
| ... | ... | @@ -634,6 +633,11 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 634 | 633 | .prefetch => try self.airPrefetch(inst), |
| 635 | 634 | .mul_add => try self.airMulAdd(inst), |
| 636 | 635 | |
| 636 | .call => try self.airCall(inst, .auto), | |
| 637 | .call_always_tail => try self.airCall(inst, .always_tail), | |
| 638 | .call_never_tail => try self.airCall(inst, .never_tail), | |
| 639 | .call_never_inline => try self.airCall(inst, .never_inline), | |
| 640 | ||
| 637 | 641 | .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered), |
| 638 | 642 | .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic), |
| 639 | 643 | .atomic_store_release => try self.airAtomicStore(inst, .Release), |
| ... | ... | @@ -2325,7 +2329,8 @@ fn airFence(self: *Self) !void { |
| 2325 | 2329 | //return self.finishAirBookkeeping(); |
| 2326 | 2330 | } |
| 2327 | 2331 | |
| 2328 | fn airCall(self: *Self, inst: Air.Inst.Index) !void { | |
| 2332 | fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.Modifier) !void { | |
| 2333 | if (modifier == .always_tail) return self.fail("TODO implement tail calls for aarch64", .{}); | |
| 2329 | 2334 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| 2330 | 2335 | const callee = pl_op.operand; |
| 2331 | 2336 | const extra = self.air.extraData(Air.Call, pl_op.payload); |
src/arch/arm/CodeGen.zig+7-2| ... | ... | @@ -581,7 +581,6 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 581 | 581 | .ret_addr => try self.airRetAddr(inst), |
| 582 | 582 | .frame_addr => try self.airFrameAddress(inst), |
| 583 | 583 | .fence => try self.airFence(), |
| 584 | .call => try self.airCall(inst), | |
| 585 | 584 | .cond_br => try self.airCondBr(inst), |
| 586 | 585 | .dbg_stmt => try self.airDbgStmt(inst), |
| 587 | 586 | .fptrunc => try self.airFptrunc(inst), |
| ... | ... | @@ -630,6 +629,11 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 630 | 629 | .prefetch => try self.airPrefetch(inst), |
| 631 | 630 | .mul_add => try self.airMulAdd(inst), |
| 632 | 631 | |
| 632 | .call => try self.airCall(inst, .auto), | |
| 633 | .call_always_tail => try self.airCall(inst, .always_tail), | |
| 634 | .call_never_tail => try self.airCall(inst, .never_tail), | |
| 635 | .call_never_inline => try self.airCall(inst, .never_inline), | |
| 636 | ||
| 633 | 637 | .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered), |
| 634 | 638 | .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic), |
| 635 | 639 | .atomic_store_release => try self.airAtomicStore(inst, .Release), |
| ... | ... | @@ -2510,7 +2514,8 @@ fn airFence(self: *Self) !void { |
| 2510 | 2514 | //return self.finishAirBookkeeping(); |
| 2511 | 2515 | } |
| 2512 | 2516 | |
| 2513 | fn airCall(self: *Self, inst: Air.Inst.Index) !void { | |
| 2517 | fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.Modifier) !void { | |
| 2518 | if (modifier == .always_tail) return self.fail("TODO implement tail calls for arm", .{}); | |
| 2514 | 2519 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| 2515 | 2520 | const callee = pl_op.operand; |
| 2516 | 2521 | const extra = self.air.extraData(Air.Call, pl_op.payload); |
src/arch/riscv64/CodeGen.zig+8-3| ... | ... | @@ -553,7 +553,6 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 553 | 553 | .ret_addr => try self.airRetAddr(inst), |
| 554 | 554 | .frame_addr => try self.airFrameAddress(inst), |
| 555 | 555 | .fence => try self.airFence(), |
| 556 | .call => try self.airCall(inst), | |
| 557 | 556 | .cond_br => try self.airCondBr(inst), |
| 558 | 557 | .dbg_stmt => try self.airDbgStmt(inst), |
| 559 | 558 | .fptrunc => try self.airFptrunc(inst), |
| ... | ... | @@ -602,6 +601,11 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 602 | 601 | .prefetch => try self.airPrefetch(inst), |
| 603 | 602 | .mul_add => try self.airMulAdd(inst), |
| 604 | 603 | |
| 604 | .call => try self.airCall(inst, .auto), | |
| 605 | .call_always_tail => try self.airCall(inst, .always_tail), | |
| 606 | .call_never_tail => try self.airCall(inst, .never_tail), | |
| 607 | .call_never_inline => try self.airCall(inst, .never_inline), | |
| 608 | ||
| 605 | 609 | .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered), |
| 606 | 610 | .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic), |
| 607 | 611 | .atomic_store_release => try self.airAtomicStore(inst, .Release), |
| ... | ... | @@ -1458,7 +1462,8 @@ fn airFence(self: *Self) !void { |
| 1458 | 1462 | //return self.finishAirBookkeeping(); |
| 1459 | 1463 | } |
| 1460 | 1464 | |
| 1461 | fn airCall(self: *Self, inst: Air.Inst.Index) !void { | |
| 1465 | fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.Modifier) !void { | |
| 1466 | if (modifier == .always_tail) return self.fail("TODO implement tail calls for riscv64", .{}); | |
| 1462 | 1467 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| 1463 | 1468 | const fn_ty = self.air.typeOf(pl_op.operand); |
| 1464 | 1469 | const callee = pl_op.operand; |
| ... | ... | @@ -2496,7 +2501,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 2496 | 2501 | result.stack_byte_count = next_stack_offset; |
| 2497 | 2502 | result.stack_align = 16; |
| 2498 | 2503 | }, |
| 2499 | else => return self.fail("TODO implement function parameters for {} on aarch64", .{cc}), | |
| 2504 | else => return self.fail("TODO implement function parameters for {} on riscv64", .{cc}), | |
| 2500 | 2505 | } |
| 2501 | 2506 | |
| 2502 | 2507 | if (ret_ty.zigTypeTag() == .NoReturn) { |
src/arch/wasm/CodeGen.zig+8-3| ... | ... | @@ -1218,7 +1218,6 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue { |
| 1218 | 1218 | .breakpoint => self.airBreakpoint(inst), |
| 1219 | 1219 | .br => self.airBr(inst), |
| 1220 | 1220 | .bool_to_int => self.airBoolToInt(inst), |
| 1221 | .call => self.airCall(inst), | |
| 1222 | 1221 | .cond_br => self.airCondBr(inst), |
| 1223 | 1222 | .dbg_stmt => WValue.none, |
| 1224 | 1223 | .intcast => self.airIntcast(inst), |
| ... | ... | @@ -1227,6 +1226,11 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue { |
| 1227 | 1226 | .float_to_int => self.airFloatToInt(inst), |
| 1228 | 1227 | .get_union_tag => self.airGetUnionTag(inst), |
| 1229 | 1228 | |
| 1229 | .call => self.airCall(inst, .auto), | |
| 1230 | .call_always_tail => self.airCall(inst, .always_tail), | |
| 1231 | .call_never_tail => self.airCall(inst, .never_tail), | |
| 1232 | .call_never_inline => self.airCall(inst, .never_inline), | |
| 1233 | ||
| 1230 | 1234 | .is_err => self.airIsErr(inst, .i32_ne), |
| 1231 | 1235 | .is_non_err => self.airIsErr(inst, .i32_eq), |
| 1232 | 1236 | |
| ... | ... | @@ -1375,7 +1379,7 @@ fn airRet(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 1375 | 1379 | fn airRetPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 1376 | 1380 | const child_type = self.air.typeOfIndex(inst).childType(); |
| 1377 | 1381 | |
| 1378 | if (!child_type.isFnOrHasRuntimeBits()) { | |
| 1382 | if (!child_type.isFnOrHasRuntimeBitsIgnoreComptime()) { | |
| 1379 | 1383 | return self.allocStack(Type.usize); // create pointer to void |
| 1380 | 1384 | } |
| 1381 | 1385 | |
| ... | ... | @@ -1401,7 +1405,8 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 1401 | 1405 | return .none; |
| 1402 | 1406 | } |
| 1403 | 1407 | |
| 1404 | fn airCall(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | |
| 1408 | fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.Modifier) InnerError!WValue { | |
| 1409 | if (modifier == .always_tail) return self.fail("TODO implement tail calls for wasm", .{}); | |
| 1405 | 1410 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| 1406 | 1411 | const extra = self.air.extraData(Air.Call, pl_op.payload); |
| 1407 | 1412 | const args = self.air.extra[extra.end..][0..extra.data.args_len]; |
src/arch/x86_64/CodeGen.zig+7-2| ... | ... | @@ -670,7 +670,6 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 670 | 670 | .ret_addr => try self.airRetAddr(inst), |
| 671 | 671 | .frame_addr => try self.airFrameAddress(inst), |
| 672 | 672 | .fence => try self.airFence(), |
| 673 | .call => try self.airCall(inst), | |
| 674 | 673 | .cond_br => try self.airCondBr(inst), |
| 675 | 674 | .dbg_stmt => try self.airDbgStmt(inst), |
| 676 | 675 | .fptrunc => try self.airFptrunc(inst), |
| ... | ... | @@ -719,6 +718,11 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 719 | 718 | .prefetch => try self.airPrefetch(inst), |
| 720 | 719 | .mul_add => try self.airMulAdd(inst), |
| 721 | 720 | |
| 721 | .call => try self.airCall(inst, .auto), | |
| 722 | .call_always_tail => try self.airCall(inst, .always_tail), | |
| 723 | .call_never_tail => try self.airCall(inst, .never_tail), | |
| 724 | .call_never_inline => try self.airCall(inst, .never_inline), | |
| 725 | ||
| 722 | 726 | .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered), |
| 723 | 727 | .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic), |
| 724 | 728 | .atomic_store_release => try self.airAtomicStore(inst, .Release), |
| ... | ... | @@ -3263,7 +3267,8 @@ fn airFence(self: *Self) !void { |
| 3263 | 3267 | //return self.finishAirBookkeeping(); |
| 3264 | 3268 | } |
| 3265 | 3269 | |
| 3266 | fn airCall(self: *Self, inst: Air.Inst.Index) !void { | |
| 3270 | fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.Modifier) !void { | |
| 3271 | if (modifier == .always_tail) return self.fail("TODO implement tail calls for x86_64", .{}); | |
| 3267 | 3272 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| 3268 | 3273 | const callee = pl_op.operand; |
| 3269 | 3274 | const extra = self.air.extraData(Air.Call, pl_op.payload); |
src/codegen/c.zig+20-5| ... | ... | @@ -1685,7 +1685,6 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO |
| 1685 | 1685 | .assembly => try airAsm(f, inst), |
| 1686 | 1686 | .block => try airBlock(f, inst), |
| 1687 | 1687 | .bitcast => try airBitcast(f, inst), |
| 1688 | .call => try airCall(f, inst), | |
| 1689 | 1688 | .dbg_stmt => try airDbgStmt(f, inst), |
| 1690 | 1689 | .intcast => try airIntCast(f, inst), |
| 1691 | 1690 | .trunc => try airTrunc(f, inst), |
| ... | ... | @@ -1721,6 +1720,11 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO |
| 1721 | 1720 | .union_init => try airUnionInit(f, inst), |
| 1722 | 1721 | .prefetch => try airPrefetch(f, inst), |
| 1723 | 1722 | |
| 1723 | .call => try airCall(f, inst, .auto), | |
| 1724 | .call_always_tail => try airCall(f, inst, .always_tail), | |
| 1725 | .call_never_tail => try airCall(f, inst, .never_tail), | |
| 1726 | .call_never_inline => try airCall(f, inst, .never_inline), | |
| 1727 | ||
| 1724 | 1728 | .int_to_float, |
| 1725 | 1729 | .float_to_int, |
| 1726 | 1730 | .fptrunc, |
| ... | ... | @@ -1904,7 +1908,7 @@ fn airAlloc(f: *Function, inst: Air.Inst.Index) !CValue { |
| 1904 | 1908 | |
| 1905 | 1909 | const elem_type = inst_ty.elemType(); |
| 1906 | 1910 | const mutability: Mutability = if (inst_ty.isConstPtr()) .Const else .Mut; |
| 1907 | if (!elem_type.isFnOrHasRuntimeBits()) { | |
| 1911 | if (!elem_type.isFnOrHasRuntimeBitsIgnoreComptime()) { | |
| 1908 | 1912 | return CValue.undefined_ptr; |
| 1909 | 1913 | } |
| 1910 | 1914 | |
| ... | ... | @@ -1979,7 +1983,7 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue { |
| 1979 | 1983 | fn airRet(f: *Function, inst: Air.Inst.Index) !CValue { |
| 1980 | 1984 | const un_op = f.air.instructions.items(.data)[inst].un_op; |
| 1981 | 1985 | const writer = f.object.writer(); |
| 1982 | if (f.air.typeOf(un_op).isFnOrHasRuntimeBits()) { | |
| 1986 | if (f.air.typeOf(un_op).isFnOrHasRuntimeBitsIgnoreComptime()) { | |
| 1983 | 1987 | const operand = try f.resolveInst(un_op); |
| 1984 | 1988 | try writer.writeAll("return "); |
| 1985 | 1989 | try f.writeCValue(writer, operand); |
| ... | ... | @@ -1995,7 +1999,7 @@ fn airRetLoad(f: *Function, inst: Air.Inst.Index) !CValue { |
| 1995 | 1999 | const writer = f.object.writer(); |
| 1996 | 2000 | const ptr_ty = f.air.typeOf(un_op); |
| 1997 | 2001 | const ret_ty = ptr_ty.childType(); |
| 1998 | if (!ret_ty.isFnOrHasRuntimeBits()) { | |
| 2002 | if (!ret_ty.isFnOrHasRuntimeBitsIgnoreComptime()) { | |
| 1999 | 2003 | try writer.writeAll("return;\n"); |
| 2000 | 2004 | } |
| 2001 | 2005 | const ptr = try f.resolveInst(un_op); |
| ... | ... | @@ -2561,7 +2565,18 @@ fn airSlice(f: *Function, inst: Air.Inst.Index) !CValue { |
| 2561 | 2565 | return local; |
| 2562 | 2566 | } |
| 2563 | 2567 | |
| 2564 | fn airCall(f: *Function, inst: Air.Inst.Index) !CValue { | |
| 2568 | fn airCall( | |
| 2569 | f: *Function, | |
| 2570 | inst: Air.Inst.Index, | |
| 2571 | modifier: std.builtin.CallOptions.Modifier, | |
| 2572 | ) !CValue { | |
| 2573 | switch (modifier) { | |
| 2574 | .auto => {}, | |
| 2575 | .always_tail => return f.fail("TODO: C backend: call with always_tail attribute", .{}), | |
| 2576 | .never_tail => return f.fail("TODO: C backend: call with never_tail attribute", .{}), | |
| 2577 | .never_inline => return f.fail("TODO: C backend: call with never_inline attribute", .{}), | |
| 2578 | else => unreachable, | |
| 2579 | } | |
| 2565 | 2580 | const pl_op = f.air.instructions.items(.data)[inst].pl_op; |
| 2566 | 2581 | const extra = f.air.extraData(Air.Call, pl_op.payload); |
| 2567 | 2582 | const args = @bitCast([]const Air.Inst.Ref, f.air.extra[extra.end..][0..extra.data.args_len]); |
src/codegen/llvm.zig+64-30| ... | ... | @@ -661,14 +661,19 @@ pub const Object = struct { |
| 661 | 661 | // If the module does not already have the function, we ignore this function call |
| 662 | 662 | // because we call `updateDeclExports` at the end of `updateFunc` and `updateDecl`. |
| 663 | 663 | const llvm_global = self.decl_map.get(decl) orelse return; |
| 664 | const is_extern = decl.isExtern(); | |
| 665 | if (is_extern) { | |
| 664 | if (decl.isExtern()) { | |
| 666 | 665 | llvm_global.setValueName(decl.name); |
| 667 | 666 | llvm_global.setUnnamedAddr(.False); |
| 668 | 667 | llvm_global.setLinkage(.External); |
| 669 | 668 | if (decl.val.castTag(.variable)) |variable| { |
| 670 | if (variable.data.is_threadlocal) llvm_global.setThreadLocalMode(.GeneralDynamicTLSModel); | |
| 671 | if (variable.data.is_weak_linkage) llvm_global.setLinkage(.ExternalWeak); | |
| 669 | if (variable.data.is_threadlocal) { | |
| 670 | llvm_global.setThreadLocalMode(.GeneralDynamicTLSModel); | |
| 671 | } else { | |
| 672 | llvm_global.setThreadLocalMode(.NotThreadLocal); | |
| 673 | } | |
| 674 | if (variable.data.is_weak_linkage) { | |
| 675 | llvm_global.setLinkage(.ExternalWeak); | |
| 676 | } | |
| 672 | 677 | } |
| 673 | 678 | } else if (exports.len != 0) { |
| 674 | 679 | const exp_name = exports[0].options.name; |
| ... | ... | @@ -681,7 +686,9 @@ pub const Object = struct { |
| 681 | 686 | .LinkOnce => llvm_global.setLinkage(.LinkOnceODR), |
| 682 | 687 | } |
| 683 | 688 | if (decl.val.castTag(.variable)) |variable| { |
| 684 | if (variable.data.is_threadlocal) llvm_global.setThreadLocalMode(.GeneralDynamicTLSModel); | |
| 689 | if (variable.data.is_threadlocal) { | |
| 690 | llvm_global.setThreadLocalMode(.GeneralDynamicTLSModel); | |
| 691 | } | |
| 685 | 692 | } |
| 686 | 693 | // If a Decl is exported more than one time (which is rare), |
| 687 | 694 | // we add aliases for all but the first export. |
| ... | ... | @@ -709,6 +716,14 @@ pub const Object = struct { |
| 709 | 716 | llvm_global.setValueName2(fqn.ptr, fqn.len); |
| 710 | 717 | llvm_global.setLinkage(.Internal); |
| 711 | 718 | llvm_global.setUnnamedAddr(.True); |
| 719 | if (decl.val.castTag(.variable)) |variable| { | |
| 720 | const single_threaded = module.comp.bin_file.options.single_threaded; | |
| 721 | if (variable.data.is_threadlocal and !single_threaded) { | |
| 722 | llvm_global.setThreadLocalMode(.GeneralDynamicTLSModel); | |
| 723 | } else { | |
| 724 | llvm_global.setThreadLocalMode(.NotThreadLocal); | |
| 725 | } | |
| 726 | } | |
| 712 | 727 | } |
| 713 | 728 | } |
| 714 | 729 | |
| ... | ... | @@ -937,19 +952,6 @@ pub const DeclGen = struct { |
| 937 | 952 | const llvm_global = dg.object.llvm_module.addGlobalInAddressSpace(llvm_type, fqn, llvm_addrspace); |
| 938 | 953 | gop.value_ptr.* = llvm_global; |
| 939 | 954 | |
| 940 | if (decl.isExtern()) { | |
| 941 | llvm_global.setValueName(decl.name); | |
| 942 | llvm_global.setUnnamedAddr(.False); | |
| 943 | llvm_global.setLinkage(.External); | |
| 944 | if (decl.val.castTag(.variable)) |variable| { | |
| 945 | if (variable.data.is_threadlocal) llvm_global.setThreadLocalMode(.GeneralDynamicTLSModel); | |
| 946 | if (variable.data.is_weak_linkage) llvm_global.setLinkage(.ExternalWeak); | |
| 947 | } | |
| 948 | } else { | |
| 949 | llvm_global.setLinkage(.Internal); | |
| 950 | llvm_global.setUnnamedAddr(.True); | |
| 951 | } | |
| 952 | ||
| 953 | 955 | return llvm_global; |
| 954 | 956 | } |
| 955 | 957 | |
| ... | ... | @@ -1033,8 +1035,8 @@ pub const DeclGen = struct { |
| 1033 | 1035 | const elem_ty = ptr_info.pointee_type; |
| 1034 | 1036 | const lower_elem_ty = switch (elem_ty.zigTypeTag()) { |
| 1035 | 1037 | .Opaque, .Fn => true, |
| 1036 | .Array => elem_ty.childType().hasRuntimeBits(), | |
| 1037 | else => elem_ty.hasRuntimeBits(), | |
| 1038 | .Array => elem_ty.childType().hasRuntimeBitsIgnoreComptime(), | |
| 1039 | else => elem_ty.hasRuntimeBitsIgnoreComptime(), | |
| 1038 | 1040 | }; |
| 1039 | 1041 | const llvm_elem_ty = if (lower_elem_ty) |
| 1040 | 1042 | try dg.llvmType(elem_ty) |
| ... | ... | @@ -3158,7 +3160,6 @@ pub const FuncGen = struct { |
| 3158 | 3160 | .breakpoint => try self.airBreakpoint(inst), |
| 3159 | 3161 | .ret_addr => try self.airRetAddr(inst), |
| 3160 | 3162 | .frame_addr => try self.airFrameAddress(inst), |
| 3161 | .call => try self.airCall(inst), | |
| 3162 | 3163 | .cond_br => try self.airCondBr(inst), |
| 3163 | 3164 | .intcast => try self.airIntCast(inst), |
| 3164 | 3165 | .trunc => try self.airTrunc(inst), |
| ... | ... | @@ -3175,6 +3176,11 @@ pub const FuncGen = struct { |
| 3175 | 3176 | .slice_ptr => try self.airSliceField(inst, 0), |
| 3176 | 3177 | .slice_len => try self.airSliceField(inst, 1), |
| 3177 | 3178 | |
| 3179 | .call => try self.airCall(inst, .Auto), | |
| 3180 | .call_always_tail => try self.airCall(inst, .AlwaysTail), | |
| 3181 | .call_never_tail => try self.airCall(inst, .NeverTail), | |
| 3182 | .call_never_inline => try self.airCall(inst, .NeverInline), | |
| 3183 | ||
| 3178 | 3184 | .ptr_slice_ptr_ptr => try self.airPtrSliceFieldPtr(inst, 0), |
| 3179 | 3185 | .ptr_slice_len_ptr => try self.airPtrSliceFieldPtr(inst, 1), |
| 3180 | 3186 | |
| ... | ... | @@ -3253,7 +3259,7 @@ pub const FuncGen = struct { |
| 3253 | 3259 | } |
| 3254 | 3260 | } |
| 3255 | 3261 | |
| 3256 | fn airCall(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { | |
| 3262 | fn airCall(self: *FuncGen, inst: Air.Inst.Index, attr: llvm.CallAttr) !?*const llvm.Value { | |
| 3257 | 3263 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| 3258 | 3264 | const extra = self.air.extraData(Air.Call, pl_op.payload); |
| 3259 | 3265 | const args = @bitCast([]const Air.Inst.Ref, self.air.extra[extra.end..][0..extra.data.args_len]); |
| ... | ... | @@ -3298,7 +3304,7 @@ pub const FuncGen = struct { |
| 3298 | 3304 | llvm_args.items.ptr, |
| 3299 | 3305 | @intCast(c_uint, llvm_args.items.len), |
| 3300 | 3306 | toLlvmCallConv(zig_fn_ty.fnCallingConvention(), target), |
| 3301 | .Auto, | |
| 3307 | attr, | |
| 3302 | 3308 | "", |
| 3303 | 3309 | ); |
| 3304 | 3310 | |
| ... | ... | @@ -4063,6 +4069,34 @@ pub const FuncGen = struct { |
| 4063 | 4069 | } |
| 4064 | 4070 | const asm_source = std.mem.sliceAsBytes(self.air.extra[extra_i..])[0..extra.data.source_len]; |
| 4065 | 4071 | |
| 4072 | // hackety hacks until stage2 has proper inline asm in the frontend. | |
| 4073 | var rendered_template = std.ArrayList(u8).init(self.gpa); | |
| 4074 | defer rendered_template.deinit(); | |
| 4075 | ||
| 4076 | const State = enum { start, percent }; | |
| 4077 | ||
| 4078 | var state: State = .start; | |
| 4079 | ||
| 4080 | for (asm_source) |byte| { | |
| 4081 | switch (state) { | |
| 4082 | .start => switch (byte) { | |
| 4083 | '%' => state = .percent, | |
| 4084 | else => try rendered_template.append(byte), | |
| 4085 | }, | |
| 4086 | .percent => switch (byte) { | |
| 4087 | '%' => { | |
| 4088 | try rendered_template.append('%'); | |
| 4089 | state = .start; | |
| 4090 | }, | |
| 4091 | else => { | |
| 4092 | try rendered_template.append('%'); | |
| 4093 | try rendered_template.append(byte); | |
| 4094 | state = .start; | |
| 4095 | }, | |
| 4096 | }, | |
| 4097 | } | |
| 4098 | } | |
| 4099 | ||
| 4066 | 4100 | const ret_ty = self.air.typeOfIndex(inst); |
| 4067 | 4101 | const ret_llvm_ty = try self.dg.llvmType(ret_ty); |
| 4068 | 4102 | const llvm_fn_ty = llvm.functionType( |
| ... | ... | @@ -4073,8 +4107,8 @@ pub const FuncGen = struct { |
| 4073 | 4107 | ); |
| 4074 | 4108 | const asm_fn = llvm.getInlineAsm( |
| 4075 | 4109 | llvm_fn_ty, |
| 4076 | asm_source.ptr, | |
| 4077 | asm_source.len, | |
| 4110 | rendered_template.items.ptr, | |
| 4111 | rendered_template.items.len, | |
| 4078 | 4112 | llvm_constraints.items.ptr, |
| 4079 | 4113 | llvm_constraints.items.len, |
| 4080 | 4114 | llvm.Bool.fromBool(is_volatile), |
| ... | ... | @@ -5206,7 +5240,7 @@ pub const FuncGen = struct { |
| 5206 | 5240 | if (self.liveness.isUnused(inst)) return null; |
| 5207 | 5241 | const ptr_ty = self.air.typeOfIndex(inst); |
| 5208 | 5242 | const pointee_type = ptr_ty.childType(); |
| 5209 | if (!pointee_type.isFnOrHasRuntimeBits()) return self.dg.lowerPtrToVoid(ptr_ty); | |
| 5243 | if (!pointee_type.isFnOrHasRuntimeBitsIgnoreComptime()) return self.dg.lowerPtrToVoid(ptr_ty); | |
| 5210 | 5244 | |
| 5211 | 5245 | const pointee_llvm_ty = try self.dg.llvmType(pointee_type); |
| 5212 | 5246 | const alloca_inst = self.buildAlloca(pointee_llvm_ty); |
| ... | ... | @@ -5220,7 +5254,7 @@ pub const FuncGen = struct { |
| 5220 | 5254 | if (self.liveness.isUnused(inst)) return null; |
| 5221 | 5255 | const ptr_ty = self.air.typeOfIndex(inst); |
| 5222 | 5256 | const ret_ty = ptr_ty.childType(); |
| 5223 | if (!ret_ty.isFnOrHasRuntimeBits()) return self.dg.lowerPtrToVoid(ptr_ty); | |
| 5257 | if (!ret_ty.isFnOrHasRuntimeBitsIgnoreComptime()) return self.dg.lowerPtrToVoid(ptr_ty); | |
| 5224 | 5258 | if (self.ret_ptr) |ret_ptr| return ret_ptr; |
| 5225 | 5259 | const ret_llvm_ty = try self.dg.llvmType(ret_ty); |
| 5226 | 5260 | const target = self.dg.module.getTarget(); |
| ... | ... | @@ -5457,7 +5491,7 @@ pub const FuncGen = struct { |
| 5457 | 5491 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 5458 | 5492 | const ptr_ty = self.air.typeOf(bin_op.lhs); |
| 5459 | 5493 | const operand_ty = ptr_ty.childType(); |
| 5460 | if (!operand_ty.isFnOrHasRuntimeBits()) return null; | |
| 5494 | if (!operand_ty.isFnOrHasRuntimeBitsIgnoreComptime()) return null; | |
| 5461 | 5495 | var ptr = try self.resolveInst(bin_op.lhs); |
| 5462 | 5496 | var element = try self.resolveInst(bin_op.rhs); |
| 5463 | 5497 | const opt_abi_ty = self.dg.getAtomicAbiType(operand_ty, false); |
| ... | ... | @@ -6329,7 +6363,7 @@ pub const FuncGen = struct { |
| 6329 | 6363 | |
| 6330 | 6364 | fn load(self: *FuncGen, ptr: *const llvm.Value, ptr_ty: Type) !?*const llvm.Value { |
| 6331 | 6365 | const info = ptr_ty.ptrInfo().data; |
| 6332 | if (!info.pointee_type.hasRuntimeBits()) return null; | |
| 6366 | if (!info.pointee_type.hasRuntimeBitsIgnoreComptime()) return null; | |
| 6333 | 6367 | |
| 6334 | 6368 | const target = self.dg.module.getTarget(); |
| 6335 | 6369 | const ptr_alignment = ptr_ty.ptrAlignment(target); |
| ... | ... | @@ -6384,7 +6418,7 @@ pub const FuncGen = struct { |
| 6384 | 6418 | ) void { |
| 6385 | 6419 | const info = ptr_ty.ptrInfo().data; |
| 6386 | 6420 | const elem_ty = info.pointee_type; |
| 6387 | if (!elem_ty.isFnOrHasRuntimeBits()) { | |
| 6421 | if (!elem_ty.isFnOrHasRuntimeBitsIgnoreComptime()) { | |
| 6388 | 6422 | return; |
| 6389 | 6423 | } |
| 6390 | 6424 | const target = self.dg.module.getTarget(); |
src/print_air.zig+6-1| ... | ... | @@ -227,12 +227,17 @@ const Writer = struct { |
| 227 | 227 | .ptr_elem_ptr, |
| 228 | 228 | => try w.writeTyPlBin(s, inst), |
| 229 | 229 | |
| 230 | .call, | |
| 231 | .call_always_tail, | |
| 232 | .call_never_tail, | |
| 233 | .call_never_inline, | |
| 234 | => try w.writeCall(s, inst), | |
| 235 | ||
| 230 | 236 | .struct_field_ptr => try w.writeStructField(s, inst), |
| 231 | 237 | .struct_field_val => try w.writeStructField(s, inst), |
| 232 | 238 | .constant => try w.writeConstant(s, inst), |
| 233 | 239 | .assembly => try w.writeAssembly(s, inst), |
| 234 | 240 | .dbg_stmt => try w.writeDbgStmt(s, inst), |
| 235 | .call => try w.writeCall(s, inst), | |
| 236 | 241 | .aggregate_init => try w.writeAggregateInit(s, inst), |
| 237 | 242 | .union_init => try w.writeUnionInit(s, inst), |
| 238 | 243 | .br => try w.writeBr(s, inst), |
src/print_zir.zig+1| ... | ... | @@ -1942,6 +1942,7 @@ const Writer = struct { |
| 1942 | 1942 | break :blk init_inst; |
| 1943 | 1943 | }; |
| 1944 | 1944 | try self.writeFlag(stream, ", is_extern", small.is_extern); |
| 1945 | try self.writeFlag(stream, ", is_threadlocal", small.is_threadlocal); | |
| 1945 | 1946 | try self.writeOptionalInstRef(stream, ", align=", align_inst); |
| 1946 | 1947 | try self.writeOptionalInstRef(stream, ", init=", init_inst); |
| 1947 | 1948 | try stream.writeAll("))"); |
src/type.zig+10-1| ... | ... | @@ -2187,7 +2187,8 @@ pub const Type = extern union { |
| 2187 | 2187 | if (fn_info.is_generic) return false; |
| 2188 | 2188 | if (fn_info.is_var_args) return true; |
| 2189 | 2189 | switch (fn_info.cc) { |
| 2190 | // If there was a comptime calling convention, it should also return false here. | |
| 2190 | // If there was a comptime calling convention, | |
| 2191 | // it should also return false here. | |
| 2191 | 2192 | .Inline => return false, |
| 2192 | 2193 | else => {}, |
| 2193 | 2194 | } |
| ... | ... | @@ -2198,6 +2199,14 @@ pub const Type = extern union { |
| 2198 | 2199 | } |
| 2199 | 2200 | } |
| 2200 | 2201 | |
| 2202 | /// Same as `isFnOrHasRuntimeBits` but comptime-only types may return a false positive. | |
| 2203 | pub fn isFnOrHasRuntimeBitsIgnoreComptime(ty: Type) bool { | |
| 2204 | return switch (ty.zigTypeTag()) { | |
| 2205 | .Fn => true, | |
| 2206 | else => return ty.hasRuntimeBitsIgnoreComptime(), | |
| 2207 | }; | |
| 2208 | } | |
| 2209 | ||
| 2201 | 2210 | pub fn isNoReturn(self: Type) bool { |
| 2202 | 2211 | const definitely_correct_result = |
| 2203 | 2212 | self.tag_if_small_enough != .bound_fn and |
test/behavior/basic.zig+8-2| ... | ... | @@ -720,6 +720,11 @@ test "string concatenation" { |
| 720 | 720 | |
| 721 | 721 | test "thread local variable" { |
| 722 | 722 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 723 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | |
| 724 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | |
| 725 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 726 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | |
| 727 | if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch != .x86_64) return error.SkipZigTest; // TODO | |
| 723 | 728 | |
| 724 | 729 | const S = struct { |
| 725 | 730 | threadlocal var t: i32 = 1234; |
| ... | ... | @@ -746,11 +751,12 @@ fn maybe(x: bool) anyerror!?u32 { |
| 746 | 751 | } |
| 747 | 752 | |
| 748 | 753 | test "pointer to thread local array" { |
| 749 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | |
| 750 | 754 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 755 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | |
| 756 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | |
| 751 | 757 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 752 | 758 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 753 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | |
| 759 | if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch != .x86_64) return error.SkipZigTest; // TODO | |
| 754 | 760 | |
| 755 | 761 | const s = "Hello world"; |
| 756 | 762 | std.mem.copy(u8, buffer[0..], s); |
test/behavior/bugs/7250.zig+5| ... | ... | @@ -15,6 +15,11 @@ threadlocal var g_uart0 = nrfx_uart_t{ |
| 15 | 15 | |
| 16 | 16 | test "reference a global threadlocal variable" { |
| 17 | 17 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 18 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | |
| 19 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | |
| 20 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 21 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | |
| 22 | if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch != .x86_64) return error.SkipZigTest; // TODO | |
| 18 | 23 | |
| 19 | 24 | _ = nrfx_uart_rx(&g_uart0); |
| 20 | 25 | } |
test/stage2/aarch64.zig+1-1| ... | ... | @@ -159,7 +159,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 159 | 159 | { |
| 160 | 160 | var case = ctx.exe("hello world with updates", macos_aarch64); |
| 161 | 161 | case.addError("", &[_][]const u8{ |
| 162 | ":99:9: error: struct 'tmp.tmp' has no member named 'main'", | |
| 162 | ":108:9: error: struct 'tmp.tmp' has no member named 'main'", | |
| 163 | 163 | }); |
| 164 | 164 | |
| 165 | 165 | // Incorrect return type |
test/stage2/x86_64.zig+2-2| ... | ... | @@ -1925,7 +1925,7 @@ fn addLinuxTestCases(ctx: *TestContext) !void { |
| 1925 | 1925 | var case = ctx.exe("hello world with updates", linux_x64); |
| 1926 | 1926 | |
| 1927 | 1927 | case.addError("", &[_][]const u8{ |
| 1928 | ":99:9: error: struct 'tmp.tmp' has no member named 'main'", | |
| 1928 | ":108:9: error: struct 'tmp.tmp' has no member named 'main'", | |
| 1929 | 1929 | }); |
| 1930 | 1930 | |
| 1931 | 1931 | // Incorrect return type |
| ... | ... | @@ -2176,7 +2176,7 @@ fn addMacOsTestCases(ctx: *TestContext) !void { |
| 2176 | 2176 | { |
| 2177 | 2177 | var case = ctx.exe("darwin hello world with updates", macos_x64); |
| 2178 | 2178 | case.addError("", &[_][]const u8{ |
| 2179 | ":99:9: error: struct 'tmp.tmp' has no member named 'main'", | |
| 2179 | ":108:9: error: struct 'tmp.tmp' has no member named 'main'", | |
| 2180 | 2180 | }); |
| 2181 | 2181 | |
| 2182 | 2182 | // Incorrect return type |