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.
This commit is contained in:
Andrew Kelley 2019-10-23 18:43:24 -04:00
parent ef62452363
commit 17eb24a7e4
No known key found for this signature in database
GPG Key ID: 7C5F548F728501A9
16 changed files with 1208 additions and 945 deletions

View File

@ -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);
},

413
lib/std/builtin.zig Normal file
View File

@ -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");

View File

@ -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");
}

View File

@ -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,

View File

@ -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);
},
}
}

View File

@ -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");

614
lib/std/target.zig Normal file
View File

@ -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;
}
};

View File

@ -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,

View File

@ -1930,7 +1930,6 @@ struct CodeGen {
ZigList<ZigType *> 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;

View File

@ -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<AstNode>(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;
}

View File

@ -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

View File

@ -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);
}

View File

@ -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)";
}

View File

@ -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);
}

View File

@ -77,6 +77,7 @@ enum Error {
ErrorNoSpaceLeft,
ErrorNotLazy,
ErrorIsAsync,
ErrorImportOutsidePkgPath,
};
// ABI warning

View File

@ -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(