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 dd602ba922..4f0956d549 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 0000000000..8315cd84cf --- /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 3f8daf0290..19ca282979 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 6c4aeb4cef..f9753dc2a4 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 f42085126b..0000000000 --- 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 f41181f6e9..a7cce4fd6f 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 0000000000..6781ff250c --- /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 15f09e8da9..c62e5af9dd 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 052c67d334..a8cfa0227f 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 44223b58b4..e2df290df6 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 4592d1a0a1..5168dd2d7d 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 1b14c5551b..87cdcc8783 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 86df76ed4e..9fc0383b1b 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 4cce464a4c..8aff5e4583 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 58d5cc719a..1d01257175 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 35c6ded4a4..c7b0e09485 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( 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 cb9589e95d..9b56d0b8ce 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 19ca282979..4a2c0b971e 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 a7cce4fd6f..ea6257009f 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()); } 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 4f0956d549..6ef7286f9b 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 f2e8120a0e..ebd12a0d86 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 d786c3f4de..5fae9447a9 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 0be778b3b6..95670dc4ea 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 2f211d21e2..1092f2204a 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 81fd950e44..2f64d453af 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 1e3508de41..c5376bc9f6 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 a0b1fd3e50..fdcfd1e298 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 3fdd175e77..5517f6f280 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 44992ff47d..06a26ed481 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 560d9b58f3..f337e1df9a 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 f3a0d457d2..8723c7eab6 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 7502601650..39c3a7cf9b 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 4a2c0b971e..d239f198f4 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 0adf71affb..d3e9cefb86 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 ddbf98f2bc..5f9684b96d 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 c91b6ad98b..2c8500574d 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 d484e7374b..5f9684b96d 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 b6e6728142..1d61548396 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 f42dae5fad..31d4d2ed50 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 57b708395c..fce29ef0b3 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 f9753dc2a4..c8c99c6a59 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 c74e8c43be..fca10a240d 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 6781ff250c..b81563d327 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 278fcc827c..fbfb1afd1e 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 caf6c31b31..04dbb908e2 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;