From 17eb24a7e4b2bc5740dc15996acc4736833cb2a0 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 23 Oct 2019 18:43:24 -0400 Subject: [PATCH 1/3] move types from builtin to std * All the data types from `@import("builtin")` are moved to `@import("std").builtin`. The target-related types are moved to `std.Target`. This allows the data types to have methods, such as `std.Target.current.isDarwin()`. * `std.os.windows.subsystem` is moved to `std.Target.current.subsystem`. * Remove the concept of the panic package from the compiler implementation. Instead, `std.builtin.panic` is always the panic function. It checks for `@hasDecl(@import("root"), "panic")`, or else provides a default implementation. This is an important step for multibuilds (#3028). Without this change, the types inside the builtin namespace look like different types, when trying to merge builds with different target settings. With this change, Zig can figure out that, e.g., `std.builtin.Os` (the enum type) from one compilation and `std.builtin.Os` from another compilation are the same type, even if the target OS value differs. --- lib/std/build.zig | 435 +------------------------- lib/std/builtin.zig | 413 +++++++++++++++++++++++++ lib/std/os.zig | 34 +- lib/std/os/windows.zig | 26 -- lib/std/special/panic.zig | 31 -- lib/std/std.zig | 2 + lib/std/target.zig | 614 +++++++++++++++++++++++++++++++++++++ src-self-hosted/target.zig | 2 + src/all_types.hpp | 3 - src/analyze.cpp | 89 ++++-- src/analyze.hpp | 2 + src/codegen.cpp | 416 ++++--------------------- src/error.cpp | 1 + src/ir.cpp | 53 +--- src/userland.h | 1 + test/compile_errors.zig | 31 +- 16 files changed, 1208 insertions(+), 945 deletions(-) create mode 100644 lib/std/builtin.zig delete mode 100644 lib/std/special/panic.zig create mode 100644 lib/std/target.zig diff --git a/lib/std/build.zig b/lib/std/build.zig index dd602ba922a1412d9b08c159aa58e75cac1e5440..4f0956d549a0a140184a45426b6f5d925b5af49e 100644 --- a/lib/std/build.zig +++ b/lib/std/build.zig @@ -971,433 +971,14 @@ test "builder.findProgram compiles" { _ = builder.findProgram([_][]const u8{}, [_][]const u8{}) catch null; } -pub const Version = struct { - major: u32, - minor: u32, - patch: u32, -}; +/// Deprecated. Use `builtin.Version`. +pub const Version = builtin.Version; -pub const CrossTarget = struct { - arch: builtin.Arch, - os: builtin.Os, - abi: builtin.Abi, -}; +/// Deprecated. Use `std.Target.Cross`. +pub const CrossTarget = std.Target.Cross; -pub const Target = union(enum) { - Native: void, - Cross: CrossTarget, - - pub fn zigTriple(self: Target, allocator: *Allocator) ![]u8 { - return std.fmt.allocPrint( - allocator, - "{}{}-{}-{}", - @tagName(self.getArch()), - Target.archSubArchName(self.getArch()), - @tagName(self.getOs()), - @tagName(self.getAbi()), - ); - } - - pub fn allocDescription(self: Target, allocator: *Allocator) ![]u8 { - // TODO is there anything else worthy of the description that is not - // already captured in the triple? - return self.zigTriple(allocator); - } - - pub fn zigTripleNoSubArch(self: Target, allocator: *Allocator) ![]u8 { - return std.fmt.allocPrint( - allocator, - "{}-{}-{}", - @tagName(self.getArch()), - @tagName(self.getOs()), - @tagName(self.getAbi()), - ); - } - - pub fn linuxTriple(self: Target, allocator: *Allocator) ![]u8 { - return std.fmt.allocPrint( - allocator, - "{}-{}-{}", - @tagName(self.getArch()), - @tagName(self.getOs()), - @tagName(self.getAbi()), - ); - } - - pub fn parse(text: []const u8) !Target { - var it = mem.separate(text, "-"); - const arch_name = it.next() orelse return error.MissingArchitecture; - const os_name = it.next() orelse return error.MissingOperatingSystem; - const abi_name = it.next(); - - var cross = CrossTarget{ - .arch = try parseArchSub(arch_name), - .os = try parseOs(os_name), - .abi = undefined, - }; - cross.abi = if (abi_name) |n| try parseAbi(n) else defaultAbi(cross.arch, cross.os); - return Target{ .Cross = cross }; - } - - pub fn defaultAbi(arch: builtin.Arch, target_os: builtin.Os) builtin.Abi { - switch (arch) { - .wasm32, .wasm64 => return .musl, - else => {}, - } - switch (target_os) { - .freestanding, - .ananas, - .cloudabi, - .dragonfly, - .lv2, - .solaris, - .haiku, - .minix, - .rtems, - .nacl, - .cnk, - .aix, - .cuda, - .nvcl, - .amdhsa, - .ps4, - .elfiamcu, - .mesa3d, - .contiki, - .amdpal, - .zen, - .hermit, - => return .eabi, - .openbsd, - .macosx, - .freebsd, - .ios, - .tvos, - .watchos, - .fuchsia, - .kfreebsd, - .netbsd, - .hurd, - => return .gnu, - .windows, - .uefi, - => return .msvc, - .linux, - .wasi, - .emscripten, - => return .musl, - } - } - - pub const ParseArchSubError = error{ - UnknownArchitecture, - UnknownSubArchitecture, - }; - - pub fn parseArchSub(text: []const u8) ParseArchSubError!builtin.Arch { - const info = @typeInfo(builtin.Arch); - inline for (info.Union.fields) |field| { - if (mem.eql(u8, text, field.name)) { - if (field.field_type == void) { - return (builtin.Arch)(@field(builtin.Arch, field.name)); - } else { - const sub_info = @typeInfo(field.field_type); - inline for (sub_info.Enum.fields) |sub_field| { - const combined = field.name ++ sub_field.name; - if (mem.eql(u8, text, combined)) { - return @unionInit(builtin.Arch, field.name, @field(field.field_type, sub_field.name)); - } - } - return error.UnknownSubArchitecture; - } - } - } - return error.UnknownArchitecture; - } - - pub fn parseOs(text: []const u8) !builtin.Os { - const info = @typeInfo(builtin.Os); - inline for (info.Enum.fields) |field| { - if (mem.eql(u8, text, field.name)) { - return @field(builtin.Os, field.name); - } - } - return error.UnknownOperatingSystem; - } - - pub fn parseAbi(text: []const u8) !builtin.Abi { - const info = @typeInfo(builtin.Abi); - inline for (info.Enum.fields) |field| { - if (mem.eql(u8, text, field.name)) { - return @field(builtin.Abi, field.name); - } - } - return error.UnknownApplicationBinaryInterface; - } - - fn archSubArchName(arch: builtin.Arch) []const u8 { - return switch (arch) { - .arm => |sub| @tagName(sub), - .armeb => |sub| @tagName(sub), - .thumb => |sub| @tagName(sub), - .thumbeb => |sub| @tagName(sub), - .aarch64 => |sub| @tagName(sub), - .aarch64_be => |sub| @tagName(sub), - .kalimba => |sub| @tagName(sub), - else => "", - }; - } - - pub fn subArchName(self: Target) []const u8 { - switch (self) { - .Native => return archSubArchName(builtin.arch), - .Cross => |cross| return archSubArchName(cross.arch), - } - } - - pub fn oFileExt(self: Target) []const u8 { - return switch (self.getAbi()) { - builtin.Abi.msvc => ".obj", - else => ".o", - }; - } - - pub fn exeFileExt(self: Target) []const u8 { - if (self.isWindows()) { - return ".exe"; - } else if (self.isUefi()) { - return ".efi"; - } else if (self.isWasm()) { - return ".wasm"; - } else { - return ""; - } - } - - pub fn staticLibSuffix(self: Target) []const u8 { - if (self.isWasm()) { - return ".wasm"; - } - switch (self.getAbi()) { - .msvc => return ".lib", - else => return ".a", - } - } - - pub fn dynamicLibSuffix(self: Target) []const u8 { - if (self.isDarwin()) { - return ".dylib"; - } - switch (self.getOs()) { - .windows => return ".dll", - else => return ".so", - } - } - - pub fn libPrefix(self: Target) []const u8 { - if (self.isWasm()) { - return ""; - } - switch (self.getAbi()) { - .msvc => return "", - else => return "lib", - } - } - - pub fn getOs(self: Target) builtin.Os { - return switch (self) { - .Native => builtin.os, - .Cross => |t| t.os, - }; - } - - pub fn getArch(self: Target) builtin.Arch { - switch (self) { - .Native => return builtin.arch, - .Cross => |t| return t.arch, - } - } - - pub fn getAbi(self: Target) builtin.Abi { - switch (self) { - .Native => return builtin.abi, - .Cross => |t| return t.abi, - } - } - - pub fn isMinGW(self: Target) bool { - return self.isWindows() and self.isGnu(); - } - - pub fn isGnu(self: Target) bool { - return switch (self.getAbi()) { - .gnu, .gnuabin32, .gnuabi64, .gnueabi, .gnueabihf, .gnux32 => true, - else => false, - }; - } - - pub fn isDarwin(self: Target) bool { - return switch (self.getOs()) { - .ios, .macosx, .watchos, .tvos => true, - else => false, - }; - } - - pub fn isWindows(self: Target) bool { - return switch (self.getOs()) { - .windows => true, - else => false, - }; - } - - pub fn isLinux(self: Target) bool { - return switch (self.getOs()) { - .linux => true, - else => false, - }; - } - - pub fn isUefi(self: Target) bool { - return switch (self.getOs()) { - .uefi => true, - else => false, - }; - } - - pub fn isWasm(self: Target) bool { - return switch (self.getArch()) { - .wasm32, .wasm64 => true, - else => false, - }; - } - - pub fn isFreeBSD(self: Target) bool { - return switch (self.getOs()) { - .freebsd => true, - else => false, - }; - } - - pub fn isNetBSD(self: Target) bool { - return switch (self.getOs()) { - .netbsd => true, - else => false, - }; - } - - pub fn wantSharedLibSymLinks(self: Target) bool { - return !self.isWindows(); - } - - pub fn osRequiresLibC(self: Target) bool { - return self.isDarwin() or self.isFreeBSD() or self.isNetBSD(); - } - - pub fn getArchPtrBitWidth(self: Target) u32 { - switch (self.getArch()) { - .avr, - .msp430, - => return 16, - - .arc, - .arm, - .armeb, - .hexagon, - .le32, - .mips, - .mipsel, - .powerpc, - .r600, - .riscv32, - .sparc, - .sparcel, - .tce, - .tcele, - .thumb, - .thumbeb, - .i386, - .xcore, - .nvptx, - .amdil, - .hsail, - .spir, - .kalimba, - .shave, - .lanai, - .wasm32, - .renderscript32, - .aarch64_32, - => return 32, - - .aarch64, - .aarch64_be, - .mips64, - .mips64el, - .powerpc64, - .powerpc64le, - .riscv64, - .x86_64, - .nvptx64, - .le64, - .amdil64, - .hsail64, - .spir64, - .wasm64, - .renderscript64, - .amdgcn, - .bpfel, - .bpfeb, - .sparcv9, - .s390x, - => return 64, - } - } - - pub const Executor = union(enum) { - native, - qemu: []const u8, - wine: []const u8, - unavailable, - }; - - pub fn getExternalExecutor(self: Target) Executor { - if (@TagType(Target)(self) == .Native) return .native; - - // If the target OS matches the host OS, we can use QEMU to emulate a foreign architecture. - if (self.getOs() == builtin.os) { - return switch (self.getArch()) { - .aarch64 => Executor{ .qemu = "qemu-aarch64" }, - .aarch64_be => Executor{ .qemu = "qemu-aarch64_be" }, - .arm => Executor{ .qemu = "qemu-arm" }, - .armeb => Executor{ .qemu = "qemu-armeb" }, - .i386 => Executor{ .qemu = "qemu-i386" }, - .mips => Executor{ .qemu = "qemu-mips" }, - .mipsel => Executor{ .qemu = "qemu-mipsel" }, - .mips64 => Executor{ .qemu = "qemu-mips64" }, - .mips64el => Executor{ .qemu = "qemu-mips64el" }, - .powerpc => Executor{ .qemu = "qemu-ppc" }, - .powerpc64 => Executor{ .qemu = "qemu-ppc64" }, - .powerpc64le => Executor{ .qemu = "qemu-ppc64le" }, - .riscv32 => Executor{ .qemu = "qemu-riscv32" }, - .riscv64 => Executor{ .qemu = "qemu-riscv64" }, - .s390x => Executor{ .qemu = "qemu-s390x" }, - .sparc => Executor{ .qemu = "qemu-sparc" }, - .x86_64 => Executor{ .qemu = "qemu-x86_64" }, - else => return .unavailable, - }; - } - - if (self.isWindows()) { - switch (self.getArchPtrBitWidth()) { - 32 => return Executor{ .wine = "wine" }, - 64 => return Executor{ .wine = "wine64" }, - else => return .unavailable, - } - } - - return .unavailable; - } -}; +/// Deprecated. Use `std.Target`. +pub const Target = std.Target; const Pkg = struct { name: []const u8, @@ -2168,8 +1749,8 @@ pub const LibExeObjStep = struct { } switch (self.target) { - Target.Native => {}, - Target.Cross => { + .Native => {}, + .Cross => { try zig_args.append("-target"); try zig_args.append(self.target.zigTriple(builder.allocator) catch unreachable); }, diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig new file mode 100644 index 0000000000000000000000000000000000000000..8315cd84cf4798c8710631648237bc5d42fc8b0a --- /dev/null +++ b/lib/std/builtin.zig @@ -0,0 +1,413 @@ +pub usingnamespace @import("builtin"); + +/// Deprecated: use `std.Target.Os`. +pub const Os = std.Target.Os; + +/// Deprecated: use `std.Target.Arch`. +pub const Arch = std.Target.Arch; + +/// Deprecated: use `std.Target.Abi`. +pub const Abi = std.Target.Abi; + +/// Deprecated: use `std.Target.ObjectFormat`. +pub const ObjectFormat = std.Target.ObjectFormat; + +/// Deprecated: use `std.Target.SubSystem`. +pub const SubSystem = std.Target.SubSystem; + +/// `explicit_subsystem` is missing when the subsystem is automatically detected, +/// so Zig standard library has the subsystem detection logic here. This should generally be +/// used rather than `explicit_subsystem`. +/// On non-Windows targets, this is `null`. +pub const subsystem: ?SubSystem = blk: { + if (@hasDecl(@This(), "explicit_subsystem")) break :blk explicit_subsystem; + switch (os) { + .windows => { + if (is_test) { + break :blk SubSystem.Console; + } + if (@hasDecl(root, "WinMain") or + @hasDecl(root, "wWinMain") or + @hasDecl(root, "WinMainCRTStartup") or + @hasDecl(root, "wWinMainCRTStartup")) + { + break :blk SubSystem.Windows; + } else { + break :blk SubSystem.Console; + } + }, + else => break :blk null, + } +}; + +/// This data structure is used by the Zig language code generation and +/// therefore must be kept in sync with the compiler implementation. +pub const StackTrace = struct { + index: usize, + instruction_addresses: []usize, +}; + +/// This data structure is used by the Zig language code generation and +/// therefore must be kept in sync with the compiler implementation. +pub const GlobalLinkage = enum { + Internal, + Strong, + Weak, + LinkOnce, +}; + +/// This data structure is used by the Zig language code generation and +/// therefore must be kept in sync with the compiler implementation. +pub const AtomicOrder = enum { + Unordered, + Monotonic, + Acquire, + Release, + AcqRel, + SeqCst, +}; + +/// This data structure is used by the Zig language code generation and +/// therefore must be kept in sync with the compiler implementation. +pub const AtomicRmwOp = enum { + Xchg, + Add, + Sub, + And, + Nand, + Or, + Xor, + Max, + Min, +}; + +/// This data structure is used by the Zig language code generation and +/// therefore must be kept in sync with the compiler implementation. +pub const Mode = enum { + Debug, + ReleaseSafe, + ReleaseFast, + ReleaseSmall, +}; + +/// This data structure is used by the Zig language code generation and +/// therefore must be kept in sync with the compiler implementation. +pub const TypeId = enum { + Type, + Void, + Bool, + NoReturn, + Int, + Float, + Pointer, + Array, + Struct, + ComptimeFloat, + ComptimeInt, + Undefined, + Null, + Optional, + ErrorUnion, + ErrorSet, + Enum, + Union, + Fn, + BoundFn, + ArgTuple, + Opaque, + Frame, + AnyFrame, + Vector, + EnumLiteral, +}; + +/// This data structure is used by the Zig language code generation and +/// therefore must be kept in sync with the compiler implementation. +pub const TypeInfo = union(TypeId) { + Type: void, + Void: void, + Bool: void, + NoReturn: void, + Int: Int, + Float: Float, + Pointer: Pointer, + Array: Array, + Struct: Struct, + ComptimeFloat: void, + ComptimeInt: void, + Undefined: void, + Null: void, + Optional: Optional, + ErrorUnion: ErrorUnion, + ErrorSet: ErrorSet, + Enum: Enum, + Union: Union, + Fn: Fn, + BoundFn: Fn, + ArgTuple: void, + Opaque: void, + Frame: void, + AnyFrame: AnyFrame, + Vector: Vector, + EnumLiteral: void, + + /// This data structure is used by the Zig language code generation and + /// therefore must be kept in sync with the compiler implementation. + pub const Int = struct { + is_signed: bool, + bits: comptime_int, + }; + + /// This data structure is used by the Zig language code generation and + /// therefore must be kept in sync with the compiler implementation. + pub const Float = struct { + bits: comptime_int, + }; + + /// This data structure is used by the Zig language code generation and + /// therefore must be kept in sync with the compiler implementation. + pub const Pointer = struct { + size: Size, + is_const: bool, + is_volatile: bool, + alignment: comptime_int, + child: type, + is_allowzero: bool, + + /// This data structure is used by the Zig language code generation and + /// therefore must be kept in sync with the compiler implementation. + pub const Size = enum { + One, + Many, + Slice, + C, + }; + }; + + /// This data structure is used by the Zig language code generation and + /// therefore must be kept in sync with the compiler implementation. + pub const Array = struct { + len: comptime_int, + child: type, + }; + + /// This data structure is used by the Zig language code generation and + /// therefore must be kept in sync with the compiler implementation. + pub const ContainerLayout = enum { + Auto, + Extern, + Packed, + }; + + /// This data structure is used by the Zig language code generation and + /// therefore must be kept in sync with the compiler implementation. + pub const StructField = struct { + name: []const u8, + offset: ?comptime_int, + field_type: type, + }; + + /// This data structure is used by the Zig language code generation and + /// therefore must be kept in sync with the compiler implementation. + pub const Struct = struct { + layout: ContainerLayout, + fields: []StructField, + decls: []Declaration, + }; + + /// This data structure is used by the Zig language code generation and + /// therefore must be kept in sync with the compiler implementation. + pub const Optional = struct { + child: type, + }; + + /// This data structure is used by the Zig language code generation and + /// therefore must be kept in sync with the compiler implementation. + pub const ErrorUnion = struct { + error_set: type, + payload: type, + }; + + /// This data structure is used by the Zig language code generation and + /// therefore must be kept in sync with the compiler implementation. + pub const Error = struct { + name: []const u8, + value: comptime_int, + }; + + /// This data structure is used by the Zig language code generation and + /// therefore must be kept in sync with the compiler implementation. + pub const ErrorSet = ?[]Error; + + /// This data structure is used by the Zig language code generation and + /// therefore must be kept in sync with the compiler implementation. + pub const EnumField = struct { + name: []const u8, + value: comptime_int, + }; + + /// This data structure is used by the Zig language code generation and + /// therefore must be kept in sync with the compiler implementation. + pub const Enum = struct { + layout: ContainerLayout, + tag_type: type, + fields: []EnumField, + decls: []Declaration, + }; + + /// This data structure is used by the Zig language code generation and + /// therefore must be kept in sync with the compiler implementation. + pub const UnionField = struct { + name: []const u8, + enum_field: ?EnumField, + field_type: type, + }; + + /// This data structure is used by the Zig language code generation and + /// therefore must be kept in sync with the compiler implementation. + pub const Union = struct { + layout: ContainerLayout, + tag_type: ?type, + fields: []UnionField, + decls: []Declaration, + }; + + /// This data structure is used by the Zig language code generation and + /// therefore must be kept in sync with the compiler implementation. + pub const CallingConvention = enum { + Unspecified, + C, + Cold, + Naked, + Stdcall, + Async, + }; + + /// This data structure is used by the Zig language code generation and + /// therefore must be kept in sync with the compiler implementation. + pub const FnArg = struct { + is_generic: bool, + is_noalias: bool, + arg_type: ?type, + }; + + /// This data structure is used by the Zig language code generation and + /// therefore must be kept in sync with the compiler implementation. + pub const Fn = struct { + calling_convention: CallingConvention, + is_generic: bool, + is_var_args: bool, + return_type: ?type, + args: []FnArg, + }; + + /// This data structure is used by the Zig language code generation and + /// therefore must be kept in sync with the compiler implementation. + pub const AnyFrame = struct { + child: ?type, + }; + + /// This data structure is used by the Zig language code generation and + /// therefore must be kept in sync with the compiler implementation. + pub const Vector = struct { + len: comptime_int, + child: type, + }; + + /// This data structure is used by the Zig language code generation and + /// therefore must be kept in sync with the compiler implementation. + pub const Declaration = struct { + name: []const u8, + is_pub: bool, + data: Data, + + /// This data structure is used by the Zig language code generation and + /// therefore must be kept in sync with the compiler implementation. + pub const Data = union(enum) { + Type: type, + Var: type, + Fn: FnDecl, + + /// This data structure is used by the Zig language code generation and + /// therefore must be kept in sync with the compiler implementation. + pub const FnDecl = struct { + fn_type: type, + inline_type: Inline, + calling_convention: CallingConvention, + is_var_args: bool, + is_extern: bool, + is_export: bool, + lib_name: ?[]const u8, + return_type: type, + arg_names: [][]const u8, + + /// This data structure is used by the Zig language code generation and + /// therefore must be kept in sync with the compiler implementation. + pub const Inline = enum { + Auto, + Always, + Never, + }; + }; + }; + }; +}; + +/// This data structure is used by the Zig language code generation and +/// therefore must be kept in sync with the compiler implementation. +pub const FloatMode = enum { + Strict, + Optimized, +}; + +/// This data structure is used by the Zig language code generation and +/// therefore must be kept in sync with the compiler implementation. +pub const Endian = enum { + Big, + Little, +}; + +/// This data structure is used by the Zig language code generation and +/// therefore must be kept in sync with the compiler implementation. +pub const Version = struct { + major: u32, + minor: u32, + patch: u32, +}; + +/// This function type is used by the Zig language code generation and +/// therefore must be kept in sync with the compiler implementation. +pub const PanicFn = fn ([]const u8, ?*StackTrace) noreturn; + +/// This function is used by the Zig language code generation and +/// therefore must be kept in sync with the compiler implementation. +pub const panic: PanicFn = if (@hasDecl(root, "panic")) root.panic else default_panic; + +/// This function is used by the Zig language code generation and +/// therefore must be kept in sync with the compiler implementation. +pub fn default_panic(msg: []const u8, error_return_trace: ?*StackTrace) noreturn { + @setCold(true); + switch (os) { + .freestanding => { + while (true) { + @breakpoint(); + } + }, + .wasi => { + std.debug.warn("{}", msg); + _ = std.os.wasi.proc_raise(std.os.wasi.SIGABRT); + unreachable; + }, + .uefi => { + // TODO look into using the debug info and logging helpful messages + std.os.abort(); + }, + else => { + const first_trace_addr = @returnAddress(); + std.debug.panicExtra(error_return_trace, first_trace_addr, "{}", msg); + }, + } +} + +const std = @import("std.zig"); +const root = @import("root"); diff --git a/lib/std/os.zig b/lib/std/os.zig index 3f8daf02902622660afbca3b2e474fac43e4bf32..19ca282979e3ab80b5e7f0d79574d203037088b1 100644 --- a/lib/std/os.zig +++ b/lib/std/os.zig @@ -23,10 +23,6 @@ const elf = std.elf; const dl = @import("dynamic_library.zig"); const MAX_PATH_BYTES = std.fs.MAX_PATH_BYTES; -comptime { - assert(@import("std") == std); // std lib tests require --override-lib-dir -} - pub const darwin = @import("os/darwin.zig"); pub const freebsd = @import("os/freebsd.zig"); pub const linux = @import("os/linux.zig"); @@ -36,6 +32,22 @@ pub const wasi = @import("os/wasi.zig"); pub const windows = @import("os/windows.zig"); pub const zen = @import("os/zen.zig"); +comptime { + assert(@import("std") == std); // std lib tests require --override-lib-dir + if (builtin.is_test) { + _ = darwin; + _ = freebsd; + _ = linux; + _ = netbsd; + _ = uefi; + _ = wasi; + _ = windows; + _ = zen; + + _ = @import("os/test.zig"); + } +} + /// When linking libc, this is the C API. Otherwise, it is the OS-specific system interface. pub const system = if (builtin.link_libc) std.c else switch (builtin.os) { .macosx, .ios, .watchos, .tvos => darwin, @@ -1063,7 +1075,6 @@ pub fn unlinkatW(dirfd: fd_t, sub_path_w: [*]const u16, flags: u32) UnlinkatErro return error.FileBusy; } - var attr = w.OBJECT_ATTRIBUTES{ .Length = @sizeOf(w.OBJECT_ATTRIBUTES), .RootDirectory = dirfd, @@ -2813,16 +2824,3 @@ pub fn gethostname(name_buffer: *[HOST_NAME_MAX]u8) GetHostNameError![]u8 { @compileError("TODO implement gethostname for this OS"); } - -test "" { - _ = @import("os/darwin.zig"); - _ = @import("os/freebsd.zig"); - _ = @import("os/linux.zig"); - _ = @import("os/netbsd.zig"); - _ = @import("os/uefi.zig"); - _ = @import("os/wasi.zig"); - _ = @import("os/windows.zig"); - _ = @import("os/zen.zig"); - - _ = @import("os/test.zig"); -} diff --git a/lib/std/os/windows.zig b/lib/std/os/windows.zig index 6c4aeb4cefc2b8176441c22169dd5e3185c7b5e1..f9753dc2a4c17d3f79784aa524fdf8a39ea8df32 100644 --- a/lib/std/os/windows.zig +++ b/lib/std/os/windows.zig @@ -22,32 +22,6 @@ pub usingnamespace @import("windows/bits.zig"); pub const self_process_handle = @intToPtr(HANDLE, maxInt(usize)); -/// `builtin` is missing `subsystem` when the subsystem is automatically detected, -/// so Zig standard library has the subsystem detection logic here. This should generally be -/// used rather than `builtin.subsystem`. -/// On non-windows targets, this is `null`. -pub const subsystem: ?builtin.SubSystem = blk: { - if (@hasDecl(builtin, "subsystem")) break :blk builtin.subsystem; - switch (builtin.os) { - .windows => { - if (builtin.is_test) { - break :blk builtin.SubSystem.Console; - } - const root = @import("root"); - if (@hasDecl(root, "WinMain") or - @hasDecl(root, "wWinMain") or - @hasDecl(root, "WinMainCRTStartup") or - @hasDecl(root, "wWinMainCRTStartup")) - { - break :blk builtin.SubSystem.Windows; - } else { - break :blk builtin.SubSystem.Console; - } - }, - else => break :blk null, - } -}; - pub const CreateFileError = error{ SharingViolation, PathAlreadyExists, diff --git a/lib/std/special/panic.zig b/lib/std/special/panic.zig deleted file mode 100644 index f42085126b34b2a9e08f29bfa1d594eeaad7e584..0000000000000000000000000000000000000000 --- a/lib/std/special/panic.zig +++ /dev/null @@ -1,31 +0,0 @@ -// This file is the default panic handler if the root source file does not -// have a `pub fn panic`. -// If this file wants to import other files *by name*, support for that would -// have to be added in the compiler. - -const builtin = @import("builtin"); -const std = @import("std"); - -pub fn panic(msg: []const u8, error_return_trace: ?*builtin.StackTrace) noreturn { - @setCold(true); - switch (builtin.os) { - .freestanding => { - while (true) { - @breakpoint(); - } - }, - .wasi => { - std.debug.warn("{}", msg); - _ = std.os.wasi.proc_raise(std.os.wasi.SIGABRT); - unreachable; - }, - .uefi => { - // TODO look into using the debug info and logging helpful messages - std.os.abort(); - }, - else => { - const first_trace_addr = @returnAddress(); - std.debug.panicExtra(error_return_trace, first_trace_addr, "{}", msg); - }, - } -} diff --git a/lib/std/std.zig b/lib/std/std.zig index f41181f6e960d32d06be7bf92a5957a5214fdb80..a7cce4fd6fa5ca60088a93386589b43c3d477866 100644 --- a/lib/std/std.zig +++ b/lib/std/std.zig @@ -22,11 +22,13 @@ pub const SpinLock = @import("spinlock.zig").SpinLock; pub const StaticallyInitializedMutex = @import("statically_initialized_mutex.zig").StaticallyInitializedMutex; pub const StringHashMap = @import("hash_map.zig").StringHashMap; pub const TailQueue = @import("linked_list.zig").TailQueue; +pub const Target = @import("target.zig").Target; pub const Thread = @import("thread.zig").Thread; pub const atomic = @import("atomic.zig"); pub const base64 = @import("base64.zig"); pub const build = @import("build.zig"); +pub const builtin = @import("builtin.zig"); pub const c = @import("c.zig"); pub const coff = @import("coff.zig"); pub const crypto = @import("crypto.zig"); diff --git a/lib/std/target.zig b/lib/std/target.zig new file mode 100644 index 0000000000000000000000000000000000000000..6781ff250c9c1b04fca6c7836bbf73d5eae478bc --- /dev/null +++ b/lib/std/target.zig @@ -0,0 +1,614 @@ +const std = @import("std.zig"); +const builtin = std.builtin; + +pub const Target = union(enum) { + Native: void, + Cross: Cross, + + pub const Os = enum { + freestanding, + ananas, + cloudabi, + dragonfly, + freebsd, + fuchsia, + ios, + kfreebsd, + linux, + lv2, + macosx, + netbsd, + openbsd, + solaris, + windows, + haiku, + minix, + rtems, + nacl, + cnk, + aix, + cuda, + nvcl, + amdhsa, + ps4, + elfiamcu, + tvos, + watchos, + mesa3d, + contiki, + amdpal, + hermit, + hurd, + wasi, + emscripten, + zen, + uefi, + }; + + pub const Arch = union(enum) { + arm: Arm32, + armeb: Arm32, + aarch64: Arm64, + aarch64_be: Arm64, + aarch64_32: Arm64, + arc, + avr, + bpfel, + bpfeb, + hexagon, + mips, + mipsel, + mips64, + mips64el, + msp430, + powerpc, + powerpc64, + powerpc64le, + r600, + amdgcn, + riscv32, + riscv64, + sparc, + sparcv9, + sparcel, + s390x, + tce, + tcele, + thumb: Arm32, + thumbeb: Arm32, + i386, + x86_64, + xcore, + nvptx, + nvptx64, + le32, + le64, + amdil, + amdil64, + hsail, + hsail64, + spir, + spir64, + kalimba: Kalimba, + shave, + lanai, + wasm32, + wasm64, + renderscript32, + renderscript64, + + pub const Arm32 = enum { + v8_5a, + v8_4a, + v8_3a, + v8_2a, + v8_1a, + v8, + v8r, + v8m_baseline, + v8m_mainline, + v8_1m_mainline, + v7, + v7em, + v7m, + v7s, + v7k, + v7ve, + v6, + v6m, + v6k, + v6t2, + v5, + v5te, + v4t, + }; + pub const Arm64 = enum { + v8_5a, + v8_4a, + v8_3a, + v8_2a, + v8_1a, + v8, + v8r, + v8m_baseline, + v8m_mainline, + }; + pub const Kalimba = enum { + v5, + v4, + v3, + }; + pub const Mips = enum { + r6, + }; + }; + + pub const Abi = enum { + none, + gnu, + gnuabin32, + gnuabi64, + gnueabi, + gnueabihf, + gnux32, + code16, + eabi, + eabihf, + elfv1, + elfv2, + android, + musl, + musleabi, + musleabihf, + msvc, + itanium, + cygnus, + coreclr, + simulator, + macabi, + }; + + pub const ObjectFormat = enum { + unknown, + coff, + elf, + macho, + wasm, + }; + + pub const SubSystem = enum { + Console, + Windows, + Posix, + Native, + EfiApplication, + EfiBootServiceDriver, + EfiRom, + EfiRuntimeDriver, + }; + + pub const Cross = struct { + arch: Arch, + os: Os, + abi: Abi, + }; + + pub const current = Target{ + .Cross = Cross{ + .arch = builtin.arch, + .os = builtin.os, + .abi = builtin.abi, + }, + }; + + pub fn zigTriple(self: Target, allocator: *std.mem.Allocator) ![]u8 { + return std.fmt.allocPrint( + allocator, + "{}{}-{}-{}", + @tagName(self.getArch()), + Target.archSubArchName(self.getArch()), + @tagName(self.getOs()), + @tagName(self.getAbi()), + ); + } + + pub fn allocDescription(self: Target, allocator: *std.mem.Allocator) ![]u8 { + // TODO is there anything else worthy of the description that is not + // already captured in the triple? + return self.zigTriple(allocator); + } + + pub fn zigTripleNoSubArch(self: Target, allocator: *std.mem.Allocator) ![]u8 { + return std.fmt.allocPrint( + allocator, + "{}-{}-{}", + @tagName(self.getArch()), + @tagName(self.getOs()), + @tagName(self.getAbi()), + ); + } + + pub fn linuxTriple(self: Target, allocator: *std.mem.Allocator) ![]u8 { + return std.fmt.allocPrint( + allocator, + "{}-{}-{}", + @tagName(self.getArch()), + @tagName(self.getOs()), + @tagName(self.getAbi()), + ); + } + + pub fn parse(text: []const u8) !Target { + var it = mem.separate(text, "-"); + const arch_name = it.next() orelse return error.MissingArchitecture; + const os_name = it.next() orelse return error.MissingOperatingSystem; + const abi_name = it.next(); + + var cross = Cross{ + .arch = try parseArchSub(arch_name), + .os = try parseOs(os_name), + .abi = undefined, + }; + cross.abi = if (abi_name) |n| try parseAbi(n) else defaultAbi(cross.arch, cross.os); + return Target{ .Cross = cross }; + } + + pub fn defaultAbi(arch: Arch, target_os: Os) Abi { + switch (arch) { + .wasm32, .wasm64 => return .musl, + else => {}, + } + switch (target_os) { + .freestanding, + .ananas, + .cloudabi, + .dragonfly, + .lv2, + .solaris, + .haiku, + .minix, + .rtems, + .nacl, + .cnk, + .aix, + .cuda, + .nvcl, + .amdhsa, + .ps4, + .elfiamcu, + .mesa3d, + .contiki, + .amdpal, + .zen, + .hermit, + => return .eabi, + .openbsd, + .macosx, + .freebsd, + .ios, + .tvos, + .watchos, + .fuchsia, + .kfreebsd, + .netbsd, + .hurd, + => return .gnu, + .windows, + .uefi, + => return .msvc, + .linux, + .wasi, + .emscripten, + => return .musl, + } + } + + pub const ParseArchSubError = error{ + UnknownArchitecture, + UnknownSubArchitecture, + }; + + pub fn parseArchSub(text: []const u8) ParseArchSubError!Arch { + const info = @typeInfo(Arch); + inline for (info.Union.fields) |field| { + if (mem.eql(u8, text, field.name)) { + if (field.field_type == void) { + return (Arch)(@field(Arch, field.name)); + } else { + const sub_info = @typeInfo(field.field_type); + inline for (sub_info.Enum.fields) |sub_field| { + const combined = field.name ++ sub_field.name; + if (mem.eql(u8, text, combined)) { + return @unionInit(Arch, field.name, @field(field.field_type, sub_field.name)); + } + } + return error.UnknownSubArchitecture; + } + } + } + return error.UnknownArchitecture; + } + + pub fn parseOs(text: []const u8) !Os { + const info = @typeInfo(Os); + inline for (info.Enum.fields) |field| { + if (mem.eql(u8, text, field.name)) { + return @field(Os, field.name); + } + } + return error.UnknownOperatingSystem; + } + + pub fn parseAbi(text: []const u8) !Abi { + const info = @typeInfo(Abi); + inline for (info.Enum.fields) |field| { + if (mem.eql(u8, text, field.name)) { + return @field(Abi, field.name); + } + } + return error.UnknownApplicationBinaryInterface; + } + + fn archSubArchName(arch: Arch) []const u8 { + return switch (arch) { + .arm => |sub| @tagName(sub), + .armeb => |sub| @tagName(sub), + .thumb => |sub| @tagName(sub), + .thumbeb => |sub| @tagName(sub), + .aarch64 => |sub| @tagName(sub), + .aarch64_be => |sub| @tagName(sub), + .kalimba => |sub| @tagName(sub), + else => "", + }; + } + + pub fn subArchName(self: Target) []const u8 { + switch (self) { + .Native => return archSubArchName(builtin.arch), + .Cross => |cross| return archSubArchName(cross.arch), + } + } + + pub fn oFileExt(self: Target) []const u8 { + return switch (self.getAbi()) { + .msvc => ".obj", + else => ".o", + }; + } + + pub fn exeFileExt(self: Target) []const u8 { + if (self.isWindows()) { + return ".exe"; + } else if (self.isUefi()) { + return ".efi"; + } else if (self.isWasm()) { + return ".wasm"; + } else { + return ""; + } + } + + pub fn staticLibSuffix(self: Target) []const u8 { + if (self.isWasm()) { + return ".wasm"; + } + switch (self.getAbi()) { + .msvc => return ".lib", + else => return ".a", + } + } + + pub fn dynamicLibSuffix(self: Target) []const u8 { + if (self.isDarwin()) { + return ".dylib"; + } + switch (self.getOs()) { + .windows => return ".dll", + else => return ".so", + } + } + + pub fn libPrefix(self: Target) []const u8 { + if (self.isWasm()) { + return ""; + } + switch (self.getAbi()) { + .msvc => return "", + else => return "lib", + } + } + + pub fn getOs(self: Target) Os { + return switch (self) { + .Native => builtin.os, + .Cross => |t| t.os, + }; + } + + pub fn getArch(self: Target) Arch { + switch (self) { + .Native => return builtin.arch, + .Cross => |t| return t.arch, + } + } + + pub fn getAbi(self: Target) Abi { + switch (self) { + .Native => return builtin.abi, + .Cross => |t| return t.abi, + } + } + + pub fn isMinGW(self: Target) bool { + return self.isWindows() and self.isGnu(); + } + + pub fn isGnu(self: Target) bool { + return switch (self.getAbi()) { + .gnu, .gnuabin32, .gnuabi64, .gnueabi, .gnueabihf, .gnux32 => true, + else => false, + }; + } + + pub fn isDarwin(self: Target) bool { + return switch (self.getOs()) { + .ios, .macosx, .watchos, .tvos => true, + else => false, + }; + } + + pub fn isWindows(self: Target) bool { + return switch (self.getOs()) { + .windows => true, + else => false, + }; + } + + pub fn isLinux(self: Target) bool { + return switch (self.getOs()) { + .linux => true, + else => false, + }; + } + + pub fn isUefi(self: Target) bool { + return switch (self.getOs()) { + .uefi => true, + else => false, + }; + } + + pub fn isWasm(self: Target) bool { + return switch (self.getArch()) { + .wasm32, .wasm64 => true, + else => false, + }; + } + + pub fn isFreeBSD(self: Target) bool { + return switch (self.getOs()) { + .freebsd => true, + else => false, + }; + } + + pub fn isNetBSD(self: Target) bool { + return switch (self.getOs()) { + .netbsd => true, + else => false, + }; + } + + pub fn wantSharedLibSymLinks(self: Target) bool { + return !self.isWindows(); + } + + pub fn osRequiresLibC(self: Target) bool { + return self.isDarwin() or self.isFreeBSD() or self.isNetBSD(); + } + + pub fn getArchPtrBitWidth(self: Target) u32 { + switch (self.getArch()) { + .avr, + .msp430, + => return 16, + + .arc, + .arm, + .armeb, + .hexagon, + .le32, + .mips, + .mipsel, + .powerpc, + .r600, + .riscv32, + .sparc, + .sparcel, + .tce, + .tcele, + .thumb, + .thumbeb, + .i386, + .xcore, + .nvptx, + .amdil, + .hsail, + .spir, + .kalimba, + .shave, + .lanai, + .wasm32, + .renderscript32, + .aarch64_32, + => return 32, + + .aarch64, + .aarch64_be, + .mips64, + .mips64el, + .powerpc64, + .powerpc64le, + .riscv64, + .x86_64, + .nvptx64, + .le64, + .amdil64, + .hsail64, + .spir64, + .wasm64, + .renderscript64, + .amdgcn, + .bpfel, + .bpfeb, + .sparcv9, + .s390x, + => return 64, + } + } + + pub const Executor = union(enum) { + native, + qemu: []const u8, + wine: []const u8, + unavailable, + }; + + pub fn getExternalExecutor(self: Target) Executor { + if (@TagType(Target)(self) == .Native) return .native; + + // If the target OS matches the host OS, we can use QEMU to emulate a foreign architecture. + if (self.getOs() == builtin.os) { + return switch (self.getArch()) { + .aarch64 => Executor{ .qemu = "qemu-aarch64" }, + .aarch64_be => Executor{ .qemu = "qemu-aarch64_be" }, + .arm => Executor{ .qemu = "qemu-arm" }, + .armeb => Executor{ .qemu = "qemu-armeb" }, + .i386 => Executor{ .qemu = "qemu-i386" }, + .mips => Executor{ .qemu = "qemu-mips" }, + .mipsel => Executor{ .qemu = "qemu-mipsel" }, + .mips64 => Executor{ .qemu = "qemu-mips64" }, + .mips64el => Executor{ .qemu = "qemu-mips64el" }, + .powerpc => Executor{ .qemu = "qemu-ppc" }, + .powerpc64 => Executor{ .qemu = "qemu-ppc64" }, + .powerpc64le => Executor{ .qemu = "qemu-ppc64le" }, + .riscv32 => Executor{ .qemu = "qemu-riscv32" }, + .riscv64 => Executor{ .qemu = "qemu-riscv64" }, + .s390x => Executor{ .qemu = "qemu-s390x" }, + .sparc => Executor{ .qemu = "qemu-sparc" }, + .x86_64 => Executor{ .qemu = "qemu-x86_64" }, + else => return .unavailable, + }; + } + + if (self.isWindows()) { + switch (self.getArchPtrBitWidth()) { + 32 => return Executor{ .wine = "wine" }, + 64 => return Executor{ .wine = "wine64" }, + else => return .unavailable, + } + } + + return .unavailable; + } +}; diff --git a/src-self-hosted/target.zig b/src-self-hosted/target.zig index 15f09e8da915ee18937556420d1e52f96278c554..c62e5af9dd393f9ec6942ae4d455d62f13f44fa3 100644 --- a/src-self-hosted/target.zig +++ b/src-self-hosted/target.zig @@ -3,6 +3,8 @@ const builtin = @import("builtin"); const llvm = @import("llvm.zig"); const CInt = @import("c_int.zig").CInt; +// TODO delete this file and use std.Target + pub const FloatAbi = enum { Hard, Soft, diff --git a/src/all_types.hpp b/src/all_types.hpp index 052c67d3343ba285960d0c3cccdbe9174b1b7ac3..a8cfa0227f1abd5f59b056a8319065a3df5b55c4 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1930,7 +1930,6 @@ struct CodeGen { ZigList type_resolve_stack; ZigPackage *std_package; - ZigPackage *panic_package; ZigPackage *test_runner_package; ZigPackage *compile_var_package; ZigType *compile_var_import; @@ -2006,7 +2005,6 @@ struct CodeGen { ZigFn *cur_fn; ZigFn *main_fn; ZigFn *panic_fn; - TldFn *panic_tld_fn; ZigFn *largest_frame_fn; @@ -2030,7 +2028,6 @@ struct CodeGen { bool have_winmain; bool have_winmain_crt_startup; bool have_dllmain_crt_startup; - bool have_pub_panic; bool have_err_ret_tracing; bool c_want_stdint; bool c_want_stdbool; diff --git a/src/analyze.cpp b/src/analyze.cpp index 44223b58b420ed16a4266fe00a352b34327fbebd..e2df290df623eb8e588f6d47c0d42923e9966a8a 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -3232,21 +3232,6 @@ static bool scope_is_root_decls(Scope *scope) { zig_unreachable(); } -void typecheck_panic_fn(CodeGen *g, TldFn *tld_fn, ZigFn *panic_fn) { - ConstExprValue *panic_fn_type_val = get_builtin_value(g, "PanicFn"); - assert(panic_fn_type_val != nullptr); - assert(panic_fn_type_val->type->id == ZigTypeIdMetaType); - ZigType *panic_fn_type = panic_fn_type_val->data.x_type; - - AstNode *fake_decl = allocate(1); - *fake_decl = *panic_fn->proto_node; - fake_decl->type = NodeTypeSymbol; - fake_decl->data.symbol_expr.symbol = tld_fn->base.name; - - // call this for the side effects of casting to panic_fn_type - analyze_const_value(g, tld_fn->base.parent_scope, fake_decl, panic_fn_type, nullptr, UndefBad); -} - ZigType *get_test_fn_type(CodeGen *g) { if (g->test_fn_type) return g->test_fn_type; @@ -3356,16 +3341,9 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) { fn_table_entry->inferred_async_node = fn_table_entry->proto_node; } - if (scope_is_root_decls(tld_fn->base.parent_scope) && - (import == g->root_import || import->data.structure.root_struct->package == g->panic_package)) - { + if (scope_is_root_decls(tld_fn->base.parent_scope) && import == g->root_import) { if (g->have_pub_main && buf_eql_str(tld_fn->base.name, "main")) { g->main_fn = fn_table_entry; - } else if ((import->data.structure.root_struct->package == g->panic_package || g->have_pub_panic) && - buf_eql_str(tld_fn->base.name, "panic")) - { - g->panic_fn = fn_table_entry; - g->panic_tld_fn = tld_fn; } } } else if (source_node->type == NodeTypeTestDecl) { @@ -4710,8 +4688,8 @@ ZigType *add_source_file(CodeGen *g, ZigPackage *package, Buf *resolved_path, Bu ast_print(stderr, root_node, 0); } - if (source_kind == SourceKindRoot || package == g->panic_package) { - // Look for panic and main + if (source_kind == SourceKindRoot) { + // Look for main for (size_t decl_i = 0; decl_i < root_node->data.container_decl.decls.length; decl_i += 1) { AstNode *top_level_decl = root_node->data.container_decl.decls.at(decl_i); @@ -4724,8 +4702,6 @@ ZigType *add_source_file(CodeGen *g, ZigPackage *package, Buf *resolved_path, Bu if (is_pub) { if (buf_eql_str(proto_name, "main")) { g->have_pub_main = true; - } else if (buf_eql_str(proto_name, "panic")) { - g->have_pub_panic = true; } } } @@ -8932,3 +8908,62 @@ IrInstruction *ir_create_alloca(CodeGen *g, Scope *scope, AstNode *source_node, return &alloca_gen->base; } +Error analyze_import(CodeGen *g, ZigType *source_import, Buf *import_target_str, + ZigType **out_import, Buf **out_import_target_path, Buf *out_full_path) +{ + Error err; + + Buf *search_dir; + ZigPackage *cur_scope_pkg = source_import->data.structure.root_struct->package; + assert(cur_scope_pkg); + ZigPackage *target_package; + auto package_entry = cur_scope_pkg->package_table.maybe_get(import_target_str); + SourceKind source_kind; + if (package_entry) { + target_package = package_entry->value; + *out_import_target_path = &target_package->root_src_path; + search_dir = &target_package->root_src_dir; + source_kind = SourceKindPkgMain; + } else { + // try it as a filename + target_package = cur_scope_pkg; + *out_import_target_path = import_target_str; + + // search relative to importing file + search_dir = buf_alloc(); + os_path_dirname(source_import->data.structure.root_struct->path, search_dir); + + source_kind = SourceKindNonRoot; + } + + buf_resize(out_full_path, 0); + os_path_join(search_dir, *out_import_target_path, out_full_path); + + Buf *import_code = buf_alloc(); + Buf *resolved_path = buf_alloc(); + + Buf *resolve_paths[] = { out_full_path, }; + *resolved_path = os_path_resolve(resolve_paths, 1); + + auto import_entry = g->import_table.maybe_get(resolved_path); + if (import_entry) { + *out_import = import_entry->value; + return ErrorNone; + } + + if (source_kind == SourceKindNonRoot) { + Buf *pkg_root_src_dir = &cur_scope_pkg->root_src_dir; + Buf resolved_root_src_dir = os_path_resolve(&pkg_root_src_dir, 1); + if (!buf_starts_with_buf(resolved_path, &resolved_root_src_dir)) { + return ErrorImportOutsidePkgPath; + } + } + + if ((err = file_fetch(g, resolved_path, import_code))) { + return err; + } + + *out_import = add_source_file(g, target_package, resolved_path, import_code, source_kind); + return ErrorNone; +} + diff --git a/src/analyze.hpp b/src/analyze.hpp index 4592d1a0a13d39efb662e8a41ece51b14a88faad..5168dd2d7da4253e5a5a688712257a45cc9b78d2 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -262,5 +262,7 @@ void add_async_error_notes(CodeGen *g, ErrorMsg *msg, ZigFn *fn); IrInstruction *ir_create_alloca(CodeGen *g, Scope *scope, AstNode *source_node, ZigFn *fn, ZigType *var_type, const char *name_hint); +Error analyze_import(CodeGen *codegen, ZigType *source_import, Buf *import_target_str, + ZigType **out_import, Buf **out_import_target_path, Buf *out_full_path); #endif diff --git a/src/codegen.cpp b/src/codegen.cpp index 1b14c5551b9029ac096ddd1a6abe3118d9afc8a2..87cdcc8783ea6f6dd2ae5ccf49d9de5569ebd6e1 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -8125,55 +8125,37 @@ Buf *codegen_generate_builtin_source(CodeGen *g) { g->have_err_ret_tracing = detect_err_ret_tracing(g); Buf *contents = buf_alloc(); - - // NOTE: when editing this file, you may need to make modifications to the - // cache input parameters in define_builtin_compile_vars - - // Modifications to this struct must be coordinated with code that does anything with - // g->stack_trace_type. There are hard-coded references to the field indexes. - buf_append_str(contents, - "pub const StackTrace = struct {\n" - " index: usize,\n" - " instruction_addresses: []usize,\n" - "};\n\n"); - - buf_append_str(contents, "pub const PanicFn = fn([]const u8, ?*StackTrace) noreturn;\n\n"); + buf_appendf(contents, "usingnamespace @import(\"std\").builtin;\n\n"); const char *cur_os = nullptr; { - buf_appendf(contents, "pub const Os = enum {\n"); uint32_t field_count = (uint32_t)target_os_count(); for (uint32_t i = 0; i < field_count; i += 1) { Os os_type = target_os_enum(i); const char *name = target_os_name(os_type); - buf_appendf(contents, " %s,\n", name); if (os_type == g->zig_target->os) { g->target_os_index = i; cur_os = name; } } - buf_appendf(contents, "};\n\n"); } assert(cur_os != nullptr); const char *cur_arch = nullptr; { - buf_appendf(contents, "pub const Arch = union(enum) {\n"); uint32_t field_count = (uint32_t)target_arch_count(); for (uint32_t arch_i = 0; arch_i < field_count; arch_i += 1) { ZigLLVM_ArchType arch = target_arch_enum(arch_i); const char *arch_name = target_arch_name(arch); SubArchList sub_arch_list = target_subarch_list(arch); if (sub_arch_list == SubArchListNone) { - buf_appendf(contents, " %s,\n", arch_name); if (arch == g->zig_target->arch) { g->target_arch_index = arch_i; cur_arch = buf_ptr(buf_sprintf("Arch.%s", arch_name)); } } else { const char *sub_arch_list_name = target_subarch_list_name(sub_arch_list); - buf_appendf(contents, " %s: %s,\n", arch_name, sub_arch_list_name); if (arch == g->zig_target->arch) { size_t sub_count = target_subarch_count(sub_arch_list); for (size_t sub_i = 0; sub_i < sub_count; sub_i += 1) { @@ -8187,50 +8169,30 @@ Buf *codegen_generate_builtin_source(CodeGen *g) { } } } - - uint32_t list_count = target_subarch_list_count(); - // start at index 1 to skip None - for (uint32_t list_i = 1; list_i < list_count; list_i += 1) { - SubArchList sub_arch_list = target_subarch_list_enum(list_i); - const char *subarch_list_name = target_subarch_list_name(sub_arch_list); - buf_appendf(contents, " pub const %s = enum {\n", subarch_list_name); - size_t sub_count = target_subarch_count(sub_arch_list); - for (size_t sub_i = 0; sub_i < sub_count; sub_i += 1) { - ZigLLVM_SubArchType sub = target_subarch_enum(sub_arch_list, sub_i); - buf_appendf(contents, " %s,\n", target_subarch_name(sub)); - } - buf_appendf(contents, " };\n"); - } - buf_appendf(contents, "};\n\n"); } assert(cur_arch != nullptr); const char *cur_abi = nullptr; { - buf_appendf(contents, "pub const Abi = enum {\n"); uint32_t field_count = (uint32_t)target_abi_count(); for (uint32_t i = 0; i < field_count; i += 1) { ZigLLVM_EnvironmentType abi = target_abi_enum(i); const char *name = target_abi_name(abi); - buf_appendf(contents, " %s,\n", name); if (abi == g->zig_target->abi) { g->target_abi_index = i; cur_abi = name; } } - buf_appendf(contents, "};\n\n"); } assert(cur_abi != nullptr); const char *cur_obj_fmt = nullptr; { - buf_appendf(contents, "pub const ObjectFormat = enum {\n"); uint32_t field_count = (uint32_t)target_oformat_count(); for (uint32_t i = 0; i < field_count; i += 1) { ZigLLVM_ObjectFormatType oformat = target_oformat_enum(i); const char *name = target_oformat_name(oformat); - buf_appendf(contents, " %s,\n", name); ZigLLVM_ObjectFormatType target_oformat = target_object_format(g->zig_target); if (oformat == target_oformat) { @@ -8239,311 +8201,39 @@ Buf *codegen_generate_builtin_source(CodeGen *g) { } } - buf_appendf(contents, "};\n\n"); } assert(cur_obj_fmt != nullptr); - { - buf_appendf(contents, "pub const GlobalLinkage = enum {\n"); - uint32_t field_count = array_length(global_linkage_values); - for (uint32_t i = 0; i < field_count; i += 1) { - const GlobalLinkageValue *value = &global_linkage_values[i]; - buf_appendf(contents, " %s,\n", value->name); - } - buf_appendf(contents, "};\n\n"); - } - { - buf_appendf(contents, - "pub const AtomicOrder = enum {\n" - " Unordered,\n" - " Monotonic,\n" - " Acquire,\n" - " Release,\n" - " AcqRel,\n" - " SeqCst,\n" - "};\n\n"); - } - { - buf_appendf(contents, - "pub const AtomicRmwOp = enum {\n" - " Xchg,\n" - " Add,\n" - " Sub,\n" - " And,\n" - " Nand,\n" - " Or,\n" - " Xor,\n" - " Max,\n" - " Min,\n" - "};\n\n"); - } - { - buf_appendf(contents, - "pub const Mode = enum {\n" - " Debug,\n" - " ReleaseSafe,\n" - " ReleaseFast,\n" - " ReleaseSmall,\n" - "};\n\n"); - } - { - buf_appendf(contents, "pub const TypeId = enum {\n"); - size_t field_count = type_id_len(); - for (size_t i = 0; i < field_count; i += 1) { - const ZigTypeId id = type_id_at_index(i); - buf_appendf(contents, " %s,\n", type_id_name(id)); - } - buf_appendf(contents, "};\n\n"); - } - { - buf_appendf(contents, - "pub const TypeInfo = union(TypeId) {\n" - " Type: void,\n" - " Void: void,\n" - " Bool: void,\n" - " NoReturn: void,\n" - " Int: Int,\n" - " Float: Float,\n" - " Pointer: Pointer,\n" - " Array: Array,\n" - " Struct: Struct,\n" - " ComptimeFloat: void,\n" - " ComptimeInt: void,\n" - " Undefined: void,\n" - " Null: void,\n" - " Optional: Optional,\n" - " ErrorUnion: ErrorUnion,\n" - " ErrorSet: ErrorSet,\n" - " Enum: Enum,\n" - " Union: Union,\n" - " Fn: Fn,\n" - " BoundFn: Fn,\n" - " ArgTuple: void,\n" - " Opaque: void,\n" - " Frame: void,\n" - " AnyFrame: AnyFrame,\n" - " Vector: Vector,\n" - " EnumLiteral: void,\n" - "\n\n" - " pub const Int = struct {\n" - " is_signed: bool,\n" - " bits: comptime_int,\n" - " };\n" - "\n" - " pub const Float = struct {\n" - " bits: comptime_int,\n" - " };\n" - "\n" - " pub const Pointer = struct {\n" - " size: Size,\n" - " is_const: bool,\n" - " is_volatile: bool,\n" - " alignment: comptime_int,\n" - " child: type,\n" - " is_allowzero: bool,\n" - "\n" - " pub const Size = enum {\n" - " One,\n" - " Many,\n" - " Slice,\n" - " C,\n" - " };\n" - " };\n" - "\n" - " pub const Array = struct {\n" - " len: comptime_int,\n" - " child: type,\n" - " };\n" - "\n" - " pub const ContainerLayout = enum {\n" - " Auto,\n" - " Extern,\n" - " Packed,\n" - " };\n" - "\n" - " pub const StructField = struct {\n" - " name: []const u8,\n" - " offset: ?comptime_int,\n" - " field_type: type,\n" - " };\n" - "\n" - " pub const Struct = struct {\n" - " layout: ContainerLayout,\n" - " fields: []StructField,\n" - " decls: []Declaration,\n" - " };\n" - "\n" - " pub const Optional = struct {\n" - " child: type,\n" - " };\n" - "\n" - " pub const ErrorUnion = struct {\n" - " error_set: type,\n" - " payload: type,\n" - " };\n" - "\n" - " pub const Error = struct {\n" - " name: []const u8,\n" - " value: comptime_int,\n" - " };\n" - "\n" - " pub const ErrorSet = ?[]Error;\n" - "\n" - " pub const EnumField = struct {\n" - " name: []const u8,\n" - " value: comptime_int,\n" - " };\n" - "\n" - " pub const Enum = struct {\n" - " layout: ContainerLayout,\n" - " tag_type: type,\n" - " fields: []EnumField,\n" - " decls: []Declaration,\n" - " };\n" - "\n" - " pub const UnionField = struct {\n" - " name: []const u8,\n" - " enum_field: ?EnumField,\n" - " field_type: type,\n" - " };\n" - "\n" - " pub const Union = struct {\n" - " layout: ContainerLayout,\n" - " tag_type: ?type,\n" - " fields: []UnionField,\n" - " decls: []Declaration,\n" - " };\n" - "\n" - " pub const CallingConvention = enum {\n" - " Unspecified,\n" - " C,\n" - " Cold,\n" - " Naked,\n" - " Stdcall,\n" - " Async,\n" - " };\n" - "\n" - " pub const FnArg = struct {\n" - " is_generic: bool,\n" - " is_noalias: bool,\n" - " arg_type: ?type,\n" - " };\n" - "\n" - " pub const Fn = struct {\n" - " calling_convention: CallingConvention,\n" - " is_generic: bool,\n" - " is_var_args: bool,\n" - " return_type: ?type,\n" - " args: []FnArg,\n" - " };\n" - "\n" - " pub const AnyFrame = struct {\n" - " child: ?type,\n" - " };\n" - "\n" - " pub const Vector = struct {\n" - " len: comptime_int,\n" - " child: type,\n" - " };\n" - "\n" - " pub const Declaration = struct {\n" - " name: []const u8,\n" - " is_pub: bool,\n" - " data: Data,\n" - "\n" - " pub const Data = union(enum) {\n" - " Type: type,\n" - " Var: type,\n" - " Fn: FnDecl,\n" - "\n" - " pub const FnDecl = struct {\n" - " fn_type: type,\n" - " inline_type: Inline,\n" - " calling_convention: CallingConvention,\n" - " is_var_args: bool,\n" - " is_extern: bool,\n" - " is_export: bool,\n" - " lib_name: ?[]const u8,\n" - " return_type: type,\n" - " arg_names: [][] const u8,\n" - "\n" - " pub const Inline = enum {\n" - " Auto,\n" - " Always,\n" - " Never,\n" - " };\n" - " };\n" - " };\n" - " };\n" - "};\n\n"); - static_assert(ContainerLayoutAuto == 0, ""); - static_assert(ContainerLayoutExtern == 1, ""); - static_assert(ContainerLayoutPacked == 2, ""); + // If any of these asserts trip then you need to either fix the internal compiler enum + // or the corresponding one in std.Target or std.builtin. + static_assert(ContainerLayoutAuto == 0, ""); + static_assert(ContainerLayoutExtern == 1, ""); + static_assert(ContainerLayoutPacked == 2, ""); - static_assert(CallingConventionUnspecified == 0, ""); - static_assert(CallingConventionC == 1, ""); - static_assert(CallingConventionCold == 2, ""); - static_assert(CallingConventionNaked == 3, ""); - static_assert(CallingConventionStdcall == 4, ""); - static_assert(CallingConventionAsync == 5, ""); + static_assert(CallingConventionUnspecified == 0, ""); + static_assert(CallingConventionC == 1, ""); + static_assert(CallingConventionCold == 2, ""); + static_assert(CallingConventionNaked == 3, ""); + static_assert(CallingConventionStdcall == 4, ""); + static_assert(CallingConventionAsync == 5, ""); - static_assert(FnInlineAuto == 0, ""); - static_assert(FnInlineAlways == 1, ""); - static_assert(FnInlineNever == 2, ""); + static_assert(FnInlineAuto == 0, ""); + static_assert(FnInlineAlways == 1, ""); + static_assert(FnInlineNever == 2, ""); - static_assert(BuiltinPtrSizeOne == 0, ""); - static_assert(BuiltinPtrSizeMany == 1, ""); - static_assert(BuiltinPtrSizeSlice == 2, ""); - static_assert(BuiltinPtrSizeC == 3, ""); - } - { - buf_appendf(contents, - "pub const FloatMode = enum {\n" - " Strict,\n" - " Optimized,\n" - "};\n\n"); - assert(FloatModeStrict == 0); - assert(FloatModeOptimized == 1); - } - { - buf_appendf(contents, - "pub const Endian = enum {\n" - " Big,\n" - " Little,\n" - "};\n\n"); - //assert(EndianBig == 0); - //assert(EndianLittle == 1); - } - { - buf_appendf(contents, - "pub const Version = struct {\n" - " major: u32,\n" - " minor: u32,\n" - " patch: u32,\n" - "};\n\n"); - } - { - buf_appendf(contents, - "pub const SubSystem = enum {\n" - " Console,\n" - " Windows,\n" - " Posix,\n" - " Native,\n" - " EfiApplication,\n" - " EfiBootServiceDriver,\n" - " EfiRom,\n" - " EfiRuntimeDriver,\n" - "};\n\n"); + static_assert(BuiltinPtrSizeOne == 0, ""); + static_assert(BuiltinPtrSizeMany == 1, ""); + static_assert(BuiltinPtrSizeSlice == 2, ""); + static_assert(BuiltinPtrSizeC == 3, ""); - assert(TargetSubsystemConsole == 0); - assert(TargetSubsystemWindows == 1); - assert(TargetSubsystemPosix == 2); - assert(TargetSubsystemNative == 3); - assert(TargetSubsystemEfiApplication == 4); - assert(TargetSubsystemEfiBootServiceDriver == 5); - assert(TargetSubsystemEfiRom == 6); - assert(TargetSubsystemEfiRuntimeDriver == 7); - } + static_assert(TargetSubsystemConsole == 0, ""); + static_assert(TargetSubsystemWindows == 1, ""); + static_assert(TargetSubsystemPosix == 2, ""); + static_assert(TargetSubsystemNative == 3, ""); + static_assert(TargetSubsystemEfiApplication == 4, ""); + static_assert(TargetSubsystemEfiBootServiceDriver == 5, ""); + static_assert(TargetSubsystemEfiRom == 6, ""); + static_assert(TargetSubsystemEfiRuntimeDriver == 7, ""); { const char *endian_str = g->is_big_endian ? "Endian.Big" : "Endian.Little"; buf_appendf(contents, "pub const endian = %s;\n", endian_str); @@ -8573,7 +8263,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) { { TargetSubsystem detected_subsystem = detect_subsystem(g); if (detected_subsystem != TargetSubsystemAuto) { - buf_appendf(contents, "pub const subsystem = SubSystem.%s;\n", subsystem_to_str(detected_subsystem)); + buf_appendf(contents, "pub const explicit_subsystem = SubSystem.%s;\n", subsystem_to_str(detected_subsystem)); } } @@ -8594,10 +8284,6 @@ static ZigPackage *create_test_runner_pkg(CodeGen *g) { return codegen_create_package(g, buf_ptr(g->zig_std_special_dir), "test_runner.zig", "std.special"); } -static ZigPackage *create_panic_pkg(CodeGen *g) { - return codegen_create_package(g, buf_ptr(g->zig_std_special_dir), "panic.zig", "std.special"); -} - static Error define_builtin_compile_vars(CodeGen *g) { if (g->std_package == nullptr) return ErrorNone; @@ -8679,6 +8365,7 @@ static Error define_builtin_compile_vars(CodeGen *g) { assert(g->root_package); assert(g->std_package); g->compile_var_package = new_package(buf_ptr(this_dir), builtin_zig_basename, "builtin"); + g->compile_var_package->package_table.put(buf_create_from_str("std"), g->std_package); g->root_package->package_table.put(buf_create_from_str("builtin"), g->compile_var_package); g->std_package->package_table.put(buf_create_from_str("builtin"), g->compile_var_package); g->std_package->package_table.put(buf_create_from_str("std"), g->std_package); @@ -9377,16 +9064,43 @@ static void gen_root_source(CodeGen *g) { if (!g->is_dummy_so) { // Zig has lazy top level definitions. Here we semantically analyze the panic function. - ZigType *import_with_panic; - if (g->have_pub_panic) { - import_with_panic = g->root_import; - } else { - g->panic_package = create_panic_pkg(g); - import_with_panic = add_special_code(g, g->panic_package, "panic.zig"); + Buf *import_target_path; + Buf full_path = BUF_INIT; + ZigType *std_import; + if ((err = analyze_import(g, g->root_import, buf_create_from_str("std"), &std_import, + &import_target_path, &full_path))) + { + if (err == ErrorFileNotFound) { + fprintf(stderr, "unable to find '%s'", buf_ptr(import_target_path)); + } else { + fprintf(stderr, "unable to open '%s': %s\n", buf_ptr(&full_path), err_str(err)); + } + exit(1); } - Tld *panic_tld = find_decl(g, &get_container_scope(import_with_panic)->base, buf_create_from_str("panic")); + + Tld *builtin_tld = find_decl(g, &get_container_scope(std_import)->base, + buf_create_from_str("builtin")); + assert(builtin_tld != nullptr); + resolve_top_level_decl(g, builtin_tld, nullptr, false); + report_errors_and_maybe_exit(g); + assert(builtin_tld->id == TldIdVar); + TldVar *builtin_tld_var = (TldVar*)builtin_tld; + ConstExprValue *builtin_val = builtin_tld_var->var->const_value; + assert(builtin_val->type->id == ZigTypeIdMetaType); + ZigType *builtin_type = builtin_val->data.x_type; + + Tld *panic_tld = find_decl(g, &get_container_scope(builtin_type)->base, + buf_create_from_str("panic")); assert(panic_tld != nullptr); resolve_top_level_decl(g, panic_tld, nullptr, false); + report_errors_and_maybe_exit(g); + assert(panic_tld->id == TldIdVar); + TldVar *panic_tld_var = (TldVar*)panic_tld; + ConstExprValue *panic_fn_val = panic_tld_var->var->const_value; + assert(panic_fn_val->type->id == ZigTypeIdFn); + assert(panic_fn_val->data.x_ptr.special == ConstPtrSpecialFunction); + g->panic_fn = panic_fn_val->data.x_ptr.data.fn.fn_entry; + assert(g->panic_fn != nullptr); } @@ -9416,10 +9130,6 @@ static void gen_root_source(CodeGen *g) { } } - if (!g->is_dummy_so) { - typecheck_panic_fn(g, g->panic_tld_fn, g->panic_fn); - } - report_errors_and_maybe_exit(g); } diff --git a/src/error.cpp b/src/error.cpp index 86df76ed4eead006f73b0b7494510e47d1b9e385..9fc0383b1b5334be37b7df974b9acbd8c5def38c 100644 --- a/src/error.cpp +++ b/src/error.cpp @@ -57,6 +57,7 @@ const char *err_str(Error err) { case ErrorNoCCompilerInstalled: return "no C compiler installed"; case ErrorNotLazy: return "not lazy"; case ErrorIsAsync: return "is async"; + case ErrorImportOutsidePkgPath: return "import of file outside package path"; } return "(invalid error)"; } diff --git a/src/ir.cpp b/src/ir.cpp index 4cce464a4c72a2095445e53d54542e66f9b66e4c..8aff5e45838e9d65a158eabea477ea2d4e1aa4a8 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -19589,57 +19589,18 @@ static IrInstruction *ir_analyze_instruction_import(IrAnalyze *ira, IrInstructio AstNode *source_node = import_instruction->base.source_node; ZigType *import = source_node->owner; + ZigType *target_import; Buf *import_target_path; - Buf *search_dir; - assert(import->data.structure.root_struct->package); - ZigPackage *target_package; - auto package_entry = import->data.structure.root_struct->package->package_table.maybe_get(import_target_str); - SourceKind source_kind; - if (package_entry) { - target_package = package_entry->value; - import_target_path = &target_package->root_src_path; - search_dir = &target_package->root_src_dir; - source_kind = SourceKindPkgMain; - } else { - // try it as a filename - target_package = import->data.structure.root_struct->package; - import_target_path = import_target_str; - - // search relative to importing file - search_dir = buf_alloc(); - os_path_dirname(import->data.structure.root_struct->path, search_dir); - - source_kind = SourceKindNonRoot; - } - Buf full_path = BUF_INIT; - os_path_join(search_dir, import_target_path, &full_path); - - Buf *import_code = buf_alloc(); - Buf *resolved_path = buf_alloc(); - - Buf *resolve_paths[] = { &full_path, }; - *resolved_path = os_path_resolve(resolve_paths, 1); - - auto import_entry = ira->codegen->import_table.maybe_get(resolved_path); - if (import_entry) { - return ir_const_type(ira, &import_instruction->base, import_entry->value); - } - - if (source_kind == SourceKindNonRoot) { - ZigPackage *cur_scope_pkg = scope_package(import_instruction->base.scope); - Buf *pkg_root_src_dir = &cur_scope_pkg->root_src_dir; - Buf resolved_root_src_dir = os_path_resolve(&pkg_root_src_dir, 1); - if (!buf_starts_with_buf(resolved_path, &resolved_root_src_dir)) { + if ((err = analyze_import(ira->codegen, import, import_target_str, &target_import, + &import_target_path, &full_path))) + { + if (err == ErrorImportOutsidePkgPath) { ir_add_error_node(ira, source_node, buf_sprintf("import of file outside package path: '%s'", buf_ptr(import_target_path))); return ira->codegen->invalid_instruction; - } - } - - if ((err = file_fetch(ira->codegen, resolved_path, import_code))) { - if (err == ErrorFileNotFound) { + } else if (err == ErrorFileNotFound) { ir_add_error_node(ira, source_node, buf_sprintf("unable to find '%s'", buf_ptr(import_target_path))); return ira->codegen->invalid_instruction; @@ -19650,8 +19611,6 @@ static IrInstruction *ir_analyze_instruction_import(IrAnalyze *ira, IrInstructio } } - ZigType *target_import = add_source_file(ira->codegen, target_package, resolved_path, import_code, source_kind); - return ir_const_type(ira, &import_instruction->base, target_import); } diff --git a/src/userland.h b/src/userland.h index 58d5cc719a7c25a66d2edc2c9c9256d24c802a84..1d012571758d9ba69a5581ba5bcbf750facc3ae0 100644 --- a/src/userland.h +++ b/src/userland.h @@ -77,6 +77,7 @@ enum Error { ErrorNoSpaceLeft, ErrorNotLazy, ErrorIsAsync, + ErrorImportOutsidePkgPath, }; // ABI warning diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 35c6ded4a4a47a22c7e5c345497bc079c9eb46f4..c7b0e09485b5358767e70170e4e60a24b4da42e5 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -64,7 +64,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ _ = @Type(0); \\} , - "tmp.zig:2:15: error: expected type 'builtin.TypeInfo', found 'comptime_int'", + "tmp.zig:2:15: error: expected type 'std.builtin.TypeInfo', found 'comptime_int'", ); cases.add( @@ -88,7 +88,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ }); \\} , - "tmp.zig:3:36: error: expected type 'builtin.TypeInfo', found 'builtin.Int'", + "tmp.zig:3:36: error: expected type 'std.builtin.TypeInfo', found 'std.builtin.Int'", ); cases.add( @@ -806,7 +806,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\pub fn panic() void {} \\ , - "tmp.zig:3:5: error: expected type 'fn([]const u8, ?*builtin.StackTrace) noreturn', found 'fn() void'", + "error: expected type 'fn([]const u8, ?*std.builtin.StackTrace) noreturn', found 'fn() void'", ); cases.add( @@ -815,8 +815,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ while (true) {} \\} , - "tmp.zig:1:5: error: expected type 'fn([]const u8, ?*builtin.StackTrace) noreturn', found 'fn([]const u8,var)var'", - "tmp.zig:1:5: note: only one of the functions is generic", + "error: expected type 'fn([]const u8, ?*std.builtin.StackTrace) noreturn', found 'fn([]const u8,var)var'", + "note: only one of the functions is generic", ); cases.add( @@ -1473,7 +1473,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ const field = @typeInfo(Struct).Struct.fields[index]; \\} , - "tmp.zig:9:51: error: values of type 'builtin.StructField' must be comptime known, but index value is runtime known", + "tmp.zig:9:51: error: values of type 'std.builtin.StructField' must be comptime known, but index value is runtime known", ); cases.add( @@ -3743,13 +3743,19 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { ); cases.add( - "missing function name and param name", + "missing function name", \\fn () void {} - \\fn f(i32) void {} \\export fn entry() usize { return @sizeOf(@typeOf(f)); } , "tmp.zig:1:1: error: missing function name", - "tmp.zig:2:6: error: missing parameter name", + ); + + cases.add( + "missing param name", + \\fn f(i32) void {} + \\export fn entry() usize { return @sizeOf(@typeOf(f)); } + , + "tmp.zig:1:6: error: missing parameter name", ); cases.add( @@ -3782,7 +3788,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\export fn entry() usize { return @sizeOf(@typeOf(func)); } , "tmp.zig:2:1: error: redefinition of 'func'", - "tmp.zig:1:11: error: use of undeclared identifier 'bogus'", ); cases.add( @@ -5086,7 +5091,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ const foo = builtin.Arch.x86; \\} , - "tmp.zig:3:29: error: container 'builtin.Arch' has no member called 'x86'", + "tmp.zig:3:29: error: container 'std.target.Arch' has no member called 'x86'", ); cases.add( @@ -5731,7 +5736,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ while (!@cmpxchgWeak(i32, &x, 1234, 5678, u32(1234), u32(1234))) {} \\} , - "tmp.zig:3:50: error: expected type 'builtin.AtomicOrder', found 'u32'", + "tmp.zig:3:50: error: expected type 'std.builtin.AtomicOrder', found 'u32'", ); cases.add( @@ -5741,7 +5746,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ @export("entry", entry, u32(1234)); \\} , - "tmp.zig:3:32: error: expected type 'builtin.GlobalLinkage', found 'u32'", + "tmp.zig:3:32: error: expected type 'std.builtin.GlobalLinkage', found 'u32'", ); cases.add( -- 2.54.0 From 8591731f2b938b2b55b05181d5ec0e27f79c86fa Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 24 Oct 2019 00:30:17 -0400 Subject: [PATCH 2/3] refAllDecls in a test block to limit when it gets run --- lib/std/math.zig | 2 +- lib/std/os.zig | 23 ++++++++++++----------- lib/std/std.zig | 2 +- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/lib/std/math.zig b/lib/std/math.zig index cb9589e95de49921b028858d66bd9c2ad9d4fc52..9b56d0b8ce62a5f6ae96bdd8ae84582b2df20c21 100644 --- a/lib/std/math.zig +++ b/lib/std/math.zig @@ -202,7 +202,7 @@ pub const Complex = complex.Complex; pub const big = @import("math/big.zig"); -comptime { +test "" { std.meta.refAllDecls(@This()); } diff --git a/lib/std/os.zig b/lib/std/os.zig index 19ca282979e3ab80b5e7f0d79574d203037088b1..4a2c0b971e295c26b8037603c11be2ee4b810c21 100644 --- a/lib/std/os.zig +++ b/lib/std/os.zig @@ -34,18 +34,19 @@ pub const zen = @import("os/zen.zig"); comptime { assert(@import("std") == std); // std lib tests require --override-lib-dir - if (builtin.is_test) { - _ = darwin; - _ = freebsd; - _ = linux; - _ = netbsd; - _ = uefi; - _ = wasi; - _ = windows; - _ = zen; +} - _ = @import("os/test.zig"); - } +test "" { + _ = darwin; + _ = freebsd; + _ = linux; + _ = netbsd; + _ = uefi; + _ = wasi; + _ = windows; + _ = zen; + + _ = @import("os/test.zig"); } /// When linking libc, this is the C API. Otherwise, it is the OS-specific system interface. diff --git a/lib/std/std.zig b/lib/std/std.zig index a7cce4fd6fa5ca60088a93386589b43c3d477866..ea6257009fe941383f28314ecaee48e64f45b4ce 100644 --- a/lib/std/std.zig +++ b/lib/std/std.zig @@ -65,6 +65,6 @@ pub const unicode = @import("unicode.zig"); pub const valgrind = @import("valgrind.zig"); pub const zig = @import("zig.zig"); -comptime { +test "" { meta.refAllDecls(@This()); } -- 2.54.0 From 60cd11bd4b48e4dfdf11d1f25cb1ee842a49ee1d Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 24 Oct 2019 01:06:03 -0400 Subject: [PATCH 3/3] get rid of std.os.foo.is_the_target It had the downside of running all the comptime blocks and resolving all the usingnamespaces of each system, when just trying to discover if the current system is a particular one. For Darwin, where it's nice to use `std.Target.current.isDarwin()`, this demonstrates the utility that #425 would provide. --- lib/std/build.zig | 2 +- lib/std/c/darwin.zig | 2 +- lib/std/child_process.zig | 24 ++++---- lib/std/debug.zig | 16 ++--- lib/std/event/channel.zig | 2 +- lib/std/event/fs.zig | 2 +- lib/std/event/future.zig | 2 +- lib/std/event/lock.zig | 2 +- lib/std/fs.zig | 18 +++--- lib/std/fs/file.zig | 22 +++---- lib/std/fs/path.zig | 34 +++++------ lib/std/heap.zig | 6 +- lib/std/io.zig | 6 +- lib/std/os.zig | 125 +++++++++++++++++++------------------- lib/std/os/darwin.zig | 4 -- lib/std/os/freebsd.zig | 2 - lib/std/os/linux.zig | 3 +- lib/std/os/netbsd.zig | 2 - lib/std/os/test.zig | 6 +- lib/std/os/uefi.zig | 16 ++++- lib/std/os/wasi.zig | 2 - lib/std/os/windows.zig | 1 - lib/std/process.zig | 4 +- lib/std/target.zig | 3 + lib/std/thread.zig | 10 +-- lib/std/time.zig | 20 +++--- 26 files changed, 170 insertions(+), 166 deletions(-) diff --git a/lib/std/build.zig b/lib/std/build.zig index 4f0956d549a0a140184a45426b6f5d925b5af49e..6ef7286f9b6683f15ba34521c34d19bd85f3a1ec 100644 --- a/lib/std/build.zig +++ b/lib/std/build.zig @@ -2000,7 +2000,7 @@ pub const RunStep = struct { } pub fn addPathDir(self: *RunStep, search_path: []const u8) void { - const PATH = if (std.os.windows.is_the_target) "Path" else "PATH"; + const PATH = if (builtin.os == .windows) "Path" else "PATH"; const env_map = self.getEnvMap(); const prev_path = env_map.get(PATH) orelse { env_map.set(PATH, search_path) catch unreachable; diff --git a/lib/std/c/darwin.zig b/lib/std/c/darwin.zig index f2e8120a0e8725b11f1e36d237aaaa910ede718e..ebd12a0d86429860d4df2d40f2bda09bee2ebd87 100644 --- a/lib/std/c/darwin.zig +++ b/lib/std/c/darwin.zig @@ -36,7 +36,7 @@ const mach_hdr = if (@sizeOf(usize) == 8) mach_header_64 else mach_header; /// export a weak symbol here, to be overridden by the real one. pub extern "c" var _mh_execute_header: mach_hdr = undefined; comptime { - if (std.os.darwin.is_the_target) { + if (std.Target.current.isDarwin()) { @export("_mh_execute_header", _mh_execute_header, .Weak); } } diff --git a/lib/std/child_process.zig b/lib/std/child_process.zig index d786c3f4de356fdce76d44671e4a71c6213020f0..5fae9447a99562d868da92dd78a65afa678fea9e 100644 --- a/lib/std/child_process.zig +++ b/lib/std/child_process.zig @@ -17,9 +17,9 @@ const TailQueue = std.TailQueue; const maxInt = std.math.maxInt; pub const ChildProcess = struct { - pid: if (os.windows.is_the_target) void else i32, - handle: if (os.windows.is_the_target) windows.HANDLE else void, - thread_handle: if (os.windows.is_the_target) windows.HANDLE else void, + pid: if (builtin.os == .windows) void else i32, + handle: if (builtin.os == .windows) windows.HANDLE else void, + thread_handle: if (builtin.os == .windows) windows.HANDLE else void, allocator: *mem.Allocator, @@ -39,16 +39,16 @@ pub const ChildProcess = struct { stderr_behavior: StdIo, /// Set to change the user id when spawning the child process. - uid: if (os.windows.is_the_target) void else ?u32, + uid: if (builtin.os == .windows) void else ?u32, /// Set to change the group id when spawning the child process. - gid: if (os.windows.is_the_target) void else ?u32, + gid: if (builtin.os == .windows) void else ?u32, /// Set to change the current working directory when spawning the child process. cwd: ?[]const u8, - err_pipe: if (os.windows.is_the_target) void else [2]os.fd_t, - llnode: if (os.windows.is_the_target) void else TailQueue(*ChildProcess).Node, + err_pipe: if (builtin.os == .windows) void else [2]os.fd_t, + llnode: if (builtin.os == .windows) void else TailQueue(*ChildProcess).Node, pub const SpawnError = error{OutOfMemory} || os.ExecveError || os.SetIdError || os.ChangeCurDirError || windows.CreateProcessError; @@ -82,8 +82,8 @@ pub const ChildProcess = struct { .term = null, .env_map = null, .cwd = null, - .uid = if (os.windows.is_the_target) {} else null, - .gid = if (os.windows.is_the_target) {} else null, + .uid = if (builtin.os == .windows) {} else null, + .gid = if (builtin.os == .windows) {} else null, .stdin = null, .stdout = null, .stderr = null, @@ -103,7 +103,7 @@ pub const ChildProcess = struct { /// On success must call `kill` or `wait`. pub fn spawn(self: *ChildProcess) !void { - if (os.windows.is_the_target) { + if (builtin.os == .windows) { return self.spawnWindows(); } else { return self.spawnPosix(); @@ -117,7 +117,7 @@ pub const ChildProcess = struct { /// Forcibly terminates child process and then cleans up all resources. pub fn kill(self: *ChildProcess) !Term { - if (os.windows.is_the_target) { + if (builtin.os == .windows) { return self.killWindows(1); } else { return self.killPosix(); @@ -147,7 +147,7 @@ pub const ChildProcess = struct { /// Blocks until child process terminates and then cleans up all resources. pub fn wait(self: *ChildProcess) !Term { - if (os.windows.is_the_target) { + if (builtin.os == .windows) { return self.waitWindows(); } else { return self.waitPosix(); diff --git a/lib/std/debug.zig b/lib/std/debug.zig index 0be778b3b6a93c6beafcc27080405e455a202e5f..95670dc4eadf5a6439366964c30fb69e0b5d70e2 100644 --- a/lib/std/debug.zig +++ b/lib/std/debug.zig @@ -133,7 +133,7 @@ pub fn dumpStackTraceFromBase(bp: usize, ip: usize) void { /// chopping off the irrelevant frames and shifting so that the returned addresses pointer /// equals the passed in addresses pointer. pub fn captureStackTrace(first_address: ?usize, stack_trace: *builtin.StackTrace) void { - if (windows.is_the_target) { + if (builtin.os == .windows) { const addrs = stack_trace.instruction_addresses; const u32_addrs_len = @intCast(u32, addrs.len); const first_addr = first_address orelse { @@ -310,7 +310,7 @@ pub const StackIterator = struct { }; pub fn writeCurrentStackTrace(out_stream: var, debug_info: *DebugInfo, tty_color: bool, start_addr: ?usize) !void { - if (windows.is_the_target) { + if (builtin.os == .windows) { return writeCurrentStackTraceWindows(out_stream, debug_info, tty_color, start_addr); } var it = StackIterator.init(start_addr); @@ -342,10 +342,10 @@ pub fn writeCurrentStackTraceWindows( /// TODO once https://github.com/ziglang/zig/issues/3157 is fully implemented, /// make this `noasync fn` and remove the individual noasync calls. pub fn printSourceAtAddress(debug_info: *DebugInfo, out_stream: var, address: usize, tty_color: bool) !void { - if (windows.is_the_target) { + if (builtin.os == .windows) { return noasync printSourceAtAddressWindows(debug_info, out_stream, address, tty_color); } - if (os.darwin.is_the_target) { + if (comptime std.Target.current.isDarwin()) { return noasync printSourceAtAddressMacOs(debug_info, out_stream, address, tty_color); } return noasync printSourceAtAddressPosix(debug_info, out_stream, address, tty_color); @@ -832,10 +832,10 @@ pub const OpenSelfDebugInfoError = error{ pub fn openSelfDebugInfo(allocator: *mem.Allocator) !DebugInfo { if (builtin.strip_debug_info) return error.MissingDebugInfo; - if (windows.is_the_target) { + if (builtin.os == .windows) { return noasync openSelfDebugInfoWindows(allocator); } - if (os.darwin.is_the_target) { + if (comptime std.Target.current.isDarwin()) { return noasync openSelfDebugInfoMacOs(allocator); } return noasync openSelfDebugInfoPosix(allocator); @@ -2364,7 +2364,7 @@ pub fn attachSegfaultHandler() void { if (!have_segfault_handling_support) { @compileError("segfault handler not supported for this target"); } - if (windows.is_the_target) { + if (builtin.os == .windows) { windows_segfault_handle = windows.kernel32.AddVectoredExceptionHandler(0, handleSegfaultWindows); return; } @@ -2378,7 +2378,7 @@ pub fn attachSegfaultHandler() void { } fn resetSegfaultHandler() void { - if (windows.is_the_target) { + if (builtin.os == .windows) { if (windows_segfault_handle) |handle| { assert(windows.kernel32.RemoveVectoredExceptionHandler(handle) != 0); windows_segfault_handle = null; diff --git a/lib/std/event/channel.zig b/lib/std/event/channel.zig index 2f211d21e2b646421cc5bb0ccfaf788e5e51c018..1092f2204a272ec313557faa69936ae3a2faf4fb 100644 --- a/lib/std/event/channel.zig +++ b/lib/std/event/channel.zig @@ -307,7 +307,7 @@ test "std.event.Channel" { // https://github.com/ziglang/zig/issues/1908 if (builtin.single_threaded) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/3251 - if (std.os.freebsd.is_the_target) return error.SkipZigTest; + if (builtin.os == .freebsd) return error.SkipZigTest; var loop: Loop = undefined; // TODO make a multi threaded test diff --git a/lib/std/event/fs.zig b/lib/std/event/fs.zig index 81fd950e446aa8e6088c7b2a9509610e19eacd1a..2f64d453af48cbb8544870e3f8a7040af0e69913 100644 --- a/lib/std/event/fs.zig +++ b/lib/std/event/fs.zig @@ -909,7 +909,7 @@ fn hashString(s: []const u16) u32 { // var close_op_consumed = false; // defer if (!close_op_consumed) close_op.finish(); // -// const flags = if (os.darwin.is_the_target) os.O_SYMLINK | os.O_EVTONLY else 0; +// const flags = if (comptime std.Target.current.isDarwin()) os.O_SYMLINK | os.O_EVTONLY else 0; // const mode = 0; // const fd = try await (async openPosix(self.channel.loop, resolved_path, flags, mode) catch unreachable); // close_op.setHandle(fd); diff --git a/lib/std/event/future.zig b/lib/std/event/future.zig index 1e3508de4106a35a5991e7cc8931c252038944f6..c5376bc9f6bb62c7a45a8ec8cb01783a55f7cd12 100644 --- a/lib/std/event/future.zig +++ b/lib/std/event/future.zig @@ -86,7 +86,7 @@ test "std.event.Future" { // https://github.com/ziglang/zig/issues/1908 if (builtin.single_threaded) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/3251 - if (std.os.freebsd.is_the_target) return error.SkipZigTest; + if (builtin.os == .freebsd) return error.SkipZigTest; const allocator = std.heap.direct_allocator; diff --git a/lib/std/event/lock.zig b/lib/std/event/lock.zig index a0b1fd3e50d1e9a7c76eabd8cc1d010f5f09b7f3..fdcfd1e2981e7ec445533de12660adfcfcd49db4 100644 --- a/lib/std/event/lock.zig +++ b/lib/std/event/lock.zig @@ -119,7 +119,7 @@ test "std.event.Lock" { // TODO https://github.com/ziglang/zig/issues/1908 if (builtin.single_threaded) return error.SkipZigTest; // TODO https://github.com/ziglang/zig/issues/3251 - if (std.os.freebsd.is_the_target) return error.SkipZigTest; + if (builtin.os == .freebsd) return error.SkipZigTest; const allocator = std.heap.direct_allocator; diff --git a/lib/std/fs.zig b/lib/std/fs.zig index 3fdd175e77d514df1c119575b9addb581ab66577..5517f6f2804dcd87d96abbf39c556f63579a489c 100644 --- a/lib/std/fs.zig +++ b/lib/std/fs.zig @@ -255,7 +255,7 @@ pub const AtomicFile = struct { assert(!self.finished); self.file.close(); self.finished = true; - if (os.windows.is_the_target) { + if (builtin.os == .windows) { const dest_path_w = try os.windows.sliceToPrefixedFileW(self.dest_path); const tmp_path_w = try os.windows.cStrToPrefixedFileW(&self.tmp_path_buf); return os.renameW(&tmp_path_w, &dest_path_w); @@ -659,7 +659,7 @@ pub const Dir = struct { /// Closing the returned `Dir` is checked illegal behavior. /// On POSIX targets, this function is comptime-callable. pub fn cwd() Dir { - if (os.windows.is_the_target) { + if (builtin.os == .windows) { return Dir{ .fd = os.windows.peb().ProcessParameters.CurrentDirectory.Handle }; } else { return Dir{ .fd = os.AT_FDCWD }; @@ -711,7 +711,7 @@ pub const Dir = struct { /// Call `close` on the result when done. pub fn openDir(self: Dir, sub_path: []const u8) OpenError!Dir { - if (os.windows.is_the_target) { + if (builtin.os == .windows) { const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path); return self.openDirW(&sub_path_w); } @@ -722,7 +722,7 @@ pub const Dir = struct { /// Same as `openDir` except the parameter is null-terminated. pub fn openDirC(self: Dir, sub_path_c: [*]const u8) OpenError!Dir { - if (os.windows.is_the_target) { + if (builtin.os == .windows) { const sub_path_w = try os.windows.cStrToPrefixedFileW(sub_path_c); return self.openDirW(&sub_path_w); } @@ -829,7 +829,7 @@ pub const Dir = struct { /// Returns `error.DirNotEmpty` if the directory is not empty. /// To delete a directory recursively, see `deleteTree`. pub fn deleteDir(self: Dir, sub_path: []const u8) DeleteDirError!void { - if (os.windows.is_the_target) { + if (builtin.os == .windows) { const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path); return self.deleteDirW(&sub_path_w); } @@ -1146,10 +1146,10 @@ pub fn readLinkC(pathname_c: [*]const u8, buffer: *[MAX_PATH_BYTES]u8) ![]u8 { pub const OpenSelfExeError = os.OpenError || os.windows.CreateFileError || SelfExePathError; pub fn openSelfExe() OpenSelfExeError!File { - if (os.linux.is_the_target) { + if (builtin.os == .linux) { return File.openReadC(c"/proc/self/exe"); } - if (os.windows.is_the_target) { + if (builtin.os == .windows) { var buf: [os.windows.PATH_MAX_WIDE]u16 = undefined; const wide_slice = try selfExePathW(&buf); return File.openReadW(wide_slice.ptr); @@ -1180,7 +1180,7 @@ pub const SelfExePathError = os.ReadLinkError || os.SysCtlError; /// been deleted, the file path looks something like `/a/b/c/exe (deleted)`. /// TODO make the return type of this a null terminated pointer pub fn selfExePath(out_buffer: *[MAX_PATH_BYTES]u8) SelfExePathError![]u8 { - if (os.darwin.is_the_target) { + if (comptime std.Target.current.isDarwin()) { var u32_len: u32 = out_buffer.len; const rc = std.c._NSGetExecutablePath(out_buffer, &u32_len); if (rc != 0) return error.NameTooLong; @@ -1228,7 +1228,7 @@ pub fn selfExeDirPathAlloc(allocator: *Allocator) ![]u8 { /// Get the directory path that contains the current executable. /// Returned value is a slice of out_buffer. pub fn selfExeDirPath(out_buffer: *[MAX_PATH_BYTES]u8) SelfExePathError![]const u8 { - if (os.linux.is_the_target) { + if (builtin.os == .linux) { // If the currently executing binary has been deleted, // the file path looks something like `/a/b/c/exe (deleted)` // This path cannot be opened, but it's valid for determining the directory diff --git a/lib/std/fs/file.zig b/lib/std/fs/file.zig index 44992ff47d866b4cc61bdf9e1abd6c43803224fd..06a26ed48184bdcc541127dae685e100f3c08caa 100644 --- a/lib/std/fs/file.zig +++ b/lib/std/fs/file.zig @@ -27,7 +27,7 @@ pub const File = struct { /// Call close to clean up. pub fn openRead(path: []const u8) OpenError!File { - if (windows.is_the_target) { + if (builtin.os == .windows) { const path_w = try windows.sliceToPrefixedFileW(path); return openReadW(&path_w); } @@ -37,7 +37,7 @@ pub const File = struct { /// `openRead` except with a null terminated path pub fn openReadC(path: [*]const u8) OpenError!File { - if (windows.is_the_target) { + if (builtin.os == .windows) { const path_w = try windows.cStrToPrefixedFileW(path); return openReadW(&path_w); } @@ -69,7 +69,7 @@ pub const File = struct { /// If a file already exists in the destination it will be truncated. /// Call close to clean up. pub fn openWriteMode(path: []const u8, file_mode: Mode) OpenError!File { - if (windows.is_the_target) { + if (builtin.os == .windows) { const path_w = try windows.sliceToPrefixedFileW(path); return openWriteModeW(&path_w, file_mode); } @@ -79,7 +79,7 @@ pub const File = struct { /// Same as `openWriteMode` except `path` is null-terminated. pub fn openWriteModeC(path: [*]const u8, file_mode: Mode) OpenError!File { - if (windows.is_the_target) { + if (builtin.os == .windows) { const path_w = try windows.cStrToPrefixedFileW(path); return openWriteModeW(&path_w, file_mode); } @@ -106,7 +106,7 @@ pub const File = struct { /// If a file already exists in the destination this returns OpenError.PathAlreadyExists /// Call close to clean up. pub fn openWriteNoClobber(path: []const u8, file_mode: Mode) OpenError!File { - if (windows.is_the_target) { + if (builtin.os == .windows) { const path_w = try windows.sliceToPrefixedFileW(path); return openWriteNoClobberW(&path_w, file_mode); } @@ -115,7 +115,7 @@ pub const File = struct { } pub fn openWriteNoClobberC(path: [*]const u8, file_mode: Mode) OpenError!File { - if (windows.is_the_target) { + if (builtin.os == .windows) { const path_w = try windows.cStrToPrefixedFileW(path); return openWriteNoClobberW(&path_w, file_mode); } @@ -174,7 +174,7 @@ pub const File = struct { /// Test whether ANSI escape codes will be treated as such. pub fn supportsAnsiEscapeCodes(self: File) bool { - if (windows.is_the_target) { + if (builtin.os == .windows) { return os.isCygwinPty(self.handle); } if (self.isTty()) { @@ -214,7 +214,7 @@ pub const File = struct { } pub fn getEndPos(self: File) GetPosError!u64 { - if (windows.is_the_target) { + if (builtin.os == .windows) { return windows.GetFileSizeEx(self.handle); } return (try self.stat()).size; @@ -223,7 +223,7 @@ pub const File = struct { pub const ModeError = os.FStatError; pub fn mode(self: File) ModeError!Mode { - if (windows.is_the_target) { + if (builtin.os == .windows) { return {}; } return (try self.stat()).mode; @@ -246,7 +246,7 @@ pub const File = struct { pub const StatError = os.FStatError; pub fn stat(self: File) StatError!Stat { - if (windows.is_the_target) { + if (builtin.os == .windows) { var io_status_block: windows.IO_STATUS_BLOCK = undefined; var info: windows.FILE_ALL_INFORMATION = undefined; const rc = windows.ntdll.NtQueryInformationFile(self.handle, &io_status_block, &info, @sizeOf(windows.FILE_ALL_INFORMATION), .FileAllInformation); @@ -291,7 +291,7 @@ pub const File = struct { /// last modification timestamp in nanoseconds mtime: i64, ) UpdateTimesError!void { - if (windows.is_the_target) { + if (builtin.os == .windows) { const atime_ft = windows.nanoSecondsToFileTime(atime); const mtime_ft = windows.nanoSecondsToFileTime(mtime); return windows.SetFileTime(self.handle, null, &atime_ft, &mtime_ft); diff --git a/lib/std/fs/path.zig b/lib/std/fs/path.zig index 560d9b58f3440382f5e7b1050f44d3347d7f6ffc..f337e1df9ad463fb2c7341c28cf51302dbc675bd 100644 --- a/lib/std/fs/path.zig +++ b/lib/std/fs/path.zig @@ -13,16 +13,16 @@ const process = std.process; pub const sep_windows = '\\'; pub const sep_posix = '/'; -pub const sep = if (windows.is_the_target) sep_windows else sep_posix; +pub const sep = if (builtin.os == .windows) sep_windows else sep_posix; pub const sep_str = [1]u8{sep}; pub const delimiter_windows = ';'; pub const delimiter_posix = ':'; -pub const delimiter = if (windows.is_the_target) delimiter_windows else delimiter_posix; +pub const delimiter = if (builtin.os == .windows) delimiter_windows else delimiter_posix; pub fn isSep(byte: u8) bool { - if (windows.is_the_target) { + if (builtin.os == .windows) { return byte == '/' or byte == '\\'; } else { return byte == '/'; @@ -72,7 +72,7 @@ fn joinSep(allocator: *Allocator, separator: u8, paths: []const []const u8) ![]u return buf; } -pub const join = if (windows.is_the_target) joinWindows else joinPosix; +pub const join = if (builtin.os == .windows) joinWindows else joinPosix; /// Naively combines a series of paths with the native path seperator. /// Allocates memory for the result, which must be freed by the caller. @@ -129,7 +129,7 @@ test "join" { } pub fn isAbsolute(path: []const u8) bool { - if (windows.is_the_target) { + if (builtin.os == .windows) { return isAbsoluteWindows(path); } else { return isAbsolutePosix(path); @@ -327,7 +327,7 @@ test "windowsParsePath" { } pub fn diskDesignator(path: []const u8) []const u8 { - if (windows.is_the_target) { + if (builtin.os == .windows) { return diskDesignatorWindows(path); } else { return ""; @@ -392,7 +392,7 @@ fn asciiEqlIgnoreCase(s1: []const u8, s2: []const u8) bool { /// On Windows, this calls `resolveWindows` and on POSIX it calls `resolvePosix`. pub fn resolve(allocator: *Allocator, paths: []const []const u8) ![]u8 { - if (windows.is_the_target) { + if (builtin.os == .windows) { return resolveWindows(allocator, paths); } else { return resolvePosix(allocator, paths); @@ -409,7 +409,7 @@ pub fn resolve(allocator: *Allocator, paths: []const []const u8) ![]u8 { /// Without performing actual syscalls, resolving `..` could be incorrect. pub fn resolveWindows(allocator: *Allocator, paths: []const []const u8) ![]u8 { if (paths.len == 0) { - assert(windows.is_the_target); // resolveWindows called on non windows can't use getCwd + assert(builtin.os == .windows); // resolveWindows called on non windows can't use getCwd return process.getCwdAlloc(allocator); } @@ -504,7 +504,7 @@ pub fn resolveWindows(allocator: *Allocator, paths: []const []const u8) ![]u8 { result_disk_designator = result[0..result_index]; }, WindowsPath.Kind.None => { - assert(windows.is_the_target); // resolveWindows called on non windows can't use getCwd + assert(builtin.os == .windows); // resolveWindows called on non windows can't use getCwd const cwd = try process.getCwdAlloc(allocator); defer allocator.free(cwd); const parsed_cwd = windowsParsePath(cwd); @@ -519,7 +519,7 @@ pub fn resolveWindows(allocator: *Allocator, paths: []const []const u8) ![]u8 { }, } } else { - assert(windows.is_the_target); // resolveWindows called on non windows can't use getCwd + assert(builtin.os == .windows); // resolveWindows called on non windows can't use getCwd // TODO call get cwd for the result_disk_designator instead of the global one const cwd = try process.getCwdAlloc(allocator); defer allocator.free(cwd); @@ -590,7 +590,7 @@ pub fn resolveWindows(allocator: *Allocator, paths: []const []const u8) ![]u8 { /// Without performing actual syscalls, resolving `..` could be incorrect. pub fn resolvePosix(allocator: *Allocator, paths: []const []const u8) ![]u8 { if (paths.len == 0) { - assert(!windows.is_the_target); // resolvePosix called on windows can't use getCwd + assert(builtin.os != .windows); // resolvePosix called on windows can't use getCwd return process.getCwdAlloc(allocator); } @@ -612,7 +612,7 @@ pub fn resolvePosix(allocator: *Allocator, paths: []const []const u8) ![]u8 { if (have_abs) { result = try allocator.alloc(u8, max_size); } else { - assert(!windows.is_the_target); // resolvePosix called on windows can't use getCwd + assert(builtin.os != .windows); // resolvePosix called on windows can't use getCwd const cwd = try process.getCwdAlloc(allocator); defer allocator.free(cwd); result = try allocator.alloc(u8, max_size + cwd.len + 1); @@ -653,7 +653,7 @@ pub fn resolvePosix(allocator: *Allocator, paths: []const []const u8) ![]u8 { test "resolve" { const cwd = try process.getCwdAlloc(debug.global_allocator); - if (windows.is_the_target) { + if (builtin.os == .windows) { if (windowsParsePath(cwd).kind == WindowsPath.Kind.Drive) { cwd[0] = asciiUpper(cwd[0]); } @@ -669,7 +669,7 @@ test "resolveWindows" { // TODO https://github.com/ziglang/zig/issues/3288 return error.SkipZigTest; } - if (windows.is_the_target) { + if (builtin.os == .windows) { const cwd = try process.getCwdAlloc(debug.global_allocator); const parsed_cwd = windowsParsePath(cwd); { @@ -735,7 +735,7 @@ fn testResolvePosix(paths: []const []const u8) []u8 { /// If the path is a file in the current directory (no directory component) /// then returns null pub fn dirname(path: []const u8) ?[]const u8 { - if (windows.is_the_target) { + if (builtin.os == .windows) { return dirnameWindows(path); } else { return dirnamePosix(path); @@ -867,7 +867,7 @@ fn testDirnameWindows(input: []const u8, expected_output: ?[]const u8) void { } pub fn basename(path: []const u8) []const u8 { - if (windows.is_the_target) { + if (builtin.os == .windows) { return basenameWindows(path); } else { return basenamePosix(path); @@ -983,7 +983,7 @@ fn testBasenameWindows(input: []const u8, expected_output: []const u8) void { /// string is returned. /// On Windows this canonicalizes the drive to a capital letter and paths to `\\`. pub fn relative(allocator: *Allocator, from: []const u8, to: []const u8) ![]u8 { - if (windows.is_the_target) { + if (builtin.os == .windows) { return relativeWindows(allocator, from, to); } else { return relativePosix(allocator, from, to); diff --git a/lib/std/heap.zig b/lib/std/heap.zig index f3a0d457d2a0a2403bdd047bfc3c6c932ab2168f..8723c7eab667d71b509afa8682b7ef1f39f8bf35 100644 --- a/lib/std/heap.zig +++ b/lib/std/heap.zig @@ -44,7 +44,7 @@ const DirectAllocator = struct { if (n == 0) return (([*]u8)(undefined))[0..0]; - if (os.windows.is_the_target) { + if (builtin.os == .windows) { const w = os.windows; // Although officially it's at least aligned to page boundary, @@ -130,7 +130,7 @@ const DirectAllocator = struct { fn shrink(allocator: *Allocator, old_mem_unaligned: []u8, old_align: u29, new_size: usize, new_align: u29) []u8 { const old_mem = @alignCast(mem.page_size, old_mem_unaligned); - if (os.windows.is_the_target) { + if (builtin.os == .windows) { const w = os.windows; if (new_size == 0) { // From the docs: @@ -170,7 +170,7 @@ const DirectAllocator = struct { fn realloc(allocator: *Allocator, old_mem_unaligned: []u8, old_align: u29, new_size: usize, new_align: u29) ![]u8 { const old_mem = @alignCast(mem.page_size, old_mem_unaligned); - if (os.windows.is_the_target) { + if (builtin.os == .windows) { if (old_mem.len == 0) { return alloc(allocator, new_size, new_align); } diff --git a/lib/std/io.zig b/lib/std/io.zig index 7502601650ff032ad67d63f7fd9fb2aecc0bba54..39c3a7cf9bef6bf448fdf75f03173d7a062ebd91 100644 --- a/lib/std/io.zig +++ b/lib/std/io.zig @@ -37,7 +37,7 @@ pub const is_async = mode != .blocking; pub const GetStdIoError = os.windows.GetStdHandleError; pub fn getStdOut() GetStdIoError!File { - if (os.windows.is_the_target) { + if (builtin.os == .windows) { const handle = try os.windows.GetStdHandle(os.windows.STD_OUTPUT_HANDLE); return File.openHandle(handle); } @@ -45,7 +45,7 @@ pub fn getStdOut() GetStdIoError!File { } pub fn getStdErr() GetStdIoError!File { - if (os.windows.is_the_target) { + if (builtin.os == .windows) { const handle = try os.windows.GetStdHandle(os.windows.STD_ERROR_HANDLE); return File.openHandle(handle); } @@ -53,7 +53,7 @@ pub fn getStdErr() GetStdIoError!File { } pub fn getStdIn() GetStdIoError!File { - if (os.windows.is_the_target) { + if (builtin.os == .windows) { const handle = try os.windows.GetStdHandle(os.windows.STD_INPUT_HANDLE); return File.openHandle(handle); } diff --git a/lib/std/os.zig b/lib/std/os.zig index 4a2c0b971e295c26b8037603c11be2ee4b810c21..d239f198f473041f108baa4d49123ea168982ec8 100644 --- a/lib/std/os.zig +++ b/lib/std/os.zig @@ -85,13 +85,13 @@ pub const errno = system.getErrno; /// must call `fsync` before `close`. /// Note: The Zig standard library does not support POSIX thread cancellation. pub fn close(fd: fd_t) void { - if (windows.is_the_target) { + if (builtin.os == .windows) { return windows.CloseHandle(fd); } - if (wasi.is_the_target) { + if (builtin.os == .wasi) { _ = wasi.fd_close(fd); } - if (darwin.is_the_target) { + if (comptime std.Target.current.isDarwin()) { // This avoids the EINTR problem. switch (darwin.getErrno(darwin.@"close$NOCANCEL"(fd))) { EBADF => unreachable, // Always a race condition. @@ -113,12 +113,12 @@ pub const GetRandomError = OpenError; /// appropriate OS-specific library call. Otherwise it uses the zig standard /// library implementation. pub fn getrandom(buffer: []u8) GetRandomError!void { - if (windows.is_the_target) { + if (builtin.os == .windows) { return windows.RtlGenRandom(buffer); } - if (linux.is_the_target or freebsd.is_the_target) { + if (builtin.os == .linux or builtin.os == .freebsd) { var buf = buffer; - const use_c = !linux.is_the_target or + const use_c = builtin.os != .linux or std.c.versionCheck(builtin.Version{ .major = 2, .minor = 25, .patch = 0 }).ok; while (buf.len != 0) { @@ -145,7 +145,7 @@ pub fn getrandom(buffer: []u8) GetRandomError!void { } return; } - if (wasi.is_the_target) { + if (builtin.os == .wasi) { switch (wasi.random_get(buffer.ptr, buffer.len)) { 0 => return, else => |err| return unexpectedErrno(err), @@ -175,7 +175,7 @@ pub fn abort() noreturn { // MSVCRT abort() sometimes opens a popup window which is undesirable, so // even when linking libc on Windows we use our own abort implementation. // See https://github.com/ziglang/zig/issues/2071 for more details. - if (windows.is_the_target) { + if (builtin.os == .windows) { if (builtin.mode == .Debug) { @breakpoint(); } @@ -206,14 +206,14 @@ pub fn raise(sig: u8) RaiseError!void { } } - if (wasi.is_the_target) { + if (builtin.os == .wasi) { switch (wasi.proc_raise(SIGABRT)) { 0 => return, else => |err| return unexpectedErrno(err), } } - if (linux.is_the_target) { + if (builtin.os == .linux) { var set: linux.sigset_t = undefined; linux.blockAppSignals(&set); const tid = linux.syscall0(linux.SYS_gettid); @@ -245,16 +245,16 @@ pub fn exit(status: u8) noreturn { if (builtin.link_libc) { system.exit(status); } - if (windows.is_the_target) { + if (builtin.os == .windows) { windows.kernel32.ExitProcess(status); } - if (wasi.is_the_target) { + if (builtin.os == .wasi) { wasi.proc_exit(status); } - if (linux.is_the_target and !builtin.single_threaded) { + if (builtin.os == .linux and !builtin.single_threaded) { linux.exit_group(status); } - if (uefi.is_the_target) { + if (builtin.os == .uefi) { // exit() is only avaliable if exitBootServices() has not been called yet. // This call to exit should not fail, so we don't care about its return value. if (uefi.system_table.boot_services) |bs| { @@ -283,11 +283,11 @@ pub const ReadError = error{ /// If the application has a global event loop enabled, EAGAIN is handled /// via the event loop. Otherwise EAGAIN results in error.WouldBlock. pub fn read(fd: fd_t, buf: []u8) ReadError!usize { - if (windows.is_the_target) { + if (builtin.os == .windows) { return windows.ReadFile(fd, buf); } - if (wasi.is_the_target and !builtin.link_libc) { + if (builtin.os == .wasi and !builtin.link_libc) { const iovs = [1]iovec{iovec{ .iov_base = buf.ptr, .iov_len = buf.len, @@ -327,7 +327,7 @@ pub fn read(fd: fd_t, buf: []u8) ReadError!usize { /// Number of bytes read is returned. Upon reading end-of-file, zero is returned. /// This function is for blocking file descriptors only. pub fn preadv(fd: fd_t, iov: []const iovec, offset: u64) ReadError!usize { - if (darwin.is_the_target) { + if (comptime std.Target.current.isDarwin()) { // Darwin does not have preadv but it does have pread. var off: usize = 0; var iov_i: usize = 0; @@ -398,11 +398,11 @@ pub const WriteError = error{ /// Write to a file descriptor. Keeps trying if it gets interrupted. /// This function is for blocking file descriptors only. pub fn write(fd: fd_t, bytes: []const u8) WriteError!void { - if (windows.is_the_target) { + if (builtin.os == .windows) { return windows.WriteFile(fd, bytes); } - if (wasi.is_the_target and !builtin.link_libc) { + if (builtin.os == .wasi and !builtin.link_libc) { const ciovs = [1]iovec_const{iovec_const{ .iov_base = bytes.ptr, .iov_len = bytes.len, @@ -477,7 +477,7 @@ pub fn writev(fd: fd_t, iov: []const iovec_const) WriteError!void { /// This function is for blocking file descriptors only. For non-blocking, see /// `pwritevAsync`. pub fn pwritev(fd: fd_t, iov: []const iovec_const, offset: u64) WriteError!void { - if (darwin.is_the_target) { + if (comptime std.Target.current.isDarwin()) { // Darwin does not have pwritev but it does have pwrite. var off: usize = 0; var iov_i: usize = 0; @@ -841,7 +841,7 @@ pub const GetCwdError = error{ /// The result is a slice of out_buffer, indexed from 0. pub fn getcwd(out_buffer: []u8) GetCwdError![]u8 { - if (windows.is_the_target) { + if (builtin.os == .windows) { return windows.GetCurrentDirectory(out_buffer); } @@ -882,7 +882,7 @@ pub const SymLinkError = error{ /// If `sym_link_path` exists, it will not be overwritten. /// See also `symlinkC` and `symlinkW`. pub fn symlink(target_path: []const u8, sym_link_path: []const u8) SymLinkError!void { - if (windows.is_the_target) { + if (builtin.os == .windows) { const target_path_w = try windows.sliceToPrefixedFileW(target_path); const sym_link_path_w = try windows.sliceToPrefixedFileW(sym_link_path); return windows.CreateSymbolicLinkW(&sym_link_path_w, &target_path_w, 0); @@ -896,7 +896,7 @@ pub fn symlink(target_path: []const u8, sym_link_path: []const u8) SymLinkError! /// This is the same as `symlink` except the parameters are null-terminated pointers. /// See also `symlink`. pub fn symlinkC(target_path: [*]const u8, sym_link_path: [*]const u8) SymLinkError!void { - if (windows.is_the_target) { + if (builtin.os == .windows) { const target_path_w = try windows.cStrToPrefixedFileW(target_path); const sym_link_path_w = try windows.cStrToPrefixedFileW(sym_link_path); return windows.CreateSymbolicLinkW(&sym_link_path_w, &target_path_w, 0); @@ -971,7 +971,7 @@ pub const UnlinkError = error{ /// Delete a name and possibly the file it refers to. /// See also `unlinkC`. pub fn unlink(file_path: []const u8) UnlinkError!void { - if (windows.is_the_target) { + if (builtin.os == .windows) { const file_path_w = try windows.sliceToPrefixedFileW(file_path); return windows.DeleteFileW(&file_path_w); } else { @@ -982,7 +982,7 @@ pub fn unlink(file_path: []const u8) UnlinkError!void { /// Same as `unlink` except the parameter is a null terminated UTF8-encoded string. pub fn unlinkC(file_path: [*]const u8) UnlinkError!void { - if (windows.is_the_target) { + if (builtin.os == .windows) { const file_path_w = try windows.cStrToPrefixedFileW(file_path); return windows.DeleteFileW(&file_path_w); } @@ -1012,7 +1012,7 @@ pub const UnlinkatError = UnlinkError || error{ /// Delete a file name and possibly the file it refers to, based on an open directory handle. pub fn unlinkat(dirfd: fd_t, file_path: []const u8, flags: u32) UnlinkatError!void { - if (windows.is_the_target) { + if (builtin.os == .windows) { const file_path_w = try windows.sliceToPrefixedFileW(file_path); return unlinkatW(dirfd, &file_path_w, flags); } @@ -1022,7 +1022,7 @@ pub fn unlinkat(dirfd: fd_t, file_path: []const u8, flags: u32) UnlinkatError!vo /// Same as `unlinkat` but `file_path` is a null-terminated string. pub fn unlinkatC(dirfd: fd_t, file_path_c: [*]const u8, flags: u32) UnlinkatError!void { - if (windows.is_the_target) { + if (builtin.os == .windows) { const file_path_w = try windows.cStrToPrefixedFileW(file_path_c); return unlinkatW(dirfd, &file_path_w, flags); } @@ -1133,7 +1133,7 @@ const RenameError = error{ /// Change the name or location of a file. pub fn rename(old_path: []const u8, new_path: []const u8) RenameError!void { - if (windows.is_the_target) { + if (builtin.os == .windows) { const old_path_w = try windows.sliceToPrefixedFileW(old_path); const new_path_w = try windows.sliceToPrefixedFileW(new_path); return renameW(&old_path_w, &new_path_w); @@ -1146,7 +1146,7 @@ pub fn rename(old_path: []const u8, new_path: []const u8) RenameError!void { /// Same as `rename` except the parameters are null-terminated byte arrays. pub fn renameC(old_path: [*]const u8, new_path: [*]const u8) RenameError!void { - if (windows.is_the_target) { + if (builtin.os == .windows) { const old_path_w = try windows.cStrToPrefixedFileW(old_path); const new_path_w = try windows.cStrToPrefixedFileW(new_path); return renameW(&old_path_w, &new_path_w); @@ -1201,7 +1201,7 @@ pub const MakeDirError = error{ /// Create a directory. /// `mode` is ignored on Windows. pub fn mkdir(dir_path: []const u8, mode: u32) MakeDirError!void { - if (windows.is_the_target) { + if (builtin.os == .windows) { const dir_path_w = try windows.sliceToPrefixedFileW(dir_path); return windows.CreateDirectoryW(&dir_path_w, null); } else { @@ -1212,7 +1212,7 @@ pub fn mkdir(dir_path: []const u8, mode: u32) MakeDirError!void { /// Same as `mkdir` but the parameter is a null-terminated UTF8-encoded string. pub fn mkdirC(dir_path: [*]const u8, mode: u32) MakeDirError!void { - if (windows.is_the_target) { + if (builtin.os == .windows) { const dir_path_w = try windows.cStrToPrefixedFileW(dir_path); return windows.CreateDirectoryW(&dir_path_w, null); } @@ -1251,7 +1251,7 @@ pub const DeleteDirError = error{ /// Deletes an empty directory. pub fn rmdir(dir_path: []const u8) DeleteDirError!void { - if (windows.is_the_target) { + if (builtin.os == .windows) { const dir_path_w = try windows.sliceToPrefixedFileW(dir_path); return windows.RemoveDirectoryW(&dir_path_w); } else { @@ -1262,7 +1262,7 @@ pub fn rmdir(dir_path: []const u8) DeleteDirError!void { /// Same as `rmdir` except the parameter is null-terminated. pub fn rmdirC(dir_path: [*]const u8) DeleteDirError!void { - if (windows.is_the_target) { + if (builtin.os == .windows) { const dir_path_w = try windows.cStrToPrefixedFileW(dir_path); return windows.RemoveDirectoryW(&dir_path_w); } @@ -1298,7 +1298,7 @@ pub const ChangeCurDirError = error{ /// Changes the current working directory of the calling process. /// `dir_path` is recommended to be a UTF-8 encoded string. pub fn chdir(dir_path: []const u8) ChangeCurDirError!void { - if (windows.is_the_target) { + if (builtin.os == .windows) { const dir_path_w = try windows.sliceToPrefixedFileW(dir_path); @compileError("TODO implement chdir for Windows"); } else { @@ -1309,7 +1309,7 @@ pub fn chdir(dir_path: []const u8) ChangeCurDirError!void { /// Same as `chdir` except the parameter is null-terminated. pub fn chdirC(dir_path: [*]const u8) ChangeCurDirError!void { - if (windows.is_the_target) { + if (builtin.os == .windows) { const dir_path_w = try windows.cStrToPrefixedFileW(dir_path); @compileError("TODO implement chdir for Windows"); } @@ -1340,7 +1340,7 @@ pub const ReadLinkError = error{ /// Read value of a symbolic link. /// The return value is a slice of `out_buffer` from index 0. pub fn readlink(file_path: []const u8, out_buffer: []u8) ReadLinkError![]u8 { - if (windows.is_the_target) { + if (builtin.os == .windows) { const file_path_w = try windows.sliceToPrefixedFileW(file_path); @compileError("TODO implement readlink for Windows"); } else { @@ -1351,7 +1351,7 @@ pub fn readlink(file_path: []const u8, out_buffer: []u8) ReadLinkError![]u8 { /// Same as `readlink` except `file_path` is null-terminated. pub fn readlinkC(file_path: [*]const u8, out_buffer: []u8) ReadLinkError![]u8 { - if (windows.is_the_target) { + if (builtin.os == .windows) { const file_path_w = try windows.cStrToPrefixedFileW(file_path); @compileError("TODO implement readlink for Windows"); } @@ -1372,7 +1372,7 @@ pub fn readlinkC(file_path: [*]const u8, out_buffer: []u8) ReadLinkError![]u8 { } pub fn readlinkatC(dirfd: fd_t, file_path: [*]const u8, out_buffer: []u8) ReadLinkError![]u8 { - if (windows.is_the_target) { + if (builtin.os == .windows) { const file_path_w = try windows.cStrToPrefixedFileW(file_path); @compileError("TODO implement readlink for Windows"); } @@ -1440,7 +1440,7 @@ pub fn setregid(rgid: u32, egid: u32) SetIdError!void { /// Test whether a file descriptor refers to a terminal. pub fn isatty(handle: fd_t) bool { - if (windows.is_the_target) { + if (builtin.os == .windows) { if (isCygwinPty(handle)) return true; @@ -1450,10 +1450,10 @@ pub fn isatty(handle: fd_t) bool { if (builtin.link_libc) { return system.isatty(handle) != 0; } - if (wasi.is_the_target) { + if (builtin.os == .wasi) { @compileError("TODO implement std.os.isatty for WASI"); } - if (linux.is_the_target) { + if (builtin.os == .linux) { var wsz: linux.winsize = undefined; return linux.syscall3(linux.SYS_ioctl, @bitCast(usize, isize(handle)), linux.TIOCGWINSZ, @ptrToInt(&wsz)) == 0; } @@ -1461,7 +1461,7 @@ pub fn isatty(handle: fd_t) bool { } pub fn isCygwinPty(handle: fd_t) bool { - if (!windows.is_the_target) return false; + if (builtin.os != .windows) return false; const size = @sizeOf(windows.FILE_NAME_INFO); var name_info_bytes align(@alignOf(windows.FILE_NAME_INFO)) = [_]u8{0} ** (size + windows.MAX_PATH); @@ -1961,7 +1961,7 @@ pub const FStatError = error{SystemResources} || UnexpectedError; pub fn fstat(fd: fd_t) FStatError!Stat { var stat: Stat = undefined; - if (darwin.is_the_target) { + if (comptime std.Target.current.isDarwin()) { switch (darwin.getErrno(darwin.@"fstat$INODE64"(fd, &stat))) { 0 => return stat, EINVAL => unreachable, @@ -2227,7 +2227,7 @@ pub const AccessError = error{ /// check user's permissions for a file /// TODO currently this assumes `mode` is `F_OK` on Windows. pub fn access(path: []const u8, mode: u32) AccessError!void { - if (windows.is_the_target) { + if (builtin.os == .windows) { const path_w = try windows.sliceToPrefixedFileW(path); _ = try windows.GetFileAttributesW(&path_w); return; @@ -2238,7 +2238,7 @@ pub fn access(path: []const u8, mode: u32) AccessError!void { /// Same as `access` except `path` is null-terminated. pub fn accessC(path: [*]const u8, mode: u32) AccessError!void { - if (windows.is_the_target) { + if (builtin.os == .windows) { const path_w = try windows.cStrToPrefixedFileW(path); _ = try windows.GetFileAttributesW(&path_w); return; @@ -2358,7 +2358,7 @@ pub const SeekError = error{Unseekable} || UnexpectedError; /// Repositions read/write file offset relative to the beginning. pub fn lseek_SET(fd: fd_t, offset: u64) SeekError!void { - if (linux.is_the_target and !builtin.link_libc and @sizeOf(usize) == 4) { + if (builtin.os == .linux and !builtin.link_libc and @sizeOf(usize) == 4) { var result: u64 = undefined; switch (errno(system.llseek(fd, offset, &result, SEEK_SET))) { 0 => return, @@ -2370,7 +2370,7 @@ pub fn lseek_SET(fd: fd_t, offset: u64) SeekError!void { else => |err| return unexpectedErrno(err), } } - if (windows.is_the_target) { + if (builtin.os == .windows) { return windows.SetFilePointerEx_BEGIN(fd, offset); } const ipos = @bitCast(i64, offset); // the OS treats this as unsigned @@ -2387,7 +2387,7 @@ pub fn lseek_SET(fd: fd_t, offset: u64) SeekError!void { /// Repositions read/write file offset relative to the current offset. pub fn lseek_CUR(fd: fd_t, offset: i64) SeekError!void { - if (linux.is_the_target and !builtin.link_libc and @sizeOf(usize) == 4) { + if (builtin.os == .linux and !builtin.link_libc and @sizeOf(usize) == 4) { var result: u64 = undefined; switch (errno(system.llseek(fd, @bitCast(u64, offset), &result, SEEK_CUR))) { 0 => return, @@ -2399,7 +2399,7 @@ pub fn lseek_CUR(fd: fd_t, offset: i64) SeekError!void { else => |err| return unexpectedErrno(err), } } - if (windows.is_the_target) { + if (builtin.os == .windows) { return windows.SetFilePointerEx_CURRENT(fd, offset); } switch (errno(system.lseek(fd, offset, SEEK_CUR))) { @@ -2415,7 +2415,7 @@ pub fn lseek_CUR(fd: fd_t, offset: i64) SeekError!void { /// Repositions read/write file offset relative to the end. pub fn lseek_END(fd: fd_t, offset: i64) SeekError!void { - if (linux.is_the_target and !builtin.link_libc and @sizeOf(usize) == 4) { + if (builtin.os == .linux and !builtin.link_libc and @sizeOf(usize) == 4) { var result: u64 = undefined; switch (errno(system.llseek(fd, @bitCast(u64, offset), &result, SEEK_END))) { 0 => return, @@ -2427,7 +2427,7 @@ pub fn lseek_END(fd: fd_t, offset: i64) SeekError!void { else => |err| return unexpectedErrno(err), } } - if (windows.is_the_target) { + if (builtin.os == .windows) { return windows.SetFilePointerEx_END(fd, offset); } switch (errno(system.lseek(fd, offset, SEEK_END))) { @@ -2443,7 +2443,7 @@ pub fn lseek_END(fd: fd_t, offset: i64) SeekError!void { /// Returns the read/write file offset relative to the beginning. pub fn lseek_CUR_get(fd: fd_t) SeekError!u64 { - if (linux.is_the_target and !builtin.link_libc and @sizeOf(usize) == 4) { + if (builtin.os == .linux and !builtin.link_libc and @sizeOf(usize) == 4) { var result: u64 = undefined; switch (errno(system.llseek(fd, 0, &result, SEEK_CUR))) { 0 => return result, @@ -2455,7 +2455,7 @@ pub fn lseek_CUR_get(fd: fd_t) SeekError!u64 { else => |err| return unexpectedErrno(err), } } - if (windows.is_the_target) { + if (builtin.os == .windows) { return windows.SetFilePointerEx_CURRENT_get(fd); } const rc = system.lseek(fd, 0, SEEK_CUR); @@ -2504,7 +2504,7 @@ pub const RealPathError = error{ /// The return value is a slice of `out_buffer`, but not necessarily from the beginning. /// See also `realpathC` and `realpathW`. pub fn realpath(pathname: []const u8, out_buffer: *[MAX_PATH_BYTES]u8) RealPathError![]u8 { - if (windows.is_the_target) { + if (builtin.os == .windows) { const pathname_w = try windows.sliceToPrefixedFileW(pathname); return realpathW(&pathname_w, out_buffer); } @@ -2514,11 +2514,11 @@ pub fn realpath(pathname: []const u8, out_buffer: *[MAX_PATH_BYTES]u8) RealPathE /// Same as `realpath` except `pathname` is null-terminated. pub fn realpathC(pathname: [*]const u8, out_buffer: *[MAX_PATH_BYTES]u8) RealPathError![]u8 { - if (windows.is_the_target) { + if (builtin.os == .windows) { const pathname_w = try windows.cStrToPrefixedFileW(pathname); return realpathW(&pathname_w, out_buffer); } - if (linux.is_the_target and !builtin.link_libc) { + if (builtin.os == .linux and !builtin.link_libc) { const fd = try openC(pathname, linux.O_PATH | linux.O_NONBLOCK | linux.O_CLOEXEC, 0); defer close(fd); @@ -2596,9 +2596,12 @@ pub fn nanosleep(seconds: u64, nanoseconds: u64) void { } } -pub fn dl_iterate_phdr(comptime T: type, callback: extern fn (info: *dl_phdr_info, size: usize, data: ?*T) i32, data: ?*T) isize { - // This is implemented only for systems using ELF executables - if (windows.is_the_target or builtin.os == .uefi or wasi.is_the_target or darwin.is_the_target) +pub fn dl_iterate_phdr( + comptime T: type, + callback: extern fn (info: *dl_phdr_info, size: usize, data: ?*T) i32, + data: ?*T, +) isize { + if (builtin.object_format != .elf) @compileError("dl_iterate_phdr is not available for this target"); if (builtin.link_libc) { @@ -2737,7 +2740,7 @@ pub const SigaltstackError = error{ } || UnexpectedError; pub fn sigaltstack(ss: ?*stack_t, old_ss: ?*stack_t) SigaltstackError!void { - if (windows.is_the_target or uefi.is_the_target or wasi.is_the_target) + if (builtin.os == .windows or builtin.os == .uefi or builtin.os == .wasi) @compileError("std.os.sigaltstack not available for this target"); switch (errno(system.sigaltstack(ss, old_ss))) { @@ -2809,7 +2812,7 @@ pub fn gethostname(name_buffer: *[HOST_NAME_MAX]u8) GetHostNameError![]u8 { else => |err| return unexpectedErrno(err), } } - if (linux.is_the_target) { + if (builtin.os == .linux) { var uts: utsname = undefined; switch (errno(system.uname(&uts))) { 0 => { diff --git a/lib/std/os/darwin.zig b/lib/std/os/darwin.zig index 0adf71affbddf042dca6c283d8b542296e3a438b..d3e9cefb86dd311ea01b756c6c579cb4317abad7 100644 --- a/lib/std/os/darwin.zig +++ b/lib/std/os/darwin.zig @@ -1,8 +1,4 @@ const builtin = @import("builtin"); const std = @import("../std.zig"); -pub const is_the_target = switch (builtin.os) { - .macosx, .tvos, .watchos, .ios => true, - else => false, -}; pub usingnamespace std.c; pub usingnamespace @import("bits.zig"); diff --git a/lib/std/os/freebsd.zig b/lib/std/os/freebsd.zig index ddbf98f2bca1b12121f06e8a60b35d3c7ded6477..5f9684b96de967ee7422a2d96322c156ed2dbdbf 100644 --- a/lib/std/os/freebsd.zig +++ b/lib/std/os/freebsd.zig @@ -1,5 +1,3 @@ const std = @import("../std.zig"); -const builtin = @import("builtin"); -pub const is_the_target = builtin.os == .freebsd; pub usingnamespace std.c; pub usingnamespace @import("bits.zig"); diff --git a/lib/std/os/linux.zig b/lib/std/os/linux.zig index c91b6ad98b1e9b0e9a318b6e912d4d9f52bd1a72..2c8500574dc3aab27c0b01a1850bbc5bf1889e4a 100644 --- a/lib/std/os/linux.zig +++ b/lib/std/os/linux.zig @@ -13,7 +13,6 @@ const elf = std.elf; const vdso = @import("linux/vdso.zig"); const dl = @import("../dynamic_library.zig"); -pub const is_the_target = builtin.os == .linux; pub usingnamespace switch (builtin.arch) { .x86_64 => @import("linux/x86_64.zig"), .aarch64 => @import("linux/arm64.zig"), @@ -1079,7 +1078,7 @@ pub fn io_uring_register(fd: i32, opcode: u32, arg: ?*const c_void, nr_args: u32 } test "" { - if (is_the_target) { + if (builtin.os == .linux) { _ = @import("linux/test.zig"); } } diff --git a/lib/std/os/netbsd.zig b/lib/std/os/netbsd.zig index d484e7374b96450bd584d95023a92d7c466c22c5..5f9684b96de967ee7422a2d96322c156ed2dbdbf 100644 --- a/lib/std/os/netbsd.zig +++ b/lib/std/os/netbsd.zig @@ -1,5 +1,3 @@ -const builtin = @import("builtin"); const std = @import("../std.zig"); -pub const is_the_target = builtin.os == .netbsd; pub usingnamespace std.c; pub usingnamespace @import("bits.zig"); diff --git a/lib/std/os/test.zig b/lib/std/os/test.zig index b6e6728142ffae0f9a2b47c0a91b70bd36fb4333..1d615483969a0c1464126c57e0e3d495e4ce6f8b 100644 --- a/lib/std/os/test.zig +++ b/lib/std/os/test.zig @@ -53,7 +53,7 @@ test "std.Thread.getCurrentId" { thread.wait(); if (Thread.use_pthreads) { expect(thread_current_id == thread_id); - } else if (os.windows.is_the_target) { + } else if (builtin.os == .windows) { expect(Thread.getCurrentId() != thread_current_id); } else { // If the thread completes very quickly, then thread_id can be 0. See the @@ -212,7 +212,7 @@ test "dl_iterate_phdr" { } test "gethostname" { - if (os.windows.is_the_target) + if (builtin.os == .windows) return error.SkipZigTest; var buf: [os.HOST_NAME_MAX]u8 = undefined; @@ -221,7 +221,7 @@ test "gethostname" { } test "pipe" { - if (os.windows.is_the_target) + if (builtin.os == .windows) return error.SkipZigTest; var fds = try os.pipe(); diff --git a/lib/std/os/uefi.zig b/lib/std/os/uefi.zig index f42dae5fad53606d12b36d0c89fa54b14e89ab04..31d4d2ed50409258a8bd96fe4afee246be484f34 100644 --- a/lib/std/os/uefi.zig +++ b/lib/std/os/uefi.zig @@ -1,16 +1,15 @@ /// A protocol is an interface identified by a GUID. pub const protocols = @import("uefi/protocols.zig"); + /// Status codes returned by EFI interfaces pub const status = @import("uefi/status.zig"); pub const tables = @import("uefi/tables.zig"); const fmt = @import("std").fmt; -const builtin = @import("builtin"); -pub const is_the_target = builtin.os == .uefi; - /// The EFI image's handle that is passed to its entry point. pub var handle: Handle = undefined; + /// A pointer to the EFI System Table that is passed to the EFI image's entry point. pub var system_table: *tables.SystemTable = undefined; @@ -50,26 +49,35 @@ pub const Handle = *@OpaqueType(); pub const Time = extern struct { /// 1900 - 9999 year: u16, + /// 1 - 12 month: u8, + /// 1 - 31 day: u8, + /// 0 - 23 hour: u8, + /// 0 - 59 minute: u8, + /// 0 - 59 second: u8, _pad1: u8, + /// 0 - 999999999 nanosecond: u32, + /// The time's offset in minutes from UTC. /// Allowed values are -1440 to 1440 or unspecified_timezone timezone: i16, daylight: packed struct { _pad1: u6, + /// If true, the time has been adjusted for daylight savings time. in_daylight: bool, + /// If true, the time is affected by daylight savings time. adjust_daylight: bool, }, @@ -83,8 +91,10 @@ pub const Time = extern struct { pub const TimeCapabilities = extern struct { /// Resolution in Hz resolution: u32, + /// Accuracy in an error rate of 1e-6 parts per million. accuracy: u32, + /// If true, a time set operation clears the device's time below the resolution level. sets_to_zero: bool, }; diff --git a/lib/std/os/wasi.zig b/lib/std/os/wasi.zig index 57b708395c3aaf0ed869514154dc8cf9bd1580b2..fce29ef0b30cb8d19ec2a2ef30d31210b6c39722 100644 --- a/lib/std/os/wasi.zig +++ b/lib/std/os/wasi.zig @@ -1,10 +1,8 @@ // Based on https://github.com/CraneStation/wasi-sysroot/blob/wasi/libc-bottom-half/headers/public/wasi/core.h // and https://github.com/WebAssembly/WASI/blob/master/design/WASI-core.md -const builtin = @import("builtin"); const std = @import("std"); const assert = std.debug.assert; -pub const is_the_target = builtin.os == .wasi; pub usingnamespace @import("bits.zig"); comptime { diff --git a/lib/std/os/windows.zig b/lib/std/os/windows.zig index f9753dc2a4c17d3f79784aa524fdf8a39ea8df32..c8c99c6a59179390e96e2aeb18e5474c9354618d 100644 --- a/lib/std/os/windows.zig +++ b/lib/std/os/windows.zig @@ -11,7 +11,6 @@ const assert = std.debug.assert; const math = std.math; const maxInt = std.math.maxInt; -pub const is_the_target = builtin.os == .windows; pub const advapi32 = @import("windows/advapi32.zig"); pub const kernel32 = @import("windows/kernel32.zig"); pub const ntdll = @import("windows/ntdll.zig"); diff --git a/lib/std/process.zig b/lib/std/process.zig index c74e8c43be479197473d31d9ffa4f17ce9a3bf5f..fca10a240d2313a7fa846ba610edcc116c6bf562 100644 --- a/lib/std/process.zig +++ b/lib/std/process.zig @@ -39,7 +39,7 @@ pub fn getEnvMap(allocator: *Allocator) !BufMap { var result = BufMap.init(allocator); errdefer result.deinit(); - if (os.windows.is_the_target) { + if (builtin.os == .windows) { const ptr = try os.windows.GetEnvironmentStringsW(); defer os.windows.FreeEnvironmentStringsW(ptr); @@ -129,7 +129,7 @@ pub const GetEnvVarOwnedError = error{ /// Caller must free returned memory. /// TODO make this go through libc when we have it pub fn getEnvVarOwned(allocator: *mem.Allocator, key: []const u8) GetEnvVarOwnedError![]u8 { - if (os.windows.is_the_target) { + if (builtin.os == .windows) { const key_with_null = try std.unicode.utf8ToUtf16LeWithNull(allocator, key); defer allocator.free(key_with_null); diff --git a/lib/std/target.zig b/lib/std/target.zig index 6781ff250c9c1b04fca6c7836bbf73d5eae478bc..b81563d327ab7bbb342b3fb34ecbf16587152e31 100644 --- a/lib/std/target.zig +++ b/lib/std/target.zig @@ -1,6 +1,9 @@ const std = @import("std.zig"); const builtin = std.builtin; +/// TODO Nearly all the functions in this namespace would be +/// better off if https://github.com/ziglang/zig/issues/425 +/// was solved. pub const Target = union(enum) { Native: void, Cross: Cross, diff --git a/lib/std/thread.zig b/lib/std/thread.zig index 278fcc827c0c3416d3eced392548fb4dd646baee..fbfb1afd1e10124242ac4b7f35c44748618c0ca8 100644 --- a/lib/std/thread.zig +++ b/lib/std/thread.zig @@ -9,7 +9,7 @@ const assert = std.debug.assert; pub const Thread = struct { data: Data, - pub const use_pthreads = !windows.is_the_target and builtin.link_libc; + pub const use_pthreads = builtin.os != .windows and builtin.link_libc; /// Represents a kernel thread handle. /// May be an integer or a pointer depending on the platform. @@ -309,7 +309,7 @@ pub const Thread = struct { os.EINVAL => unreachable, else => return os.unexpectedErrno(@intCast(usize, err)), } - } else if (os.linux.is_the_target) { + } else if (builtin.os == .linux) { var flags: u32 = os.CLONE_VM | os.CLONE_FS | os.CLONE_FILES | os.CLONE_SIGHAND | os.CLONE_THREAD | os.CLONE_SYSVSEM | os.CLONE_PARENT_SETTID | os.CLONE_CHILD_CLEARTID | os.CLONE_DETACHED; @@ -342,18 +342,18 @@ pub const Thread = struct { }; pub fn cpuCount() CpuCountError!usize { - if (os.linux.is_the_target) { + if (builtin.os == .linux) { const cpu_set = try os.sched_getaffinity(0); return usize(os.CPU_COUNT(cpu_set)); // TODO should not need this usize cast } - if (os.windows.is_the_target) { + if (builtin.os == .windows) { var system_info: windows.SYSTEM_INFO = undefined; windows.kernel32.GetSystemInfo(&system_info); return @intCast(usize, system_info.dwNumberOfProcessors); } var count: c_int = undefined; var count_len: usize = @sizeOf(c_int); - const name = if (os.darwin.is_the_target) c"hw.logicalcpu" else c"hw.ncpu"; + const name = if (comptime std.Target.current.isDarwin()) c"hw.logicalcpu" else c"hw.ncpu"; os.sysctlbynameC(name, &count, &count_len, null, 0) catch |err| switch (err) { error.NameTooLong => unreachable, else => |e| return e, diff --git a/lib/std/time.zig b/lib/std/time.zig index caf6c31b31b5d65cec6dd1ab64ff7fec3403c801..04dbb908e29609e99b546e3fbc12208dd866063d 100644 --- a/lib/std/time.zig +++ b/lib/std/time.zig @@ -9,7 +9,7 @@ pub const epoch = @import("time/epoch.zig"); /// Spurious wakeups are possible and no precision of timing is guaranteed. pub fn sleep(nanoseconds: u64) void { - if (os.windows.is_the_target) { + if (builtin.os == .windows) { const ns_per_ms = ns_per_s / ms_per_s; const big_ms_from_ns = nanoseconds / ns_per_ms; const ms = math.cast(os.windows.DWORD, big_ms_from_ns) catch math.maxInt(os.windows.DWORD); @@ -30,7 +30,7 @@ pub fn timestamp() u64 { /// Get the posix timestamp, UTC, in milliseconds /// TODO audit this function. is it possible to return an error? pub fn milliTimestamp() u64 { - if (os.windows.is_the_target) { + if (builtin.os == .windows) { //FileTime has a granularity of 100 nanoseconds // and uses the NTFS/Windows epoch var ft: os.windows.FILETIME = undefined; @@ -41,7 +41,7 @@ pub fn milliTimestamp() u64 { const ft64 = (u64(ft.dwHighDateTime) << 32) | ft.dwLowDateTime; return @divFloor(ft64, hns_per_ms) - -epoch_adj; } - if (os.wasi.is_the_target and !builtin.link_libc) { + if (builtin.os == .wasi and !builtin.link_libc) { var ns: os.wasi.timestamp_t = undefined; // TODO: Verify that precision is ignored @@ -51,7 +51,7 @@ pub fn milliTimestamp() u64 { const ns_per_ms = 1000; return @divFloor(ns, ns_per_ms); } - if (os.darwin.is_the_target) { + if (comptime std.Target.current.isDarwin()) { var tv: os.darwin.timeval = undefined; var err = os.darwin.gettimeofday(&tv, null); assert(err == 0); @@ -126,11 +126,11 @@ pub const Timer = struct { pub fn start() Error!Timer { var self: Timer = undefined; - if (os.windows.is_the_target) { + if (builtin.os == .windows) { self.frequency = os.windows.QueryPerformanceFrequency(); self.resolution = @divFloor(ns_per_s, self.frequency); self.start_time = os.windows.QueryPerformanceCounter(); - } else if (os.darwin.is_the_target) { + } else if (comptime std.Target.current.isDarwin()) { os.darwin.mach_timebase_info(&self.frequency); self.resolution = @divFloor(self.frequency.numer, self.frequency.denom); self.start_time = os.darwin.mach_absolute_time(); @@ -154,10 +154,10 @@ pub const Timer = struct { /// Reads the timer value since start or the last reset in nanoseconds pub fn read(self: *Timer) u64 { var clock = clockNative() - self.start_time; - if (os.windows.is_the_target) { + if (builtin.os == .windows) { return @divFloor(clock * ns_per_s, self.frequency); } - if (os.darwin.is_the_target) { + if (comptime std.Target.current.isDarwin()) { return @divFloor(clock * self.frequency.numer, self.frequency.denom); } return clock; @@ -177,10 +177,10 @@ pub const Timer = struct { } fn clockNative() u64 { - if (os.windows.is_the_target) { + if (builtin.os == .windows) { return os.windows.QueryPerformanceCounter(); } - if (os.darwin.is_the_target) { + if (comptime std.Target.current.isDarwin()) { return os.darwin.mach_absolute_time(); } var ts: os.timespec = undefined; -- 2.54.0