Merge branch 'master' into freebsd2
commit
e3bf40742d
86
README.md
86
README.md
|
@ -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
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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)";
|
||||
}
|
||||
|
|
|
@ -35,6 +35,7 @@ enum Error {
|
|||
ErrorSharingViolation,
|
||||
ErrorPipeBusy,
|
||||
ErrorPrimitiveTypeNotFound,
|
||||
ErrorCacheUnavailable,
|
||||
};
|
||||
|
||||
const char *err_str(Error err);
|
||||
|
|
110
src/ir.cpp
110
src/ir.cpp
|
@ -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,
|
||||
|
|
12
src/os.cpp
12
src/os.cpp
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
27
std/json.zig
27
std/json.zig
|
@ -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
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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")) {
|
||||
|
|
Loading…
Reference in New Issue