diff --git a/README.md b/README.md index 344695764f..e50d31856d 100644 --- a/README.md +++ b/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 diff --git a/src/analyze.cpp b/src/analyze.cpp index 076b281073..2f4b173c5f 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -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(); } diff --git a/src/analyze.hpp b/src/analyze.hpp index e727b050ea..b506b533ca 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -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 diff --git a/src/cache_hash.cpp b/src/cache_hash.cpp index 7a3c08bc27..5e6c3b9a9d 100644 --- a/src/cache_hash.cpp +++ b/src/cache_hash.cpp @@ -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; diff --git a/src/codegen.cpp b/src/codegen.cpp index 40f71e38fe..1033ed8120 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -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); } diff --git a/src/error.cpp b/src/error.cpp index d0575a8494..10186fbde5 100644 --- a/src/error.cpp +++ b/src/error.cpp @@ -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)"; } diff --git a/src/error.hpp b/src/error.hpp index 8b8fa5ce17..b60cb8517e 100644 --- a/src/error.hpp +++ b/src/error.hpp @@ -35,6 +35,7 @@ enum Error { ErrorSharingViolation, ErrorPipeBusy, ErrorPrimitiveTypeNotFound, + ErrorCacheUnavailable, }; const char *err_str(Error err); diff --git a/src/ir.cpp b/src/ir.cpp index a62da827bc..1edb122670 100644 --- a/src/ir.cpp +++ b/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, diff --git a/src/os.cpp b/src/os.cpp index a323ef2cf5..eba95b9f2f 100644 --- a/src/os.cpp +++ b/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; } diff --git a/std/debug/index.zig b/std/debug/index.zig index 722f95ccb0..c317432654 100644 --- a/std/debug/index.zig +++ b/std/debug/index.zig @@ -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; diff --git a/std/json.zig b/std/json.zig index 23573b6d72..4d07d7b89d 100644 --- a/std/json.zig +++ b/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, , 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 -> [ ..., , 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")); } diff --git a/std/json_test.zig b/std/json_test.zig index 8c8862441a..9e19ec592a 100644 --- a/std/json_test.zig +++ b/std/json_test.zig @@ -21,7 +21,7 @@ fn any(comptime s: []const u8) void { // // Additional tests not part of test JSONTestSuite. -test "y_trailing_comma_after_empty" { +test "json.test.y_trailing_comma_after_empty" { ok( \\{"1":[],"2":{},"3":"4"} ); @@ -29,252 +29,252 @@ test "y_trailing_comma_after_empty" { //////////////////////////////////////////////////////////////////////////////////////////////////// -test "y_array_arraysWithSpaces" { +test "json.test.y_array_arraysWithSpaces" { ok( \\[[] ] ); } -test "y_array_empty" { +test "json.test.y_array_empty" { ok( \\[] ); } -test "y_array_empty-string" { +test "json.test.y_array_empty-string" { ok( \\[""] ); } -test "y_array_ending_with_newline" { +test "json.test.y_array_ending_with_newline" { ok( \\["a"] ); } -test "y_array_false" { +test "json.test.y_array_false" { ok( \\[false] ); } -test "y_array_heterogeneous" { +test "json.test.y_array_heterogeneous" { ok( \\[null, 1, "1", {}] ); } -test "y_array_null" { +test "json.test.y_array_null" { ok( \\[null] ); } -test "y_array_with_1_and_newline" { +test "json.test.y_array_with_1_and_newline" { ok( \\[1 \\] ); } -test "y_array_with_leading_space" { +test "json.test.y_array_with_leading_space" { ok( \\ [1] ); } -test "y_array_with_several_null" { +test "json.test.y_array_with_several_null" { ok( \\[1,null,null,null,2] ); } -test "y_array_with_trailing_space" { +test "json.test.y_array_with_trailing_space" { ok("[2] "); } -test "y_number_0e+1" { +test "json.test.y_number_0e+1" { ok( \\[0e+1] ); } -test "y_number_0e1" { +test "json.test.y_number_0e1" { ok( \\[0e1] ); } -test "y_number_after_space" { +test "json.test.y_number_after_space" { ok( \\[ 4] ); } -test "y_number_double_close_to_zero" { +test "json.test.y_number_double_close_to_zero" { ok( \\[-0.000000000000000000000000000000000000000000000000000000000000000000000000000001] ); } -test "y_number_int_with_exp" { +test "json.test.y_number_int_with_exp" { ok( \\[20e1] ); } -test "y_number" { +test "json.test.y_number" { ok( \\[123e65] ); } -test "y_number_minus_zero" { +test "json.test.y_number_minus_zero" { ok( \\[-0] ); } -test "y_number_negative_int" { +test "json.test.y_number_negative_int" { ok( \\[-123] ); } -test "y_number_negative_one" { +test "json.test.y_number_negative_one" { ok( \\[-1] ); } -test "y_number_negative_zero" { +test "json.test.y_number_negative_zero" { ok( \\[-0] ); } -test "y_number_real_capital_e" { +test "json.test.y_number_real_capital_e" { ok( \\[1E22] ); } -test "y_number_real_capital_e_neg_exp" { +test "json.test.y_number_real_capital_e_neg_exp" { ok( \\[1E-2] ); } -test "y_number_real_capital_e_pos_exp" { +test "json.test.y_number_real_capital_e_pos_exp" { ok( \\[1E+2] ); } -test "y_number_real_exponent" { +test "json.test.y_number_real_exponent" { ok( \\[123e45] ); } -test "y_number_real_fraction_exponent" { +test "json.test.y_number_real_fraction_exponent" { ok( \\[123.456e78] ); } -test "y_number_real_neg_exp" { +test "json.test.y_number_real_neg_exp" { ok( \\[1e-2] ); } -test "y_number_real_pos_exponent" { +test "json.test.y_number_real_pos_exponent" { ok( \\[1e+2] ); } -test "y_number_simple_int" { +test "json.test.y_number_simple_int" { ok( \\[123] ); } -test "y_number_simple_real" { +test "json.test.y_number_simple_real" { ok( \\[123.456789] ); } -test "y_object_basic" { +test "json.test.y_object_basic" { ok( \\{"asd":"sdf"} ); } -test "y_object_duplicated_key_and_value" { +test "json.test.y_object_duplicated_key_and_value" { ok( \\{"a":"b","a":"b"} ); } -test "y_object_duplicated_key" { +test "json.test.y_object_duplicated_key" { ok( \\{"a":"b","a":"c"} ); } -test "y_object_empty" { +test "json.test.y_object_empty" { ok( \\{} ); } -test "y_object_empty_key" { +test "json.test.y_object_empty_key" { ok( \\{"":0} ); } -test "y_object_escaped_null_in_key" { +test "json.test.y_object_escaped_null_in_key" { ok( \\{"foo\u0000bar": 42} ); } -test "y_object_extreme_numbers" { +test "json.test.y_object_extreme_numbers" { ok( \\{ "min": -1.0e+28, "max": 1.0e+28 } ); } -test "y_object" { +test "json.test.y_object" { ok( \\{"asd":"sdf", "dfg":"fgh"} ); } -test "y_object_long_strings" { +test "json.test.y_object_long_strings" { ok( \\{"x":[{"id": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"}], "id": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"} ); } -test "y_object_simple" { +test "json.test.y_object_simple" { ok( \\{"a":[]} ); } -test "y_object_string_unicode" { +test "json.test.y_object_string_unicode" { ok( \\{"title":"\u041f\u043e\u043b\u0442\u043e\u0440\u0430 \u0417\u0435\u043c\u043b\u0435\u043a\u043e\u043f\u0430" } ); } -test "y_object_with_newlines" { +test "json.test.y_object_with_newlines" { ok( \\{ \\"a": "b" @@ -282,419 +282,419 @@ test "y_object_with_newlines" { ); } -test "y_string_1_2_3_bytes_UTF-8_sequences" { +test "json.test.y_string_1_2_3_bytes_UTF-8_sequences" { ok( \\["\u0060\u012a\u12AB"] ); } -test "y_string_accepted_surrogate_pair" { +test "json.test.y_string_accepted_surrogate_pair" { ok( \\["\uD801\udc37"] ); } -test "y_string_accepted_surrogate_pairs" { +test "json.test.y_string_accepted_surrogate_pairs" { ok( \\["\ud83d\ude39\ud83d\udc8d"] ); } -test "y_string_allowed_escapes" { +test "json.test.y_string_allowed_escapes" { ok( \\["\"\\\/\b\f\n\r\t"] ); } -test "y_string_backslash_and_u_escaped_zero" { +test "json.test.y_string_backslash_and_u_escaped_zero" { ok( \\["\\u0000"] ); } -test "y_string_backslash_doublequotes" { +test "json.test.y_string_backslash_doublequotes" { ok( \\["\""] ); } -test "y_string_comments" { +test "json.test.y_string_comments" { ok( \\["a/*b*/c/*d//e"] ); } -test "y_string_double_escape_a" { +test "json.test.y_string_double_escape_a" { ok( \\["\\a"] ); } -test "y_string_double_escape_n" { +test "json.test.y_string_double_escape_n" { ok( \\["\\n"] ); } -test "y_string_escaped_control_character" { +test "json.test.y_string_escaped_control_character" { ok( \\["\u0012"] ); } -test "y_string_escaped_noncharacter" { +test "json.test.y_string_escaped_noncharacter" { ok( \\["\uFFFF"] ); } -test "y_string_in_array" { +test "json.test.y_string_in_array" { ok( \\["asd"] ); } -test "y_string_in_array_with_leading_space" { +test "json.test.y_string_in_array_with_leading_space" { ok( \\[ "asd"] ); } -test "y_string_last_surrogates_1_and_2" { +test "json.test.y_string_last_surrogates_1_and_2" { ok( \\["\uDBFF\uDFFF"] ); } -test "y_string_nbsp_uescaped" { +test "json.test.y_string_nbsp_uescaped" { ok( \\["new\u00A0line"] ); } -test "y_string_nonCharacterInUTF-8_U+10FFFF" { +test "json.test.y_string_nonCharacterInUTF-8_U+10FFFF" { ok( \\["􏿿"] ); } -test "y_string_nonCharacterInUTF-8_U+FFFF" { +test "json.test.y_string_nonCharacterInUTF-8_U+FFFF" { ok( \\["￿"] ); } -test "y_string_null_escape" { +test "json.test.y_string_null_escape" { ok( \\["\u0000"] ); } -test "y_string_one-byte-utf-8" { +test "json.test.y_string_one-byte-utf-8" { ok( \\["\u002c"] ); } -test "y_string_pi" { +test "json.test.y_string_pi" { ok( \\["π"] ); } -test "y_string_reservedCharacterInUTF-8_U+1BFFF" { +test "json.test.y_string_reservedCharacterInUTF-8_U+1BFFF" { ok( \\["𛿿"] ); } -test "y_string_simple_ascii" { +test "json.test.y_string_simple_ascii" { ok( \\["asd "] ); } -test "y_string_space" { +test "json.test.y_string_space" { ok( \\" " ); } -test "y_string_surrogates_U+1D11E_MUSICAL_SYMBOL_G_CLEF" { +test "json.test.y_string_surrogates_U+1D11E_MUSICAL_SYMBOL_G_CLEF" { ok( \\["\uD834\uDd1e"] ); } -test "y_string_three-byte-utf-8" { +test "json.test.y_string_three-byte-utf-8" { ok( \\["\u0821"] ); } -test "y_string_two-byte-utf-8" { +test "json.test.y_string_two-byte-utf-8" { ok( \\["\u0123"] ); } -test "y_string_u+2028_line_sep" { +test "json.test.y_string_u+2028_line_sep" { ok("[\"\xe2\x80\xa8\"]"); } -test "y_string_u+2029_par_sep" { +test "json.test.y_string_u+2029_par_sep" { ok("[\"\xe2\x80\xa9\"]"); } -test "y_string_uescaped_newline" { +test "json.test.y_string_uescaped_newline" { ok( \\["new\u000Aline"] ); } -test "y_string_uEscape" { +test "json.test.y_string_uEscape" { ok( \\["\u0061\u30af\u30EA\u30b9"] ); } -test "y_string_unescaped_char_delete" { +test "json.test.y_string_unescaped_char_delete" { ok("[\"\x7f\"]"); } -test "y_string_unicode_2" { +test "json.test.y_string_unicode_2" { ok( \\["⍂㈴⍂"] ); } -test "y_string_unicodeEscapedBackslash" { +test "json.test.y_string_unicodeEscapedBackslash" { ok( \\["\u005C"] ); } -test "y_string_unicode_escaped_double_quote" { +test "json.test.y_string_unicode_escaped_double_quote" { ok( \\["\u0022"] ); } -test "y_string_unicode" { +test "json.test.y_string_unicode" { ok( \\["\uA66D"] ); } -test "y_string_unicode_U+10FFFE_nonchar" { +test "json.test.y_string_unicode_U+10FFFE_nonchar" { ok( \\["\uDBFF\uDFFE"] ); } -test "y_string_unicode_U+1FFFE_nonchar" { +test "json.test.y_string_unicode_U+1FFFE_nonchar" { ok( \\["\uD83F\uDFFE"] ); } -test "y_string_unicode_U+200B_ZERO_WIDTH_SPACE" { +test "json.test.y_string_unicode_U+200B_ZERO_WIDTH_SPACE" { ok( \\["\u200B"] ); } -test "y_string_unicode_U+2064_invisible_plus" { +test "json.test.y_string_unicode_U+2064_invisible_plus" { ok( \\["\u2064"] ); } -test "y_string_unicode_U+FDD0_nonchar" { +test "json.test.y_string_unicode_U+FDD0_nonchar" { ok( \\["\uFDD0"] ); } -test "y_string_unicode_U+FFFE_nonchar" { +test "json.test.y_string_unicode_U+FFFE_nonchar" { ok( \\["\uFFFE"] ); } -test "y_string_utf8" { +test "json.test.y_string_utf8" { ok( \\["€𝄞"] ); } -test "y_string_with_del_character" { +test "json.test.y_string_with_del_character" { ok("[\"a\x7fa\"]"); } -test "y_structure_lonely_false" { +test "json.test.y_structure_lonely_false" { ok( \\false ); } -test "y_structure_lonely_int" { +test "json.test.y_structure_lonely_int" { ok( \\42 ); } -test "y_structure_lonely_negative_real" { +test "json.test.y_structure_lonely_negative_real" { ok( \\-0.1 ); } -test "y_structure_lonely_null" { +test "json.test.y_structure_lonely_null" { ok( \\null ); } -test "y_structure_lonely_string" { +test "json.test.y_structure_lonely_string" { ok( \\"asd" ); } -test "y_structure_lonely_true" { +test "json.test.y_structure_lonely_true" { ok( \\true ); } -test "y_structure_string_empty" { +test "json.test.y_structure_string_empty" { ok( \\"" ); } -test "y_structure_trailing_newline" { +test "json.test.y_structure_trailing_newline" { ok( \\["a"] ); } -test "y_structure_true_in_array" { +test "json.test.y_structure_true_in_array" { ok( \\[true] ); } -test "y_structure_whitespace_array" { +test "json.test.y_structure_whitespace_array" { ok(" [] "); } //////////////////////////////////////////////////////////////////////////////////////////////////// -test "n_array_1_true_without_comma" { +test "json.test.n_array_1_true_without_comma" { err( \\[1 true] ); } -test "n_array_a_invalid_utf8" { +test "json.test.n_array_a_invalid_utf8" { err( \\[aå] ); } -test "n_array_colon_instead_of_comma" { +test "json.test.n_array_colon_instead_of_comma" { err( \\["": 1] ); } -test "n_array_comma_after_close" { +test "json.test.n_array_comma_after_close" { //err( // \\[""], //); } -test "n_array_comma_and_number" { +test "json.test.n_array_comma_and_number" { err( \\[,1] ); } -test "n_array_double_comma" { +test "json.test.n_array_double_comma" { err( \\[1,,2] ); } -test "n_array_double_extra_comma" { +test "json.test.n_array_double_extra_comma" { err( \\["x",,] ); } -test "n_array_extra_close" { +test "json.test.n_array_extra_close" { err( \\["x"]] ); } -test "n_array_extra_comma" { +test "json.test.n_array_extra_comma" { //err( // \\["",] //); } -test "n_array_incomplete_invalid_value" { +test "json.test.n_array_incomplete_invalid_value" { err( \\[x ); } -test "n_array_incomplete" { +test "json.test.n_array_incomplete" { err( \\["x" ); } -test "n_array_inner_array_no_comma" { +test "json.test.n_array_inner_array_no_comma" { err( \\[3[4]] ); } -test "n_array_invalid_utf8" { +test "json.test.n_array_invalid_utf8" { err( \\[ÿ] ); } -test "n_array_items_separated_by_semicolon" { +test "json.test.n_array_items_separated_by_semicolon" { err( \\[1:2] ); } -test "n_array_just_comma" { +test "json.test.n_array_just_comma" { err( \\[,] ); } -test "n_array_just_minus" { +test "json.test.n_array_just_minus" { err( \\[-] ); } -test "n_array_missing_value" { +test "json.test.n_array_missing_value" { err( \\[ , ""] ); } -test "n_array_newlines_unclosed" { +test "json.test.n_array_newlines_unclosed" { err( \\["a", \\4 @@ -702,41 +702,41 @@ test "n_array_newlines_unclosed" { ); } -test "n_array_number_and_comma" { +test "json.test.n_array_number_and_comma" { err( \\[1,] ); } -test "n_array_number_and_several_commas" { +test "json.test.n_array_number_and_several_commas" { err( \\[1,,] ); } -test "n_array_spaces_vertical_tab_formfeed" { +test "json.test.n_array_spaces_vertical_tab_formfeed" { err("[\"\x0aa\"\\f]"); } -test "n_array_star_inside" { +test "json.test.n_array_star_inside" { err( \\[*] ); } -test "n_array_unclosed" { +test "json.test.n_array_unclosed" { err( \\["" ); } -test "n_array_unclosed_trailing_comma" { +test "json.test.n_array_unclosed_trailing_comma" { err( \\[1, ); } -test "n_array_unclosed_with_new_lines" { +test "json.test.n_array_unclosed_with_new_lines" { err( \\[1, \\1 @@ -744,956 +744,956 @@ test "n_array_unclosed_with_new_lines" { ); } -test "n_array_unclosed_with_object_inside" { +test "json.test.n_array_unclosed_with_object_inside" { err( \\[{} ); } -test "n_incomplete_false" { +test "json.test.n_incomplete_false" { err( \\[fals] ); } -test "n_incomplete_null" { +test "json.test.n_incomplete_null" { err( \\[nul] ); } -test "n_incomplete_true" { +test "json.test.n_incomplete_true" { err( \\[tru] ); } -test "n_multidigit_number_then_00" { +test "json.test.n_multidigit_number_then_00" { err("123\x00"); } -test "n_number_0.1.2" { +test "json.test.n_number_0.1.2" { err( \\[0.1.2] ); } -test "n_number_-01" { +test "json.test.n_number_-01" { err( \\[-01] ); } -test "n_number_0.3e" { +test "json.test.n_number_0.3e" { err( \\[0.3e] ); } -test "n_number_0.3e+" { +test "json.test.n_number_0.3e+" { err( \\[0.3e+] ); } -test "n_number_0_capital_E" { +test "json.test.n_number_0_capital_E" { err( \\[0E] ); } -test "n_number_0_capital_E+" { +test "json.test.n_number_0_capital_E+" { err( \\[0E+] ); } -test "n_number_0.e1" { +test "json.test.n_number_0.e1" { err( \\[0.e1] ); } -test "n_number_0e" { +test "json.test.n_number_0e" { err( \\[0e] ); } -test "n_number_0e+" { +test "json.test.n_number_0e+" { err( \\[0e+] ); } -test "n_number_1_000" { +test "json.test.n_number_1_000" { err( \\[1 000.0] ); } -test "n_number_1.0e-" { +test "json.test.n_number_1.0e-" { err( \\[1.0e-] ); } -test "n_number_1.0e" { +test "json.test.n_number_1.0e" { err( \\[1.0e] ); } -test "n_number_1.0e+" { +test "json.test.n_number_1.0e+" { err( \\[1.0e+] ); } -test "n_number_-1.0." { +test "json.test.n_number_-1.0." { err( \\[-1.0.] ); } -test "n_number_1eE2" { +test "json.test.n_number_1eE2" { err( \\[1eE2] ); } -test "n_number_.-1" { +test "json.test.n_number_.-1" { err( \\[.-1] ); } -test "n_number_+1" { +test "json.test.n_number_+1" { err( \\[+1] ); } -test "n_number_.2e-3" { +test "json.test.n_number_.2e-3" { err( \\[.2e-3] ); } -test "n_number_2.e-3" { +test "json.test.n_number_2.e-3" { err( \\[2.e-3] ); } -test "n_number_2.e+3" { +test "json.test.n_number_2.e+3" { err( \\[2.e+3] ); } -test "n_number_2.e3" { +test "json.test.n_number_2.e3" { err( \\[2.e3] ); } -test "n_number_-2." { +test "json.test.n_number_-2." { err( \\[-2.] ); } -test "n_number_9.e+" { +test "json.test.n_number_9.e+" { err( \\[9.e+] ); } -test "n_number_expression" { +test "json.test.n_number_expression" { err( \\[1+2] ); } -test "n_number_hex_1_digit" { +test "json.test.n_number_hex_1_digit" { err( \\[0x1] ); } -test "n_number_hex_2_digits" { +test "json.test.n_number_hex_2_digits" { err( \\[0x42] ); } -test "n_number_infinity" { +test "json.test.n_number_infinity" { err( \\[Infinity] ); } -test "n_number_+Inf" { +test "json.test.n_number_+Inf" { err( \\[+Inf] ); } -test "n_number_Inf" { +test "json.test.n_number_Inf" { err( \\[Inf] ); } -test "n_number_invalid+-" { +test "json.test.n_number_invalid+-" { err( \\[0e+-1] ); } -test "n_number_invalid-negative-real" { +test "json.test.n_number_invalid-negative-real" { err( \\[-123.123foo] ); } -test "n_number_invalid-utf-8-in-bigger-int" { +test "json.test.n_number_invalid-utf-8-in-bigger-int" { err( \\[123å] ); } -test "n_number_invalid-utf-8-in-exponent" { +test "json.test.n_number_invalid-utf-8-in-exponent" { err( \\[1e1å] ); } -test "n_number_invalid-utf-8-in-int" { +test "json.test.n_number_invalid-utf-8-in-int" { err( \\[0å] ); } -test "n_number_++" { +test "json.test.n_number_++" { err( \\[++1234] ); } -test "n_number_minus_infinity" { +test "json.test.n_number_minus_infinity" { err( \\[-Infinity] ); } -test "n_number_minus_sign_with_trailing_garbage" { +test "json.test.n_number_minus_sign_with_trailing_garbage" { err( \\[-foo] ); } -test "n_number_minus_space_1" { +test "json.test.n_number_minus_space_1" { err( \\[- 1] ); } -test "n_number_-NaN" { +test "json.test.n_number_-NaN" { err( \\[-NaN] ); } -test "n_number_NaN" { +test "json.test.n_number_NaN" { err( \\[NaN] ); } -test "n_number_neg_int_starting_with_zero" { +test "json.test.n_number_neg_int_starting_with_zero" { err( \\[-012] ); } -test "n_number_neg_real_without_int_part" { +test "json.test.n_number_neg_real_without_int_part" { err( \\[-.123] ); } -test "n_number_neg_with_garbage_at_end" { +test "json.test.n_number_neg_with_garbage_at_end" { err( \\[-1x] ); } -test "n_number_real_garbage_after_e" { +test "json.test.n_number_real_garbage_after_e" { err( \\[1ea] ); } -test "n_number_real_with_invalid_utf8_after_e" { +test "json.test.n_number_real_with_invalid_utf8_after_e" { err( \\[1eå] ); } -test "n_number_real_without_fractional_part" { +test "json.test.n_number_real_without_fractional_part" { err( \\[1.] ); } -test "n_number_starting_with_dot" { +test "json.test.n_number_starting_with_dot" { err( \\[.123] ); } -test "n_number_U+FF11_fullwidth_digit_one" { +test "json.test.n_number_U+FF11_fullwidth_digit_one" { err( \\[1] ); } -test "n_number_with_alpha_char" { +test "json.test.n_number_with_alpha_char" { err( \\[1.8011670033376514H-308] ); } -test "n_number_with_alpha" { +test "json.test.n_number_with_alpha" { err( \\[1.2a-3] ); } -test "n_number_with_leading_zero" { +test "json.test.n_number_with_leading_zero" { err( \\[012] ); } -test "n_object_bad_value" { +test "json.test.n_object_bad_value" { err( \\["x", truth] ); } -test "n_object_bracket_key" { +test "json.test.n_object_bracket_key" { err( \\{[: "x"} ); } -test "n_object_comma_instead_of_colon" { +test "json.test.n_object_comma_instead_of_colon" { err( \\{"x", null} ); } -test "n_object_double_colon" { +test "json.test.n_object_double_colon" { err( \\{"x"::"b"} ); } -test "n_object_emoji" { +test "json.test.n_object_emoji" { err( \\{🇨🇭} ); } -test "n_object_garbage_at_end" { +test "json.test.n_object_garbage_at_end" { err( \\{"a":"a" 123} ); } -test "n_object_key_with_single_quotes" { +test "json.test.n_object_key_with_single_quotes" { err( \\{key: 'value'} ); } -test "n_object_lone_continuation_byte_in_key_and_trailing_comma" { +test "json.test.n_object_lone_continuation_byte_in_key_and_trailing_comma" { err( \\{"¹":"0",} ); } -test "n_object_missing_colon" { +test "json.test.n_object_missing_colon" { err( \\{"a" b} ); } -test "n_object_missing_key" { +test "json.test.n_object_missing_key" { err( \\{:"b"} ); } -test "n_object_missing_semicolon" { +test "json.test.n_object_missing_semicolon" { err( \\{"a" "b"} ); } -test "n_object_missing_value" { +test "json.test.n_object_missing_value" { err( \\{"a": ); } -test "n_object_no-colon" { +test "json.test.n_object_no-colon" { err( \\{"a" ); } -test "n_object_non_string_key_but_huge_number_instead" { +test "json.test.n_object_non_string_key_but_huge_number_instead" { err( \\{9999E9999:1} ); } -test "n_object_non_string_key" { +test "json.test.n_object_non_string_key" { err( \\{1:1} ); } -test "n_object_repeated_null_null" { +test "json.test.n_object_repeated_null_null" { err( \\{null:null,null:null} ); } -test "n_object_several_trailing_commas" { +test "json.test.n_object_several_trailing_commas" { err( \\{"id":0,,,,,} ); } -test "n_object_single_quote" { +test "json.test.n_object_single_quote" { err( \\{'a':0} ); } -test "n_object_trailing_comma" { +test "json.test.n_object_trailing_comma" { err( \\{"id":0,} ); } -test "n_object_trailing_comment" { +test "json.test.n_object_trailing_comment" { err( \\{"a":"b"}/**/ ); } -test "n_object_trailing_comment_open" { +test "json.test.n_object_trailing_comment_open" { err( \\{"a":"b"}/**// ); } -test "n_object_trailing_comment_slash_open_incomplete" { +test "json.test.n_object_trailing_comment_slash_open_incomplete" { err( \\{"a":"b"}/ ); } -test "n_object_trailing_comment_slash_open" { +test "json.test.n_object_trailing_comment_slash_open" { err( \\{"a":"b"}// ); } -test "n_object_two_commas_in_a_row" { +test "json.test.n_object_two_commas_in_a_row" { err( \\{"a":"b",,"c":"d"} ); } -test "n_object_unquoted_key" { +test "json.test.n_object_unquoted_key" { err( \\{a: "b"} ); } -test "n_object_unterminated-value" { +test "json.test.n_object_unterminated-value" { err( \\{"a":"a ); } -test "n_object_with_single_string" { +test "json.test.n_object_with_single_string" { err( \\{ "foo" : "bar", "a" } ); } -test "n_object_with_trailing_garbage" { +test "json.test.n_object_with_trailing_garbage" { err( \\{"a":"b"}# ); } -test "n_single_space" { +test "json.test.n_single_space" { err(" "); } -test "n_string_1_surrogate_then_escape" { +test "json.test.n_string_1_surrogate_then_escape" { err( \\["\uD800\"] ); } -test "n_string_1_surrogate_then_escape_u1" { +test "json.test.n_string_1_surrogate_then_escape_u1" { err( \\["\uD800\u1"] ); } -test "n_string_1_surrogate_then_escape_u1x" { +test "json.test.n_string_1_surrogate_then_escape_u1x" { err( \\["\uD800\u1x"] ); } -test "n_string_1_surrogate_then_escape_u" { +test "json.test.n_string_1_surrogate_then_escape_u" { err( \\["\uD800\u"] ); } -test "n_string_accentuated_char_no_quotes" { +test "json.test.n_string_accentuated_char_no_quotes" { err( \\[é] ); } -test "n_string_backslash_00" { +test "json.test.n_string_backslash_00" { err("[\"\x00\"]"); } -test "n_string_escaped_backslash_bad" { +test "json.test.n_string_escaped_backslash_bad" { err( \\["\\\"] ); } -test "n_string_escaped_ctrl_char_tab" { +test "json.test.n_string_escaped_ctrl_char_tab" { err("\x5b\x22\x5c\x09\x22\x5d"); } -test "n_string_escaped_emoji" { +test "json.test.n_string_escaped_emoji" { err("[\"\x5c\xc3\xb0\xc2\x9f\xc2\x8c\xc2\x80\"]"); } -test "n_string_escape_x" { +test "json.test.n_string_escape_x" { err( \\["\x00"] ); } -test "n_string_incomplete_escaped_character" { +test "json.test.n_string_incomplete_escaped_character" { err( \\["\u00A"] ); } -test "n_string_incomplete_escape" { +test "json.test.n_string_incomplete_escape" { err( \\["\"] ); } -test "n_string_incomplete_surrogate_escape_invalid" { +test "json.test.n_string_incomplete_surrogate_escape_invalid" { err( \\["\uD800\uD800\x"] ); } -test "n_string_incomplete_surrogate" { +test "json.test.n_string_incomplete_surrogate" { err( \\["\uD834\uDd"] ); } -test "n_string_invalid_backslash_esc" { +test "json.test.n_string_invalid_backslash_esc" { err( \\["\a"] ); } -test "n_string_invalid_unicode_escape" { +test "json.test.n_string_invalid_unicode_escape" { err( \\["\uqqqq"] ); } -test "n_string_invalid_utf8_after_escape" { +test "json.test.n_string_invalid_utf8_after_escape" { err("[\"\\\x75\xc3\xa5\"]"); } -test "n_string_invalid-utf-8-in-escape" { +test "json.test.n_string_invalid-utf-8-in-escape" { err( \\["\uå"] ); } -test "n_string_leading_uescaped_thinspace" { +test "json.test.n_string_leading_uescaped_thinspace" { err( \\[\u0020"asd"] ); } -test "n_string_no_quotes_with_bad_escape" { +test "json.test.n_string_no_quotes_with_bad_escape" { err( \\[\n] ); } -test "n_string_single_doublequote" { +test "json.test.n_string_single_doublequote" { err( \\" ); } -test "n_string_single_quote" { +test "json.test.n_string_single_quote" { err( \\['single quote'] ); } -test "n_string_single_string_no_double_quotes" { +test "json.test.n_string_single_string_no_double_quotes" { err( \\abc ); } -test "n_string_start_escape_unclosed" { +test "json.test.n_string_start_escape_unclosed" { err( \\["\ ); } -test "n_string_unescaped_crtl_char" { +test "json.test.n_string_unescaped_crtl_char" { err("[\"a\x00a\"]"); } -test "n_string_unescaped_newline" { +test "json.test.n_string_unescaped_newline" { err( \\["new \\line"] ); } -test "n_string_unescaped_tab" { +test "json.test.n_string_unescaped_tab" { err("[\"\t\"]"); } -test "n_string_unicode_CapitalU" { +test "json.test.n_string_unicode_CapitalU" { err( \\"\UA66D" ); } -test "n_string_with_trailing_garbage" { +test "json.test.n_string_with_trailing_garbage" { err( \\""x ); } -test "n_structure_100000_opening_arrays" { +test "json.test.n_structure_100000_opening_arrays" { err("[" ** 100000); } -test "n_structure_angle_bracket_." { +test "json.test.n_structure_angle_bracket_." { err( \\<.> ); } -test "n_structure_angle_bracket_null" { +test "json.test.n_structure_angle_bracket_null" { err( \\[] ); } -test "n_structure_array_trailing_garbage" { +test "json.test.n_structure_array_trailing_garbage" { err( \\[1]x ); } -test "n_structure_array_with_extra_array_close" { +test "json.test.n_structure_array_with_extra_array_close" { err( \\[1]] ); } -test "n_structure_array_with_unclosed_string" { +test "json.test.n_structure_array_with_unclosed_string" { err( \\["asd] ); } -test "n_structure_ascii-unicode-identifier" { +test "json.test.n_structure_ascii-unicode-identifier" { err( \\aÃ¥ ); } -test "n_structure_capitalized_True" { +test "json.test.n_structure_capitalized_True" { err( \\[True] ); } -test "n_structure_close_unopened_array" { +test "json.test.n_structure_close_unopened_array" { err( \\1] ); } -test "n_structure_comma_instead_of_closing_brace" { +test "json.test.n_structure_comma_instead_of_closing_brace" { err( \\{"x": true, ); } -test "n_structure_double_array" { +test "json.test.n_structure_double_array" { err( \\[][] ); } -test "n_structure_end_array" { +test "json.test.n_structure_end_array" { err( \\] ); } -test "n_structure_incomplete_UTF8_BOM" { +test "json.test.n_structure_incomplete_UTF8_BOM" { err( \\ï»{} ); } -test "n_structure_lone-invalid-utf-8" { +test "json.test.n_structure_lone-invalid-utf-8" { err( \\å ); } -test "n_structure_lone-open-bracket" { +test "json.test.n_structure_lone-open-bracket" { err( \\[ ); } -test "n_structure_no_data" { +test "json.test.n_structure_no_data" { err( \\ ); } -test "n_structure_null-byte-outside-string" { +test "json.test.n_structure_null-byte-outside-string" { err("[\x00]"); } -test "n_structure_number_with_trailing_garbage" { +test "json.test.n_structure_number_with_trailing_garbage" { err( \\2@ ); } -test "n_structure_object_followed_by_closing_object" { +test "json.test.n_structure_object_followed_by_closing_object" { err( \\{}} ); } -test "n_structure_object_unclosed_no_value" { +test "json.test.n_structure_object_unclosed_no_value" { err( \\{"": ); } -test "n_structure_object_with_comment" { +test "json.test.n_structure_object_with_comment" { err( \\{"a":/*comment*/"b"} ); } -test "n_structure_object_with_trailing_garbage" { +test "json.test.n_structure_object_with_trailing_garbage" { err( \\{"a": true} "x" ); } -test "n_structure_open_array_apostrophe" { +test "json.test.n_structure_open_array_apostrophe" { err( \\[' ); } -test "n_structure_open_array_comma" { +test "json.test.n_structure_open_array_comma" { err( \\[, ); } -test "n_structure_open_array_object" { +test "json.test.n_structure_open_array_object" { err("[{\"\":" ** 50000); } -test "n_structure_open_array_open_object" { +test "json.test.n_structure_open_array_open_object" { err( \\[{ ); } -test "n_structure_open_array_open_string" { +test "json.test.n_structure_open_array_open_string" { err( \\["a ); } -test "n_structure_open_array_string" { +test "json.test.n_structure_open_array_string" { err( \\["a" ); } -test "n_structure_open_object_close_array" { +test "json.test.n_structure_open_object_close_array" { err( \\{] ); } -test "n_structure_open_object_comma" { +test "json.test.n_structure_open_object_comma" { err( \\{, ); } -test "n_structure_open_object" { +test "json.test.n_structure_open_object" { err( \\{ ); } -test "n_structure_open_object_open_array" { +test "json.test.n_structure_open_object_open_array" { err( \\{[ ); } -test "n_structure_open_object_open_string" { +test "json.test.n_structure_open_object_open_string" { err( \\{"a ); } -test "n_structure_open_object_string_with_apostrophes" { +test "json.test.n_structure_open_object_string_with_apostrophes" { err( \\{'a' ); } -test "n_structure_open_open" { +test "json.test.n_structure_open_open" { err( \\["\{["\{["\{["\{ ); } -test "n_structure_single_eacute" { +test "json.test.n_structure_single_eacute" { err( \\é ); } -test "n_structure_single_star" { +test "json.test.n_structure_single_star" { err( \\* ); } -test "n_structure_trailing_#" { +test "json.test.n_structure_trailing_#" { err( \\{"a":"b"}#{} ); } -test "n_structure_U+2060_word_joined" { +test "json.test.n_structure_U+2060_word_joined" { err( \\[⁠] ); } -test "n_structure_uescaped_LF_before_string" { +test "json.test.n_structure_uescaped_LF_before_string" { err( \\[\u000A""] ); } -test "n_structure_unclosed_array" { +test "json.test.n_structure_unclosed_array" { err( \\[1 ); } -test "n_structure_unclosed_array_partial_null" { +test "json.test.n_structure_unclosed_array_partial_null" { err( \\[ false, nul ); } -test "n_structure_unclosed_array_unfinished_false" { +test "json.test.n_structure_unclosed_array_unfinished_false" { err( \\[ true, fals ); } -test "n_structure_unclosed_array_unfinished_true" { +test "json.test.n_structure_unclosed_array_unfinished_true" { err( \\[ false, tru ); } -test "n_structure_unclosed_object" { +test "json.test.n_structure_unclosed_object" { err( \\{"asd":"asd" ); } -test "n_structure_unicode-identifier" { +test "json.test.n_structure_unicode-identifier" { err( \\Ã¥ ); } -test "n_structure_UTF8_BOM_no_data" { +test "json.test.n_structure_UTF8_BOM_no_data" { err( \\ ); } -test "n_structure_whitespace_formfeed" { +test "json.test.n_structure_whitespace_formfeed" { err("[\x0c]"); } -test "n_structure_whitespace_U+2060_word_joiner" { +test "json.test.n_structure_whitespace_U+2060_word_joiner" { err( \\[⁠] ); @@ -1701,203 +1701,203 @@ test "n_structure_whitespace_U+2060_word_joiner" { //////////////////////////////////////////////////////////////////////////////////////////////////// -test "i_number_double_huge_neg_exp" { +test "json.test.i_number_double_huge_neg_exp" { any( \\[123.456e-789] ); } -test "i_number_huge_exp" { +test "json.test.i_number_huge_exp" { any( \\[0.4e00669999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999969999999006] ); } -test "i_number_neg_int_huge_exp" { +test "json.test.i_number_neg_int_huge_exp" { any( \\[-1e+9999] ); } -test "i_number_pos_double_huge_exp" { +test "json.test.i_number_pos_double_huge_exp" { any( \\[1.5e+9999] ); } -test "i_number_real_neg_overflow" { +test "json.test.i_number_real_neg_overflow" { any( \\[-123123e100000] ); } -test "i_number_real_pos_overflow" { +test "json.test.i_number_real_pos_overflow" { any( \\[123123e100000] ); } -test "i_number_real_underflow" { +test "json.test.i_number_real_underflow" { any( \\[123e-10000000] ); } -test "i_number_too_big_neg_int" { +test "json.test.i_number_too_big_neg_int" { any( \\[-123123123123123123123123123123] ); } -test "i_number_too_big_pos_int" { +test "json.test.i_number_too_big_pos_int" { any( \\[100000000000000000000] ); } -test "i_number_very_big_negative_int" { +test "json.test.i_number_very_big_negative_int" { any( \\[-237462374673276894279832749832423479823246327846] ); } -test "i_object_key_lone_2nd_surrogate" { +test "json.test.i_object_key_lone_2nd_surrogate" { any( \\{"\uDFAA":0} ); } -test "i_string_1st_surrogate_but_2nd_missing" { +test "json.test.i_string_1st_surrogate_but_2nd_missing" { any( \\["\uDADA"] ); } -test "i_string_1st_valid_surrogate_2nd_invalid" { +test "json.test.i_string_1st_valid_surrogate_2nd_invalid" { any( \\["\uD888\u1234"] ); } -test "i_string_incomplete_surrogate_and_escape_valid" { +test "json.test.i_string_incomplete_surrogate_and_escape_valid" { any( \\["\uD800\n"] ); } -test "i_string_incomplete_surrogate_pair" { +test "json.test.i_string_incomplete_surrogate_pair" { any( \\["\uDd1ea"] ); } -test "i_string_incomplete_surrogates_escape_valid" { +test "json.test.i_string_incomplete_surrogates_escape_valid" { any( \\["\uD800\uD800\n"] ); } -test "i_string_invalid_lonely_surrogate" { +test "json.test.i_string_invalid_lonely_surrogate" { any( \\["\ud800"] ); } -test "i_string_invalid_surrogate" { +test "json.test.i_string_invalid_surrogate" { any( \\["\ud800abc"] ); } -test "i_string_invalid_utf-8" { +test "json.test.i_string_invalid_utf-8" { any( \\["ÿ"] ); } -test "i_string_inverted_surrogates_U+1D11E" { +test "json.test.i_string_inverted_surrogates_U+1D11E" { any( \\["\uDd1e\uD834"] ); } -test "i_string_iso_latin_1" { +test "json.test.i_string_iso_latin_1" { any( \\["é"] ); } -test "i_string_lone_second_surrogate" { +test "json.test.i_string_lone_second_surrogate" { any( \\["\uDFAA"] ); } -test "i_string_lone_utf8_continuation_byte" { +test "json.test.i_string_lone_utf8_continuation_byte" { any( \\[""] ); } -test "i_string_not_in_unicode_range" { +test "json.test.i_string_not_in_unicode_range" { any( \\["ô¿¿¿"] ); } -test "i_string_overlong_sequence_2_bytes" { +test "json.test.i_string_overlong_sequence_2_bytes" { any( \\["À¯"] ); } -test "i_string_overlong_sequence_6_bytes" { +test "json.test.i_string_overlong_sequence_6_bytes" { any( \\["üƒ¿¿¿¿"] ); } -test "i_string_overlong_sequence_6_bytes_null" { +test "json.test.i_string_overlong_sequence_6_bytes_null" { any( \\["ü€€€€€"] ); } -test "i_string_truncated-utf-8" { +test "json.test.i_string_truncated-utf-8" { any( \\["àÿ"] ); } -test "i_string_utf16BE_no_BOM" { +test "json.test.i_string_utf16BE_no_BOM" { any("\x00\x5b\x00\x22\x00\xc3\xa9\x00\x22\x00\x5d"); } -test "i_string_utf16LE_no_BOM" { +test "json.test.i_string_utf16LE_no_BOM" { any("\x5b\x00\x22\x00\xc3\xa9\x00\x22\x00\x5d\x00"); } -test "i_string_UTF-16LE_with_BOM" { +test "json.test.i_string_UTF-16LE_with_BOM" { any("\xc3\xbf\xc3\xbe\x5b\x00\x22\x00\xc3\xa9\x00\x22\x00\x5d\x00"); } -test "i_string_UTF-8_invalid_sequence" { +test "json.test.i_string_UTF-8_invalid_sequence" { any( \\["日шú"] ); } -test "i_string_UTF8_surrogate_U+D800" { +test "json.test.i_string_UTF8_surrogate_U+D800" { any( \\["í €"] ); } -test "i_structure_500_nested_arrays" { +test "json.test.i_structure_500_nested_arrays" { any(("[" ** 500) ++ ("]" ** 500)); } -test "i_structure_UTF-8_BOM_empty_object" { +test "json.test.i_structure_UTF-8_BOM_empty_object" { any( \\{} ); diff --git a/std/math/index.zig b/std/math/index.zig index de09a6e944..83bd2310d0 100644 --- a/std/math/index.zig +++ b/std/math/index.zig @@ -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(); diff --git a/std/mem.zig b/std/mem.zig index 6b115a56f6..9914a08e65 100644 --- a/std/mem.zig +++ b/std/mem.zig @@ -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; } diff --git a/std/meta/index.zig b/std/meta/index.zig index 2019543b54..69a3097288 100644 --- a/std/meta/index.zig +++ b/std/meta/index.zig @@ -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, diff --git a/std/os/linux/index.zig b/std/os/linux/index.zig index bfa046ba0f..ec90755164 100644 --- a/std/os/linux/index.zig +++ b/std/os/linux/index.zig @@ -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; diff --git a/std/os/path.zig b/std/os/path.zig index e2ef150ba5..af767b0dca 100644 --- a/std/os/path.zig +++ b/std/os/path.zig @@ -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); diff --git a/std/os/zen.zig b/std/os/zen.zig index 6ac480b890..76c4df9d62 100644 --- a/std/os/zen.zig +++ b/std/os/zen.zig @@ -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, } diff --git a/std/pdb.zig b/std/pdb.zig index 17275ab2a5..2c5df3e597 100644 --- a/std/pdb.zig +++ b/std/pdb.zig @@ -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, diff --git a/std/rand/index.zig b/std/rand/index.zig index bb607a067e..97101bc3b7 100644 --- a/std/rand/index.zig +++ b/std/rand/index.zig @@ -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; diff --git a/test/runtime_safety.zig b/test/runtime_safety.zig index 343b3ff592..7c13f5b6fa 100644 --- a/test/runtime_safety.zig +++ b/test/runtime_safety.zig @@ -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")) {