commit 773bf8013391d2b309cfcb50bf9e1c7db25cc3f2 (tree)
parent c26f543970771acba5484553e2c10ec90b3c39eb
Author: Marcio Giaxa <i@mgxm.me>
Date: Sun, 23 Dec 2018 23:21:59 -0200
Merge branch 'master' into fbsd2
Diffstat:
19 files changed, 233 insertions(+), 53 deletions(-)
diff --git a/.builds/freebsd.yml b/.builds/freebsd.yml
@@ -0,0 +1,22 @@
+arch: x86_64
+image: freebsd
+packages:
+ - cmake
+ - ninja
+ - llvm70
+sources:
+ - https://github.com/ziglang/zig.git
+tasks:
+ - build: |
+ cd zig && mkdir build && cd build
+ cmake .. -GNinja -DCMAKE_BUILD_TYPE=Release
+ ninja install
+ - test: |
+ cd zig/build
+ bin/zig test ../test/behavior.zig
+ # TODO enable all tests
+ #bin/zig build --build-file ../build.zig test
+ # TODO integrate with the download page updater and make a
+ # static build available to download for FreeBSD.
+ # This will require setting up a cache of LLVM/Clang built
+ # statically.
diff --git a/doc/langref.html.in b/doc/langref.html.in
@@ -165,7 +165,7 @@ const std = @import("std");
pub fn main() !void {
// If this program is run without stdout attached, exit with an error.
- var stdout_file = try std.io.getStdOut();
+ const stdout_file = try std.io.getStdOut();
// If this program encounters pipe failure when printing to stdout, exit
// with an error.
try stdout_file.write("Hello, world!\n");
diff --git a/example/hello_world/hello.zig b/example/hello_world/hello.zig
@@ -2,7 +2,7 @@ const std = @import("std");
pub fn main() !void {
// If this program is run without stdout attached, exit with an error.
- var stdout_file = try std.io.getStdOut();
+ const stdout_file = try std.io.getStdOut();
// If this program encounters pipe failure when printing to stdout, exit
// with an error.
try stdout_file.write("Hello, world!\n");
diff --git a/src-self-hosted/compilation.zig b/src-self-hosted/compilation.zig
@@ -300,6 +300,7 @@ pub const Compilation = struct {
UserResourceLimitReached,
InvalidUtf8,
BadPathName,
+ DeviceBusy,
};
pub const Event = union(enum) {
diff --git a/src/analyze.cpp b/src/analyze.cpp
@@ -2681,39 +2681,50 @@ static Error resolve_struct_alignment(CodeGen *g, ZigType *struct_type) {
assert(decl_node->type == NodeTypeContainerDecl);
assert(struct_type->di_type);
+ size_t field_count = struct_type->data.structure.src_field_count;
if (struct_type->data.structure.layout == ContainerLayoutPacked) {
struct_type->data.structure.abi_alignment = 1;
- }
-
- size_t field_count = struct_type->data.structure.src_field_count;
- for (size_t i = 0; i < field_count; i += 1) {
- TypeStructField *field = &struct_type->data.structure.fields[i];
-
- // If this assertion trips, look up the call stack. Probably something is
- // calling type_resolve with ResolveStatusAlignmentKnown when it should only
- // be resolving ResolveStatusZeroBitsKnown
- assert(field->type_entry != nullptr);
-
- if (type_is_invalid(field->type_entry)) {
- struct_type->data.structure.resolve_status = ResolveStatusInvalid;
- break;
+ for (size_t i = 0; i < field_count; i += 1) {
+ TypeStructField *field = &struct_type->data.structure.fields[i];
+ if (field->type_entry != nullptr && type_is_invalid(field->type_entry)) {
+ struct_type->data.structure.resolve_status = ResolveStatusInvalid;
+ break;
+ }
}
+ } else for (size_t i = 0; i < field_count; i += 1) {
+ TypeStructField *field = &struct_type->data.structure.fields[i];
+ uint32_t this_field_align;
+
+ // TODO If we have no type_entry for the field, we've already failed to
+ // compile the program correctly. This stage1 compiler needs a deeper
+ // reworking to make this correct, or we can ignore the problem
+ // and make sure it is fixed in stage2. This workaround is for when
+ // there is a false positive of a dependency loop, of alignment depending
+ // on itself. When this false positive happens we assume a pointer-aligned
+ // field, which is usually fine but could be incorrectly over-aligned or
+ // even under-aligned. See https://github.com/ziglang/zig/issues/1512
+ if (field->type_entry == nullptr) {
+ this_field_align = LLVMABIAlignmentOfType(g->target_data_ref, LLVMPointerType(LLVMInt8Type(), 0));
+ } else {
+ if (type_is_invalid(field->type_entry)) {
+ struct_type->data.structure.resolve_status = ResolveStatusInvalid;
+ break;
+ }
- if (!type_has_bits(field->type_entry))
- continue;
+ if (!type_has_bits(field->type_entry))
+ continue;
- // alignment of structs is the alignment of the most-aligned field
- if (struct_type->data.structure.layout != ContainerLayoutPacked) {
if ((err = type_resolve(g, field->type_entry, ResolveStatusAlignmentKnown))) {
struct_type->data.structure.resolve_status = ResolveStatusInvalid;
break;
}
- uint32_t this_field_align = get_abi_alignment(g, field->type_entry);
+ this_field_align = get_abi_alignment(g, field->type_entry);
assert(this_field_align != 0);
- if (this_field_align > struct_type->data.structure.abi_alignment) {
- struct_type->data.structure.abi_alignment = this_field_align;
- }
+ }
+ // alignment of structs is the alignment of the most-aligned field
+ if (this_field_align > struct_type->data.structure.abi_alignment) {
+ struct_type->data.structure.abi_alignment = this_field_align;
}
}
diff --git a/src/ir.cpp b/src/ir.cpp
@@ -159,7 +159,7 @@ static ZigType *ir_resolve_atomic_operand_type(IrAnalyze *ira, IrInstruction *op
static IrInstruction *ir_lval_wrap(IrBuilder *irb, Scope *scope, IrInstruction *value, LVal lval);
static ZigType *adjust_ptr_align(CodeGen *g, ZigType *ptr_type, uint32_t new_align);
static ZigType *adjust_slice_align(CodeGen *g, ZigType *slice_type, uint32_t new_align);
-static void buf_read_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue *val);
+static Error buf_read_value_bytes(IrAnalyze *ira, AstNode *source_node, uint8_t *buf, ConstExprValue *val);
static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue *val);
static Error ir_read_const_ptr(IrAnalyze *ira, AstNode *source_node,
ConstExprValue *out_val, ConstExprValue *ptr_val);
@@ -12495,6 +12495,7 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruct
case ReqCompTimeNo:
if (casted_init_value->value.special == ConstValSpecialStatic &&
casted_init_value->value.type->id == ZigTypeIdFn &&
+ casted_init_value->value.data.x_ptr.special != ConstPtrSpecialHardCodedAddr &&
casted_init_value->value.data.x_ptr.data.fn.fn_entry->fn_inline == FnInlineAlways)
{
var_class_requires_const = true;
@@ -13724,7 +13725,8 @@ static Error ir_read_const_ptr(IrAnalyze *ira, AstNode *source_node,
Buf buf = BUF_INIT;
buf_resize(&buf, src_size);
buf_write_value_bytes(ira->codegen, (uint8_t*)buf_ptr(&buf), pointee);
- buf_read_value_bytes(ira->codegen, (uint8_t*)buf_ptr(&buf), out_val);
+ if ((err = buf_read_value_bytes(ira, source_node, (uint8_t*)buf_ptr(&buf), out_val)))
+ return err;
return ErrorNone;
}
@@ -13758,7 +13760,8 @@ static Error ir_read_const_ptr(IrAnalyze *ira, AstNode *source_node,
ConstExprValue *elem_val = &array_val->data.x_array.data.s_none.elements[elem_index + i];
buf_write_value_bytes(ira->codegen, (uint8_t*)buf_ptr(&buf) + (i * elem_size), elem_val);
}
- buf_read_value_bytes(ira->codegen, (uint8_t*)buf_ptr(&buf), out_val);
+ if ((err = buf_read_value_bytes(ira, source_node, (uint8_t*)buf_ptr(&buf), out_val)))
+ return err;
return ErrorNone;
}
case ConstPtrSpecialBaseStruct:
@@ -20076,7 +20079,8 @@ static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue
zig_unreachable();
}
-static void buf_read_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue *val) {
+static Error buf_read_value_bytes(IrAnalyze *ira, AstNode *source_node, uint8_t *buf, ConstExprValue *val) {
+ Error err;
assert(val->special == ConstValSpecialStatic);
switch (val->type->id) {
case ZigTypeIdInvalid:
@@ -20093,30 +20097,60 @@ static void buf_read_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue
case ZigTypeIdPromise:
zig_unreachable();
case ZigTypeIdVoid:
- return;
+ return ErrorNone;
case ZigTypeIdBool:
val->data.x_bool = (buf[0] != 0);
- return;
+ return ErrorNone;
case ZigTypeIdInt:
bigint_read_twos_complement(&val->data.x_bigint, buf, val->type->data.integral.bit_count,
- codegen->is_big_endian, val->type->data.integral.is_signed);
- return;
+ ira->codegen->is_big_endian, val->type->data.integral.is_signed);
+ return ErrorNone;
case ZigTypeIdFloat:
- float_read_ieee597(val, buf, codegen->is_big_endian);
- return;
+ float_read_ieee597(val, buf, ira->codegen->is_big_endian);
+ return ErrorNone;
case ZigTypeIdPointer:
{
val->data.x_ptr.special = ConstPtrSpecialHardCodedAddr;
BigInt bn;
- bigint_read_twos_complement(&bn, buf, codegen->builtin_types.entry_usize->data.integral.bit_count,
- codegen->is_big_endian, false);
+ bigint_read_twos_complement(&bn, buf, ira->codegen->builtin_types.entry_usize->data.integral.bit_count,
+ ira->codegen->is_big_endian, false);
val->data.x_ptr.data.hard_coded_addr.addr = bigint_as_unsigned(&bn);
- return;
+ return ErrorNone;
}
case ZigTypeIdArray:
zig_panic("TODO buf_read_value_bytes array type");
case ZigTypeIdStruct:
- zig_panic("TODO buf_read_value_bytes struct type");
+ switch (val->type->data.structure.layout) {
+ case ContainerLayoutAuto: {
+ ErrorMsg *msg = ir_add_error_node(ira, source_node,
+ buf_sprintf("non-extern, non-packed struct '%s' cannot have its bytes reinterpreted",
+ buf_ptr(&val->type->name)));
+ add_error_note(ira->codegen, msg, val->type->data.structure.decl_node,
+ buf_sprintf("declared here"));
+ return ErrorSemanticAnalyzeFail;
+ }
+ case ContainerLayoutExtern: {
+ size_t src_field_count = val->type->data.structure.src_field_count;
+ val->data.x_struct.fields = create_const_vals(src_field_count);
+ for (size_t field_i = 0; field_i < src_field_count; field_i += 1) {
+ ConstExprValue *field_val = &val->data.x_struct.fields[field_i];
+ field_val->special = ConstValSpecialStatic;
+ TypeStructField *type_field = &val->type->data.structure.fields[field_i];
+ field_val->type = type_field->type_entry;
+ if (type_field->gen_index == SIZE_MAX)
+ continue;
+ size_t offset = LLVMOffsetOfElement(ira->codegen->target_data_ref, val->type->type_ref,
+ type_field->gen_index);
+ uint8_t *new_buf = buf + offset;
+ if ((err = buf_read_value_bytes(ira, source_node, new_buf, field_val)))
+ return err;
+ }
+ return ErrorNone;
+ }
+ case ContainerLayoutPacked:
+ zig_panic("TODO buf_read_value_bytes packed struct");
+ }
+ zig_unreachable();
case ZigTypeIdOptional:
zig_panic("TODO buf_read_value_bytes maybe type");
case ZigTypeIdErrorUnion:
@@ -20219,7 +20253,8 @@ static IrInstruction *ir_analyze_instruction_bit_cast(IrAnalyze *ira, IrInstruct
IrInstruction *result = ir_const(ira, &instruction->base, dest_type);
uint8_t *buf = allocate_nonzero<uint8_t>(src_size_bytes);
buf_write_value_bytes(ira->codegen, buf, val);
- buf_read_value_bytes(ira->codegen, buf, &result->value);
+ if ((err = buf_read_value_bytes(ira, instruction->base.source_node, buf, &result->value)))
+ return ira->codegen->invalid_instruction;
return result;
}
diff --git a/src/translate_c.cpp b/src/translate_c.cpp
@@ -4776,6 +4776,14 @@ Error parse_h_file(ImportTableEntry *import, ZigList<ErrorMsg *> *errors, const
clang_argv.append(target_file);
+ if (codegen->verbose_cimport) {
+ fprintf(stderr, "clang");
+ for (size_t i = 0; i < clang_argv.length; i += 1) {
+ fprintf(stderr, " %s", clang_argv.at(i));
+ }
+ fprintf(stderr, "\n");
+ }
+
// to make the [start...end] argument work
clang_argv.append(nullptr);
diff --git a/std/array_list.zig b/std/array_list.zig
@@ -398,3 +398,14 @@ test "std.ArrayList.insertSlice" {
assert(list.len == 6);
assert(list.items[0] == 1);
}
+
+const Item = struct {
+ integer: i32,
+ sub_items: ArrayList(Item),
+};
+
+test "std.ArrayList: ArrayList(T) of struct T" {
+ var root = Item{ .integer = 1, .sub_items = ArrayList(Item).init(debug.global_allocator) };
+ try root.sub_items.append( Item{ .integer = 42, .sub_items = ArrayList(Item).init(debug.global_allocator) } );
+ assert(root.sub_items.items[0].integer == 42);
+}
diff --git a/std/dynamic_library.zig b/std/dynamic_library.zig
@@ -19,7 +19,6 @@ pub const DynLib = switch (builtin.os) {
};
pub const LinuxDynLib = struct {
- allocator: *mem.Allocator,
elf_lib: ElfLib,
fd: i32,
map_addr: usize,
@@ -27,7 +26,7 @@ pub const LinuxDynLib = struct {
/// Trusts the file
pub fn open(allocator: *mem.Allocator, path: []const u8) !DynLib {
- const fd = try std.os.posixOpen(allocator, path, 0, linux.O_RDONLY | linux.O_CLOEXEC);
+ const fd = try std.os.posixOpen(path, 0, linux.O_RDONLY | linux.O_CLOEXEC);
errdefer std.os.close(fd);
const size = @intCast(usize, (try std.os.posixFStat(fd)).size);
@@ -45,7 +44,6 @@ pub const LinuxDynLib = struct {
const bytes = @intToPtr([*]align(std.os.page_size) u8, addr)[0..size];
return DynLib{
- .allocator = allocator,
.elf_lib = try ElfLib.init(bytes),
.fd = fd,
.map_addr = addr,
diff --git a/std/fmt/index.zig b/std/fmt/index.zig
@@ -243,6 +243,9 @@ pub fn formatType(
}
return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(&value));
},
+ builtin.TypeId.Fn => {
+ return format(context, Errors, output, "{}@{x}", @typeName(T), @ptrToInt(value));
+ },
else => @compileError("Unable to format type '" ++ @typeName(T) ++ "'"),
}
}
@@ -1013,6 +1016,10 @@ test "fmt.format" {
const value = @intToPtr(fn () void, 0xdeadbeef);
try testFmt("pointer: fn() void@deadbeef\n", "pointer: {}\n", value);
}
+ {
+ const value = @intToPtr(fn () void, 0xdeadbeef);
+ try testFmt("pointer: fn() void@deadbeef\n", "pointer: {}\n", value);
+ }
try testFmt("buf: Test \n", "buf: {s5}\n", "Test");
try testFmt("buf: Test\n Other text", "buf: {s}\n Other text", "Test");
try testFmt("cstr: Test C\n", "cstr: {s}\n", c"Test C");
diff --git a/std/index.zig b/std/index.zig
@@ -57,7 +57,8 @@ test "std" {
_ = @import("mutex.zig");
_ = @import("segmented_list.zig");
_ = @import("spinlock.zig");
-
+
+ _ = @import("dynamic_library.zig");
_ = @import("base64.zig");
_ = @import("build.zig");
_ = @import("c/index.zig");
diff --git a/std/io.zig b/std/io.zig
@@ -155,32 +155,32 @@ pub fn InStream(comptime ReadError: type) type {
pub fn readIntNative(self: *Self, comptime T: type) !T {
var bytes: [@sizeOf(T)]u8 = undefined;
try self.readNoEof(bytes[0..]);
- return mem.readIntSliceNative(T, bytes);
+ return mem.readIntNative(T, &bytes);
}
/// Reads a foreign-endian integer
pub fn readIntForeign(self: *Self, comptime T: type) !T {
var bytes: [@sizeOf(T)]u8 = undefined;
try self.readNoEof(bytes[0..]);
- return mem.readIntSliceForeign(T, bytes);
+ return mem.readIntForeign(T, &bytes);
}
pub fn readIntLittle(self: *Self, comptime T: type) !T {
var bytes: [@sizeOf(T)]u8 = undefined;
try self.readNoEof(bytes[0..]);
- return mem.readIntSliceLittle(T, bytes);
+ return mem.readIntLittle(T, &bytes);
}
pub fn readIntBig(self: *Self, comptime T: type) !T {
var bytes: [@sizeOf(T)]u8 = undefined;
try self.readNoEof(bytes[0..]);
- return mem.readIntSliceBig(T, bytes);
+ return mem.readIntBig(T, &bytes);
}
pub fn readInt(self: *Self, comptime T: type, endian: builtin.Endian) !T {
var bytes: [@sizeOf(T)]u8 = undefined;
try self.readNoEof(bytes[0..]);
- return mem.readIntSlice(T, bytes, endian);
+ return mem.readInt(T, &bytes, endian);
}
pub fn readVarInt(self: *Self, comptime ReturnType: type, endian: builtin.Endian, size: usize) !ReturnType {
diff --git a/std/os/index.zig b/std/os/index.zig
@@ -459,6 +459,7 @@ pub const PosixOpenError = error{
NoSpaceLeft,
NotDir,
PathAlreadyExists,
+ DeviceBusy,
/// See https://github.com/ziglang/zig/issues/1396
Unexpected,
@@ -497,6 +498,7 @@ pub fn posixOpenC(file_path: [*]const u8, flags: u32, perm: usize) !i32 {
posix.ENOTDIR => return PosixOpenError.NotDir,
posix.EPERM => return PosixOpenError.AccessDenied,
posix.EEXIST => return PosixOpenError.PathAlreadyExists,
+ posix.EBUSY => return PosixOpenError.DeviceBusy,
else => return unexpectedErrorPosix(err),
}
}
@@ -1402,6 +1404,7 @@ const DeleteTreeError = error{
FileSystem,
FileBusy,
DirNotEmpty,
+ DeviceBusy,
/// On Windows, file paths must be valid Unicode.
InvalidUtf8,
@@ -1463,6 +1466,7 @@ pub fn deleteTree(allocator: *Allocator, full_path: []const u8) DeleteTreeError!
error.Unexpected,
error.InvalidUtf8,
error.BadPathName,
+ error.DeviceBusy,
=> return err,
};
defer dir.close();
@@ -1545,6 +1549,7 @@ pub const Dir = struct {
OutOfMemory,
InvalidUtf8,
BadPathName,
+ DeviceBusy,
/// See https://github.com/ziglang/zig/issues/1396
Unexpected,
diff --git a/std/os/path.zig b/std/os/path.zig
@@ -1093,6 +1093,7 @@ pub const RealError = error{
NoSpaceLeft,
FileSystem,
BadPathName,
+ DeviceBusy,
/// On Windows, file paths must be valid Unicode.
InvalidUtf8,
diff --git a/test/behavior.zig b/test/behavior.zig
@@ -42,6 +42,7 @@ comptime {
_ = @import("cases/if.zig");
_ = @import("cases/import.zig");
_ = @import("cases/incomplete_struct_param_tld.zig");
+ _ = @import("cases/inttoptr.zig");
_ = @import("cases/ir_block_deps.zig");
_ = @import("cases/math.zig");
_ = @import("cases/merge_error_sets.zig");
diff --git a/test/cases/inttoptr.zig b/test/cases/inttoptr.zig
@@ -0,0 +1,13 @@
+const builtin = @import("builtin");
+const std = @import("std");
+const assertOrPanic = std.debug.assertOrPanic;
+
+test "casting random address to function pointer" {
+ randomAddressToFunction();
+ comptime randomAddressToFunction();
+}
+
+fn randomAddressToFunction() void {
+ var addr: usize = 0xdeadbeef;
+ var ptr = @intToPtr(fn () void, addr);
+}
diff --git a/test/cases/ptrcast.zig b/test/cases/ptrcast.zig
@@ -15,3 +15,22 @@ fn testReinterpretBytesAsInteger() void {
};
assertOrPanic(@ptrCast(*align(1) const u32, bytes[1..5].ptr).* == expected);
}
+
+test "reinterpret bytes of an array into an extern struct" {
+ testReinterpretBytesAsExternStruct();
+ comptime testReinterpretBytesAsExternStruct();
+}
+
+fn testReinterpretBytesAsExternStruct() void {
+ var bytes align(2) = []u8{ 1, 2, 3, 4, 5, 6 };
+
+ const S = extern struct {
+ a: u8,
+ b: u16,
+ c: u8,
+ };
+
+ var ptr = @ptrCast(*const S, &bytes);
+ var val = ptr.c;
+ assertOrPanic(val == 5);
+}
diff --git a/test/cases/struct_contains_slice_of_itself.zig b/test/cases/struct_contains_slice_of_itself.zig
@@ -5,6 +5,11 @@ const Node = struct {
children: []Node,
};
+const NodeAligned = struct {
+ payload: i32,
+ children: []align(@alignOf(NodeAligned)) NodeAligned,
+};
+
test "struct contains slice of itself" {
var other_nodes = []Node{
Node{
@@ -41,3 +46,40 @@ test "struct contains slice of itself" {
assert(root.children[2].children[0].payload == 31);
assert(root.children[2].children[1].payload == 32);
}
+
+test "struct contains aligned slice of itself" {
+ var other_nodes = []NodeAligned{
+ NodeAligned{
+ .payload = 31,
+ .children = []NodeAligned{},
+ },
+ NodeAligned{
+ .payload = 32,
+ .children = []NodeAligned{},
+ },
+ };
+ var nodes = []NodeAligned{
+ NodeAligned{
+ .payload = 1,
+ .children = []NodeAligned{},
+ },
+ NodeAligned{
+ .payload = 2,
+ .children = []NodeAligned{},
+ },
+ NodeAligned{
+ .payload = 3,
+ .children = other_nodes[0..],
+ },
+ };
+ const root = NodeAligned{
+ .payload = 1234,
+ .children = nodes[0..],
+ };
+ assert(root.payload == 1234);
+ assert(root.children[0].payload == 1);
+ assert(root.children[1].payload == 2);
+ assert(root.children[2].payload == 3);
+ assert(root.children[2].children[0].payload == 31);
+ assert(root.children[2].children[1].payload == 32);
+}
diff --git a/test/cases/type_info.zig b/test/cases/type_info.zig
@@ -144,15 +144,20 @@ test "type info: enum info" {
}
fn testEnum() void {
- const Os = @import("builtin").Os;
+ const Os = enum {
+ Windows,
+ Macos,
+ Linux,
+ FreeBSD,
+ };
const os_info = @typeInfo(Os);
assert(TypeId(os_info) == TypeId.Enum);
assert(os_info.Enum.layout == TypeInfo.ContainerLayout.Auto);
- assert(os_info.Enum.fields.len == 32);
- assert(mem.eql(u8, os_info.Enum.fields[1].name, "ananas"));
- assert(os_info.Enum.fields[10].value == 10);
- assert(os_info.Enum.tag_type == u5);
+ assert(os_info.Enum.fields.len == 4);
+ assert(mem.eql(u8, os_info.Enum.fields[1].name, "Macos"));
+ assert(os_info.Enum.fields[3].value == 3);
+ assert(os_info.Enum.tag_type == u2);
assert(os_info.Enum.defs.len == 0);
}