Merge branch 'master' into freebsd2

master
Andrew Kelley 2018-11-27 20:36:44 -05:00
commit e3bf40742d
No known key found for this signature in database
GPG Key ID: 7C5F548F728501A9
21 changed files with 871 additions and 546 deletions

View File

@ -42,33 +42,71 @@ clarity.
* In addition to creating executables, creating a C library is a primary use
case. You can export an auto-generated .h file.
### Support Table
### Supported Targets
Freestanding means that you do not directly interact with the OS
or you are writing your own OS.
#### Tier 1 Support
Note that if you use libc or other libraries to interact with the OS,
that counts as "freestanding" for the purposes of this table.
* Not only can Zig generate machine code for these targets, but the standard
library cross-platform abstractions have implementations for these targets.
Thus it is practical to write a pure Zig application with no dependency on
libc.
* The CI server automatically tests these targets on every commit to master
branch, and updates ziglang.org/download with links to pre-built binaries.
* These targets have debug info capabilities and therefore produce stack
traces on failed assertions.
| | freestanding | linux | macosx | windows | other |
|-------------|--------------|---------|---------|---------|---------|
|i386 | OK | planned | OK | planned | planned |
|x86_64 | OK | OK | OK | OK | planned |
|arm | OK | planned | planned | planned | planned |
|bpf | OK | planned | N/A | N/A | planned |
|hexagon | OK | planned | N/A | N/A | planned |
|mips | OK | planned | N/A | N/A | planned |
|powerpc | OK | planned | N/A | N/A | planned |
|r600 | OK | planned | N/A | N/A | planned |
|amdgcn | OK | planned | N/A | N/A | planned |
|sparc | OK | planned | N/A | N/A | planned |
|s390x | OK | planned | N/A | N/A | planned |
|spir | OK | planned | N/A | N/A | planned |
|lanai | OK | planned | N/A | N/A | planned |
|wasm32 | planned | N/A | N/A | N/A | N/A |
|wasm64 | planned | N/A | N/A | N/A | N/A |
|riscv32 | planned | planned | N/A | N/A | planned |
|riscv64 | planned | planned | N/A | N/A | planned |
#### Tier 2 Support
* There may be some standard library implementations, but many abstractions
will give an "Unsupported OS" compile error. One can link with libc or other
libraries to fill in the gaps in the standard library.
* These targets are known to work, but are not automatically tested, so there
are occasional regressions.
* Some tests may be disabled for these targets as we work toward Tier 1
support.
#### Tier 3 Support
* The standard library has little to no knowledge of the existence of this
target.
* Because Zig is based on LLVM, it has the capability to build for these
targets, and LLVM has the target enabled by default.
* These targets are not frequently tested; one will likely need to contribute
to Zig in order to build for these targets.
* The Zig compiler might need to be updated with a few things such as
- what sizes are the C integer types
- C ABI calling convention for this target
- bootstrap code and default panic handler
#### Tier 4 Support
* Support for these targets is entirely experimental.
* LLVM may have the target as an experimental target, which means that you
need to use Zig-provided binaries for the target to be available, or
build LLVM from source with special configure flags.
#### Support Table
| | freestanding | linux | macosx | windows | freebsd | other |
|--------|--------------|--------|--------|---------|---------|--------|
|x86_64 | Tier 2 | Tier 1 | Tier 1 | Tier 1 | Tier 3 | Tier 3 |
|i386 | Tier 2 | Tier 2 | Tier 2 | Tier 2 | Tier 3 | Tier 3 |
|arm | Tier 2 | Tier 3 | Tier 3 | Tier 3 | Tier 3 | Tier 3 |
|arm64 | Tier 2 | Tier 2 | Tier 3 | Tier 3 | Tier 3 | Tier 3 |
|bpf | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 |
|hexagon | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 |
|mips | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 |
|powerpc | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 |
|r600 | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 |
|amdgcn | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 |
|sparc | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 |
|s390x | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 |
|spir | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 |
|lanai | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 |
|wasm32 | Tier 4 | N/A | N/A | N/A | N/A | N/A |
|wasm64 | Tier 4 | N/A | N/A | N/A | N/A | N/A |
|riscv32 | Tier 4 | Tier 4 | N/A | N/A | Tier 4 | Tier 4 |
|riscv64 | Tier 4 | Tier 4 | N/A | N/A | Tier 4 | Tier 4 |
## Community

View File

