| author | |
| committer | |
| log | 3ed9cdc1cc848119d857c8e88b17cc3698eaedac |
| tree | fb191657475cbee057f017f7c55e411a0740c8b2 |
| parent | 656b9429d05c4aad2d514e6d4df15326d903e3f4 |
| parent | df507edffe6c1087b5f4786cb64ccaffd02b6848 |
| signature |
21 files changed, 249 insertions(+), 134 deletions(-)
ci/azure/pipelines.yml+1-1| ... | @@ -103,7 +103,7 @@ jobs: | ... | @@ -103,7 +103,7 @@ jobs: |
| 103 | #& "$ZIGINSTALLDIR\bin\zig.exe" test "..\test\behavior.zig" -fno-stage1 -fLLVM -I "..\test" 2>&1 | 103 | #& "$ZIGINSTALLDIR\bin\zig.exe" test "..\test\behavior.zig" -fno-stage1 -fLLVM -I "..\test" 2>&1 |
| 104 | #CheckLastExitCode | 104 | #CheckLastExitCode |
| 105 | 105 | ||
| 106 | & "$ZIGINSTALLDIR\bin\zig.exe" build test-toolchain -Dskip-non-native -Dskip-stage2-tests 2>&1 | 106 | & "$ZIGINSTALLDIR\bin\zig.exe" build test-toolchain -Dskip-non-native -Dskip-stage2-tests -Domit-stage2 2>&1 |
| 107 | CheckLastExitCode | 107 | CheckLastExitCode |
| 108 | & "$ZIGINSTALLDIR\bin\zig.exe" build test-std -Dskip-non-native 2>&1 | 108 | & "$ZIGINSTALLDIR\bin\zig.exe" build test-std -Dskip-non-native 2>&1 |
| 109 | CheckLastExitCode | 109 | CheckLastExitCode |
lib/std/os.zig+1| ... | @@ -2651,6 +2651,7 @@ pub fn renameatW( | ... | @@ -2651,6 +2651,7 @@ pub fn renameatW( |
| 2651 | .creation = windows.FILE_OPEN, | 2651 | .creation = windows.FILE_OPEN, |
| 2652 | .io_mode = .blocking, | 2652 | .io_mode = .blocking, |
| 2653 | .filter = .any, // This function is supposed to rename both files and directories. | 2653 | .filter = .any, // This function is supposed to rename both files and directories. |
| 2654 | .follow_symlinks = false, | ||
| 2654 | }) catch |err| switch (err) { | 2655 | }) catch |err| switch (err) { |
| 2655 | error.WouldBlock => unreachable, // Not possible without `.share_access_nonblocking = true`. | 2656 | error.WouldBlock => unreachable, // Not possible without `.share_access_nonblocking = true`. |
| 2656 | else => |e| return e, | 2657 | else => |e| return e, |
lib/std/pdb.zig+6-3| ... | @@ -310,6 +310,10 @@ pub const SymbolKind = enum(u16) { | ... | @@ -310,6 +310,10 @@ pub const SymbolKind = enum(u16) { |
| 310 | 310 | ||
| 311 | pub const TypeIndex = u32; | 311 | pub const TypeIndex = u32; |
| 312 | 312 | ||
| 313 | // TODO According to this header: | ||
| 314 | // https://github.com/microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L3722 | ||
| 315 | // we should define RecordPrefix as part of the ProcSym structure. | ||
| 316 | // This might be important when we start generating PDB in self-hosted with our own PE linker. | ||
| 313 | pub const ProcSym = extern struct { | 317 | pub const ProcSym = extern struct { |
| 314 | Parent: u32, | 318 | Parent: u32, |
| 315 | End: u32, | 319 | End: u32, |
| ... | @@ -321,8 +325,7 @@ pub const ProcSym = extern struct { | ... | @@ -321,8 +325,7 @@ pub const ProcSym = extern struct { |
| 321 | CodeOffset: u32, | 325 | CodeOffset: u32, |
| 322 | Segment: u16, | 326 | Segment: u16, |
| 323 | Flags: ProcSymFlags, | 327 | Flags: ProcSymFlags, |
| 324 | // following is a null terminated string | 328 | Name: [1]u8, // null-terminated |
| 325 | // Name: [*]u8, | ||
| 326 | }; | 329 | }; |
| 327 | 330 | ||
| 328 | pub const ProcSymFlags = packed struct { | 331 | pub const ProcSymFlags = packed struct { |
| ... | @@ -693,7 +696,7 @@ pub const Pdb = struct { | ... | @@ -693,7 +696,7 @@ pub const Pdb = struct { |
| 693 | .S_LPROC32, .S_GPROC32 => { | 696 | .S_LPROC32, .S_GPROC32 => { |
| 694 | const proc_sym = @ptrCast(*align(1) ProcSym, &module.symbols[symbol_i + @sizeOf(RecordPrefix)]); | 697 | const proc_sym = @ptrCast(*align(1) ProcSym, &module.symbols[symbol_i + @sizeOf(RecordPrefix)]); |
| 695 | if (address >= proc_sym.CodeOffset and address < proc_sym.CodeOffset + proc_sym.CodeSize) { | 698 | if (address >= proc_sym.CodeOffset and address < proc_sym.CodeOffset + proc_sym.CodeSize) { |
| 696 | return mem.sliceTo(@ptrCast([*:0]u8, proc_sym) + @sizeOf(ProcSym), 0); | 699 | return mem.sliceTo(@ptrCast([*:0]u8, &proc_sym.Name[0]), 0); |
| 697 | } | 700 | } |
| 698 | }, | 701 | }, |
| 699 | else => {}, | 702 | else => {}, |
lib/std/zig/system/NativePaths.zig+2| ... | @@ -109,6 +109,8 @@ pub fn detect(allocator: Allocator, native_info: NativeTargetInfo) !NativePaths | ... | @@ -109,6 +109,8 @@ pub fn detect(allocator: Allocator, native_info: NativeTargetInfo) !NativePaths |
| 109 | 109 | ||
| 110 | if (native_target.os.tag != .windows) { | 110 | if (native_target.os.tag != .windows) { |
| 111 | const triple = try native_target.linuxTriple(allocator); | 111 | const triple = try native_target.linuxTriple(allocator); |
| 112 | defer allocator.free(triple); | ||
| 113 | |||
| 112 | const qual = native_target.cpu.arch.ptrBitWidth(); | 114 | const qual = native_target.cpu.arch.ptrBitWidth(); |
| 113 | 115 | ||
| 114 | // TODO: $ ld --verbose | grep SEARCH_DIR | 116 | // TODO: $ ld --verbose | grep SEARCH_DIR |
src/Sema.zig+52-19| ... | @@ -1495,7 +1495,8 @@ pub fn resolveInst(sema: *Sema, zir_ref: Zir.Inst.Ref) !Air.Inst.Ref { | ... | @@ -1495,7 +1495,8 @@ pub fn resolveInst(sema: *Sema, zir_ref: Zir.Inst.Ref) !Air.Inst.Ref { |
| 1495 | 1495 | ||
| 1496 | // Finally, the last section of indexes refers to the map of ZIR=>AIR. | 1496 | // Finally, the last section of indexes refers to the map of ZIR=>AIR. |
| 1497 | const inst = sema.inst_map.get(@intCast(u32, i)).?; | 1497 | const inst = sema.inst_map.get(@intCast(u32, i)).?; |
| 1498 | if (sema.typeOf(inst).tag() == .generic_poison) return error.GenericPoison; | 1498 | const ty = sema.typeOf(inst); |
| 1499 | if (ty.tag() == .generic_poison) return error.GenericPoison; | ||
| 1499 | return inst; | 1500 | return inst; |
| 1500 | } | 1501 | } |
| 1501 | 1502 | ||
| ... | @@ -5570,11 +5571,15 @@ const GenericCallAdapter = struct { | ... | @@ -5570,11 +5571,15 @@ const GenericCallAdapter = struct { |
| 5570 | generic_fn: *Module.Fn, | 5571 | generic_fn: *Module.Fn, |
| 5571 | precomputed_hash: u64, | 5572 | precomputed_hash: u64, |
| 5572 | func_ty_info: Type.Payload.Function.Data, | 5573 | func_ty_info: Type.Payload.Function.Data, |
| 5573 | /// Unlike comptime_args, the Type here is not always present. | 5574 | args: []const Arg, |
| 5574 | /// .generic_poison is used to communicate non-anytype parameters. | ||
| 5575 | comptime_tvs: []const TypedValue, | ||
| 5576 | module: *Module, | 5575 | module: *Module, |
| 5577 | 5576 | ||
| 5577 | const Arg = struct { | ||
| 5578 | ty: Type, | ||
| 5579 | val: Value, | ||
| 5580 | is_anytype: bool, | ||
| 5581 | }; | ||
| 5582 | |||
| 5578 | pub fn eql(ctx: @This(), adapted_key: void, other_key: *Module.Fn) bool { | 5583 | pub fn eql(ctx: @This(), adapted_key: void, other_key: *Module.Fn) bool { |
| 5579 | _ = adapted_key; | 5584 | _ = adapted_key; |
| 5580 | // The generic function Decl is guaranteed to be the first dependency | 5585 | // The generic function Decl is guaranteed to be the first dependency |
| ... | @@ -5585,10 +5590,10 @@ const GenericCallAdapter = struct { | ... | @@ -5585,10 +5590,10 @@ const GenericCallAdapter = struct { |
| 5585 | 5590 | ||
| 5586 | const other_comptime_args = other_key.comptime_args.?; | 5591 | const other_comptime_args = other_key.comptime_args.?; |
| 5587 | for (other_comptime_args[0..ctx.func_ty_info.param_types.len]) |other_arg, i| { | 5592 | for (other_comptime_args[0..ctx.func_ty_info.param_types.len]) |other_arg, i| { |
| 5588 | const this_arg = ctx.comptime_tvs[i]; | 5593 | const this_arg = ctx.args[i]; |
| 5589 | const this_is_comptime = this_arg.val.tag() != .generic_poison; | 5594 | const this_is_comptime = this_arg.val.tag() != .generic_poison; |
| 5590 | const other_is_comptime = other_arg.val.tag() != .generic_poison; | 5595 | const other_is_comptime = other_arg.val.tag() != .generic_poison; |
| 5591 | const this_is_anytype = this_arg.ty.tag() != .generic_poison; | 5596 | const this_is_anytype = this_arg.is_anytype; |
| 5592 | const other_is_anytype = other_key.isAnytypeParam(ctx.module, @intCast(u32, i)); | 5597 | const other_is_anytype = other_key.isAnytypeParam(ctx.module, @intCast(u32, i)); |
| 5593 | 5598 | ||
| 5594 | if (other_is_anytype != this_is_anytype) return false; | 5599 | if (other_is_anytype != this_is_anytype) return false; |
| ... | @@ -5607,7 +5612,17 @@ const GenericCallAdapter = struct { | ... | @@ -5607,7 +5612,17 @@ const GenericCallAdapter = struct { |
| 5607 | } | 5612 | } |
| 5608 | } else if (this_is_comptime) { | 5613 | } else if (this_is_comptime) { |
| 5609 | // Both are comptime parameters but not anytype parameters. | 5614 | // Both are comptime parameters but not anytype parameters. |
| 5610 | if (!this_arg.val.eql(other_arg.val, other_arg.ty, ctx.module)) { | 5615 | // We assert no error is possible here because any lazy values must be resolved |
| 5616 | // before inserting into the generic function hash map. | ||
| 5617 | const is_eql = Value.eqlAdvanced( | ||
| 5618 | this_arg.val, | ||
| 5619 | this_arg.ty, | ||
| 5620 | other_arg.val, | ||
| 5621 | other_arg.ty, | ||
| 5622 | ctx.module, | ||
| 5623 | null, | ||
| 5624 | ) catch unreachable; | ||
| 5625 | if (!is_eql) { | ||
| 5611 | return false; | 5626 | return false; |
| 5612 | } | 5627 | } |
| 5613 | } | 5628 | } |
| ... | @@ -6258,8 +6273,7 @@ fn instantiateGenericCall( | ... | @@ -6258,8 +6273,7 @@ fn instantiateGenericCall( |
| 6258 | var hasher = std.hash.Wyhash.init(0); | 6273 | var hasher = std.hash.Wyhash.init(0); |
| 6259 | std.hash.autoHash(&hasher, @ptrToInt(module_fn)); | 6274 | std.hash.autoHash(&hasher, @ptrToInt(module_fn)); |
| 6260 | 6275 | ||
| 6261 | const comptime_tvs = try sema.arena.alloc(TypedValue, func_ty_info.param_types.len); | 6276 | const generic_args = try sema.arena.alloc(GenericCallAdapter.Arg, func_ty_info.param_types.len); |
| 6262 | |||
| 6263 | { | 6277 | { |
| 6264 | var i: usize = 0; | 6278 | var i: usize = 0; |
| 6265 | for (fn_info.param_body) |inst| { | 6279 | for (fn_info.param_body) |inst| { |
| ... | @@ -6283,8 +6297,9 @@ fn instantiateGenericCall( | ... | @@ -6283,8 +6297,9 @@ fn instantiateGenericCall( |
| 6283 | else => continue, | 6297 | else => continue, |
| 6284 | } | 6298 | } |
| 6285 | 6299 | ||
| 6300 | const arg_ty = sema.typeOf(uncasted_args[i]); | ||
| 6301 | |||
| 6286 | if (is_comptime) { | 6302 | if (is_comptime) { |
| 6287 | const arg_ty = sema.typeOf(uncasted_args[i]); | ||
| 6288 | const arg_val = sema.analyzeGenericCallArgVal(block, .unneeded, uncasted_args[i]) catch |err| switch (err) { | 6303 | const arg_val = sema.analyzeGenericCallArgVal(block, .unneeded, uncasted_args[i]) catch |err| switch (err) { |
| 6289 | error.NeededSourceLocation => { | 6304 | error.NeededSourceLocation => { |
| 6290 | const decl = sema.mod.declPtr(block.src_decl); | 6305 | const decl = sema.mod.declPtr(block.src_decl); |
| ... | @@ -6297,27 +6312,30 @@ fn instantiateGenericCall( | ... | @@ -6297,27 +6312,30 @@ fn instantiateGenericCall( |
| 6297 | arg_val.hash(arg_ty, &hasher, mod); | 6312 | arg_val.hash(arg_ty, &hasher, mod); |
| 6298 | if (is_anytype) { | 6313 | if (is_anytype) { |
| 6299 | arg_ty.hashWithHasher(&hasher, mod); | 6314 | arg_ty.hashWithHasher(&hasher, mod); |
| 6300 | comptime_tvs[i] = .{ | 6315 | generic_args[i] = .{ |
| 6301 | .ty = arg_ty, | 6316 | .ty = arg_ty, |
| 6302 | .val = arg_val, | 6317 | .val = arg_val, |
| 6318 | .is_anytype = true, | ||
| 6303 | }; | 6319 | }; |
| 6304 | } else { | 6320 | } else { |
| 6305 | comptime_tvs[i] = .{ | 6321 | generic_args[i] = .{ |
| 6306 | .ty = Type.initTag(.generic_poison), | 6322 | .ty = arg_ty, |
| 6307 | .val = arg_val, | 6323 | .val = arg_val, |
| 6324 | .is_anytype = false, | ||
| 6308 | }; | 6325 | }; |
| 6309 | } | 6326 | } |
| 6310 | } else if (is_anytype) { | 6327 | } else if (is_anytype) { |
| 6311 | const arg_ty = sema.typeOf(uncasted_args[i]); | ||
| 6312 | arg_ty.hashWithHasher(&hasher, mod); | 6328 | arg_ty.hashWithHasher(&hasher, mod); |
| 6313 | comptime_tvs[i] = .{ | 6329 | generic_args[i] = .{ |
| 6314 | .ty = arg_ty, | 6330 | .ty = arg_ty, |
| 6315 | .val = Value.initTag(.generic_poison), | 6331 | .val = Value.initTag(.generic_poison), |
| 6332 | .is_anytype = true, | ||
| 6316 | }; | 6333 | }; |
| 6317 | } else { | 6334 | } else { |
| 6318 | comptime_tvs[i] = .{ | 6335 | generic_args[i] = .{ |
| 6319 | .ty = Type.initTag(.generic_poison), | 6336 | .ty = arg_ty, |
| 6320 | .val = Value.initTag(.generic_poison), | 6337 | .val = Value.initTag(.generic_poison), |
| 6338 | .is_anytype = false, | ||
| 6321 | }; | 6339 | }; |
| 6322 | } | 6340 | } |
| 6323 | 6341 | ||
| ... | @@ -6331,7 +6349,7 @@ fn instantiateGenericCall( | ... | @@ -6331,7 +6349,7 @@ fn instantiateGenericCall( |
| 6331 | .generic_fn = module_fn, | 6349 | .generic_fn = module_fn, |
| 6332 | .precomputed_hash = precomputed_hash, | 6350 | .precomputed_hash = precomputed_hash, |
| 6333 | .func_ty_info = func_ty_info, | 6351 | .func_ty_info = func_ty_info, |
| 6334 | .comptime_tvs = comptime_tvs, | 6352 | .args = generic_args, |
| 6335 | .module = mod, | 6353 | .module = mod, |
| 6336 | }; | 6354 | }; |
| 6337 | const gop = try mod.monomorphed_funcs.getOrPutAdapted(gpa, {}, adapter); | 6355 | const gop = try mod.monomorphed_funcs.getOrPutAdapted(gpa, {}, adapter); |
| ... | @@ -11184,6 +11202,21 @@ fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins | ... | @@ -11184,6 +11202,21 @@ fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins |
| 11184 | const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(block, lhs_src, casted_lhs); | 11202 | const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(block, lhs_src, casted_lhs); |
| 11185 | const maybe_rhs_val = try sema.resolveMaybeUndefValIntable(block, rhs_src, casted_rhs); | 11203 | const maybe_rhs_val = try sema.resolveMaybeUndefValIntable(block, rhs_src, casted_rhs); |
| 11186 | 11204 | ||
| 11205 | if ((lhs_ty.zigTypeTag() == .ComptimeFloat and rhs_ty.zigTypeTag() == .ComptimeInt) or | ||
| 11206 | (lhs_ty.zigTypeTag() == .ComptimeInt and rhs_ty.zigTypeTag() == .ComptimeFloat)) | ||
| 11207 | { | ||
| 11208 | // If it makes a difference whether we coerce to ints or floats before doing the division, error. | ||
| 11209 | // If lhs % rhs is 0, it doesn't matter. | ||
| 11210 | const lhs_val = maybe_lhs_val orelse unreachable; | ||
| 11211 | const rhs_val = maybe_rhs_val orelse unreachable; | ||
| 11212 | const rem = lhs_val.floatRem(rhs_val, resolved_type, sema.arena, target) catch unreachable; | ||
| 11213 | if (rem.compareWithZero(.neq)) { | ||
| 11214 | return sema.fail(block, src, "ambiguous coercion of division operands '{s}' and '{s}'; non-zero remainder '{}'", .{ | ||
| 11215 | @tagName(lhs_ty.tag()), @tagName(rhs_ty.tag()), rem.fmtValue(resolved_type, sema.mod), | ||
| 11216 | }); | ||
| 11217 | } | ||
| 11218 | } | ||
| 11219 | |||
| 11187 | // TODO: emit compile error when .div is used on integers and there would be an | 11220 | // TODO: emit compile error when .div is used on integers and there would be an |
| 11188 | // ambiguous result between div_floor and div_trunc. | 11221 | // ambiguous result between div_floor and div_trunc. |
| 11189 | 11222 | ||
| ... | @@ -30124,7 +30157,7 @@ fn valuesEqual( | ... | @@ -30124,7 +30157,7 @@ fn valuesEqual( |
| 30124 | rhs: Value, | 30157 | rhs: Value, |
| 30125 | ty: Type, | 30158 | ty: Type, |
| 30126 | ) CompileError!bool { | 30159 | ) CompileError!bool { |
| 30127 | return Value.eqlAdvanced(lhs, rhs, ty, sema.mod, sema.kit(block, src)); | 30160 | return Value.eqlAdvanced(lhs, ty, rhs, ty, sema.mod, sema.kit(block, src)); |
| 30128 | } | 30161 | } |
| 30129 | 30162 | ||
| 30130 | /// Asserts the values are comparable vectors of type `ty`. | 30163 | /// Asserts the values are comparable vectors of type `ty`. |
src/value.zig+54-23| ... | @@ -2004,6 +2004,10 @@ pub const Value = extern union { | ... | @@ -2004,6 +2004,10 @@ pub const Value = extern union { |
| 2004 | return (try orderAgainstZeroAdvanced(lhs, sema_kit)).compare(op); | 2004 | return (try orderAgainstZeroAdvanced(lhs, sema_kit)).compare(op); |
| 2005 | } | 2005 | } |
| 2006 | 2006 | ||
| 2007 | pub fn eql(a: Value, b: Value, ty: Type, mod: *Module) bool { | ||
| 2008 | return eqlAdvanced(a, ty, b, ty, mod, null) catch unreachable; | ||
| 2009 | } | ||
| 2010 | |||
| 2007 | /// This function is used by hash maps and so treats floating-point NaNs as equal | 2011 | /// This function is used by hash maps and so treats floating-point NaNs as equal |
| 2008 | /// to each other, and not equal to other floating-point values. | 2012 | /// to each other, and not equal to other floating-point values. |
| 2009 | /// Similarly, it treats `undef` as a distinct value from all other values. | 2013 | /// Similarly, it treats `undef` as a distinct value from all other values. |
| ... | @@ -2012,13 +2016,10 @@ pub const Value = extern union { | ... | @@ -2012,13 +2016,10 @@ pub const Value = extern union { |
| 2012 | /// for `a`. This function must act *as if* `a` has been coerced to `ty`. This complication | 2016 | /// for `a`. This function must act *as if* `a` has been coerced to `ty`. This complication |
| 2013 | /// is required in order to make generic function instantiation efficient - specifically | 2017 | /// is required in order to make generic function instantiation efficient - specifically |
| 2014 | /// the insertion into the monomorphized function table. | 2018 | /// the insertion into the monomorphized function table. |
| 2015 | pub fn eql(a: Value, b: Value, ty: Type, mod: *Module) bool { | ||
| 2016 | return eqlAdvanced(a, b, ty, mod, null) catch unreachable; | ||
| 2017 | } | ||
| 2018 | |||
| 2019 | /// If `null` is provided for `sema_kit` then it is guaranteed no error will be returned. | 2019 | /// If `null` is provided for `sema_kit` then it is guaranteed no error will be returned. |
| 2020 | pub fn eqlAdvanced( | 2020 | pub fn eqlAdvanced( |
| 2021 | a: Value, | 2021 | a: Value, |
| 2022 | a_ty: Type, | ||
| 2022 | b: Value, | 2023 | b: Value, |
| 2023 | ty: Type, | 2024 | ty: Type, |
| 2024 | mod: *Module, | 2025 | mod: *Module, |
| ... | @@ -2044,33 +2045,34 @@ pub const Value = extern union { | ... | @@ -2044,33 +2045,34 @@ pub const Value = extern union { |
| 2044 | const a_payload = a.castTag(.opt_payload).?.data; | 2045 | const a_payload = a.castTag(.opt_payload).?.data; |
| 2045 | const b_payload = b.castTag(.opt_payload).?.data; | 2046 | const b_payload = b.castTag(.opt_payload).?.data; |
| 2046 | var buffer: Type.Payload.ElemType = undefined; | 2047 | var buffer: Type.Payload.ElemType = undefined; |
| 2047 | return eqlAdvanced(a_payload, b_payload, ty.optionalChild(&buffer), mod, sema_kit); | 2048 | const payload_ty = ty.optionalChild(&buffer); |
| 2049 | return eqlAdvanced(a_payload, payload_ty, b_payload, payload_ty, mod, sema_kit); | ||
| 2048 | }, | 2050 | }, |
| 2049 | .slice => { | 2051 | .slice => { |
| 2050 | const a_payload = a.castTag(.slice).?.data; | 2052 | const a_payload = a.castTag(.slice).?.data; |
| 2051 | const b_payload = b.castTag(.slice).?.data; | 2053 | const b_payload = b.castTag(.slice).?.data; |
| 2052 | if (!(try eqlAdvanced(a_payload.len, b_payload.len, Type.usize, mod, sema_kit))) { | 2054 | if (!(try eqlAdvanced(a_payload.len, Type.usize, b_payload.len, Type.usize, mod, sema_kit))) { |
| 2053 | return false; | 2055 | return false; |
| 2054 | } | 2056 | } |
| 2055 | 2057 | ||
| 2056 | var ptr_buf: Type.SlicePtrFieldTypeBuffer = undefined; | 2058 | var ptr_buf: Type.SlicePtrFieldTypeBuffer = undefined; |
| 2057 | const ptr_ty = ty.slicePtrFieldType(&ptr_buf); | 2059 | const ptr_ty = ty.slicePtrFieldType(&ptr_buf); |
| 2058 | 2060 | ||
| 2059 | return eqlAdvanced(a_payload.ptr, b_payload.ptr, ptr_ty, mod, sema_kit); | 2061 | return eqlAdvanced(a_payload.ptr, ptr_ty, b_payload.ptr, ptr_ty, mod, sema_kit); |
| 2060 | }, | 2062 | }, |
| 2061 | .elem_ptr => { | 2063 | .elem_ptr => { |
| 2062 | const a_payload = a.castTag(.elem_ptr).?.data; | 2064 | const a_payload = a.castTag(.elem_ptr).?.data; |
| 2063 | const b_payload = b.castTag(.elem_ptr).?.data; | 2065 | const b_payload = b.castTag(.elem_ptr).?.data; |
| 2064 | if (a_payload.index != b_payload.index) return false; | 2066 | if (a_payload.index != b_payload.index) return false; |
| 2065 | 2067 | ||
| 2066 | return eqlAdvanced(a_payload.array_ptr, b_payload.array_ptr, ty, mod, sema_kit); | 2068 | return eqlAdvanced(a_payload.array_ptr, ty, b_payload.array_ptr, ty, mod, sema_kit); |
| 2067 | }, | 2069 | }, |
| 2068 | .field_ptr => { | 2070 | .field_ptr => { |
| 2069 | const a_payload = a.castTag(.field_ptr).?.data; | 2071 | const a_payload = a.castTag(.field_ptr).?.data; |
| 2070 | const b_payload = b.castTag(.field_ptr).?.data; | 2072 | const b_payload = b.castTag(.field_ptr).?.data; |
| 2071 | if (a_payload.field_index != b_payload.field_index) return false; | 2073 | if (a_payload.field_index != b_payload.field_index) return false; |
| 2072 | 2074 | ||
| 2073 | return eqlAdvanced(a_payload.container_ptr, b_payload.container_ptr, ty, mod, sema_kit); | 2075 | return eqlAdvanced(a_payload.container_ptr, ty, b_payload.container_ptr, ty, mod, sema_kit); |
| 2074 | }, | 2076 | }, |
| 2075 | .@"error" => { | 2077 | .@"error" => { |
| 2076 | const a_name = a.castTag(.@"error").?.data.name; | 2078 | const a_name = a.castTag(.@"error").?.data.name; |
| ... | @@ -2080,7 +2082,8 @@ pub const Value = extern union { | ... | @@ -2080,7 +2082,8 @@ pub const Value = extern union { |
| 2080 | .eu_payload => { | 2082 | .eu_payload => { |
| 2081 | const a_payload = a.castTag(.eu_payload).?.data; | 2083 | const a_payload = a.castTag(.eu_payload).?.data; |
| 2082 | const b_payload = b.castTag(.eu_payload).?.data; | 2084 | const b_payload = b.castTag(.eu_payload).?.data; |
| 2083 | return eqlAdvanced(a_payload, b_payload, ty.errorUnionPayload(), mod, sema_kit); | 2085 | const payload_ty = ty.errorUnionPayload(); |
| 2086 | return eqlAdvanced(a_payload, payload_ty, b_payload, payload_ty, mod, sema_kit); | ||
| 2084 | }, | 2087 | }, |
| 2085 | .eu_payload_ptr => @panic("TODO: Implement more pointer eql cases"), | 2088 | .eu_payload_ptr => @panic("TODO: Implement more pointer eql cases"), |
| 2086 | .opt_payload_ptr => @panic("TODO: Implement more pointer eql cases"), | 2089 | .opt_payload_ptr => @panic("TODO: Implement more pointer eql cases"), |
| ... | @@ -2098,7 +2101,7 @@ pub const Value = extern union { | ... | @@ -2098,7 +2101,7 @@ pub const Value = extern union { |
| 2098 | const types = ty.tupleFields().types; | 2101 | const types = ty.tupleFields().types; |
| 2099 | assert(types.len == a_field_vals.len); | 2102 | assert(types.len == a_field_vals.len); |
| 2100 | for (types) |field_ty, i| { | 2103 | for (types) |field_ty, i| { |
| 2101 | if (!(try eqlAdvanced(a_field_vals[i], b_field_vals[i], field_ty, mod, sema_kit))) { | 2104 | if (!(try eqlAdvanced(a_field_vals[i], field_ty, b_field_vals[i], field_ty, mod, sema_kit))) { |
| 2102 | return false; | 2105 | return false; |
| 2103 | } | 2106 | } |
| 2104 | } | 2107 | } |
| ... | @@ -2109,7 +2112,7 @@ pub const Value = extern union { | ... | @@ -2109,7 +2112,7 @@ pub const Value = extern union { |
| 2109 | const fields = ty.structFields().values(); | 2112 | const fields = ty.structFields().values(); |
| 2110 | assert(fields.len == a_field_vals.len); | 2113 | assert(fields.len == a_field_vals.len); |
| 2111 | for (fields) |field, i| { | 2114 | for (fields) |field, i| { |
| 2112 | if (!(try eqlAdvanced(a_field_vals[i], b_field_vals[i], field.ty, mod, sema_kit))) { | 2115 | if (!(try eqlAdvanced(a_field_vals[i], field.ty, b_field_vals[i], field.ty, mod, sema_kit))) { |
| 2113 | return false; | 2116 | return false; |
| 2114 | } | 2117 | } |
| 2115 | } | 2118 | } |
| ... | @@ -2120,7 +2123,7 @@ pub const Value = extern union { | ... | @@ -2120,7 +2123,7 @@ pub const Value = extern union { |
| 2120 | for (a_field_vals) |a_elem, i| { | 2123 | for (a_field_vals) |a_elem, i| { |
| 2121 | const b_elem = b_field_vals[i]; | 2124 | const b_elem = b_field_vals[i]; |
| 2122 | 2125 | ||
| 2123 | if (!(try eqlAdvanced(a_elem, b_elem, elem_ty, mod, sema_kit))) { | 2126 | if (!(try eqlAdvanced(a_elem, elem_ty, b_elem, elem_ty, mod, sema_kit))) { |
| 2124 | return false; | 2127 | return false; |
| 2125 | } | 2128 | } |
| 2126 | } | 2129 | } |
| ... | @@ -2132,7 +2135,7 @@ pub const Value = extern union { | ... | @@ -2132,7 +2135,7 @@ pub const Value = extern union { |
| 2132 | switch (ty.containerLayout()) { | 2135 | switch (ty.containerLayout()) { |
| 2133 | .Packed, .Extern => { | 2136 | .Packed, .Extern => { |
| 2134 | const tag_ty = ty.unionTagTypeHypothetical(); | 2137 | const tag_ty = ty.unionTagTypeHypothetical(); |
| 2135 | if (!(try a_union.tag.eqlAdvanced(b_union.tag, tag_ty, mod, sema_kit))) { | 2138 | if (!(try eqlAdvanced(a_union.tag, tag_ty, b_union.tag, tag_ty, mod, sema_kit))) { |
| 2136 | // In this case, we must disregard mismatching tags and compare | 2139 | // In this case, we must disregard mismatching tags and compare |
| 2137 | // based on the in-memory bytes of the payloads. | 2140 | // based on the in-memory bytes of the payloads. |
| 2138 | @panic("TODO comptime comparison of extern union values with mismatching tags"); | 2141 | @panic("TODO comptime comparison of extern union values with mismatching tags"); |
| ... | @@ -2140,13 +2143,13 @@ pub const Value = extern union { | ... | @@ -2140,13 +2143,13 @@ pub const Value = extern union { |
| 2140 | }, | 2143 | }, |
| 2141 | .Auto => { | 2144 | .Auto => { |
| 2142 | const tag_ty = ty.unionTagTypeHypothetical(); | 2145 | const tag_ty = ty.unionTagTypeHypothetical(); |
| 2143 | if (!(try a_union.tag.eqlAdvanced(b_union.tag, tag_ty, mod, sema_kit))) { | 2146 | if (!(try eqlAdvanced(a_union.tag, tag_ty, b_union.tag, tag_ty, mod, sema_kit))) { |
| 2144 | return false; | 2147 | return false; |
| 2145 | } | 2148 | } |
| 2146 | }, | 2149 | }, |
| 2147 | } | 2150 | } |
| 2148 | const active_field_ty = ty.unionFieldType(a_union.tag, mod); | 2151 | const active_field_ty = ty.unionFieldType(a_union.tag, mod); |
| 2149 | return a_union.val.eqlAdvanced(b_union.val, active_field_ty, mod, sema_kit); | 2152 | return eqlAdvanced(a_union.val, active_field_ty, b_union.val, active_field_ty, mod, sema_kit); |
| 2150 | }, | 2153 | }, |
| 2151 | else => {}, | 2154 | else => {}, |
| 2152 | } else if (a_tag == .null_value or b_tag == .null_value) { | 2155 | } else if (a_tag == .null_value or b_tag == .null_value) { |
| ... | @@ -2180,7 +2183,7 @@ pub const Value = extern union { | ... | @@ -2180,7 +2183,7 @@ pub const Value = extern union { |
| 2180 | const b_val = b.enumToInt(ty, &buf_b); | 2183 | const b_val = b.enumToInt(ty, &buf_b); |
| 2181 | var buf_ty: Type.Payload.Bits = undefined; | 2184 | var buf_ty: Type.Payload.Bits = undefined; |
| 2182 | const int_ty = ty.intTagType(&buf_ty); | 2185 | const int_ty = ty.intTagType(&buf_ty); |
| 2183 | return eqlAdvanced(a_val, b_val, int_ty, mod, sema_kit); | 2186 | return eqlAdvanced(a_val, int_ty, b_val, int_ty, mod, sema_kit); |
| 2184 | }, | 2187 | }, |
| 2185 | .Array, .Vector => { | 2188 | .Array, .Vector => { |
| 2186 | const len = ty.arrayLen(); | 2189 | const len = ty.arrayLen(); |
| ... | @@ -2191,17 +2194,44 @@ pub const Value = extern union { | ... | @@ -2191,17 +2194,44 @@ pub const Value = extern union { |
| 2191 | while (i < len) : (i += 1) { | 2194 | while (i < len) : (i += 1) { |
| 2192 | const a_elem = elemValueBuffer(a, mod, i, &a_buf); | 2195 | const a_elem = elemValueBuffer(a, mod, i, &a_buf); |
| 2193 | const b_elem = elemValueBuffer(b, mod, i, &b_buf); | 2196 | const b_elem = elemValueBuffer(b, mod, i, &b_buf); |
| 2194 | if (!(try eqlAdvanced(a_elem, b_elem, elem_ty, mod, sema_kit))) { | 2197 | if (!(try eqlAdvanced(a_elem, elem_ty, b_elem, elem_ty, mod, sema_kit))) { |
| 2195 | return false; | 2198 | return false; |
| 2196 | } | 2199 | } |
| 2197 | } | 2200 | } |
| 2198 | return true; | 2201 | return true; |
| 2199 | }, | 2202 | }, |
| 2200 | .Struct => { | 2203 | .Struct => { |
| 2201 | // A tuple can be represented with .empty_struct_value, | 2204 | // A struct can be represented with one of: |
| 2202 | // the_one_possible_value, .aggregate in which case we could | 2205 | // .empty_struct_value, |
| 2203 | // end up here and the values are equal if the type has zero fields. | 2206 | // .the_one_possible_value, |
| 2204 | return ty.isTupleOrAnonStruct() and ty.structFieldCount() != 0; | 2207 | // .aggregate, |
| 2208 | // Note that we already checked above for matching tags, e.g. both .aggregate. | ||
| 2209 | return ty.onePossibleValue() != null; | ||
| 2210 | }, | ||
| 2211 | .Union => { | ||
| 2212 | // Here we have to check for value equality, as-if `a` has been coerced to `ty`. | ||
| 2213 | if (ty.onePossibleValue() != null) { | ||
| 2214 | return true; | ||
| 2215 | } | ||
| 2216 | if (a_ty.castTag(.anon_struct)) |payload| { | ||
| 2217 | const tuple = payload.data; | ||
| 2218 | if (tuple.values.len != 1) { | ||
| 2219 | return false; | ||
| 2220 | } | ||
| 2221 | const field_name = tuple.names[0]; | ||
| 2222 | const union_obj = ty.cast(Type.Payload.Union).?.data; | ||
| 2223 | const field_index = union_obj.fields.getIndex(field_name) orelse return false; | ||
| 2224 | const tag_and_val = b.castTag(.@"union").?.data; | ||
| 2225 | var field_tag_buf: Value.Payload.U32 = .{ | ||
| 2226 | .base = .{ .tag = .enum_field_index }, | ||
| 2227 | .data = @intCast(u32, field_index), | ||
| 2228 | }; | ||
| 2229 | const field_tag = Value.initPayload(&field_tag_buf.base); | ||
| 2230 | const tag_matches = tag_and_val.tag.eql(field_tag, union_obj.tag_ty, mod); | ||
| 2231 | if (!tag_matches) return false; | ||
| 2232 | return eqlAdvanced(tag_and_val.val, union_obj.tag_ty, tuple.values[0], tuple.types[0], mod, sema_kit); | ||
| 2233 | } | ||
| 2234 | return false; | ||
| 2205 | }, | 2235 | }, |
| 2206 | .Float => { | 2236 | .Float => { |
| 2207 | switch (ty.floatBits(target)) { | 2237 | switch (ty.floatBits(target)) { |
| ... | @@ -2230,7 +2260,8 @@ pub const Value = extern union { | ... | @@ -2230,7 +2260,8 @@ pub const Value = extern union { |
| 2230 | .base = .{ .tag = .opt_payload }, | 2260 | .base = .{ .tag = .opt_payload }, |
| 2231 | .data = a, | 2261 | .data = a, |
| 2232 | }; | 2262 | }; |
| 2233 | return eqlAdvanced(Value.initPayload(&buffer.base), b, ty, mod, sema_kit); | 2263 | const opt_val = Value.initPayload(&buffer.base); |
| 2264 | return eqlAdvanced(opt_val, ty, b, ty, mod, sema_kit); | ||
| 2234 | } | 2265 | } |
| 2235 | }, | 2266 | }, |
| 2236 | else => {}, | 2267 | else => {}, |
test/behavior/floatop.zig+4-4| ... | @@ -194,8 +194,8 @@ fn testSin() !void { | ... | @@ -194,8 +194,8 @@ fn testSin() !void { |
| 194 | const eps = epsForType(ty); | 194 | const eps = epsForType(ty); |
| 195 | try expect(@sin(@as(ty, 0)) == 0); | 195 | try expect(@sin(@as(ty, 0)) == 0); |
| 196 | try expect(math.approxEqAbs(ty, @sin(@as(ty, std.math.pi)), 0, eps)); | 196 | try expect(math.approxEqAbs(ty, @sin(@as(ty, std.math.pi)), 0, eps)); |
| 197 | try expect(math.approxEqAbs(ty, @sin(@as(ty, std.math.pi / 2)), 1, eps)); | 197 | try expect(math.approxEqAbs(ty, @sin(@as(ty, std.math.pi / 2.0)), 1, eps)); |
| 198 | try expect(math.approxEqAbs(ty, @sin(@as(ty, std.math.pi / 4)), 0.7071067811865475, eps)); | 198 | try expect(math.approxEqAbs(ty, @sin(@as(ty, std.math.pi / 4.0)), 0.7071067811865475, eps)); |
| 199 | } | 199 | } |
| 200 | 200 | ||
| 201 | { | 201 | { |
| ... | @@ -228,8 +228,8 @@ fn testCos() !void { | ... | @@ -228,8 +228,8 @@ fn testCos() !void { |
| 228 | const eps = epsForType(ty); | 228 | const eps = epsForType(ty); |
| 229 | try expect(@cos(@as(ty, 0)) == 1); | 229 | try expect(@cos(@as(ty, 0)) == 1); |
| 230 | try expect(math.approxEqAbs(ty, @cos(@as(ty, std.math.pi)), -1, eps)); | 230 | try expect(math.approxEqAbs(ty, @cos(@as(ty, std.math.pi)), -1, eps)); |
| 231 | try expect(math.approxEqAbs(ty, @cos(@as(ty, std.math.pi / 2)), 0, eps)); | 231 | try expect(math.approxEqAbs(ty, @cos(@as(ty, std.math.pi / 2.0)), 0, eps)); |
| 232 | try expect(math.approxEqAbs(ty, @cos(@as(ty, std.math.pi / 4)), 0.7071067811865475, eps)); | 232 | try expect(math.approxEqAbs(ty, @cos(@as(ty, std.math.pi / 4.0)), 0.7071067811865475, eps)); |
| 233 | } | 233 | } |
| 234 | 234 | ||
| 235 | { | 235 | { |
test/behavior/generics.zig+19| ... | @@ -323,3 +323,22 @@ test "generic function instantiation non-duplicates" { | ... | @@ -323,3 +323,22 @@ test "generic function instantiation non-duplicates" { |
| 323 | S.copy(u8, &buffer, "hello"); | 323 | S.copy(u8, &buffer, "hello"); |
| 324 | S.copy(u8, &buffer, "hello2"); | 324 | S.copy(u8, &buffer, "hello2"); |
| 325 | } | 325 | } |
| 326 | |||
| 327 | test "generic instantiation of tagged union with only one field" { | ||
| 328 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | ||
| 329 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | ||
| 330 | if (builtin.os.tag == .wasi) return error.SkipZigTest; | ||
| 331 | |||
| 332 | const S = struct { | ||
| 333 | const U = union(enum) { | ||
| 334 | s: []const u8, | ||
| 335 | }; | ||
| 336 | |||
| 337 | fn foo(comptime u: U) usize { | ||
| 338 | return u.s.len; | ||
| 339 | } | ||
| 340 | }; | ||
| 341 | |||
| 342 | try expect(S.foo(.{ .s = "a" }) == 1); | ||
| 343 | try expect(S.foo(.{ .s = "ab" }) == 2); | ||
| 344 | } |
test/cases/compile_errors/ambiguous_coercion_of_division_operands.zig created+23| ... | @@ -0,0 +1,23 @@ | ||
| 1 | export fn entry1() void { | ||
| 2 | var f: f32 = 54.0 / 5; | ||
| 3 | _ = f; | ||
| 4 | } | ||
| 5 | export fn entry2() void { | ||
| 6 | var f: f32 = 54 / 5.0; | ||
| 7 | _ = f; | ||
| 8 | } | ||
| 9 | export fn entry3() void { | ||
| 10 | var f: f32 = 55.0 / 5; | ||
| 11 | _ = f; | ||
| 12 | } | ||
| 13 | export fn entry4() void { | ||
| 14 | var f: f32 = 55 / 5.0; | ||
| 15 | _ = f; | ||
| 16 | } | ||
| 17 | |||
| 18 | // error | ||
| 19 | // backend=stage2 | ||
| 20 | // target=native | ||
| 21 | // | ||
| 22 | // :2:23: error: ambiguous coercion of division operands 'comptime_float' and 'comptime_int'; non-zero remainder '4' | ||
| 23 | // :6:21: error: ambiguous coercion of division operands 'comptime_int' and 'comptime_float'; non-zero remainder '4' | ||
test/link.zig+30-30| ... | @@ -3,11 +3,6 @@ const builtin = @import("builtin"); | ... | @@ -3,11 +3,6 @@ const builtin = @import("builtin"); |
| 3 | const tests = @import("tests.zig"); | 3 | const tests = @import("tests.zig"); |
| 4 | 4 | ||
| 5 | pub fn addCases(cases: *tests.StandaloneContext) void { | 5 | pub fn addCases(cases: *tests.StandaloneContext) void { |
| 6 | if (builtin.os.tag == .windows) { | ||
| 7 | // https://github.com/ziglang/zig/issues/12421 | ||
| 8 | return; | ||
| 9 | } | ||
| 10 | |||
| 11 | cases.addBuildFile("test/link/bss/build.zig", .{ | 6 | cases.addBuildFile("test/link/bss/build.zig", .{ |
| 12 | .build_modes = false, // we only guarantee zerofill for undefined in Debug | 7 | .build_modes = false, // we only guarantee zerofill for undefined in Debug |
| 13 | }); | 8 | }); |
| ... | @@ -28,11 +23,12 @@ pub fn addCases(cases: *tests.StandaloneContext) void { | ... | @@ -28,11 +23,12 @@ pub fn addCases(cases: *tests.StandaloneContext) void { |
| 28 | .build_modes = true, | 23 | .build_modes = true, |
| 29 | }); | 24 | }); |
| 30 | 25 | ||
| 31 | cases.addBuildFile("test/link/tls/build.zig", .{ | 26 | addWasmCases(cases); |
| 32 | .build_modes = true, | 27 | addMachOCases(cases); |
| 33 | }); | 28 | } |
| 34 | 29 | ||
| 35 | cases.addBuildFile("test/link/wasm/type/build.zig", .{ | 30 | fn addWasmCases(cases: *tests.StandaloneContext) void { |
| 31 | cases.addBuildFile("test/link/wasm/bss/build.zig", .{ | ||
| 36 | .build_modes = true, | 32 | .build_modes = true, |
| 37 | .requires_stage2 = true, | 33 | .requires_stage2 = true, |
| 38 | }); | 34 | }); |
| ... | @@ -47,23 +43,13 @@ pub fn addCases(cases: *tests.StandaloneContext) void { | ... | @@ -47,23 +43,13 @@ pub fn addCases(cases: *tests.StandaloneContext) void { |
| 47 | .requires_stage2 = true, | 43 | .requires_stage2 = true, |
| 48 | }); | 44 | }); |
| 49 | 45 | ||
| 50 | cases.addBuildFile("test/link/wasm/bss/build.zig", .{ | 46 | cases.addBuildFile("test/link/wasm/type/build.zig", .{ |
| 51 | .build_modes = true, | 47 | .build_modes = true, |
| 52 | .requires_stage2 = true, | 48 | .requires_stage2 = true, |
| 53 | }); | 49 | }); |
| 50 | } | ||
| 54 | 51 | ||
| 55 | cases.addBuildFile("test/link/macho/entry/build.zig", .{ | 52 | fn addMachOCases(cases: *tests.StandaloneContext) void { |
| 56 | .build_modes = true, | ||
| 57 | }); | ||
| 58 | |||
| 59 | cases.addBuildFile("test/link/macho/pagezero/build.zig", .{ | ||
| 60 | .build_modes = false, | ||
| 61 | }); | ||
| 62 | |||
| 63 | cases.addBuildFile("test/link/macho/dylib/build.zig", .{ | ||
| 64 | .build_modes = true, | ||
| 65 | }); | ||
| 66 | |||
| 67 | cases.addBuildFile("test/link/macho/dead_strip/build.zig", .{ | 53 | cases.addBuildFile("test/link/macho/dead_strip/build.zig", .{ |
| 68 | .build_modes = false, | 54 | .build_modes = false, |
| 69 | }); | 55 | }); |
| ... | @@ -73,45 +59,59 @@ pub fn addCases(cases: *tests.StandaloneContext) void { | ... | @@ -73,45 +59,59 @@ pub fn addCases(cases: *tests.StandaloneContext) void { |
| 73 | .requires_macos_sdk = true, | 59 | .requires_macos_sdk = true, |
| 74 | }); | 60 | }); |
| 75 | 61 | ||
| 76 | cases.addBuildFile("test/link/macho/needed_library/build.zig", .{ | 62 | cases.addBuildFile("test/link/macho/dylib/build.zig", .{ |
| 77 | .build_modes = true, | 63 | .build_modes = true, |
| 78 | }); | 64 | }); |
| 79 | 65 | ||
| 80 | cases.addBuildFile("test/link/macho/weak_library/build.zig", .{ | 66 | cases.addBuildFile("test/link/macho/entry/build.zig", .{ |
| 81 | .build_modes = true, | 67 | .build_modes = true, |
| 82 | }); | 68 | }); |
| 83 | 69 | ||
| 84 | cases.addBuildFile("test/link/macho/needed_framework/build.zig", .{ | 70 | cases.addBuildFile("test/link/macho/headerpad/build.zig", .{ |
| 85 | .build_modes = true, | 71 | .build_modes = true, |
| 86 | .requires_macos_sdk = true, | 72 | .requires_macos_sdk = true, |
| 87 | }); | 73 | }); |
| 88 | 74 | ||
| 89 | cases.addBuildFile("test/link/macho/weak_framework/build.zig", .{ | 75 | cases.addBuildFile("test/link/macho/needed_framework/build.zig", .{ |
| 90 | .build_modes = true, | 76 | .build_modes = true, |
| 91 | .requires_macos_sdk = true, | 77 | .requires_macos_sdk = true, |
| 92 | }); | 78 | }); |
| 93 | 79 | ||
| 94 | // Try to build and run an Objective-C executable. | 80 | cases.addBuildFile("test/link/macho/needed_library/build.zig", .{ |
| 81 | .build_modes = true, | ||
| 82 | }); | ||
| 83 | |||
| 95 | cases.addBuildFile("test/link/macho/objc/build.zig", .{ | 84 | cases.addBuildFile("test/link/macho/objc/build.zig", .{ |
| 96 | .build_modes = true, | 85 | .build_modes = true, |
| 97 | .requires_macos_sdk = true, | 86 | .requires_macos_sdk = true, |
| 98 | }); | 87 | }); |
| 99 | 88 | ||
| 100 | // Try to build and run an Objective-C++ executable. | ||
| 101 | cases.addBuildFile("test/link/macho/objcpp/build.zig", .{ | 89 | cases.addBuildFile("test/link/macho/objcpp/build.zig", .{ |
| 102 | .build_modes = true, | 90 | .build_modes = true, |
| 103 | .requires_macos_sdk = true, | 91 | .requires_macos_sdk = true, |
| 104 | }); | 92 | }); |
| 105 | 93 | ||
| 94 | cases.addBuildFile("test/link/macho/pagezero/build.zig", .{ | ||
| 95 | .build_modes = false, | ||
| 96 | }); | ||
| 97 | |||
| 98 | cases.addBuildFile("test/link/macho/search_strategy/build.zig", .{ | ||
| 99 | .build_modes = true, | ||
| 100 | }); | ||
| 101 | |||
| 106 | cases.addBuildFile("test/link/macho/stack_size/build.zig", .{ | 102 | cases.addBuildFile("test/link/macho/stack_size/build.zig", .{ |
| 107 | .build_modes = true, | 103 | .build_modes = true, |
| 108 | }); | 104 | }); |
| 109 | 105 | ||
| 110 | cases.addBuildFile("test/link/macho/search_strategy/build.zig", .{ | 106 | cases.addBuildFile("test/link/macho/tls/build.zig", .{ |
| 111 | .build_modes = true, | 107 | .build_modes = true, |
| 112 | }); | 108 | }); |
| 113 | 109 | ||
| 114 | cases.addBuildFile("test/link/macho/headerpad/build.zig", .{ | 110 | cases.addBuildFile("test/link/macho/weak_library/build.zig", .{ |
| 111 | .build_modes = true, | ||
| 112 | }); | ||
| 113 | |||
| 114 | cases.addBuildFile("test/link/macho/weak_framework/build.zig", .{ | ||
| 115 | .build_modes = true, | 115 | .build_modes = true, |
| 116 | .requires_macos_sdk = true, | 116 | .requires_macos_sdk = true, |
| 117 | }); | 117 | }); |
test/link/macho/dead_strip/build.zig+5-3| ... | @@ -4,13 +4,14 @@ const LibExeObjectStep = std.build.LibExeObjStep; | ... | @@ -4,13 +4,14 @@ const LibExeObjectStep = std.build.LibExeObjStep; |
| 4 | 4 | ||
| 5 | pub fn build(b: *Builder) void { | 5 | pub fn build(b: *Builder) void { |
| 6 | const mode = b.standardReleaseOptions(); | 6 | const mode = b.standardReleaseOptions(); |
| 7 | const target: std.zig.CrossTarget = .{ .os_tag = .macos }; | ||
| 7 | 8 | ||
| 8 | const test_step = b.step("test", "Test the program"); | 9 | const test_step = b.step("test", "Test the program"); |
| 9 | test_step.dependOn(b.getInstallStep()); | 10 | test_step.dependOn(b.getInstallStep()); |
| 10 | 11 | ||
| 11 | { | 12 | { |
| 12 | // Without -dead_strip, we expect `iAmUnused` symbol present | 13 | // Without -dead_strip, we expect `iAmUnused` symbol present |
| 13 | const exe = createScenario(b, mode); | 14 | const exe = createScenario(b, mode, target); |
| 14 | 15 | ||
| 15 | const check = exe.checkObject(.macho); | 16 | const check = exe.checkObject(.macho); |
| 16 | check.checkInSymtab(); | 17 | check.checkInSymtab(); |
| ... | @@ -23,7 +24,7 @@ pub fn build(b: *Builder) void { | ... | @@ -23,7 +24,7 @@ pub fn build(b: *Builder) void { |
| 23 | 24 | ||
| 24 | { | 25 | { |
| 25 | // With -dead_strip, no `iAmUnused` symbol should be present | 26 | // With -dead_strip, no `iAmUnused` symbol should be present |
| 26 | const exe = createScenario(b, mode); | 27 | const exe = createScenario(b, mode, target); |
| 27 | exe.link_gc_sections = true; | 28 | exe.link_gc_sections = true; |
| 28 | 29 | ||
| 29 | const check = exe.checkObject(.macho); | 30 | const check = exe.checkObject(.macho); |
| ... | @@ -36,10 +37,11 @@ pub fn build(b: *Builder) void { | ... | @@ -36,10 +37,11 @@ pub fn build(b: *Builder) void { |
| 36 | } | 37 | } |
| 37 | } | 38 | } |
| 38 | 39 | ||
| 39 | fn createScenario(b: *Builder, mode: std.builtin.Mode) *LibExeObjectStep { | 40 | fn createScenario(b: *Builder, mode: std.builtin.Mode, target: std.zig.CrossTarget) *LibExeObjectStep { |
| 40 | const exe = b.addExecutable("test", null); | 41 | const exe = b.addExecutable("test", null); |
| 41 | exe.addCSourceFile("main.c", &[0][]const u8{}); | 42 | exe.addCSourceFile("main.c", &[0][]const u8{}); |
| 42 | exe.setBuildMode(mode); | 43 | exe.setBuildMode(mode); |
| 44 | exe.setTarget(target); | ||
| 43 | exe.linkLibC(); | 45 | exe.linkLibC(); |
| 44 | return exe; | 46 | return exe; |
| 45 | } | 47 | } |
test/link/macho/pagezero/build.zig+3-2| ... | @@ -3,13 +3,14 @@ const Builder = std.build.Builder; | ... | @@ -3,13 +3,14 @@ const Builder = std.build.Builder; |
| 3 | 3 | ||
| 4 | pub fn build(b: *Builder) void { | 4 | pub fn build(b: *Builder) void { |
| 5 | const mode = b.standardReleaseOptions(); | 5 | const mode = b.standardReleaseOptions(); |
| 6 | const target: std.zig.CrossTarget = .{ .os_tag = .macos }; | ||
| 6 | 7 | ||
| 7 | const test_step = b.step("test", "Test"); | 8 | const test_step = b.step("test", "Test"); |
| 8 | test_step.dependOn(b.getInstallStep()); | 9 | test_step.dependOn(b.getInstallStep()); |
| 9 | 10 | ||
| 10 | { | 11 | { |
| 11 | const exe = b.addExecutable("pagezero", null); | 12 | const exe = b.addExecutable("pagezero", null); |
| 12 | exe.setTarget(.{ .os_tag = .macos }); | 13 | exe.setTarget(target); |
| 13 | exe.setBuildMode(mode); | 14 | exe.setBuildMode(mode); |
| 14 | exe.addCSourceFile("main.c", &.{}); | 15 | exe.addCSourceFile("main.c", &.{}); |
| 15 | exe.linkLibC(); | 16 | exe.linkLibC(); |
| ... | @@ -29,7 +30,7 @@ pub fn build(b: *Builder) void { | ... | @@ -29,7 +30,7 @@ pub fn build(b: *Builder) void { |
| 29 | 30 | ||
| 30 | { | 31 | { |
| 31 | const exe = b.addExecutable("no_pagezero", null); | 32 | const exe = b.addExecutable("no_pagezero", null); |
| 32 | exe.setTarget(.{ .os_tag = .macos }); | 33 | exe.setTarget(target); |
| 33 | exe.setBuildMode(mode); | 34 | exe.setBuildMode(mode); |
| 34 | exe.addCSourceFile("main.c", &.{}); | 35 | exe.addCSourceFile("main.c", &.{}); |
| 35 | exe.linkLibC(); | 36 | exe.linkLibC(); |
test/link/macho/search_strategy/build.zig+4-4| ... | @@ -1,17 +1,17 @@ | ... | @@ -1,17 +1,17 @@ |
| 1 | const std = @import("std"); | 1 | const std = @import("std"); |
| 2 | const Builder = std.build.Builder; | 2 | const Builder = std.build.Builder; |
| 3 | const LibExeObjectStep = std.build.LibExeObjStep; | 3 | const LibExeObjectStep = std.build.LibExeObjStep; |
| 4 | const target: std.zig.CrossTarget = .{ .os_tag = .macos }; | ||
| 5 | 4 | ||
| 6 | pub fn build(b: *Builder) void { | 5 | pub fn build(b: *Builder) void { |
| 7 | const mode = b.standardReleaseOptions(); | 6 | const mode = b.standardReleaseOptions(); |
| 7 | const target: std.zig.CrossTarget = .{ .os_tag = .macos }; | ||
| 8 | 8 | ||
| 9 | const test_step = b.step("test", "Test"); | 9 | const test_step = b.step("test", "Test"); |
| 10 | test_step.dependOn(b.getInstallStep()); | 10 | test_step.dependOn(b.getInstallStep()); |
| 11 | 11 | ||
| 12 | { | 12 | { |
| 13 | // -search_dylibs_first | 13 | // -search_dylibs_first |
| 14 | const exe = createScenario(b, mode); | 14 | const exe = createScenario(b, mode, target); |
| 15 | exe.search_strategy = .dylibs_first; | 15 | exe.search_strategy = .dylibs_first; |
| 16 | 16 | ||
| 17 | const check = exe.checkObject(.macho); | 17 | const check = exe.checkObject(.macho); |
| ... | @@ -26,7 +26,7 @@ pub fn build(b: *Builder) void { | ... | @@ -26,7 +26,7 @@ pub fn build(b: *Builder) void { |
| 26 | 26 | ||
| 27 | { | 27 | { |
| 28 | // -search_paths_first | 28 | // -search_paths_first |
| 29 | const exe = createScenario(b, mode); | 29 | const exe = createScenario(b, mode, target); |
| 30 | exe.search_strategy = .paths_first; | 30 | exe.search_strategy = .paths_first; |
| 31 | 31 | ||
| 32 | const run = std.build.EmulatableRunStep.create(b, "run", exe); | 32 | const run = std.build.EmulatableRunStep.create(b, "run", exe); |
| ... | @@ -36,7 +36,7 @@ pub fn build(b: *Builder) void { | ... | @@ -36,7 +36,7 @@ pub fn build(b: *Builder) void { |
| 36 | } | 36 | } |
| 37 | } | 37 | } |
| 38 | 38 | ||
| 39 | fn createScenario(b: *Builder, mode: std.builtin.Mode) *LibExeObjectStep { | 39 | fn createScenario(b: *Builder, mode: std.builtin.Mode, target: std.zig.CrossTarget) *LibExeObjectStep { |
| 40 | const static = b.addStaticLibrary("a", null); | 40 | const static = b.addStaticLibrary("a", null); |
| 41 | static.setTarget(target); | 41 | static.setTarget(target); |
| 42 | static.setBuildMode(mode); | 42 | static.setBuildMode(mode); |
test/link/macho/stack_size/build.zig+2-1| ... | @@ -3,12 +3,13 @@ const Builder = std.build.Builder; | ... | @@ -3,12 +3,13 @@ const Builder = std.build.Builder; |
| 3 | 3 | ||
| 4 | pub fn build(b: *Builder) void { | 4 | pub fn build(b: *Builder) void { |
| 5 | const mode = b.standardReleaseOptions(); | 5 | const mode = b.standardReleaseOptions(); |
| 6 | const target: std.zig.CrossTarget = .{ .os_tag = .macos }; | ||
| 6 | 7 | ||
| 7 | const test_step = b.step("test", "Test"); | 8 | const test_step = b.step("test", "Test"); |
| 8 | test_step.dependOn(b.getInstallStep()); | 9 | test_step.dependOn(b.getInstallStep()); |
| 9 | 10 | ||
| 10 | const exe = b.addExecutable("main", null); | 11 | const exe = b.addExecutable("main", null); |
| 11 | exe.setTarget(.{ .os_tag = .macos }); | 12 | exe.setTarget(target); |
| 12 | exe.setBuildMode(mode); | 13 | exe.setBuildMode(mode); |
| 13 | exe.addCSourceFile("main.c", &.{}); | 14 | exe.addCSourceFile("main.c", &.{}); |
| 14 | exe.linkLibC(); | 15 | exe.linkLibC(); |
test/link/macho/tls/a.c created+5| ... | @@ -0,0 +1,5 @@ | ||
| 1 | _Thread_local int a; | ||
| 2 | |||
| 3 | int getA() { | ||
| 4 | return a; | ||
| 5 | } | ||
test/link/macho/tls/build.zig created+22| ... | @@ -0,0 +1,22 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const Builder = std.build.Builder; | ||
| 3 | |||
| 4 | pub fn build(b: *Builder) void { | ||
| 5 | const mode = b.standardReleaseOptions(); | ||
| 6 | const target: std.zig.CrossTarget = .{ .os_tag = .macos }; | ||
| 7 | |||
| 8 | const lib = b.addSharedLibrary("a", null, b.version(1, 0, 0)); | ||
| 9 | lib.setBuildMode(mode); | ||
| 10 | lib.setTarget(target); | ||
| 11 | lib.addCSourceFile("a.c", &.{}); | ||
| 12 | lib.linkLibC(); | ||
| 13 | |||
| 14 | const test_exe = b.addTest("main.zig"); | ||
| 15 | test_exe.setBuildMode(mode); | ||
| 16 | test_exe.setTarget(target); | ||
| 17 | test_exe.linkLibrary(lib); | ||
| 18 | test_exe.linkLibC(); | ||
| 19 | |||
| 20 | const test_step = b.step("test", "Test it"); | ||
| 21 | test_step.dependOn(&test_exe.step); | ||
| 22 | } | ||
test/link/macho/tls/main.zig created+15| ... | @@ -0,0 +1,15 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | |||
| 3 | extern threadlocal var a: i32; | ||
| 4 | extern fn getA() i32; | ||
| 5 | |||
| 6 | fn getA2() i32 { | ||
| 7 | return a; | ||
| 8 | } | ||
| 9 | |||
| 10 | test { | ||
| 11 | a = 2; | ||
| 12 | try std.testing.expect(getA() == 2); | ||
| 13 | try std.testing.expect(2 == getA2()); | ||
| 14 | try std.testing.expect(getA() == getA2()); | ||
| 15 | } | ||
test/link/tls/a.c deleted-5| ... | @@ -1,5 +0,0 @@ | ||
| 1 | _Thread_local int a; | ||
| 2 | |||
| 3 | int getA() { | ||
| 4 | return a; | ||
| 5 | } | ||
test/link/tls/build.zig deleted-18| ... | @@ -1,18 +0,0 @@ | ||
| 1 | const Builder = @import("std").build.Builder; | ||
| 2 | |||
| 3 | pub fn build(b: *Builder) void { | ||
| 4 | const mode = b.standardReleaseOptions(); | ||
| 5 | |||
| 6 | const lib = b.addSharedLibrary("a", null, b.version(1, 0, 0)); | ||
| 7 | lib.setBuildMode(mode); | ||
| 8 | lib.addCSourceFile("a.c", &.{}); | ||
| 9 | lib.linkLibC(); | ||
| 10 | |||
| 11 | const test_exe = b.addTest("main.zig"); | ||
| 12 | test_exe.setBuildMode(mode); | ||
| 13 | test_exe.linkLibrary(lib); | ||
| 14 | test_exe.linkLibC(); | ||
| 15 | |||
| 16 | const test_step = b.step("test", "Test it"); | ||
| 17 | test_step.dependOn(&test_exe.step); | ||
| 18 | } | ||
test/link/tls/main.zig deleted-15| ... | @@ -1,15 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | |||
| 3 | extern threadlocal var a: i32; | ||
| 4 | extern fn getA() i32; | ||
| 5 | |||
| 6 | fn getA2() i32 { | ||
| 7 | return a; | ||
| 8 | } | ||
| 9 | |||
| 10 | test { | ||
| 11 | a = 2; | ||
| 12 | try std.testing.expect(getA() == 2); | ||
| 13 | try std.testing.expect(2 == getA2()); | ||
| 14 | try std.testing.expect(getA() == getA2()); | ||
| 15 | } | ||
test/stack_traces.zig+1-6| ... | @@ -3,11 +3,6 @@ const os = std.os; | ... | @@ -3,11 +3,6 @@ const os = std.os; |
| 3 | const tests = @import("tests.zig"); | 3 | const tests = @import("tests.zig"); |
| 4 | 4 | ||
| 5 | pub fn addCases(cases: *tests.StackTracesContext) void { | 5 | pub fn addCases(cases: *tests.StackTracesContext) void { |
| 6 | if (@import("builtin").os.tag == .windows) { | ||
| 7 | // https://github.com/ziglang/zig/issues/12422 | ||
| 8 | return; | ||
| 9 | } | ||
| 10 | |||
| 11 | cases.addCase(.{ | 6 | cases.addCase(.{ |
| 12 | .name = "return", | 7 | .name = "return", |
| 13 | .source = | 8 | .source = |
| ... | @@ -178,7 +173,7 @@ pub fn addCases(cases: *tests.StackTracesContext) void { | ... | @@ -178,7 +173,7 @@ pub fn addCases(cases: *tests.StackTracesContext) void { |
| 178 | cases.addCase(.{ | 173 | cases.addCase(.{ |
| 179 | .exclude_os = .{ | 174 | .exclude_os = .{ |
| 180 | .openbsd, // integer overflow | 175 | .openbsd, // integer overflow |
| 181 | .windows, | 176 | .windows, // TODO intermittent failures |
| 182 | }, | 177 | }, |
| 183 | .name = "dumpCurrentStackTrace", | 178 | .name = "dumpCurrentStackTrace", |
| 184 | .source = | 179 | .source = |