Merge remote-tracking branch 'origin/master' into self-hosted-libc-hello-world

master
Andrew Kelley 2018-07-23 14:32:13 -04:00
commit 5a919dd82d
14 changed files with 355 additions and 59 deletions

View File

@ -556,7 +556,7 @@ set(ZIG_STD_FILES
"net.zig"
"os/child_process.zig"
"os/darwin.zig"
"os/darwin_errno.zig"
"os/darwin/errno.zig"
"os/epoch.zig"
"os/file.zig"
"os/get_app_data_dir.zig"

View File

@ -70,7 +70,7 @@ that counts as "freestanding" for the purposes of this table.
## Community
* IRC: `#zig` on Freenode.
* IRC: `#zig` on Freenode ([Channel Logs](https://irclog.whitequark.org/zig/)).
* Reddit: [/r/zig](https://www.reddit.com/r/zig)
* Email list: [ziglang@googlegroups.com](https://groups.google.com/forum/#!forum/ziglang)

View File

@ -2172,8 +2172,7 @@ const Analyze = struct {
break :fits true;
}
if (dest_type.cast(Type.Int)) |int| {
break :fits (from_int.positive or from_int.eqZero() or int.key.is_signed) and
int.key.bit_count >= from_int.bitcount();
break :fits from_int.fitsInTwosComp(int.key.is_signed, int.key.bit_count);
}
break :cast;
};

View File

@ -60,6 +60,33 @@ PackageTableEntry *new_anonymous_package(void) {
return new_package("", "");
}
static const char *symbols_that_llvm_depends_on[] = {
"memcpy",
"memset",
"sqrt",
"powi",
"sin",
"cos",
"pow",
"exp",
"exp2",
"log",
"log10",
"log2",
"fma",
"fabs",
"minnum",
"maxnum",
"copysign",
"floor",
"ceil",
"trunc",
"rint",
"nearbyint",
"round",
// TODO probably all of compiler-rt needs to go here
};
CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out_type, BuildMode build_mode,
Buf *zig_lib_dir)
{
@ -94,6 +121,10 @@ CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out
g->want_h_file = (out_type == OutTypeObj || out_type == OutTypeLib);
buf_resize(&g->global_asm, 0);
for (size_t i = 0; i < array_length(symbols_that_llvm_depends_on); i += 1) {
g->external_prototypes.put(buf_create_from_str(symbols_that_llvm_depends_on[i]), nullptr);
}
if (root_src_path) {
Buf *src_basename = buf_alloc();
Buf *src_dir = buf_alloc();

View File

@ -2961,16 +2961,34 @@ static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_sco
results[ReturnKindUnconditional] = 0;
results[ReturnKindError] = 0;
while (inner_scope != outer_scope) {
assert(inner_scope);
if (inner_scope->id == ScopeIdDefer) {
AstNode *defer_node = inner_scope->source_node;
assert(defer_node->type == NodeTypeDefer);
ReturnKind defer_kind = defer_node->data.defer.kind;
results[defer_kind] += 1;
Scope *scope = inner_scope;
while (scope != outer_scope) {
assert(scope);
switch (scope->id) {
case ScopeIdDefer: {
AstNode *defer_node = scope->source_node;
assert(defer_node->type == NodeTypeDefer);
ReturnKind defer_kind = defer_node->data.defer.kind;
results[defer_kind] += 1;
scope = scope->parent;
continue;
}
case ScopeIdDecls:
case ScopeIdFnDef:
return;
case ScopeIdBlock:
case ScopeIdVarDecl:
case ScopeIdLoop:
case ScopeIdSuspend:
case ScopeIdCompTime:
scope = scope->parent;
continue;
case ScopeIdDeferExpr:
case ScopeIdCImport:
case ScopeIdCoroPrelude:
zig_unreachable();
}
inner_scope = inner_scope->parent;
}
}
@ -2986,27 +3004,43 @@ static bool ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *o
if (!scope)
return is_noreturn;
if (scope->id == ScopeIdDefer) {
AstNode *defer_node = scope->source_node;
assert(defer_node->type == NodeTypeDefer);
ReturnKind defer_kind = defer_node->data.defer.kind;
if (defer_kind == ReturnKindUnconditional ||
(gen_error_defers && defer_kind == ReturnKindError))
{
AstNode *defer_expr_node = defer_node->data.defer.expr;
Scope *defer_expr_scope = defer_node->data.defer.expr_scope;
IrInstruction *defer_expr_value = ir_gen_node(irb, defer_expr_node, defer_expr_scope);
if (defer_expr_value != irb->codegen->invalid_instruction) {
if (defer_expr_value->value.type != nullptr && defer_expr_value->value.type->id == TypeTableEntryIdUnreachable) {
is_noreturn = true;
} else {
ir_mark_gen(ir_build_check_statement_is_void(irb, defer_expr_scope, defer_expr_node, defer_expr_value));
switch (scope->id) {
case ScopeIdDefer: {
AstNode *defer_node = scope->source_node;
assert(defer_node->type == NodeTypeDefer);
ReturnKind defer_kind = defer_node->data.defer.kind;
if (defer_kind == ReturnKindUnconditional ||
(gen_error_defers && defer_kind == ReturnKindError))
{
AstNode *defer_expr_node = defer_node->data.defer.expr;
Scope *defer_expr_scope = defer_node->data.defer.expr_scope;
IrInstruction *defer_expr_value = ir_gen_node(irb, defer_expr_node, defer_expr_scope);
if (defer_expr_value != irb->codegen->invalid_instruction) {
if (defer_expr_value->value.type != nullptr && defer_expr_value->value.type->id == TypeTableEntryIdUnreachable) {
is_noreturn = true;
} else {
ir_mark_gen(ir_build_check_statement_is_void(irb, defer_expr_scope, defer_expr_node, defer_expr_value));
}
}
}
scope = scope->parent;
continue;
}
case ScopeIdDecls:
case ScopeIdFnDef:
return is_noreturn;
case ScopeIdBlock:
case ScopeIdVarDecl:
case ScopeIdLoop:
case ScopeIdSuspend:
case ScopeIdCompTime:
scope = scope->parent;
continue;
case ScopeIdDeferExpr:
case ScopeIdCImport:
case ScopeIdCoroPrelude:
zig_unreachable();
}
scope = scope->parent;
}
return is_noreturn;
}

View File

@ -30,7 +30,7 @@ pub extern "c" fn sysctl(name: [*]c_int, namelen: c_uint, oldp: ?*c_void, oldlen
pub extern "c" fn sysctlbyname(name: [*]const u8, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) c_int;
pub extern "c" fn sysctlnametomib(name: [*]const u8, mibp: ?*c_int, sizep: ?*usize) c_int;
pub use @import("../os/darwin_errno.zig");
pub use @import("../os/darwin/errno.zig");
pub const _errno = __error;

View File

@ -125,8 +125,9 @@ pub async fn connect(loop: *Loop, _address: *const std.net.Address) !std.os.File
test "listen on a port, send bytes, receive bytes" {
if (builtin.os != builtin.Os.linux) {
// TODO build abstractions for other operating systems
return;
return error.SkipZigTest;
}
const MyServer = struct {
tcp_server: Server,

View File

@ -116,13 +116,63 @@ pub const Int = struct {
return !r.isOdd();
}
fn bitcount(self: Int) usize {
const u_bit_count = (self.len - 1) * Limb.bit_count + (Limb.bit_count - @clz(self.limbs[self.len - 1]));
return @boolToInt(!self.positive) + u_bit_count;
// Returns the number of bits required to represent the absolute value of self.
fn bitCountAbs(self: Int) usize {
return (self.len - 1) * Limb.bit_count + (Limb.bit_count - @clz(self.limbs[self.len - 1]));
}
// Returns the number of bits required to represent the integer in twos-complement form.
//
// If the integer is negative the value returned is the number of bits needed by a signed
// integer to represent the value. If positive the value is the number of bits for an
// unsigned integer. Any unsigned integer will fit in the signed integer with bitcount
// one greater than the returned value.
//
// e.g. -127 returns 8 as it will fit in an i8. 127 returns 7 since it fits in a u7.
fn bitCountTwosComp(self: Int) usize {
var bits = self.bitCountAbs();
// If the entire value has only one bit set (e.g. 0b100000000) then the negation in twos
// complement requires one less bit.
if (!self.positive) block: {
bits += 1;
if (@popCount(self.limbs[self.len - 1]) == 1) {
for (self.limbs[0 .. self.len - 1]) |limb| {
if (@popCount(limb) != 0) {
break :block;
}
}
bits -= 1;
}
}
return bits;
}
pub fn fitsInTwosComp(self: Int, is_signed: bool, bit_count: usize) bool {
if (self.eqZero()) {
return true;
}
if (!is_signed and !self.positive) {
return false;
}
const req_bits = self.bitCountTwosComp() + @boolToInt(self.positive and is_signed);
return bit_count >= req_bits;
}
pub fn fits(self: Int, comptime T: type) bool {
return self.fitsInTwosComp(T.is_signed, T.bit_count);
}
// Returns the approximate size of the integer in the given base. Negative values accomodate for
// the minus sign. This is used for determining the number of characters needed to print the
// value. It is inexact and will exceed the given value by 1-2 digits.
pub fn sizeInBase(self: Int, base: usize) usize {
return (self.bitcount() / math.log2(base)) + 1;
const bit_count = usize(@boolToInt(!self.positive)) + self.bitCountAbs();
return (bit_count / math.log2(base)) + 1;
}
pub fn set(self: *Int, value: var) Allocator.Error!void {
@ -190,9 +240,9 @@ pub const Int = struct {
pub fn to(self: Int, comptime T: type) ConvertError!T {
switch (@typeId(T)) {
TypeId.Int => {
const UT = if (T.is_signed) @IntType(false, T.bit_count - 1) else T;
const UT = @IntType(false, T.bit_count);
if (self.bitcount() > 8 * @sizeOf(UT)) {
if (self.bitCountTwosComp() > T.bit_count) {
return error.TargetTooSmall;
}
@ -209,9 +259,17 @@ pub const Int = struct {
}
if (!T.is_signed) {
return if (self.positive) r else error.NegativeIntoUnsigned;
return if (self.positive) @intCast(T, r) else error.NegativeIntoUnsigned;
} else {
return if (self.positive) @intCast(T, r) else -@intCast(T, r);
if (self.positive) {
return @intCast(T, r);
} else {
if (math.cast(T, r)) |ok| {
return -ok;
} else |_| {
return @minValue(T);
}
}
}
},
else => {
@ -1137,24 +1195,88 @@ test "big.int bitcount + sizeInBase" {
var a = try Int.init(al);
try a.set(0b100);
debug.assert(a.bitcount() == 3);
debug.assert(a.bitCountAbs() == 3);
debug.assert(a.sizeInBase(2) >= 3);
debug.assert(a.sizeInBase(10) >= 1);
a.negate();
debug.assert(a.bitCountAbs() == 3);
debug.assert(a.sizeInBase(2) >= 4);
debug.assert(a.sizeInBase(10) >= 2);
try a.set(0xffffffff);
debug.assert(a.bitcount() == 32);
debug.assert(a.bitCountAbs() == 32);
debug.assert(a.sizeInBase(2) >= 32);
debug.assert(a.sizeInBase(10) >= 10);
try a.shiftLeft(a, 5000);
debug.assert(a.bitcount() == 5032);
debug.assert(a.bitCountAbs() == 5032);
debug.assert(a.sizeInBase(2) >= 5032);
a.positive = false;
debug.assert(a.bitcount() == 5033);
debug.assert(a.bitCountAbs() == 5032);
debug.assert(a.sizeInBase(2) >= 5033);
}
test "big.int bitcount/to" {
var a = try Int.init(al);
try a.set(0);
debug.assert(a.bitCountTwosComp() == 0);
// TODO: stack smashing
// debug.assert((try a.to(u0)) == 0);
// TODO: sigsegv
// debug.assert((try a.to(i0)) == 0);
try a.set(-1);
debug.assert(a.bitCountTwosComp() == 1);
debug.assert((try a.to(i1)) == -1);
try a.set(-8);
debug.assert(a.bitCountTwosComp() == 4);
debug.assert((try a.to(i4)) == -8);
try a.set(127);
debug.assert(a.bitCountTwosComp() == 7);
debug.assert((try a.to(u7)) == 127);
try a.set(-128);
debug.assert(a.bitCountTwosComp() == 8);
debug.assert((try a.to(i8)) == -128);
try a.set(-129);
debug.assert(a.bitCountTwosComp() == 9);
debug.assert((try a.to(i9)) == -129);
}
test "big.int fits" {
var a = try Int.init(al);
try a.set(0);
debug.assert(a.fits(u0));
debug.assert(a.fits(i0));
try a.set(255);
debug.assert(!a.fits(u0));
debug.assert(!a.fits(u1));
debug.assert(!a.fits(i8));
debug.assert(a.fits(u8));
debug.assert(a.fits(u9));
debug.assert(a.fits(i9));
try a.set(-128);
debug.assert(!a.fits(i7));
debug.assert(a.fits(i8));
debug.assert(a.fits(i9));
debug.assert(!a.fits(u9));
try a.set(0x1ffffffffeeeeeeee);
debug.assert(!a.fits(u32));
debug.assert(!a.fits(u64));
debug.assert(a.fits(u65));
}
test "big.int string set" {
var a = try Int.init(al);
try a.setString(10, "120317241209124781241290847124");

View File

@ -2,7 +2,7 @@ const std = @import("../index.zig");
const c = std.c;
const assert = std.debug.assert;
pub use @import("darwin_errno.zig");
pub use @import("darwin/errno.zig");
pub const PATH_MAX = 1024;
@ -482,6 +482,92 @@ pub const NOTE_MACH_CONTINUOUS_TIME = 0x00000080;
/// data is mach absolute time units
pub const NOTE_MACHTIME = 0x00000100;
pub const AF_UNSPEC: c_int = 0;
pub const AF_LOCAL: c_int = 1;
pub const AF_UNIX: c_int = AF_LOCAL;
pub const AF_INET: c_int = 2;
pub const AF_SYS_CONTROL: c_int = 2;
pub const AF_IMPLINK: c_int = 3;
pub const AF_PUP: c_int = 4;
pub const AF_CHAOS: c_int = 5;
pub const AF_NS: c_int = 6;
pub const AF_ISO: c_int = 7;
pub const AF_OSI: c_int = AF_ISO;
pub const AF_ECMA: c_int = 8;
pub const AF_DATAKIT: c_int = 9;
pub const AF_CCITT: c_int = 10;
pub const AF_SNA: c_int = 11;
pub const AF_DECnet: c_int = 12;
pub const AF_DLI: c_int = 13;
pub const AF_LAT: c_int = 14;
pub const AF_HYLINK: c_int = 15;
pub const AF_APPLETALK: c_int = 16;
pub const AF_ROUTE: c_int = 17;
pub const AF_LINK: c_int = 18;
pub const AF_XTP: c_int = 19;
pub const AF_COIP: c_int = 20;
pub const AF_CNT: c_int = 21;
pub const AF_RTIP: c_int = 22;
pub const AF_IPX: c_int = 23;
pub const AF_SIP: c_int = 24;
pub const AF_PIP: c_int = 25;
pub const AF_ISDN: c_int = 28;
pub const AF_E164: c_int = AF_ISDN;
pub const AF_KEY: c_int = 29;
pub const AF_INET6: c_int = 30;
pub const AF_NATM: c_int = 31;
pub const AF_SYSTEM: c_int = 32;
pub const AF_NETBIOS: c_int = 33;
pub const AF_PPP: c_int = 34;
pub const AF_MAX: c_int = 40;
pub const PF_UNSPEC: c_int = AF_UNSPEC;
pub const PF_LOCAL: c_int = AF_LOCAL;
pub const PF_UNIX: c_int = PF_LOCAL;
pub const PF_INET: c_int = AF_INET;
pub const PF_IMPLINK: c_int = AF_IMPLINK;
pub const PF_PUP: c_int = AF_PUP;
pub const PF_CHAOS: c_int = AF_CHAOS;
pub const PF_NS: c_int = AF_NS;
pub const PF_ISO: c_int = AF_ISO;
pub const PF_OSI: c_int = AF_ISO;
pub const PF_ECMA: c_int = AF_ECMA;
pub const PF_DATAKIT: c_int = AF_DATAKIT;
pub const PF_CCITT: c_int = AF_CCITT;
pub const PF_SNA: c_int = AF_SNA;
pub const PF_DECnet: c_int = AF_DECnet;
pub const PF_DLI: c_int = AF_DLI;
pub const PF_LAT: c_int = AF_LAT;
pub const PF_HYLINK: c_int = AF_HYLINK;
pub const PF_APPLETALK: c_int = AF_APPLETALK;
pub const PF_ROUTE: c_int = AF_ROUTE;
pub const PF_LINK: c_int = AF_LINK;
pub const PF_XTP: c_int = AF_XTP;
pub const PF_COIP: c_int = AF_COIP;
pub const PF_CNT: c_int = AF_CNT;
pub const PF_SIP: c_int = AF_SIP;
pub const PF_IPX: c_int = AF_IPX;
pub const PF_RTIP: c_int = AF_RTIP;
pub const PF_PIP: c_int = AF_PIP;
pub const PF_ISDN: c_int = AF_ISDN;
pub const PF_KEY: c_int = AF_KEY;
pub const PF_INET6: c_int = AF_INET6;
pub const PF_NATM: c_int = AF_NATM;
pub const PF_SYSTEM: c_int = AF_SYSTEM;
pub const PF_NETBIOS: c_int = AF_NETBIOS;
pub const PF_PPP: c_int = AF_PPP;
pub const PF_MAX: c_int = AF_MAX;
pub const SYSPROTO_EVENT: c_int = 1;
pub const SYSPROTO_CONTROL: c_int = 2;
pub const SOCK_STREAM: c_int = 1;
pub const SOCK_DGRAM: c_int = 2;
pub const SOCK_RAW: c_int = 3;
pub const SOCK_RDM: c_int = 4;
pub const SOCK_SEQPACKET: c_int = 5;
pub const SOCK_MAXADDRLEN: c_int = 255;
fn wstatus(x: i32) i32 {
return x & 0o177;
}

View File

@ -15,7 +15,7 @@ pub const File = struct {
/// The OS-specific file descriptor or file handle.
handle: os.FileHandle,
const OpenError = os.WindowsOpenError || os.PosixOpenError;
pub const OpenError = os.WindowsOpenError || os.PosixOpenError;
/// `path` needs to be copied in memory to add a null terminating byte, hence the allocator.
/// Call close to clean up.
@ -239,7 +239,7 @@ pub const File = struct {
},
Os.windows => {
var pos: windows.LARGE_INTEGER = undefined;
if (windows.SetFilePointerEx(self.handle, 0, *pos, windows.FILE_CURRENT) == 0) {
if (windows.SetFilePointerEx(self.handle, 0, &pos, windows.FILE_CURRENT) == 0) {
const err = windows.GetLastError();
return switch (err) {
windows.ERROR.INVALID_PARAMETER => error.BadFd,
@ -248,13 +248,7 @@ pub const File = struct {
}
assert(pos >= 0);
if (@sizeOf(@typeOf(pos)) > @sizeOf(usize)) {
if (pos > @maxValue(usize)) {
return error.FilePosLargerThanPointerRange;
}
}
return usize(pos);
return math.cast(usize, pos) catch error.FilePosLargerThanPointerRange;
},
else => @compileError("unsupported OS"),
}
@ -286,7 +280,7 @@ pub const File = struct {
Unexpected,
};
fn mode(self: *File) ModeError!os.FileMode {
pub fn mode(self: *File) ModeError!os.FileMode {
if (is_posix) {
var stat: posix.Stat = undefined;
const err = posix.getErrno(posix.fstat(self.handle, &stat));
@ -361,7 +355,7 @@ pub const File = struct {
pub const WriteError = os.WindowsWriteError || os.PosixWriteError;
fn write(self: *File, bytes: []const u8) WriteError!void {
pub fn write(self: *File, bytes: []const u8) WriteError!void {
if (is_posix) {
try os.posixWrite(self.handle, bytes);
} else if (is_windows) {

View File

@ -11,7 +11,7 @@ const os = this;
test "std.os" {
_ = @import("child_process.zig");
_ = @import("darwin.zig");
_ = @import("darwin_errno.zig");
_ = @import("darwin/errno.zig");
_ = @import("get_user_id.zig");
_ = @import("linux/index.zig");
_ = @import("path.zig");

View File

@ -5,11 +5,25 @@ const test_fn_list = builtin.__zig_test_fn_slice;
const warn = std.debug.warn;
pub fn main() !void {
var ok_count: usize = 0;
var skip_count: usize = 0;
for (test_fn_list) |test_fn, i| {
warn("Test {}/{} {}...", i + 1, test_fn_list.len, test_fn.name);
try test_fn.func();
warn("OK\n");
if (test_fn.func()) |_| {
ok_count += 1;
warn("OK\n");
} else |err| switch (err) {
error.SkipZigTest => {
skip_count += 1;
warn("SKIP\n");
},
else => return err,
}
}
if (ok_count == test_fn_list.len) {
warn("All tests passed.\n");
} else {
warn("{} passed; {} skipped.\n", ok_count, skip_count);
}
}

View File

@ -61,3 +61,18 @@ test "defer and labeled break" {
assert(i == 1);
}
test "errdefer does not apply to fn inside fn" {
if (testNestedFnErrDefer()) |_| @panic("expected error") else |e| assert(e == error.Bad);
}
fn testNestedFnErrDefer() error!void {
var a: i32 = 0;
errdefer a += 1;
const S = struct {
fn baz() error {
return error.Bad;
}
};
return S.baz();
}