@ -1619,13 +1619,16 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc
case ZigTypeIdUnion:
case ZigTypeIdFn:
case ZigTypeIdPromise:
if ((err = type_resolve(g, type_entry, ResolveStatusZeroBitsKnown)))
return g->builtin_types.entry_invalid;
if (type_requires_comptime(type_entry)) {
add_node_error(g, param_node->data.param_decl.type,
buf_sprintf("parameter of type '%s' must be declared comptime",
buf_ptr(&type_entry->name)));
return g->builtin_types.entry_invalid;
switch (type_requires_comptime(g, type_entry)) {
case ReqCompTimeNo:
break;
case ReqCompTimeYes:
add_node_error(g, param_node->data.param_decl.type,
buf_sprintf("parameter of type '%s' must be declared comptime",
buf_ptr(&type_entry->name)));
return g->builtin_types.entry_invalid;
case ReqCompTimeInvalid:
return g->builtin_types.entry_invalid;
}
break;
}
@ -1711,10 +1714,13 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc
case ZigTypeIdUnion:
case ZigTypeIdFn:
case ZigTypeIdPromise:
if ((err = type_resolve(g, fn_type_id.return_type, ResolveStatusZeroBitsKnown)))
return g->builtin_types.entry_invalid;
if (type_requires_comptime(fn_type_id.return_type)) {
return get_generic_fn_type(g, &fn_type_id);
switch (type_requires_comptime(g, fn_type_id.return_type)) {
case ReqCompTimeInvalid:
return g->builtin_types.entry_invalid;
case ReqCompTimeYes:
return get_generic_fn_type(g, &fn_type_id);
case ReqCompTimeNo:
break;
}
break;
}
@ -2560,8 +2566,6 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) {
static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) {
assert(struct_type->id == ZigTypeIdStruct);
Error err;
if (struct_type->data.structure.resolve_status == ResolveStatusInvalid)
return ErrorSemanticAnalyzeFail;
if (struct_type->data.structure.resolve_status >= ResolveStatusZeroBitsKnown)
@ -2619,13 +2623,15 @@ static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) {
buf_sprintf("enums, not structs, support field assignment"));
}
if ((err = type_resolve(g, field_type, ResolveStatusZeroBitsKnown))) {
struct_type->data.structure.resolve_status = ResolveStatusInvalid;
continue;
}
if (type_requires_comptime(field_type)) {
struct_type->data.structure.requires_comptime = true;
switch (type_requires_comptime(g, field_type)) {
case ReqCompTimeYes:
struct_type->data.structure.requires_comptime = true;
break;
case ReqCompTimeInvalid:
struct_type->data.structure.resolve_status = ResolveStatusInvalid;
continue;
case ReqCompTimeNo:
break;
}
if (!type_has_bits(field_type))
@ -2890,11 +2896,17 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) {
}
union_field->type_entry = field_type;
if (type_requires_comptime(field_type)) {
union_type->data.unionation.requires_comptime = true;
switch (type_requires_comptime(g, field_type)) {
case ReqCompTimeInvalid:
union_type->data.unionation.is_invalid = true;
continue;
case ReqCompTimeYes:
union_type->data.unionation.requires_comptime = true;
break;
case ReqCompTimeNo:
break;
}
if (field_node->data.struct_field.value != nullptr && !decl_node->data.container_decl.auto_enum) {
ErrorMsg *msg = add_node_error(g, field_node->data.struct_field.value,
buf_sprintf("non-enum union field assignment"));
@ -5096,7 +5108,10 @@ bool type_has_bits(ZigType *type_entry) {
return !type_entry->zero_bits;
}
bool type_requires_comptime(ZigType *type_entry) {
ReqCompTime type_requires_comptime(CodeGen *g, ZigType *type_entry) {
Error err;
if ((err = type_resolve(g, type_entry, ResolveStatusZeroBitsKnown)))
return ReqCompTimeInvalid;
switch (type_entry->id) {
case ZigTypeIdInvalid:
case ZigTypeIdOpaque:
@ -5109,27 +5124,25 @@ bool type_requires_comptime(ZigType *type_entry) {
case ZigTypeIdNamespace:
case ZigTypeIdBoundFn:
case ZigTypeIdArgTuple:
return true;
return ReqCompTimeYes;
case ZigTypeIdArray:
return type_requires_comptime(type_entry->data.array.child_type);
return type_requires_comptime(g, type_entry->data.array.child_type);
case ZigTypeIdStruct:
assert(type_is_resolved(type_entry, ResolveStatusZeroBitsKnown));
return type_entry->data.structure.requires_comptime;
return type_entry->data.structure.requires_comptime ? ReqCompTimeYes : ReqCompTimeNo;
case ZigTypeIdUnion:
assert(type_is_resolved(type_entry, ResolveStatusZeroBitsKnown));
return type_entry->data.unionation.requires_comptime;
return type_entry->data.unionation.requires_comptime ? ReqCompTimeYes : ReqCompTimeNo;
case ZigTypeIdOptional:
return type_requires_comptime(type_entry->data.maybe.child_type);
return type_requires_comptime(g, type_entry->data.maybe.child_type);
case ZigTypeIdErrorUnion:
return type_requires_comptime(type_entry->data.error_union.payload_type);
return type_requires_comptime(g, type_entry->data.error_union.payload_type);
case ZigTypeIdPointer:
if (type_entry->data.pointer.child_type->id == ZigTypeIdOpaque) {
return false;
return ReqCompTimeNo;
} else {
return type_requires_comptime(type_entry->data.pointer.child_type);
return type_requires_comptime(g, type_entry->data.pointer.child_type);
}
case ZigTypeIdFn:
return type_entry->data.fn.is_generic;
return type_entry->data.fn.is_generic ? ReqCompTimeYes : ReqCompTimeNo;
case ZigTypeIdEnum:
case ZigTypeIdErrorSet:
case ZigTypeIdBool:
@ -5138,7 +5151,7 @@ bool type_requires_comptime(ZigType *type_entry) {
case ZigTypeIdVoid:
case ZigTypeIdUnreachable:
case ZigTypeIdPromise:
return false;
return ReqCompTimeNo;
}
zig_unreachable();
}

View File

@ -87,7 +87,6 @@ ZigFn *create_fn(CodeGen *g, AstNode *proto_node);
ZigFn *create_fn_raw(CodeGen *g, FnInline inline_value);
void init_fn_type_id(FnTypeId *fn_type_id, AstNode *proto_node, size_t param_count_alloc);
AstNode *get_param_decl_node(ZigFn *fn_entry, size_t index);
bool type_requires_comptime(ZigType *type_entry);
Error ATTRIBUTE_MUST_USE ensure_complete_type(CodeGen *g, ZigType *type_entry);
Error ATTRIBUTE_MUST_USE type_resolve(CodeGen *g, ZigType *type_entry, ResolveStatus status);
void complete_enum(CodeGen *g, ZigType *enum_type);
@ -216,4 +215,11 @@ bool want_first_arg_sret(CodeGen *g, FnTypeId *fn_type_id);
uint32_t get_host_int_bytes(CodeGen *g, ZigType *struct_type, TypeStructField *field);
enum ReqCompTime {
ReqCompTimeInvalid,
ReqCompTimeNo,
ReqCompTimeYes,
};
ReqCompTime type_requires_comptime(CodeGen *g, ZigType *type_entry);
#endif

View File

@ -352,8 +352,9 @@ Error cache_hit(CacheHash *ch, Buf *out_digest) {
// if the mtime matches we can trust the digest
OsFile this_file;
if ((err = os_file_open_r(chf->path, &this_file))) {
fprintf(stderr, "Unable to open %s\n: %s", buf_ptr(chf->path), err_str(err));
os_file_close(ch->manifest_file);
return err;
return ErrorCacheUnavailable;
}
OsTimeStamp actual_mtime;
if ((err = os_file_mtime(this_file, &actual_mtime))) {
@ -392,8 +393,9 @@ Error cache_hit(CacheHash *ch, Buf *out_digest) {
for (; file_i < input_file_count; file_i += 1) {
CacheHashFile *chf = &ch->files.at(file_i);
if ((err = populate_file_hash(ch, chf, nullptr))) {
fprintf(stderr, "Unable to hash %s: %s\n", buf_ptr(chf->path), err_str(err));
os_file_close(ch->manifest_file);
return err;
return ErrorCacheUnavailable;
}
}
return ErrorNone;

View File

@ -129,6 +129,11 @@ CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out
Buf *src_dir = buf_alloc();
os_path_split(root_src_path, src_dir, src_basename);
if (buf_len(src_basename) == 0) {
fprintf(stderr, "Invalid root source path: %s\n", buf_ptr(root_src_path));
exit(1);
}
g->root_package = new_package(buf_ptr(src_dir), buf_ptr(src_basename));
g->std_package = new_package(buf_ptr(g->zig_std_dir), "index.zig");
g->root_package->package_table.put(buf_create_from_str("std"), g->std_package);
@ -1645,7 +1650,7 @@ static LLVMValueRef gen_widen_or_shorten(CodeGen *g, bool want_runtime_safety, Z
zig_unreachable();
}
if (actual_bits >= wanted_bits && actual_type->id == ZigTypeIdInt &&
if (actual_type->id == ZigTypeIdInt &&
!wanted_type->data.integral.is_signed && actual_type->data.integral.is_signed &&
want_runtime_safety)
{
@ -6281,8 +6286,14 @@ static void do_code_gen(CodeGen *g) {
}
if (ir_get_var_is_comptime(var))
continue;
if (type_requires_comptime(var->value->type))
continue;
switch (type_requires_comptime(g, var->value->type)) {
case ReqCompTimeInvalid:
zig_unreachable();
case ReqCompTimeYes:
continue;
case ReqCompTimeNo:
break;
}
if (var->src_arg_index == SIZE_MAX) {
var->value_ref = build_alloca(g, var->value->type, buf_ptr(&var->name), var->align_bytes);
@ -8172,7 +8183,11 @@ void codegen_build_and_link(CodeGen *g) {
os_path_join(stage1_dir, buf_create_from_str("build"), manifest_dir);
if ((err = check_cache(g, manifest_dir, &digest))) {
fprintf(stderr, "Unable to check cache: %s\n", err_str(err));
if (err == ErrorCacheUnavailable) {
// message already printed
} else {
fprintf(stderr, "Unable to check cache: %s\n", err_str(err));
}
exit(1);
}

View File

@ -33,6 +33,7 @@ const char *err_str(Error err) {
case ErrorSharingViolation: return "sharing violation";
case ErrorPipeBusy: return "pipe busy";
case ErrorPrimitiveTypeNotFound: return "primitive type not found";
case ErrorCacheUnavailable: return "cache unavailable";
}
return "(invalid error)";
}

View File

@ -35,6 +35,7 @@ enum Error {
ErrorSharingViolation,
ErrorPipeBusy,
ErrorPrimitiveTypeNotFound,
ErrorCacheUnavailable,
};
const char *err_str(Error err);

View File

@ -11276,7 +11276,6 @@ static bool optional_value_is_null(ConstExprValue *val) {
}
static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *bin_op_instruction) {
Error err;
IrInstruction *op1 = bin_op_instruction->op1->child;
if (type_is_invalid(op1->value.type))
return ira->codegen->invalid_instruction;
@ -11470,10 +11469,19 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *
if (casted_op2 == ira->codegen->invalid_instruction)
return ira->codegen->invalid_instruction;
if ((err = type_resolve(ira->codegen, resolved_type, ResolveStatusZeroBitsKnown)))
return ira->codegen->invalid_instruction;
bool requires_comptime;
switch (type_requires_comptime(ira->codegen, resolved_type)) {
case ReqCompTimeYes:
requires_comptime = true;
break;
case ReqCompTimeNo:
requires_comptime = false;
break;
case ReqCompTimeInvalid:
return ira->codegen->invalid_instruction;
}
bool one_possible_value = !type_requires_comptime(resolved_type) && !type_has_bits(resolved_type);
bool one_possible_value = !requires_comptime && !type_has_bits(resolved_type);
if (one_possible_value || (instr_is_comptime(casted_op1) && instr_is_comptime(casted_op2))) {
ConstExprValue *op1_val = one_possible_value ? &casted_op1->value : ir_resolve_const(ira, casted_op1, UndefBad);
if (op1_val == nullptr)
@ -12406,42 +12414,41 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruct
ZigType *result_type = casted_init_value->value.type;
if (type_is_invalid(result_type)) {
result_type = ira->codegen->builtin_types.entry_invalid;
} else {
if ((err = type_resolve(ira->codegen, result_type, ResolveStatusZeroBitsKnown))) {
result_type = ira->codegen->builtin_types.entry_invalid;
}
} else if (result_type->id == ZigTypeIdUnreachable || result_type->id == ZigTypeIdOpaque) {
ir_add_error_node(ira, source_node,
buf_sprintf("variable of type '%s' not allowed", buf_ptr(&result_type->name)));
result_type = ira->codegen->builtin_types.entry_invalid;
}
if (!type_is_invalid(result_type)) {
if (result_type->id == ZigTypeIdUnreachable ||
result_type->id == ZigTypeIdOpaque)
{
switch (type_requires_comptime(ira->codegen, result_type)) {
case ReqCompTimeInvalid:
result_type = ira->codegen->builtin_types.entry_invalid;
break;
case ReqCompTimeYes: {
var_class_requires_const = true;
if (!var->gen_is_const && !is_comptime_var) {
ir_add_error_node(ira, source_node,
buf_sprintf("variable of type '%s' not allowed", buf_ptr(&result_type->name)));
buf_sprintf("variable of type '%s' must be const or comptime",
buf_ptr(&result_type->name)));
result_type = ira->codegen->builtin_types.entry_invalid;
} else if (type_requires_comptime(result_type)) {
}
break;
}
case ReqCompTimeNo:
if (casted_init_value->value.special == ConstValSpecialStatic &&
casted_init_value->value.type->id == ZigTypeIdFn &&
casted_init_value->value.data.x_ptr.data.fn.fn_entry->fn_inline == FnInlineAlways)
{
var_class_requires_const = true;
if (!var->gen_is_const && !is_comptime_var) {
ir_add_error_node(ira, source_node,
buf_sprintf("variable of type '%s' must be const or comptime",
buf_ptr(&result_type->name)));
if (!var->src_is_const && !is_comptime_var) {
ErrorMsg *msg = ir_add_error_node(ira, source_node,
buf_sprintf("functions marked inline must be stored in const or comptime var"));
AstNode *proto_node = casted_init_value->value.data.x_ptr.data.fn.fn_entry->proto_node;
add_error_note(ira->codegen, msg, proto_node, buf_sprintf("declared here"));
result_type = ira->codegen->builtin_types.entry_invalid;
}
} else {
if (casted_init_value->value.special == ConstValSpecialStatic &&
casted_init_value->value.type->id == ZigTypeIdFn &&
casted_init_value->value.data.x_ptr.data.fn.fn_entry->fn_inline == FnInlineAlways)
{
var_class_requires_const = true;
if (!var->src_is_const && !is_comptime_var) {
ErrorMsg *msg = ir_add_error_node(ira, source_node,
buf_sprintf("functions marked inline must be stored in const or comptime var"));
AstNode *proto_node = casted_init_value->value.data.x_ptr.data.fn.fn_entry->proto_node;
add_error_note(ira->codegen, msg, proto_node, buf_sprintf("declared here"));
result_type = ira->codegen->builtin_types.entry_invalid;
}
}
}
break;
}
if (var->value->type != nullptr && !is_comptime_var) {
@ -12912,10 +12919,15 @@ static bool ir_analyze_fn_call_generic_arg(IrAnalyze *ira, AstNode *fn_proto_nod
}
if (!comptime_arg) {
if (type_requires_comptime(casted_arg->value.type)) {
switch (type_requires_comptime(ira->codegen, casted_arg->value.type)) {
case ReqCompTimeYes:
ir_add_error(ira, casted_arg,
buf_sprintf("parameter of type '%s' requires comptime", buf_ptr(&casted_arg->value.type->name)));
return false;
case ReqCompTimeInvalid:
return false;
case ReqCompTimeNo:
break;
}
casted_args[fn_type_id->param_count] = casted_arg;
@ -13388,12 +13400,15 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call
inst_fn_type_id.return_type = specified_return_type;
}
if ((err = type_resolve(ira->codegen, specified_return_type, ResolveStatusZeroBitsKnown)))
return ira->codegen->invalid_instruction;
if (type_requires_comptime(specified_return_type)) {
switch (type_requires_comptime(ira->codegen, specified_return_type)) {
case ReqCompTimeYes:
// Throw out our work and call the function as if it were comptime.
return ir_analyze_fn_call(ira, call_instruction, fn_entry, fn_type, fn_ref, first_arg_ptr, true, FnInlineAuto);
return ir_analyze_fn_call(ira, call_instruction, fn_entry, fn_type, fn_ref, first_arg_ptr,
true, FnInlineAuto);
case ReqCompTimeInvalid:
return ira->codegen->invalid_instruction;
case ReqCompTimeNo:
break;
}
}
IrInstruction *async_allocator_inst = nullptr;
@ -14334,11 +14349,16 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct
} else {
// runtime known element index
if (type_requires_comptime(return_type)) {
switch (type_requires_comptime(ira->codegen, return_type)) {
case ReqCompTimeYes:
ir_add_error(ira, elem_index,
buf_sprintf("values of type '%s' must be comptime known, but index value is runtime known",
buf_ptr(&return_type->data.pointer.child_type->name)));
return ira->codegen->invalid_instruction;
case ReqCompTimeInvalid:
return ira->codegen->invalid_instruction;
case ReqCompTimeNo:
break;
}
if (ptr_align < abi_align) {
if (elem_size >= ptr_align && elem_size % ptr_align == 0) {
@ -19390,7 +19410,6 @@ static IrInstruction *ir_analyze_instruction_unwrap_err_payload(IrAnalyze *ira,
}
static IrInstruction *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstructionFnProto *instruction) {
Error err;
AstNode *proto_node = instruction->base.source_node;
assert(proto_node->type == NodeTypeFnProto);
@ -19429,11 +19448,8 @@ static IrInstruction *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstruct
if (type_is_invalid(param_type_value->value.type))
return ira->codegen->invalid_instruction;
ZigType *param_type = ir_resolve_type(ira, param_type_value);
if (type_is_invalid(param_type))
return ira->codegen->invalid_instruction;
if ((err = type_resolve(ira->codegen, param_type, ResolveStatusZeroBitsKnown)))
return ira->codegen->invalid_instruction;
if (type_requires_comptime(param_type)) {
switch (type_requires_comptime(ira->codegen, param_type)) {
case ReqCompTimeYes:
if (!calling_convention_allows_zig_types(fn_type_id.cc)) {
ir_add_error(ira, param_type_value,
buf_sprintf("parameter of type '%s' not allowed in function with calling convention '%s'",
@ -19443,6 +19459,10 @@ static IrInstruction *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstruct
param_info->type = param_type;
fn_type_id.next_param_index += 1;
return ir_const_type(ira, &instruction->base, get_generic_fn_type(ira->codegen, &fn_type_id));
case ReqCompTimeInvalid:
return ira->codegen->invalid_instruction;
case ReqCompTimeNo:
break;
}
if (!type_has_bits(param_type) && !calling_convention_allows_zig_types(fn_type_id.cc)) {
ir_add_error(ira, param_type_value,

View File

@ -193,14 +193,20 @@ void os_path_split(Buf *full_path, Buf *out_dirname, Buf *out_basename) {
size_t len = buf_len(full_path);
if (len != 0) {
size_t last_index = len - 1;
if (os_is_sep(buf_ptr(full_path)[last_index])) {
char last_char = buf_ptr(full_path)[last_index];
if (os_is_sep(last_char)) {
if (last_index == 0) {
if (out_dirname) buf_init_from_mem(out_dirname, &last_char, 1);
if (out_basename) buf_init_from_str(out_basename, "");
return;
}
last_index -= 1;
}
for (size_t i = last_index;;) {
uint8_t c = buf_ptr(full_path)[i];
if (os_is_sep(c)) {
if (out_dirname) {
buf_init_from_mem(out_dirname, buf_ptr(full_path), i);
buf_init_from_mem(out_dirname, buf_ptr(full_path), (i == 0) ? 1 : i);
}
if (out_basename) {
buf_init_from_mem(out_basename, buf_ptr(full_path) + i + 1, buf_len(full_path) - (i + 1));
@ -1990,7 +1996,7 @@ Error os_file_read(OsFile file, void *ptr, size_t *len) {
case EFAULT:
zig_unreachable();
case EISDIR:
zig_unreachable();
return ErrorIsDir;
default:
return ErrorFileSystem;
}

View File

@ -282,8 +282,9 @@ fn printSourceAtAddressWindows(di: *DebugInfo, out_stream: var, relocated_addres
var coff_section: *coff.Section = undefined;
const mod_index = for (di.sect_contribs) |sect_contrib| {
if (sect_contrib.Section >= di.coff.sections.len) continue;
coff_section = &di.coff.sections.toSlice()[sect_contrib.Section];
if (sect_contrib.Section > di.coff.sections.len) continue;
// Remember that SectionContribEntry.Section is 1-based.
coff_section = &di.coff.sections.toSlice()[sect_contrib.Section-1];
const vaddr_start = coff_section.header.virtual_address + sect_contrib.Offset;
const vaddr_end = vaddr_start + sect_contrib.Size;

View File

@ -910,7 +910,7 @@ fn checkNext(p: *TokenStream, id: Token.Id) void {
debug.assert(token.id == id);
}
test "token" {
test "json.token" {
const s =
\\{
\\ "Image": {
@ -980,7 +980,7 @@ pub fn validate(s: []const u8) bool {
return p.complete;
}
test "json validate" {
test "json.validate" {
debug.assert(validate("{}"));
}
@ -1188,7 +1188,7 @@ pub const Parser = struct {
}
var value = p.stack.pop();
try p.pushToParent(value);
try p.pushToParent(&value);
},
Token.Id.String => {
try p.stack.append(try p.parseString(allocator, token, input, i));
@ -1251,7 +1251,7 @@ pub const Parser = struct {
}
var value = p.stack.pop();
try p.pushToParent(value);
try p.pushToParent(&value);
},
Token.Id.ObjectBegin => {
try p.stack.append(Value{ .Object = ObjectMap.init(allocator) });
@ -1312,19 +1312,19 @@ pub const Parser = struct {
}
}
fn pushToParent(p: *Parser, value: Value) !void {
switch (p.stack.at(p.stack.len - 1)) {
fn pushToParent(p: *Parser, value: *const Value) !void {
switch (p.stack.toSlice()[p.stack.len - 1]) {
// Object Parent -> [ ..., object, <key>, value ]
Value.String => |key| {
_ = p.stack.pop();
var object = &p.stack.items[p.stack.len - 1].Object;
_ = try object.put(key, value);
_ = try object.put(key, value.*);
p.state = State.ObjectKey;
},
// Array Parent -> [ ..., <array>, value ]
Value.Array => |*array| {
try array.append(value);
try array.append(value.*);
p.state = State.ArrayValue;
},
else => {
@ -1348,7 +1348,7 @@ pub const Parser = struct {
}
};
test "json parser dynamic" {
test "json.parser.dynamic" {
var p = Parser.init(debug.global_allocator, false);
defer p.deinit();
@ -1364,7 +1364,8 @@ test "json parser dynamic" {
\\ "Width": 100
\\ },
\\ "Animated" : false,
\\ "IDs": [116, 943, 234, 38793]
\\ "IDs": [116, 943, 234, 38793],
\\ "ArrayOfObject": [{"n": "m"}]
\\ }
\\}
;
@ -1387,4 +1388,10 @@ test "json parser dynamic" {
const animated = image.Object.get("Animated").?.value;
debug.assert(animated.Bool == false);
const array_of_object = image.Object.get("ArrayOfObject").?.value;
debug.assert(array_of_object.Array.len == 1);
const obj0 = array_of_object.Array.at(0).Object.get("n").?.value;
debug.assert(mem.eql(u8, obj0.String, "m"));
}

File diff suppressed because it is too large Load Diff

View File

@ -365,6 +365,69 @@ pub fn Log2Int(comptime T: type) type {
return @IntType(false, count);
}
pub fn IntFittingRange(comptime from: comptime_int, comptime to: comptime_int) type {
assert(from <= to);
if (from == 0 and to == 0) {
return u0;
}
const is_signed = from < 0;
const largest_positive_integer = max(if (from<0) (-from)-1 else from, to); // two's complement
const base = log2(largest_positive_integer);
const upper = (1 << base) - 1;
var magnitude_bits = if (upper >= largest_positive_integer) base else base + 1;
if (is_signed) {
magnitude_bits += 1;
}
return @IntType(is_signed, magnitude_bits);
}
test "math.IntFittingRange" {
assert(IntFittingRange(0, 0) == u0);
assert(IntFittingRange(0, 1) == u1);
assert(IntFittingRange(0, 2) == u2);
assert(IntFittingRange(0, 3) == u2);
assert(IntFittingRange(0, 4) == u3);
assert(IntFittingRange(0, 7) == u3);
assert(IntFittingRange(0, 8) == u4);
assert(IntFittingRange(0, 9) == u4);
assert(IntFittingRange(0, 15) == u4);
assert(IntFittingRange(0, 16) == u5);
assert(IntFittingRange(0, 17) == u5);
assert(IntFittingRange(0, 4095) == u12);
assert(IntFittingRange(2000, 4095) == u12);
assert(IntFittingRange(0, 4096) == u13);
assert(IntFittingRange(2000, 4096) == u13);
assert(IntFittingRange(0, 4097) == u13);
assert(IntFittingRange(2000, 4097) == u13);
assert(IntFittingRange(0, 123456789123456798123456789) == u87);
assert(IntFittingRange(0, 123456789123456798123456789123456789123456798123456789) == u177);
assert(IntFittingRange(-1, -1) == i1);
assert(IntFittingRange(-1, 0) == i1);
assert(IntFittingRange(-1, 1) == i2);
assert(IntFittingRange(-2, -2) == i2);
assert(IntFittingRange(-2, -1) == i2);
assert(IntFittingRange(-2, 0) == i2);
assert(IntFittingRange(-2, 1) == i2);
assert(IntFittingRange(-2, 2) == i3);
assert(IntFittingRange(-1, 2) == i3);
assert(IntFittingRange(-1, 3) == i3);
assert(IntFittingRange(-1, 4) == i4);
assert(IntFittingRange(-1, 7) == i4);
assert(IntFittingRange(-1, 8) == i5);
assert(IntFittingRange(-1, 9) == i5);
assert(IntFittingRange(-1, 15) == i5);
assert(IntFittingRange(-1, 16) == i6);
assert(IntFittingRange(-1, 17) == i6);
assert(IntFittingRange(-1, 4095) == i13);
assert(IntFittingRange(-4096, 4095) == i13);
assert(IntFittingRange(-1, 4096) == i14);
assert(IntFittingRange(-4097, 4095) == i14);
assert(IntFittingRange(-1, 4097) == i14);
assert(IntFittingRange(-1, 123456789123456798123456789) == i88);
assert(IntFittingRange(-1, 123456789123456798123456789123456789123456798123456789) == i178);
}
test "math overflow functions" {
testOverflow();
comptime testOverflow();

View File

@ -546,9 +546,7 @@ pub fn writeIntLE(comptime T: type, buf: *[@sizeOf(T)]u8, value: T) void {
buf[0] = bits;
return;
}
// FIXME: this should just be for (buf).
// See https://github.com/ziglang/zig/issues/1663
for (buf.*) |*b| {
for (buf) |*b| {
b.* = @truncate(u8, bits);
bits >>= 8;
}

View File

@ -76,6 +76,25 @@ test "std.meta.tagName" {
debug.assert(mem.eql(u8, tagName(u2b), "D"));
}
pub fn stringToEnum(comptime T: type, str: []const u8) ?T {
inline for (@typeInfo(T).Enum.fields) |enumField| {
if (std.mem.eql(u8, str, enumField.name)) {
return @field(T, enumField.name);
}
}
return null;
}
test "std.meta.stringToEnum" {
const E1 = enum {
A,
B,
};
debug.assert(E1.A == stringToEnum(E1, "A").?);
debug.assert(E1.B == stringToEnum(E1, "B").?);
debug.assert(null == stringToEnum(E1, "C"));
}
pub fn bitCount(comptime T: type) u32 {
return switch (@typeInfo(T)) {
TypeId.Int => |info| info.bits,

View File

@ -703,7 +703,7 @@ pub fn dup2(old: i32, new: i32) usize {
}
pub fn dup3(old: i32, new: i32, flags: u32) usize {
return syscall3(SYS_dup3, @intCast(usize, old), @intCast(usize, new), flags);
return syscall3(SYS_dup3, @bitCast(usize, isize(old)), @bitCast(usize, isize(new)), flags);
}
// TODO https://github.com/ziglang/zig/issues/265
@ -747,7 +747,7 @@ pub fn getcwd(buf: [*]u8, size: usize) usize {
}
pub fn getdents64(fd: i32, dirp: [*]u8, count: usize) usize {
return syscall3(SYS_getdents64, @intCast(usize, fd), @ptrToInt(dirp), count);
return syscall3(SYS_getdents64, @bitCast(usize, isize(fd)), @ptrToInt(dirp), count);
}
pub fn inotify_init1(flags: u32) usize {
@ -755,16 +755,16 @@ pub fn inotify_init1(flags: u32) usize {
}
pub fn inotify_add_watch(fd: i32, pathname: [*]const u8, mask: u32) usize {
return syscall3(SYS_inotify_add_watch, @intCast(usize, fd), @ptrToInt(pathname), mask);
return syscall3(SYS_inotify_add_watch, @bitCast(usize, isize(fd)), @ptrToInt(pathname), mask);
}
pub fn inotify_rm_watch(fd: i32, wd: i32) usize {
return syscall2(SYS_inotify_rm_watch, @intCast(usize, fd), @intCast(usize, wd));
return syscall2(SYS_inotify_rm_watch, @bitCast(usize, isize(fd)), @bitCast(usize, isize(wd)));
}
pub fn isatty(fd: i32) bool {
var wsz: winsize = undefined;
return syscall3(SYS_ioctl, @intCast(usize, fd), TIOCGWINSZ, @ptrToInt(&wsz)) == 0;
return syscall3(SYS_ioctl, @bitCast(usize, isize(fd)), TIOCGWINSZ, @ptrToInt(&wsz)) == 0;
}
// TODO https://github.com/ziglang/zig/issues/265
@ -774,7 +774,7 @@ pub fn readlink(noalias path: [*]const u8, noalias buf_ptr: [*]u8, buf_len: usiz
// TODO https://github.com/ziglang/zig/issues/265
pub fn readlinkat(dirfd: i32, noalias path: [*]const u8, noalias buf_ptr: [*]u8, buf_len: usize) usize {
return syscall4(SYS_readlinkat, @intCast(usize, dirfd), @ptrToInt(path), @ptrToInt(buf_ptr), buf_len);
return syscall4(SYS_readlinkat, @bitCast(usize, isize(dirfd)), @ptrToInt(path), @ptrToInt(buf_ptr), buf_len);
}
// TODO https://github.com/ziglang/zig/issues/265
@ -784,7 +784,7 @@ pub fn mkdir(path: [*]const u8, mode: u32) usize {
// TODO https://github.com/ziglang/zig/issues/265
pub fn mkdirat(dirfd: i32, path: [*]const u8, mode: u32) usize {
return syscall3(SYS_mkdirat, @intCast(usize, dirfd), @ptrToInt(path), mode);
return syscall3(SYS_mkdirat, @bitCast(usize, isize(dirfd)), @ptrToInt(path), mode);
}
// TODO https://github.com/ziglang/zig/issues/265
@ -803,7 +803,7 @@ pub fn umount2(special: [*]const u8, flags: u32) usize {
}
pub fn mmap(address: ?[*]u8, length: usize, prot: usize, flags: u32, fd: i32, offset: isize) usize {
return syscall6(SYS_mmap, @ptrToInt(address), length, prot, flags, @intCast(usize, fd), @bitCast(usize, offset));
return syscall6(SYS_mmap, @ptrToInt(address), length, prot, flags, @bitCast(usize, isize(fd)), @bitCast(usize, offset));
}
pub fn munmap(address: usize, length: usize) usize {
@ -811,23 +811,23 @@ pub fn munmap(address: usize, length: usize) usize {
}
pub fn read(fd: i32, buf: [*]u8, count: usize) usize {
return syscall3(SYS_read, @intCast(usize, fd), @ptrToInt(buf), count);
return syscall3(SYS_read, @bitCast(usize, isize(fd)), @ptrToInt(buf), count);
}
pub fn preadv(fd: i32, iov: [*]const iovec, count: usize, offset: u64) usize {
return syscall4(SYS_preadv, @intCast(usize, fd), @ptrToInt(iov), count, offset);
return syscall4(SYS_preadv, @bitCast(usize, isize(fd)), @ptrToInt(iov), count, offset);
}
pub fn readv(fd: i32, iov: [*]const iovec, count: usize) usize {
return syscall3(SYS_readv, @intCast(usize, fd), @ptrToInt(iov), count);
return syscall3(SYS_readv, @bitCast(usize, isize(fd)), @ptrToInt(iov), count);
}
pub fn writev(fd: i32, iov: [*]const iovec_const, count: usize) usize {
return syscall3(SYS_writev, @intCast(usize, fd), @ptrToInt(iov), count);
return syscall3(SYS_writev, @bitCast(usize, isize(fd)), @ptrToInt(iov), count);
}
pub fn pwritev(fd: i32, iov: [*]const iovec_const, count: usize, offset: u64) usize {
return syscall4(SYS_pwritev, @intCast(usize, fd), @ptrToInt(iov), count, offset);
return syscall4(SYS_pwritev, @bitCast(usize, isize(fd)), @ptrToInt(iov), count, offset);
}
// TODO https://github.com/ziglang/zig/issues/265
@ -842,12 +842,12 @@ pub fn symlink(existing: [*]const u8, new: [*]const u8) usize {
// TODO https://github.com/ziglang/zig/issues/265
pub fn symlinkat(existing: [*]const u8, newfd: i32, newpath: [*]const u8) usize {
return syscall3(SYS_symlinkat, @ptrToInt(existing), @intCast(usize, newfd), @ptrToInt(newpath));
return syscall3(SYS_symlinkat, @ptrToInt(existing), @bitCast(usize, isize(newfd)), @ptrToInt(newpath));
}
// TODO https://github.com/ziglang/zig/issues/265
pub fn pread(fd: i32, buf: [*]u8, count: usize, offset: usize) usize {
return syscall4(SYS_pread, @intCast(usize, fd), @ptrToInt(buf), count, offset);
return syscall4(SYS_pread, @bitCast(usize, isize(fd)), @ptrToInt(buf), count, offset);
}
// TODO https://github.com/ziglang/zig/issues/265
@ -856,7 +856,7 @@ pub fn access(path: [*]const u8, mode: u32) usize {
}
pub fn faccessat(dirfd: i32, path: [*]const u8, mode: u32) usize {
return syscall3(SYS_faccessat, @intCast(usize, dirfd), @ptrToInt(path), mode);
return syscall3(SYS_faccessat, @bitCast(usize, isize(dirfd)), @ptrToInt(path), mode);
}
pub fn pipe(fd: *[2]i32) usize {
@ -868,11 +868,11 @@ pub fn pipe2(fd: *[2]i32, flags: u32) usize {
}
pub fn write(fd: i32, buf: [*]const u8, count: usize) usize {
return syscall3(SYS_write, @intCast(usize, fd), @ptrToInt(buf), count);
return syscall3(SYS_write, @bitCast(usize, isize(fd)), @ptrToInt(buf), count);
}
pub fn pwrite(fd: i32, buf: [*]const u8, count: usize, offset: usize) usize {
return syscall4(SYS_pwrite, @intCast(usize, fd), @ptrToInt(buf), count, offset);
return syscall4(SYS_pwrite, @bitCast(usize, isize(fd)), @ptrToInt(buf), count, offset);
}
// TODO https://github.com/ziglang/zig/issues/265
@ -882,7 +882,7 @@ pub fn rename(old: [*]const u8, new: [*]const u8) usize {
// TODO https://github.com/ziglang/zig/issues/265
pub fn renameat2(oldfd: i32, oldpath: [*]const u8, newfd: i32, newpath: [*]const u8, flags: u32) usize {
return syscall5(SYS_renameat2, @intCast(usize, oldfd), @ptrToInt(oldpath), @intCast(usize, newfd), @ptrToInt(newpath), flags);
return syscall5(SYS_renameat2, @bitCast(usize, isize(oldfd)), @ptrToInt(oldpath), @bitCast(usize, isize(newfd)), @ptrToInt(newpath), flags);
}
// TODO https://github.com/ziglang/zig/issues/265
@ -897,7 +897,8 @@ pub fn create(path: [*]const u8, perm: usize) usize {
// TODO https://github.com/ziglang/zig/issues/265
pub fn openat(dirfd: i32, path: [*]const u8, flags: u32, mode: usize) usize {
return syscall4(SYS_openat, @intCast(usize, dirfd), @ptrToInt(path), flags, mode);
// dirfd could be negative, for example AT_FDCWD is -100
return syscall4(SYS_openat, @bitCast(usize, isize(dirfd)), @ptrToInt(path), flags, mode);
}
/// See also `clone` (from the arch-specific include)
@ -911,11 +912,11 @@ pub fn clone2(flags: u32, child_stack_ptr: usize) usize {
}
pub fn close(fd: i32) usize {
return syscall1(SYS_close, @intCast(usize, fd));
return syscall1(SYS_close, @bitCast(usize, isize(fd)));
}
pub fn lseek(fd: i32, offset: isize, ref_pos: usize) usize {
return syscall3(SYS_lseek, @intCast(usize, fd), @bitCast(usize, offset), ref_pos);
return syscall3(SYS_lseek, @bitCast(usize, isize(fd)), @bitCast(usize, offset), ref_pos);
}
pub fn exit(status: i32) noreturn {
@ -933,7 +934,7 @@ pub fn getrandom(buf: [*]u8, count: usize, flags: u32) usize {
}
pub fn kill(pid: i32, sig: i32) usize {
return syscall2(SYS_kill, @bitCast(usize, isize(pid)), @intCast(usize, sig));
return syscall2(SYS_kill, @bitCast(usize, isize(pid)), @bitCast(usize, isize(sig)));
}
// TODO https://github.com/ziglang/zig/issues/265
@ -943,7 +944,7 @@ pub fn unlink(path: [*]const u8) usize {
// TODO https://github.com/ziglang/zig/issues/265
pub fn unlinkat(dirfd: i32, path: [*]const u8, flags: u32) usize {
return syscall3(SYS_unlinkat, @intCast(usize, dirfd), @ptrToInt(path), flags);
return syscall3(SYS_unlinkat, @bitCast(usize, isize(dirfd)), @ptrToInt(path), flags);
}
pub fn waitpid(pid: i32, status: *i32, options: i32) usize {
@ -1120,8 +1121,8 @@ pub const empty_sigset = []usize{0} ** sigset_t.len;
pub fn raise(sig: i32) usize {
var set: sigset_t = undefined;
blockAppSignals(&set);
const tid = @intCast(i32, syscall0(SYS_gettid));
const ret = syscall2(SYS_tkill, @intCast(usize, tid), @intCast(usize, sig));
const tid = syscall0(SYS_gettid);
const ret = syscall2(SYS_tkill, tid, @bitCast(usize, isize(sig)));
restoreSignals(&set);
return ret;
}
@ -1189,11 +1190,11 @@ pub const iovec_const = extern struct {
};
pub fn getsockname(fd: i32, noalias addr: *sockaddr, noalias len: *socklen_t) usize {
return syscall3(SYS_getsockname, @intCast(usize, fd), @ptrToInt(addr), @ptrToInt(len));
return syscall3(SYS_getsockname, @bitCast(usize, isize(fd)), @ptrToInt(addr), @ptrToInt(len));
}
pub fn getpeername(fd: i32, noalias addr: *sockaddr, noalias len: *socklen_t) usize {
return syscall3(SYS_getpeername, @intCast(usize, fd), @ptrToInt(addr), @ptrToInt(len));
return syscall3(SYS_getpeername, @bitCast(usize, isize(fd)), @ptrToInt(addr), @ptrToInt(len));
}
pub fn socket(domain: u32, socket_type: u32, protocol: u32) usize {
@ -1201,47 +1202,47 @@ pub fn socket(domain: u32, socket_type: u32, protocol: u32) usize {
}
pub fn setsockopt(fd: i32, level: u32, optname: u32, optval: [*]const u8, optlen: socklen_t) usize {
return syscall5(SYS_setsockopt, @intCast(usize, fd), level, optname, @ptrToInt(optval), @intCast(usize, optlen));
return syscall5(SYS_setsockopt, @bitCast(usize, isize(fd)), level, optname, @ptrToInt(optval), @intCast(usize, optlen));
}
pub fn getsockopt(fd: i32, level: u32, optname: u32, noalias optval: [*]u8, noalias optlen: *socklen_t) usize {
return syscall5(SYS_getsockopt, @intCast(usize, fd), level, optname, @ptrToInt(optval), @ptrToInt(optlen));
return syscall5(SYS_getsockopt, @bitCast(usize, isize(fd)), level, optname, @ptrToInt(optval), @ptrToInt(optlen));
}
pub fn sendmsg(fd: i32, msg: *const msghdr, flags: u32) usize {
return syscall3(SYS_sendmsg, @intCast(usize, fd), @ptrToInt(msg), flags);
return syscall3(SYS_sendmsg, @bitCast(usize, isize(fd)), @ptrToInt(msg), flags);
}
pub fn connect(fd: i32, addr: *const c_void, len: socklen_t) usize {
return syscall3(SYS_connect, @intCast(usize, fd), @ptrToInt(addr), len);
return syscall3(SYS_connect, @bitCast(usize, isize(fd)), @ptrToInt(addr), len);
}
pub fn recvmsg(fd: i32, msg: *msghdr, flags: u32) usize {
return syscall3(SYS_recvmsg, @intCast(usize, fd), @ptrToInt(msg), flags);
return syscall3(SYS_recvmsg, @bitCast(usize, isize(fd)), @ptrToInt(msg), flags);
}
pub fn recvfrom(fd: i32, noalias buf: [*]u8, len: usize, flags: u32, noalias addr: ?*sockaddr, noalias alen: ?*socklen_t) usize {
return syscall6(SYS_recvfrom, @intCast(usize, fd), @ptrToInt(buf), len, flags, @ptrToInt(addr), @ptrToInt(alen));
return syscall6(SYS_recvfrom, @bitCast(usize, isize(fd)), @ptrToInt(buf), len, flags, @ptrToInt(addr), @ptrToInt(alen));
}
pub fn shutdown(fd: i32, how: i32) usize {
return syscall2(SYS_shutdown, @intCast(usize, fd), @intCast(usize, how));
return syscall2(SYS_shutdown, @bitCast(usize, isize(fd)), @bitCast(usize, isize(how)));
}
pub fn bind(fd: i32, addr: *const sockaddr, len: socklen_t) usize {
return syscall3(SYS_bind, @intCast(usize, fd), @ptrToInt(addr), @intCast(usize, len));
return syscall3(SYS_bind, @bitCast(usize, isize(fd)), @ptrToInt(addr), @intCast(usize, len));
}
pub fn listen(fd: i32, backlog: u32) usize {
return syscall2(SYS_listen, @intCast(usize, fd), backlog);
return syscall2(SYS_listen, @bitCast(usize, isize(fd)), backlog);
}
pub fn sendto(fd: i32, buf: [*]const u8, len: usize, flags: u32, addr: ?*const sockaddr, alen: socklen_t) usize {
return syscall6(SYS_sendto, @intCast(usize, fd), @ptrToInt(buf), len, flags, @ptrToInt(addr), @intCast(usize, alen));
return syscall6(SYS_sendto, @bitCast(usize, isize(fd)), @ptrToInt(buf), len, flags, @ptrToInt(addr), @intCast(usize, alen));
}
pub fn socketpair(domain: i32, socket_type: i32, protocol: i32, fd: [2]i32) usize {
return syscall4(SYS_socketpair, @intCast(usize, domain), @intCast(usize, socket_type), @intCast(usize, protocol), @ptrToInt(*fd[0]));
return syscall4(SYS_socketpair, @intCast(usize, domain), @intCast(usize, socket_type), @intCast(usize, protocol), @ptrToInt(&fd[0]));
}
pub fn accept(fd: i32, noalias addr: *sockaddr, noalias len: *socklen_t) usize {
@ -1249,11 +1250,11 @@ pub fn accept(fd: i32, noalias addr: *sockaddr, noalias len: *socklen_t) usize {
}
pub fn accept4(fd: i32, noalias addr: *sockaddr, noalias len: *socklen_t, flags: u32) usize {
return syscall4(SYS_accept4, @intCast(usize, fd), @ptrToInt(addr), @ptrToInt(len), flags);
return syscall4(SYS_accept4, @bitCast(usize, isize(fd)), @ptrToInt(addr), @ptrToInt(len), flags);
}
pub fn fstat(fd: i32, stat_buf: *Stat) usize {
return syscall2(SYS_fstat, @intCast(usize, fd), @ptrToInt(stat_buf));
return syscall2(SYS_fstat, @bitCast(usize, isize(fd)), @ptrToInt(stat_buf));
}
// TODO https://github.com/ziglang/zig/issues/265
@ -1268,7 +1269,7 @@ pub fn lstat(pathname: [*]const u8, statbuf: *Stat) usize {
// TODO https://github.com/ziglang/zig/issues/265
pub fn fstatat(dirfd: i32, path: [*]const u8, stat_buf: *Stat, flags: u32) usize {
return syscall4(SYS_fstatat, @intCast(usize, dirfd), @ptrToInt(path), @ptrToInt(stat_buf), flags);
return syscall4(SYS_fstatat, @bitCast(usize, isize(dirfd)), @ptrToInt(path), @ptrToInt(stat_buf), flags);
}
// TODO https://github.com/ziglang/zig/issues/265
@ -1355,7 +1356,7 @@ pub fn epoll_create1(flags: usize) usize {
}
pub fn epoll_ctl(epoll_fd: i32, op: u32, fd: i32, ev: *epoll_event) usize {
return syscall4(SYS_epoll_ctl, @intCast(usize, epoll_fd), @intCast(usize, op), @intCast(usize, fd), @ptrToInt(ev));
return syscall4(SYS_epoll_ctl, @bitCast(usize, isize(epoll_fd)), @intCast(usize, op), @bitCast(usize, isize(fd)), @ptrToInt(ev));
}
pub fn epoll_wait(epoll_fd: i32, events: [*]epoll_event, maxevents: u32, timeout: i32) usize {
@ -1363,7 +1364,15 @@ pub fn epoll_wait(epoll_fd: i32, events: [*]epoll_event, maxevents: u32, timeout
}
pub fn epoll_pwait(epoll_fd: i32, events: [*]epoll_event, maxevents: u32, timeout: i32, sigmask: ?*sigset_t) usize {
return syscall6(SYS_epoll_pwait, @intCast(usize, epoll_fd), @ptrToInt(events), @intCast(usize, maxevents), @intCast(usize, timeout), @ptrToInt(sigmask), @sizeOf(sigset_t));
return syscall6(
SYS_epoll_pwait,
@bitCast(usize, isize(epoll_fd)),
@ptrToInt(events),
@intCast(usize, maxevents),
@bitCast(usize, isize(timeout)),
@ptrToInt(sigmask),
@sizeOf(sigset_t),
);
}
pub fn eventfd(count: u32, flags: u32) usize {
@ -1371,7 +1380,7 @@ pub fn eventfd(count: u32, flags: u32) usize {
}
pub fn timerfd_create(clockid: i32, flags: u32) usize {
return syscall2(SYS_timerfd_create, @intCast(usize, clockid), flags);
return syscall2(SYS_timerfd_create, @bitCast(usize, isize(clockid)), flags);
}
pub const itimerspec = extern struct {
@ -1380,11 +1389,11 @@ pub const itimerspec = extern struct {
};
pub fn timerfd_gettime(fd: i32, curr_value: *itimerspec) usize {
return syscall2(SYS_timerfd_gettime, @intCast(usize, fd), @ptrToInt(curr_value));
return syscall2(SYS_timerfd_gettime, @bitCast(usize, isize(fd)), @ptrToInt(curr_value));
}
pub fn timerfd_settime(fd: i32, flags: u32, new_value: *const itimerspec, old_value: ?*itimerspec) usize {
return syscall4(SYS_timerfd_settime, @intCast(usize, fd), flags, @ptrToInt(new_value), @ptrToInt(old_value));
return syscall4(SYS_timerfd_settime, @bitCast(usize, isize(fd)), flags, @ptrToInt(new_value), @ptrToInt(old_value));
}
pub const _LINUX_CAPABILITY_VERSION_1 = 0x19980330;

View File

@ -1183,7 +1183,7 @@ pub fn realC(out_buffer: *[os.MAX_PATH_BYTES]u8, pathname: [*]const u8) RealErro
const fd = try os.posixOpenC(pathname, posix.O_PATH | posix.O_NONBLOCK | posix.O_CLOEXEC, 0);
defer os.close(fd);
var buf: ["/proc/self/fd/-2147483648".len]u8 = undefined;
var buf: ["/proc/self/fd/-2147483648\x00".len]u8 = undefined;
const proc_path = fmt.bufPrint(buf[0..], "/proc/self/fd/{}\x00", fd) catch unreachable;
return os.readLinkC(out_buffer, proc_path.ptr);

View File

@ -12,20 +12,20 @@ pub const Message = struct {
args: [5]usize,
payload: ?[]const u8,
pub fn from(mailbox_id: *const MailboxId) Message {
pub fn from(mailbox_id: MailboxId) Message {
return Message{
.sender = MailboxId.Undefined,
.receiver = mailbox_id.*,
.receiver = mailbox_id,
.code = undefined,
.args = undefined,
.payload = null,
};
}
pub fn to(mailbox_id: *const MailboxId, msg_code: usize, args: ...) Message {
pub fn to(mailbox_id: MailboxId, msg_code: usize, args: ...) Message {
var message = Message{
.sender = MailboxId.This,
.receiver = mailbox_id.*,
.receiver = mailbox_id,
.code = msg_code,
.args = undefined,
.payload = null,
@ -40,14 +40,14 @@ pub const Message = struct {
return message;
}
pub fn as(self: *const Message, sender: *const MailboxId) Message {
var message = self.*;
message.sender = sender.*;
pub fn as(self: Message, sender: MailboxId) Message {
var message = self;
message.sender = sender;
return message;
}
pub fn withPayload(self: *const Message, payload: []const u8) Message {
var message = self.*;
pub fn withPayload(self: Message, payload: []const u8) Message {
var message = self;
message.payload = payload;
return message;
}
@ -93,7 +93,7 @@ pub fn read(fd: i32, buf: [*]u8, count: usize) usize {
STDIN_FILENO => {
var i: usize = 0;
while (i < count) : (i += 1) {
send(Message.to(Server.Keyboard, 0));
send(&Message.to(Server.Keyboard, 0));
// FIXME: we should be certain that we are receiving from Keyboard.
var message = Message.from(MailboxId.This);
@ -111,7 +111,7 @@ pub fn read(fd: i32, buf: [*]u8, count: usize) usize {
pub fn write(fd: i32, buf: [*]const u8, count: usize) usize {
switch (fd) {
STDOUT_FILENO, STDERR_FILENO => {
send(Message.to(Server.Terminal, 1).withPayload(buf[0..count]));
send(&Message.to(Server.Terminal, 1).withPayload(buf[0..count]));
},
else => unreachable,
}

View File

@ -34,6 +34,7 @@ pub const DbiStreamHeader = packed struct {
};
pub const SectionContribEntry = packed struct {
/// COFF Section index, 1-based
Section: u16,
Padding1: [2]u8,
Offset: u32,

View File

@ -57,6 +57,18 @@ pub const Random = struct {
return @bitCast(T, unsigned_result);
}
/// Constant-time implementation off ::uintLessThan.
/// The results of this function may be biased.
pub fn uintLessThanBiased(r: *Random, comptime T: type, less_than: T) T {
comptime assert(T.is_signed == false);
comptime assert(T.bit_count <= 64); // TODO: workaround: LLVM ERROR: Unsupported library call operation!
assert(0 < less_than);
if (T.bit_count <= 32) {
return @intCast(T, limitRangeBiased(u32, r.int(u32), less_than));
} else {
return @intCast(T, limitRangeBiased(u64, r.int(u64), less_than));
}
}
/// Returns an evenly distributed random unsigned integer `0 <= i < less_than`.
/// This function assumes that the underlying ::fillFn produces evenly distributed values.
/// Within this assumption, the runtime of this function is exponentially distributed.
@ -64,29 +76,53 @@ pub const Random = struct {
/// the runtime of this function would technically be unbounded.
/// However, if ::fillFn is backed by any evenly distributed pseudo random number generator,
/// this function is guaranteed to return.
/// If you need deterministic runtime bounds, consider instead using `r.int(T) % less_than`,
/// which will usually be biased toward smaller values.
/// If you need deterministic runtime bounds, use `::uintLessThanBiased`.
pub fn uintLessThan(r: *Random, comptime T: type, less_than: T) T {
assert(T.is_signed == false);
comptime assert(T.is_signed == false);
comptime assert(T.bit_count <= 64); // TODO: workaround: LLVM ERROR: Unsupported library call operation!
assert(0 < less_than);
// Small is typically u32
const Small = @IntType(false, @divTrunc(T.bit_count + 31, 32) * 32);
// Large is typically u64
const Large = @IntType(false, Small.bit_count * 2);
const last_group_size_minus_one: T = maxInt(T) % less_than;
if (last_group_size_minus_one == less_than - 1) {
// less_than is a power of two.
assert(math.floorPowerOfTwo(T, less_than) == less_than);
// There is no retry zone. The optimal retry_zone_start would be maxInt(T) + 1.
return r.int(T) % less_than;
}
const retry_zone_start = maxInt(T) - last_group_size_minus_one;
// adapted from:
// http://www.pcg-random.org/posts/bounded-rands.html
// "Lemire's (with an extra tweak from me)"
var x: Small = r.int(Small);
var m: Large = Large(x) * Large(less_than);
var l: Small = @truncate(Small, m);
if (l < less_than) {
// TODO: workaround for https://github.com/ziglang/zig/issues/1770
// should be:
// var t: Small = -%less_than;
var t: Small = @bitCast(Small, -%@bitCast(@IntType(true, Small.bit_count), Small(less_than)));
while (true) {
const rand_val = r.int(T);
if (rand_val < retry_zone_start) {
return rand_val % less_than;
if (t >= less_than) {
t -= less_than;
if (t >= less_than) {
t %= less_than;
}
}
while (l < t) {
x = r.int(Small);
m = Large(x) * Large(less_than);
l = @truncate(Small, m);
}
}
return @intCast(T, m >> Small.bit_count);
}
/// Constant-time implementation off ::uintAtMost.
/// The results of this function may be biased.
pub fn uintAtMostBiased(r: *Random, comptime T: type, at_most: T) T {
assert(T.is_signed == false);
if (at_most == maxInt(T)) {
// have the full range
return r.int(T);
}
return r.uintLessThanBiased(T, at_most + 1);
}
/// Returns an evenly distributed random unsigned integer `0 <= i <= at_most`.
/// See ::uintLessThan, which this function uses in most cases,
/// for commentary on the runtime of this function.
@ -99,6 +135,22 @@ pub const Random = struct {
return r.uintLessThan(T, at_most + 1);
}
/// Constant-time implementation off ::intRangeLessThan.
/// The results of this function may be biased.
pub fn intRangeLessThanBiased(r: *Random, comptime T: type, at_least: T, less_than: T) T {
assert(at_least < less_than);
if (T.is_signed) {
// Two's complement makes this math pretty easy.
const UnsignedT = @IntType(false, T.bit_count);
const lo = @bitCast(UnsignedT, at_least);
const hi = @bitCast(UnsignedT, less_than);
const result = lo +% r.uintLessThanBiased(UnsignedT, hi -% lo);
return @bitCast(T, result);
} else {
// The signed implementation would work fine, but we can use stricter arithmetic operators here.
return at_least + r.uintLessThanBiased(T, less_than - at_least);
}
}
/// Returns an evenly distributed random integer `at_least <= i < less_than`.
/// See ::uintLessThan, which this function uses in most cases,
/// for commentary on the runtime of this function.
@ -117,6 +169,22 @@ pub const Random = struct {
}
}
/// Constant-time implementation off ::intRangeAtMostBiased.
/// The results of this function may be biased.
pub fn intRangeAtMostBiased(r: *Random, comptime T: type, at_least: T, at_most: T) T {
assert(at_least <= at_most);
if (T.is_signed) {
// Two's complement makes this math pretty easy.
const UnsignedT = @IntType(false, T.bit_count);
const lo = @bitCast(UnsignedT, at_least);
const hi = @bitCast(UnsignedT, at_most);
const result = lo +% r.uintAtMostBiased(UnsignedT, hi -% lo);
return @bitCast(T, result);
} else {
// The signed implementation would work fine, but we can use stricter arithmetic operators here.
return at_least + r.uintAtMostBiased(T, at_most - at_least);
}
}
/// Returns an evenly distributed random integer `at_least <= i <= at_most`.
/// See ::uintLessThan, which this function uses in most cases,
/// for commentary on the runtime of this function.
@ -135,15 +203,11 @@ pub const Random = struct {
}
}
/// Return a random integer/boolean type.
/// TODO: deprecated. use ::boolean or ::int instead.
pub fn scalar(r: *Random, comptime T: type) T {
if (T == bool) return r.boolean();
return r.int(T);
return if (T == bool) r.boolean() else r.int(T);
}
/// Return a random integer with even distribution between `start`
/// inclusive and `end` exclusive. `start` must be less than `end`.
/// TODO: deprecated. renamed to ::intRangeLessThan
pub fn range(r: *Random, comptime T: type, start: T, end: T) T {
return r.intRangeLessThan(T, start, end);
@ -206,6 +270,20 @@ pub const Random = struct {
}
};
/// Convert a random integer 0 <= random_int <= maxValue(T),
/// into an integer 0 <= result < less_than.
/// This function introduces a minor bias.
pub fn limitRangeBiased(comptime T: type, random_int: T, less_than: T) T {
comptime assert(T.is_signed == false);
const T2 = @IntType(false, T.bit_count * 2);
// adapted from:
// http://www.pcg-random.org/posts/bounded-rands.html
// "Integer Multiplication (Biased)"
var m: T2 = T2(random_int) * T2(less_than);
return @intCast(T, m >> T.bit_count);
}
const SequentialPrng = struct {
const Self = @This();
random: Random,
@ -294,10 +372,19 @@ fn testRandomIntLessThan() void {
var r = SequentialPrng.init();
r.next_value = 0xff;
assert(r.random.uintLessThan(u8, 4) == 3);
r.next_value = 0xff;
assert(r.random.uintLessThan(u8, 3) == 0);
assert(r.next_value == 0);
assert(r.random.uintLessThan(u8, 4) == 0);
assert(r.next_value == 1);
r.next_value = 0;
assert(r.random.uintLessThan(u64, 32) == 0);
// trigger the bias rejection code path
r.next_value = 0;
assert(r.random.uintLessThan(u8, 3) == 0);
// verify we incremented twice
assert(r.next_value == 2);
r.next_value = 0xff;
assert(r.random.intRangeLessThan(u8, 0, 0x80) == 0x7f);
r.next_value = 0xff;
@ -310,17 +397,10 @@ fn testRandomIntLessThan() void {
r.next_value = 0xff;
assert(r.random.intRangeLessThan(i8, -0x80, 0) == -1);
r.next_value = 0xff;
assert(r.random.intRangeLessThan(i64, -0x8000000000000000, 0) == -1);
r.next_value = 0xff;
assert(r.random.intRangeLessThan(i3, -4, 0) == -1);
r.next_value = 0xff;
assert(r.random.intRangeLessThan(i3, -2, 2) == 1);
// test retrying and eventually getting a good value
// start just out of bounds
r.next_value = 0x81;
assert(r.random.uintLessThan(u8, 0x81) == 0);
}
test "Random intAtMost" {
@ -332,9 +412,14 @@ fn testRandomIntAtMost() void {
var r = SequentialPrng.init();
r.next_value = 0xff;
assert(r.random.uintAtMost(u8, 3) == 3);
r.next_value = 0xff;
assert(r.next_value == 0);
assert(r.random.uintAtMost(u8, 3) == 0);
// trigger the bias rejection code path
r.next_value = 0;
assert(r.random.uintAtMost(u8, 2) == 0);
assert(r.next_value == 1);
// verify we incremented twice
assert(r.next_value == 2);
r.next_value = 0xff;
assert(r.random.intRangeAtMost(u8, 0, 0x7f) == 0x7f);
@ -348,17 +433,43 @@ fn testRandomIntAtMost() void {
r.next_value = 0xff;
assert(r.random.intRangeAtMost(i8, -0x80, -1) == -1);
r.next_value = 0xff;
assert(r.random.intRangeAtMost(i64, -0x8000000000000000, -1) == -1);
r.next_value = 0xff;
assert(r.random.intRangeAtMost(i3, -4, -1) == -1);
r.next_value = 0xff;
assert(r.random.intRangeAtMost(i3, -2, 1) == 1);
// test retrying and eventually getting a good value
// start just out of bounds
r.next_value = 0x81;
assert(r.random.uintAtMost(u8, 0x80) == 0);
assert(r.random.uintAtMost(u0, 0) == 0);
}
test "Random Biased" {
var r = DefaultPrng.init(0);
// Not thoroughly checking the logic here.
// Just want to execute all the paths with different types.
assert(r.random.uintLessThanBiased(u1, 1) == 0);
assert(r.random.uintLessThanBiased(u32, 10) < 10);
assert(r.random.uintLessThanBiased(u64, 20) < 20);
assert(r.random.uintAtMostBiased(u0, 0) == 0);
assert(r.random.uintAtMostBiased(u1, 0) <= 0);
assert(r.random.uintAtMostBiased(u32, 10) <= 10);
assert(r.random.uintAtMostBiased(u64, 20) <= 20);
assert(r.random.intRangeLessThanBiased(u1, 0, 1) == 0);
assert(r.random.intRangeLessThanBiased(i1, -1, 0) == -1);
assert(r.random.intRangeLessThanBiased(u32, 10, 20) >= 10);
assert(r.random.intRangeLessThanBiased(i32, 10, 20) >= 10);
assert(r.random.intRangeLessThanBiased(u64, 20, 40) >= 20);
assert(r.random.intRangeLessThanBiased(i64, 20, 40) >= 20);
// uncomment for broken module error:
//assert(r.random.intRangeAtMostBiased(u0, 0, 0) == 0);
assert(r.random.intRangeAtMostBiased(u1, 0, 1) >= 0);
assert(r.random.intRangeAtMostBiased(i1, -1, 0) >= -1);
assert(r.random.intRangeAtMostBiased(u32, 10, 20) >= 10);
assert(r.random.intRangeAtMostBiased(i32, 10, 20) >= 10);
assert(r.random.intRangeAtMostBiased(u64, 20, 40) >= 20);
assert(r.random.intRangeAtMostBiased(i64, 20, 40) >= 20);
}
// Generator to extend 64-bit seed values into longer sequences.
@ -870,12 +981,16 @@ test "Random range" {
}
fn testRange(r: *Random, start: i8, end: i8) void {
testRangeBias(r, start, end, true);
testRangeBias(r, start, end, false);
}
fn testRangeBias(r: *Random, start: i8, end: i8, biased: bool) void {
const count = @intCast(usize, i32(end) - i32(start));
var values_buffer = []bool{false} ** 0x100;
const values = values_buffer[0..count];
var i: usize = 0;
while (i < count) {
const value: i32 = r.intRangeLessThan(i8, start, end);
const value: i32 = if (biased) r.intRangeLessThanBiased(i8, start, end) else r.intRangeLessThan(i8, start, end);
const index = @intCast(usize, value - start);
if (!values[index]) {
i += 1;

View File

@ -275,6 +275,16 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
\\}
);
cases.addRuntimeSafety("signed integer not fitting in cast to unsigned integer - widening",
\\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
\\ @import("std").os.exit(126);
\\}
\\pub fn main() void {
\\ var value: c_short = -1;
\\ var casted = @intCast(u32, value);
\\}
);
cases.addRuntimeSafety("unwrap error",
\\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
\\ if (@import("std").mem.eql(u8, message, "attempt to unwrap error: Whatever")) {