authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-01-16 12:26:04-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-01-16 12:26:04-05:00
logb897e98d30b7e471cdabf6b8f0baab44998265cd
tree642a2e9b0eb824c9cae69bfd29a72c11eb4b7101
parenteb3726c502e92ec4a3689732a76479c6d561cff5
parentee9ab15679ee04a40bdc582779faf43fb10836ce

Merge remote-tracking branch 'origin/master' into llvm6


61 files changed, 3197 insertions(+), 344 deletions(-)

CMakeLists.txt+5
......@@ -364,6 +364,11 @@ set(ZIG_STD_FILES
364364 "c/index.zig"
365365 "c/linux.zig"
366366 "c/windows.zig"
367 "crypto/index.zig"
368 "crypto/md5.zig"
369 "crypto/sha1.zig"
370 "crypto/sha2.zig"
371 "crypto/blake2.zig"
367372 "cstr.zig"
368373 "debug/failing_allocator.zig"
369374 "debug/index.zig"
README.md+5-2
......@@ -54,7 +54,7 @@ that counts as "freestanding" for the purposes of this table.
5454
5555| | freestanding | linux | macosx | windows | other |
5656|-------------|--------------|---------|---------|---------|---------|
57|i386 | OK | planned | OK | OK | planned |
57|i386 | OK | planned | OK | planned | planned |
5858|x86_64 | OK | OK | OK | OK | planned |
5959|arm | OK | planned | planned | N/A | planned |
6060|aarch64 | OK | planned | planned | planned | planned |
......@@ -125,17 +125,20 @@ libc. Create demo games using Zig.
125125
126126##### POSIX
127127
128 * gcc >= 5.0.0 or clang >= 3.6.0
129128 * cmake >= 2.8.5
129 * gcc >= 5.0.0 or clang >= 3.6.0
130130 * LLVM, Clang, LLD libraries == 6.x, compiled with the same gcc or clang version above
131131
132132##### Windows
133133
134 * cmake >= 2.8.5
134135 * Microsoft Visual Studio 2015
135136 * LLVM, Clang, LLD libraries == 6.x, compiled with the same MSVC version above
136137
137138#### Instructions
138139
140##### POSIX
141
139142If you have gcc or clang installed, you can find out what `ZIG_LIBC_LIB_DIR`,
140143`ZIG_LIBC_STATIC_LIB_DIR`, and `ZIG_LIBC_INCLUDE_DIR` should be set to
141144(example below).
build.zig+6-6
......@@ -10,7 +10,7 @@ const ArrayList = std.ArrayList;
1010const Buffer = std.Buffer;
1111const io = std.io;
1212
13pub fn build(b: &Builder) {
13pub fn build(b: &Builder) -> %void {
1414 const mode = b.standardReleaseOptions();
1515
1616 var docgen_exe = b.addExecutable("docgen", "doc/docgen.zig");
......@@ -36,7 +36,7 @@ pub fn build(b: &Builder) {
3636 const test_step = b.step("test", "Run all the tests");
3737
3838 // find the stage0 build artifacts because we're going to re-use config.h and zig_cpp library
39 const build_info = b.exec([][]const u8{b.zig_exe, "BUILD_INFO"});
39 const build_info = try b.exec([][]const u8{b.zig_exe, "BUILD_INFO"});
4040 var index: usize = 0;
4141 const cmake_binary_dir = nextValue(&index, build_info);
4242 const cxx_compiler = nextValue(&index, build_info);
......@@ -68,7 +68,7 @@ pub fn build(b: &Builder) {
6868 dependOnLib(exe, llvm);
6969
7070 if (exe.target.getOs() == builtin.Os.linux) {
71 const libstdcxx_path_padded = b.exec([][]const u8{cxx_compiler, "-print-file-name=libstdc++.a"});
71 const libstdcxx_path_padded = try b.exec([][]const u8{cxx_compiler, "-print-file-name=libstdc++.a"});
7272 const libstdcxx_path = ??mem.split(libstdcxx_path_padded, "\r\n").next();
7373 exe.addObjectFile(libstdcxx_path);
7474
......@@ -155,9 +155,9 @@ const LibraryDep = struct {
155155};
156156
157157fn findLLVM(b: &Builder, llvm_config_exe: []const u8) -> %LibraryDep {
158 const libs_output = b.exec([][]const u8{llvm_config_exe, "--libs", "--system-libs"});
159 const includes_output = b.exec([][]const u8{llvm_config_exe, "--includedir"});
160 const libdir_output = b.exec([][]const u8{llvm_config_exe, "--libdir"});
158 const libs_output = try b.exec([][]const u8{llvm_config_exe, "--libs", "--system-libs"});
159 const includes_output = try b.exec([][]const u8{llvm_config_exe, "--includedir"});
160 const libdir_output = try b.exec([][]const u8{llvm_config_exe, "--libdir"});
161161
162162 var result = LibraryDep {
163163 .libs = ArrayList([]const u8).init(b.allocator),
doc/langref.html.in+8
......@@ -142,6 +142,7 @@
142142 <li><a href="#builtin-TagType">@TagType</a></li>
143143 <li><a href="#builtin-EnumTagType">@EnumTagType</a></li>
144144 <li><a href="#builtin-errorName">@errorName</a></li>
145 <li><a href="#builtin-errorReturnTrace">@errorReturnTrace</a></li>
145146 <li><a href="#builtin-fence">@fence</a></li>
146147 <li><a href="#builtin-fieldParentPtr">@fieldParentPtr</a></li>
147148 <li><a href="#builtin-frameAddress">@frameAddress</a></li>
......@@ -4412,6 +4413,13 @@ test.zig:6:2: error: found compile log statement
44124413 or all calls have a compile-time known value for <code>err</code>, then no
44134414 error name table will be generated.
44144415 </p>
4416 <h3 id="builtin-errorReturnTrace">@errorReturnTrace</h3>
4417 <pre><code class="zig">@errorReturnTrace() -&gt; ?&amp;builtin.StackTrace</code></pre>
4418 <p>
4419 If the binary is built with error return tracing, and this function is invoked in a
4420 function that calls a function with an error or error union return type, returns a
4421 stack trace object. Otherwise returns `null`.
4422 </p>
44154423 <h3 id="builtin-fence">@fence</h3>
44164424 <pre><code class="zig">@fence(order: AtomicOrder)</code></pre>
44174425 <p>
example/mix_o_files/build.zig+1-1
......@@ -1,6 +1,6 @@
11const Builder = @import("std").build.Builder;
22
3pub fn build(b: &Builder) {
3pub fn build(b: &Builder) -> %void {
44 const obj = b.addObject("base64", "base64.zig");
55
66 const exe = b.addCExecutable("test");
example/shared_library/build.zig+1-1
......@@ -1,6 +1,6 @@
11const Builder = @import("std").build.Builder;
22
3pub fn build(b: &Builder) {
3pub fn build(b: &Builder) -> %void {
44 const lib = b.addSharedLibrary("mathtest", "mathtest.zig", b.version(1, 0, 0));
55
66 const exe = b.addCExecutable("test");
src-self-hosted/parser.zig-6
......@@ -1146,12 +1146,6 @@ fn testCanonical(source: []const u8) {
11461146}
11471147
11481148test "zig fmt" {
1149 if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) {
1150 // TODO get this test passing
1151 // https://github.com/zig-lang/zig/issues/537
1152 return;
1153 }
1154
11551149 testCanonical(
11561150 \\extern fn puts(s: &const u8) -> c_int;
11571151 \\
src/all_types.hpp+13
......@@ -1205,6 +1205,7 @@ struct FnTableEntry {
12051205 uint32_t alignstack_value;
12061206
12071207 ZigList<FnExport> export_list;
1208 bool calls_errorable_function;
12081209};
12091210
12101211uint32_t fn_table_entry_hash(FnTableEntry*);
......@@ -1273,6 +1274,7 @@ enum BuiltinFnId {
12731274 BuiltinFnIdSetAlignStack,
12741275 BuiltinFnIdArgType,
12751276 BuiltinFnIdExport,
1277 BuiltinFnIdErrorReturnTrace,
12761278};
12771279
12781280struct BuiltinFnEntry {
......@@ -1498,6 +1500,7 @@ struct CodeGen {
14981500 Buf triple_str;
14991501 BuildMode build_mode;
15001502 bool is_test_build;
1503 bool have_err_ret_tracing;
15011504 uint32_t target_os_index;
15021505 uint32_t target_arch_index;
15031506 uint32_t target_environ_index;
......@@ -1530,6 +1533,7 @@ struct CodeGen {
15301533 FnTableEntry *panic_fn;
15311534 LLVMValueRef cur_ret_ptr;
15321535 LLVMValueRef cur_fn_val;
1536 LLVMValueRef cur_err_ret_trace_val;
15331537 bool c_want_stdint;
15341538 bool c_want_stdbool;
15351539 AstNode *root_export_decl;
......@@ -1572,6 +1576,8 @@ struct CodeGen {
15721576 size_t largest_err_name_len;
15731577 LLVMValueRef safety_crash_err_fn;
15741578
1579 LLVMValueRef return_err_fn;
1580
15751581 IrInstruction *invalid_instruction;
15761582 ConstExprValue const_void_val;
15771583
......@@ -1595,6 +1601,8 @@ struct CodeGen {
15951601 ZigList<AstNode *> tld_ref_source_node_stack;
15961602
15971603 TypeTableEntry *align_amt_type;
1604 TypeTableEntry *stack_trace_type;
1605 TypeTableEntry *ptr_to_stack_trace_type;
15981606};
15991607
16001608enum VarLinkage {
......@@ -1896,6 +1904,7 @@ enum IrInstructionId {
18961904 IrInstructionIdSetAlignStack,
18971905 IrInstructionIdArgType,
18981906 IrInstructionIdExport,
1907 IrInstructionIdErrorReturnTrace,
18991908};
19001909
19011910struct IrInstruction {
......@@ -2717,6 +2726,10 @@ struct IrInstructionExport {
27172726 IrInstruction *target;
27182727};
27192728
2729struct IrInstructionErrorReturnTrace {
2730 IrInstruction base;
2731};
2732
27202733static const size_t slice_ptr_index = 0;
27212734static const size_t slice_len_index = 1;
27222735
src/analyze.cpp+48-12
......@@ -869,6 +869,16 @@ static const char *calling_convention_fn_type_str(CallingConvention cc) {
869869 zig_unreachable();
870870}
871871
872TypeTableEntry *get_ptr_to_stack_trace_type(CodeGen *g) {
873 if (g->stack_trace_type == nullptr) {
874 ConstExprValue *stack_trace_type_val = get_builtin_value(g, "StackTrace");
875 assert(stack_trace_type_val->type->id == TypeTableEntryIdMetaType);
876 g->stack_trace_type = stack_trace_type_val->data.x_type;
877 g->ptr_to_stack_trace_type = get_pointer_to_type(g, g->stack_trace_type, false);
878 }
879 return g->ptr_to_stack_trace_type;
880}
881
872882TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
873883 auto table_entry = g->fn_type_table.maybe_get(fn_type_id);
874884 if (table_entry) {
......@@ -915,10 +925,16 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
915925 if (!skip_debug_info) {
916926 bool first_arg_return = calling_convention_does_first_arg_return(fn_type_id->cc) &&
917927 handle_is_ptr(fn_type_id->return_type);
928 bool prefix_arg_error_return_trace = g->have_err_ret_tracing &&
929 (fn_type_id->return_type->id == TypeTableEntryIdErrorUnion ||
930 fn_type_id->return_type->id == TypeTableEntryIdPureError);
918931 // +1 for maybe making the first argument the return value
919 LLVMTypeRef *gen_param_types = allocate<LLVMTypeRef>(1 + fn_type_id->param_count);
920 // +1 because 0 is the return type and +1 for maybe making first arg ret val
921 ZigLLVMDIType **param_di_types = allocate<ZigLLVMDIType*>(2 + fn_type_id->param_count);
932 // +1 for maybe last argument the error return trace
933 LLVMTypeRef *gen_param_types = allocate<LLVMTypeRef>(2 + fn_type_id->param_count);
934 // +1 because 0 is the return type and
935 // +1 for maybe making first arg ret val and
936 // +1 for maybe last argument the error return trace
937 ZigLLVMDIType **param_di_types = allocate<ZigLLVMDIType*>(3 + fn_type_id->param_count);
922938 param_di_types[0] = fn_type_id->return_type->di_type;
923939 size_t gen_param_index = 0;
924940 TypeTableEntry *gen_return_type;
......@@ -936,6 +952,14 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
936952 }
937953 fn_type->data.fn.gen_return_type = gen_return_type;
938954
955 if (prefix_arg_error_return_trace) {
956 TypeTableEntry *gen_type = get_ptr_to_stack_trace_type(g);
957 gen_param_types[gen_param_index] = gen_type->type_ref;
958 gen_param_index += 1;
959 // after the gen_param_index += 1 because 0 is the return type
960 param_di_types[gen_param_index] = gen_type->di_type;
961 }
962
939963 fn_type->data.fn.gen_param_info = allocate<FnGenParamInfo>(fn_type_id->param_count);
940964 for (size_t i = 0; i < fn_type_id->param_count; i += 1) {
941965 FnTypeParamInfo *src_param_info = &fn_type->data.fn.fn_type_id.param_info[i];
......@@ -1168,6 +1192,9 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c
11681192 }
11691193
11701194 TypeTableEntry *type_entry = analyze_type_expr(g, child_scope, param_node->data.param_decl.type);
1195 if (type_is_invalid(type_entry)) {
1196 return g->builtin_types.entry_invalid;
1197 }
11711198 if (fn_type_id.cc != CallingConventionUnspecified) {
11721199 type_ensure_zero_bits_known(g, type_entry);
11731200 if (!type_has_bits(type_entry)) {
......@@ -2204,6 +2231,7 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) {
22042231 // is a pointer to this very struct, or a function pointer with parameters that
22052232 // reference such a type.
22062233 union_type->data.unionation.zero_bits_known = true;
2234 union_type->data.unionation.zero_bits_loop_flag = false;
22072235 if (union_type->data.unionation.abi_alignment == 0) {
22082236 if (union_type->data.unionation.layout == ContainerLayoutPacked) {
22092237 union_type->data.unionation.abi_alignment = 1;
......@@ -2558,7 +2586,7 @@ static bool scope_is_root_decls(Scope *scope) {
25582586
25592587static void wrong_panic_prototype(CodeGen *g, AstNode *proto_node, TypeTableEntry *fn_type) {
25602588 add_node_error(g, proto_node,
2561 buf_sprintf("expected 'fn([]const u8) -> unreachable', found '%s'",
2589 buf_sprintf("expected 'fn([]const u8, ?&builtin.StackTrace) -> unreachable', found '%s'",
25622590 buf_ptr(&fn_type->name)));
25632591}
25642592
......@@ -2567,7 +2595,7 @@ static void typecheck_panic_fn(CodeGen *g, FnTableEntry *panic_fn) {
25672595 assert(proto_node->type == NodeTypeFnProto);
25682596 TypeTableEntry *fn_type = panic_fn->type_entry;
25692597 FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id;
2570 if (fn_type_id->param_count != 1) {
2598 if (fn_type_id->param_count != 2) {
25712599 return wrong_panic_prototype(g, proto_node, fn_type);
25722600 }
25732601 TypeTableEntry *const_u8_ptr = get_pointer_to_type(g, g->builtin_types.entry_u8, true);
......@@ -2576,6 +2604,11 @@ static void typecheck_panic_fn(CodeGen *g, FnTableEntry *panic_fn) {
25762604 return wrong_panic_prototype(g, proto_node, fn_type);
25772605 }
25782606
2607 TypeTableEntry *nullable_ptr_to_stack_trace_type = get_maybe_type(g, get_ptr_to_stack_trace_type(g));
2608 if (fn_type_id->param_info[1].type != nullable_ptr_to_stack_trace_type) {
2609 return wrong_panic_prototype(g, proto_node, fn_type);
2610 }
2611
25792612 TypeTableEntry *actual_return_type = fn_type_id->return_type;
25802613 if (actual_return_type != g->builtin_types.entry_unreachable) {
25812614 return wrong_panic_prototype(g, proto_node, fn_type);
......@@ -2680,13 +2713,6 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) {
26802713 {
26812714 if (g->have_pub_main && buf_eql_str(&fn_table_entry->symbol_name, "main")) {
26822715 g->main_fn = fn_table_entry;
2683 TypeTableEntry *err_void = get_error_type(g, g->builtin_types.entry_void);
2684 TypeTableEntry *actual_return_type = fn_table_entry->type_entry->data.fn.fn_type_id.return_type;
2685 if (actual_return_type != err_void) {
2686 add_node_error(g, fn_proto->return_type,
2687 buf_sprintf("expected return type of main to be '%%void', instead is '%s'",
2688 buf_ptr(&actual_return_type->name)));
2689 }
26902716 } else if ((import->package == g->panic_package || g->have_pub_panic) &&
26912717 buf_eql_str(&fn_table_entry->symbol_name, "panic"))
26922718 {
......@@ -5527,3 +5553,13 @@ bool type_ptr_eql(const TypeTableEntry *a, const TypeTableEntry *b) {
55275553 return a == b;
55285554}
55295555
5556ConstExprValue *get_builtin_value(CodeGen *codegen, const char *name) {
5557 Tld *tld = codegen->compile_var_import->decls_scope->decl_table.get(buf_create_from_str(name));
5558 resolve_top_level_decl(codegen, tld, false, nullptr);
5559 assert(tld->id == TldIdVar);
5560 TldVar *tld_var = (TldVar *)tld;
5561 ConstExprValue *var_value = tld_var->var->value;
5562 assert(var_value != nullptr);
5563 return var_value;
5564}
5565
src/analyze.hpp+5
......@@ -185,4 +185,9 @@ PackageTableEntry *new_anonymous_package(void);
185185Buf *const_value_to_buffer(ConstExprValue *const_val);
186186void add_fn_export(CodeGen *g, FnTableEntry *fn_table_entry, Buf *symbol_name, GlobalLinkageId linkage, bool ccc);
187187
188
189ConstExprValue *get_builtin_value(CodeGen *codegen, const char *name);
190TypeTableEntry *get_ptr_to_stack_trace_type(CodeGen *g);
191
192
188193#endif
src/bigint.cpp+440-10
......@@ -12,6 +12,9 @@
1212#include "os.hpp"
1313#include "softfloat.hpp"
1414
15#include <limits>
16#include <algorithm>
17
1518static void bigint_normalize(BigInt *dest) {
1619 const uint64_t *digits = bigint_ptr(dest);
1720
......@@ -539,7 +542,7 @@ void bigint_add(BigInt *dest, const BigInt *op1, const BigInt *op2) {
539542 dest->data.digits[i] = x;
540543 i += 1;
541544
542 if (!found_digit)
545 if (!found_digit || i >= bigger_op->digit_count)
543546 break;
544547 }
545548 assert(overflow == 0);
......@@ -670,19 +673,417 @@ void bigint_mul_wrap(BigInt *dest, const BigInt *op1, const BigInt *op2, size_t
670673 bigint_truncate(dest, &unwrapped, bit_count, is_signed);
671674}
672675
676enum ZeroBehavior {
677 /// \brief The returned value is undefined.
678 ZB_Undefined,
679 /// \brief The returned value is numeric_limits<T>::max()
680 ZB_Max,
681 /// \brief The returned value is numeric_limits<T>::digits
682 ZB_Width
683};
684
685template <typename T, std::size_t SizeOfT> struct LeadingZerosCounter {
686 static std::size_t count(T Val, ZeroBehavior) {
687 if (!Val)
688 return std::numeric_limits<T>::digits;
689
690 // Bisection method.
691 std::size_t ZeroBits = 0;
692 for (T Shift = std::numeric_limits<T>::digits >> 1; Shift; Shift >>= 1) {
693 T Tmp = Val >> Shift;
694 if (Tmp)
695 Val = Tmp;
696 else
697 ZeroBits |= Shift;
698 }
699 return ZeroBits;
700 }
701};
702
703#if __GNUC__ >= 4 || defined(_MSC_VER)
704template <typename T> struct LeadingZerosCounter<T, 4> {
705 static std::size_t count(T Val, ZeroBehavior ZB) {
706 if (ZB != ZB_Undefined && Val == 0)
707 return 32;
708
709#if defined(_MSC_VER)
710 unsigned long Index;
711 _BitScanReverse(&Index, Val);
712 return Index ^ 31;
713#else
714 return __builtin_clz(Val);
715#endif
716 }
717};
718
719#if !defined(_MSC_VER) || defined(_M_X64)
720template <typename T> struct LeadingZerosCounter<T, 8> {
721 static std::size_t count(T Val, ZeroBehavior ZB) {
722 if (ZB != ZB_Undefined && Val == 0)
723 return 64;
724
725#if defined(_MSC_VER)
726 unsigned long Index;
727 _BitScanReverse64(&Index, Val);
728 return Index ^ 63;
729#else
730 return __builtin_clzll(Val);
731#endif
732 }
733};
734#endif
735#endif
736
737/// \brief Count number of 0's from the most significant bit to the least
738/// stopping at the first 1.
739///
740/// Only unsigned integral types are allowed.
741///
742/// \param ZB the behavior on an input of 0. Only ZB_Width and ZB_Undefined are
743/// valid arguments.
744template <typename T>
745std::size_t countLeadingZeros(T Val, ZeroBehavior ZB = ZB_Width) {
746 static_assert(std::numeric_limits<T>::is_integer &&
747 !std::numeric_limits<T>::is_signed,
748 "Only unsigned integral types are allowed.");
749 return LeadingZerosCounter<T, sizeof(T)>::count(Val, ZB);
750}
751
752/// Make a 64-bit integer from a high / low pair of 32-bit integers.
753constexpr inline uint64_t Make_64(uint32_t High, uint32_t Low) {
754 return ((uint64_t)High << 32) | (uint64_t)Low;
755}
756
757/// Return the high 32 bits of a 64 bit value.
758constexpr inline uint32_t Hi_32(uint64_t Value) {
759 return static_cast<uint32_t>(Value >> 32);
760}
761
762/// Return the low 32 bits of a 64 bit value.
763constexpr inline uint32_t Lo_32(uint64_t Value) {
764 return static_cast<uint32_t>(Value);
765}
766
767/// Implementation of Knuth's Algorithm D (Division of nonnegative integers)
768/// from "Art of Computer Programming, Volume 2", section 4.3.1, p. 272. The
769/// variables here have the same names as in the algorithm. Comments explain
770/// the algorithm and any deviation from it.
771static void KnuthDiv(uint32_t *u, uint32_t *v, uint32_t *q, uint32_t* r,
772 unsigned m, unsigned n)
773{
774 assert(u && "Must provide dividend");
775 assert(v && "Must provide divisor");
776 assert(q && "Must provide quotient");
777 assert(u != v && u != q && v != q && "Must use different memory");
778 assert(n>1 && "n must be > 1");
779
780 // b denotes the base of the number system. In our case b is 2^32.
781 const uint64_t b = uint64_t(1) << 32;
782
783 // D1. [Normalize.] Set d = b / (v[n-1] + 1) and multiply all the digits of
784 // u and v by d. Note that we have taken Knuth's advice here to use a power
785 // of 2 value for d such that d * v[n-1] >= b/2 (b is the base). A power of
786 // 2 allows us to shift instead of multiply and it is easy to determine the
787 // shift amount from the leading zeros. We are basically normalizing the u
788 // and v so that its high bits are shifted to the top of v's range without
789 // overflow. Note that this can require an extra word in u so that u must
790 // be of length m+n+1.
791 unsigned shift = countLeadingZeros(v[n-1]);
792 uint32_t v_carry = 0;
793 uint32_t u_carry = 0;
794 if (shift) {
795 for (unsigned i = 0; i < m+n; ++i) {
796 uint32_t u_tmp = u[i] >> (32 - shift);
797 u[i] = (u[i] << shift) | u_carry;
798 u_carry = u_tmp;
799 }
800 for (unsigned i = 0; i < n; ++i) {
801 uint32_t v_tmp = v[i] >> (32 - shift);
802 v[i] = (v[i] << shift) | v_carry;
803 v_carry = v_tmp;
804 }
805 }
806 u[m+n] = u_carry;
807
808 // D2. [Initialize j.] Set j to m. This is the loop counter over the places.
809 int j = m;
810 do {
811 // D3. [Calculate q'.].
812 // Set qp = (u[j+n]*b + u[j+n-1]) / v[n-1]. (qp=qprime=q')
813 // Set rp = (u[j+n]*b + u[j+n-1]) % v[n-1]. (rp=rprime=r')
814 // Now test if qp == b or qp*v[n-2] > b*rp + u[j+n-2]; if so, decrease
815 // qp by 1, increase rp by v[n-1], and repeat this test if rp < b. The test
816 // on v[n-2] determines at high speed most of the cases in which the trial
817 // value qp is one too large, and it eliminates all cases where qp is two
818 // too large.
819 uint64_t dividend = Make_64(u[j+n], u[j+n-1]);
820 uint64_t qp = dividend / v[n-1];
821 uint64_t rp = dividend % v[n-1];
822 if (qp == b || qp*v[n-2] > b*rp + u[j+n-2]) {
823 qp--;
824 rp += v[n-1];
825 if (rp < b && (qp == b || qp*v[n-2] > b*rp + u[j+n-2]))
826 qp--;
827 }
828
829 // D4. [Multiply and subtract.] Replace (u[j+n]u[j+n-1]...u[j]) with
830 // (u[j+n]u[j+n-1]..u[j]) - qp * (v[n-1]...v[1]v[0]). This computation
831 // consists of a simple multiplication by a one-place number, combined with
832 // a subtraction.
833 // The digits (u[j+n]...u[j]) should be kept positive; if the result of
834 // this step is actually negative, (u[j+n]...u[j]) should be left as the
835 // true value plus b**(n+1), namely as the b's complement of
836 // the true value, and a "borrow" to the left should be remembered.
837 int64_t borrow = 0;
838 for (unsigned i = 0; i < n; ++i) {
839 uint64_t p = uint64_t(qp) * uint64_t(v[i]);
840 int64_t subres = int64_t(u[j+i]) - borrow - Lo_32(p);
841 u[j+i] = Lo_32(subres);
842 borrow = Hi_32(p) - Hi_32(subres);
843 }
844 bool isNeg = u[j+n] < borrow;
845 u[j+n] -= Lo_32(borrow);
846
847 // D5. [Test remainder.] Set q[j] = qp. If the result of step D4 was
848 // negative, go to step D6; otherwise go on to step D7.
849 q[j] = Lo_32(qp);
850 if (isNeg) {
851 // D6. [Add back]. The probability that this step is necessary is very
852 // small, on the order of only 2/b. Make sure that test data accounts for
853 // this possibility. Decrease q[j] by 1
854 q[j]--;
855 // and add (0v[n-1]...v[1]v[0]) to (u[j+n]u[j+n-1]...u[j+1]u[j]).
856 // A carry will occur to the left of u[j+n], and it should be ignored
857 // since it cancels with the borrow that occurred in D4.
858 bool carry = false;
859 for (unsigned i = 0; i < n; i++) {
860 uint32_t limit = std::min(u[j+i],v[i]);
861 u[j+i] += v[i] + carry;
862 carry = u[j+i] < limit || (carry && u[j+i] == limit);
863 }
864 u[j+n] += carry;
865 }
866
867 // D7. [Loop on j.] Decrease j by one. Now if j >= 0, go back to D3.
868 } while (--j >= 0);
869
870 // D8. [Unnormalize]. Now q[...] is the desired quotient, and the desired
871 // remainder may be obtained by dividing u[...] by d. If r is non-null we
872 // compute the remainder (urem uses this).
873 if (r) {
874 // The value d is expressed by the "shift" value above since we avoided
875 // multiplication by d by using a shift left. So, all we have to do is
876 // shift right here.
877 if (shift) {
878 uint32_t carry = 0;
879 for (int i = n-1; i >= 0; i--) {
880 r[i] = (u[i] >> shift) | carry;
881 carry = u[i] << (32 - shift);
882 }
883 } else {
884 for (int i = n-1; i >= 0; i--) {
885 r[i] = u[i];
886 }
887 }
888 }
889}
890
891// Implementation ported from LLVM/lib/Support/APInt.cpp
892static void bigint_unsigned_division(const BigInt *op1, const BigInt *op2, BigInt *Quotient, BigInt *Remainder) {
893 Cmp cmp = bigint_cmp(op1, op2);
894 if (cmp == CmpLT) {
895 if (Quotient != nullptr) {
896 bigint_init_unsigned(Quotient, 0);
897 }
898 if (Remainder != nullptr) {
899 bigint_init_bigint(Remainder, op1);
900 }
901 return;
902 }
903 if (cmp == CmpEQ) {
904 if (Quotient != nullptr) {
905 bigint_init_unsigned(Quotient, 1);
906 }
907 if (Remainder != nullptr) {
908 bigint_init_unsigned(Remainder, 0);
909 }
910 return;
911 }
912
913 const uint64_t *LHS = bigint_ptr(op1);
914 const uint64_t *RHS = bigint_ptr(op2);
915 unsigned lhsWords = op1->digit_count;
916 unsigned rhsWords = op2->digit_count;
917
918 // First, compose the values into an array of 32-bit words instead of
919 // 64-bit words. This is a necessity of both the "short division" algorithm
920 // and the Knuth "classical algorithm" which requires there to be native
921 // operations for +, -, and * on an m bit value with an m*2 bit result. We
922 // can't use 64-bit operands here because we don't have native results of
923 // 128-bits. Furthermore, casting the 64-bit values to 32-bit values won't
924 // work on large-endian machines.
925 unsigned n = rhsWords * 2;
926 unsigned m = (lhsWords * 2) - n;
927
928 // Allocate space for the temporary values we need either on the stack, if
929 // it will fit, or on the heap if it won't.
930 uint32_t SPACE[128];
931 uint32_t *U = nullptr;
932 uint32_t *V = nullptr;
933 uint32_t *Q = nullptr;
934 uint32_t *R = nullptr;
935 if ((Remainder?4:3)*n+2*m+1 <= 128) {
936 U = &SPACE[0];
937 V = &SPACE[m+n+1];
938 Q = &SPACE[(m+n+1) + n];
939 if (Remainder)
940 R = &SPACE[(m+n+1) + n + (m+n)];
941 } else {
942 U = new uint32_t[m + n + 1];
943 V = new uint32_t[n];
944 Q = new uint32_t[m+n];
945 if (Remainder)
946 R = new uint32_t[n];
947 }
948
949 // Initialize the dividend
950 memset(U, 0, (m+n+1)*sizeof(uint32_t));
951 for (unsigned i = 0; i < lhsWords; ++i) {
952 uint64_t tmp = LHS[i];
953 U[i * 2] = Lo_32(tmp);
954 U[i * 2 + 1] = Hi_32(tmp);
955 }
956 U[m+n] = 0; // this extra word is for "spill" in the Knuth algorithm.
957
958 // Initialize the divisor
959 memset(V, 0, (n)*sizeof(uint32_t));
960 for (unsigned i = 0; i < rhsWords; ++i) {
961 uint64_t tmp = RHS[i];
962 V[i * 2] = Lo_32(tmp);
963 V[i * 2 + 1] = Hi_32(tmp);
964 }
965
966 // initialize the quotient and remainder
967 memset(Q, 0, (m+n) * sizeof(uint32_t));
968 if (Remainder)
969 memset(R, 0, n * sizeof(uint32_t));
970
971 // Now, adjust m and n for the Knuth division. n is the number of words in
972 // the divisor. m is the number of words by which the dividend exceeds the
973 // divisor (i.e. m+n is the length of the dividend). These sizes must not
974 // contain any zero words or the Knuth algorithm fails.
975 for (unsigned i = n; i > 0 && V[i-1] == 0; i--) {
976 n--;
977 m++;
978 }
979 for (unsigned i = m+n; i > 0 && U[i-1] == 0; i--)
980 m--;
981
982 // If we're left with only a single word for the divisor, Knuth doesn't work
983 // so we implement the short division algorithm here. This is much simpler
984 // and faster because we are certain that we can divide a 64-bit quantity
985 // by a 32-bit quantity at hardware speed and short division is simply a
986 // series of such operations. This is just like doing short division but we
987 // are using base 2^32 instead of base 10.
988 assert(n != 0 && "Divide by zero?");
989 if (n == 1) {
990 uint32_t divisor = V[0];
991 uint32_t remainder = 0;
992 for (int i = m; i >= 0; i--) {
993 uint64_t partial_dividend = Make_64(remainder, U[i]);
994 if (partial_dividend == 0) {
995 Q[i] = 0;
996 remainder = 0;
997 } else if (partial_dividend < divisor) {
998 Q[i] = 0;
999 remainder = Lo_32(partial_dividend);
1000 } else if (partial_dividend == divisor) {
1001 Q[i] = 1;
1002 remainder = 0;
1003 } else {
1004 Q[i] = Lo_32(partial_dividend / divisor);
1005 remainder = Lo_32(partial_dividend - (Q[i] * divisor));
1006 }
1007 }
1008 if (R)
1009 R[0] = remainder;
1010 } else {
1011 // Now we're ready to invoke the Knuth classical divide algorithm. In this
1012 // case n > 1.
1013 KnuthDiv(U, V, Q, R, m, n);
1014 }
1015
1016 // If the caller wants the quotient
1017 if (Quotient) {
1018 Quotient->is_negative = false;
1019 Quotient->digit_count = lhsWords;
1020 if (lhsWords == 1) {
1021 Quotient->data.digit = Make_64(Q[1], Q[0]);
1022 } else {
1023 Quotient->data.digits = allocate<uint64_t>(lhsWords);
1024 for (size_t i = 0; i < lhsWords; i += 1) {
1025 Quotient->data.digits[i] = Make_64(Q[i*2+1], Q[i*2]);
1026 }
1027 }
1028 }
1029
1030 // If the caller wants the remainder
1031 if (Remainder) {
1032 Remainder->is_negative = false;
1033 Remainder->digit_count = rhsWords;
1034 if (rhsWords == 1) {
1035 Remainder->data.digit = Make_64(R[1], R[0]);
1036 } else {
1037 Remainder->data.digits = allocate<uint64_t>(rhsWords);
1038 for (size_t i = 0; i < rhsWords; i += 1) {
1039 Remainder->data.digits[i] = Make_64(R[i*2+1], R[i*2]);
1040 }
1041 }
1042 }
1043}
1044
6731045void bigint_div_trunc(BigInt *dest, const BigInt *op1, const BigInt *op2) {
6741046 assert(op2->digit_count != 0); // division by zero
6751047 if (op1->digit_count == 0) {
6761048 bigint_init_unsigned(dest, 0);
6771049 return;
6781050 }
679 if (op1->digit_count != 1 || op2->digit_count != 1) {
680 zig_panic("TODO bigint div_trunc with >1 digits");
681 }
6821051 const uint64_t *op1_digits = bigint_ptr(op1);
6831052 const uint64_t *op2_digits = bigint_ptr(op2);
684 dest->data.digit = op1_digits[0] / op2_digits[0];
685 dest->digit_count = 1;
1053 if (op1->digit_count == 1 && op2->digit_count == 1) {
1054 dest->data.digit = op1_digits[0] / op2_digits[0];
1055 dest->digit_count = 1;
1056 dest->is_negative = op1->is_negative != op2->is_negative;
1057 bigint_normalize(dest);
1058 return;
1059 }
1060 if (op2->digit_count == 1 && op2_digits[0] == 1) {
1061 // X / 1 == X
1062 bigint_init_bigint(dest, op1);
1063 dest->is_negative = op1->is_negative != op2->is_negative;
1064 bigint_normalize(dest);
1065 return;
1066 }
1067
1068 const BigInt *op1_positive;
1069 BigInt op1_positive_data;
1070 if (op1->is_negative) {
1071 bigint_negate(&op1_positive_data, op1);
1072 op1_positive = &op1_positive_data;
1073 } else {
1074 op1_positive = op1;
1075 }
1076
1077 const BigInt *op2_positive;
1078 BigInt op2_positive_data;
1079 if (op2->is_negative) {
1080 bigint_negate(&op2_positive_data, op2);
1081 op2_positive = &op2_positive_data;
1082 } else {
1083 op2_positive = op2;
1084 }
1085
1086 bigint_unsigned_division(op1_positive, op2_positive, dest, nullptr);
6861087 dest->is_negative = op1->is_negative != op2->is_negative;
6871088 bigint_normalize(dest);
6881089}
......@@ -714,6 +1115,14 @@ void bigint_rem(BigInt *dest, const BigInt *op1, const BigInt *op2) {
7141115 }
7151116 const uint64_t *op1_digits = bigint_ptr(op1);
7161117 const uint64_t *op2_digits = bigint_ptr(op2);
1118
1119 if (op1->digit_count == 1 && op2->digit_count == 1) {
1120 dest->data.digit = op1_digits[0] % op2_digits[0];
1121 dest->digit_count = 1;
1122 dest->is_negative = op1->is_negative;
1123 bigint_normalize(dest);
1124 return;
1125 }
7171126 if (op2->digit_count == 2 && op2_digits[0] == 0 && op2_digits[1] == 1) {
7181127 // special case this divisor
7191128 bigint_init_unsigned(dest, op1_digits[0]);
......@@ -721,11 +1130,32 @@ void bigint_rem(BigInt *dest, const BigInt *op1, const BigInt *op2) {
7211130 bigint_normalize(dest);
7221131 return;
7231132 }
724 if (op1->digit_count != 1 || op2->digit_count != 1) {
725 zig_panic("TODO bigint rem with >1 digits");
1133
1134 if (op2->digit_count == 1 && op2_digits[0] == 1) {
1135 // X % 1 == 0
1136 bigint_init_unsigned(dest, 0);
1137 return;
7261138 }
727 dest->data.digit = op1_digits[0] % op2_digits[0];
728 dest->digit_count = 1;
1139
1140 const BigInt *op1_positive;
1141 BigInt op1_positive_data;
1142 if (op1->is_negative) {
1143 bigint_negate(&op1_positive_data, op1);
1144 op1_positive = &op1_positive_data;
1145 } else {
1146 op1_positive = op1;
1147 }
1148
1149 const BigInt *op2_positive;
1150 BigInt op2_positive_data;
1151 if (op2->is_negative) {
1152 bigint_negate(&op2_positive_data, op2);
1153 op2_positive = &op2_positive_data;
1154 } else {
1155 op2_positive = op2;
1156 }
1157
1158 bigint_unsigned_division(op1_positive, op2_positive, nullptr, dest);
7291159 dest->is_negative = op1->is_negative;
7301160 bigint_normalize(dest);
7311161}
src/codegen.cpp+231-16
......@@ -404,6 +404,19 @@ static LLVMLinkage to_llvm_linkage(GlobalLinkageId id) {
404404 zig_unreachable();
405405}
406406
407static uint32_t get_err_ret_trace_arg_index(CodeGen *g, FnTableEntry *fn_table_entry) {
408 if (!g->have_err_ret_tracing) {
409 return UINT32_MAX;
410 }
411 TypeTableEntry *fn_type = fn_table_entry->type_entry;
412 TypeTableEntry *return_type = fn_type->data.fn.fn_type_id.return_type;
413 if (return_type->id != TypeTableEntryIdErrorUnion && return_type->id != TypeTableEntryIdPureError) {
414 return UINT32_MAX;
415 }
416 bool first_arg_ret = type_has_bits(return_type) && handle_is_ptr(return_type);
417 return first_arg_ret ? 1 : 0;
418}
419
407420static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) {
408421 if (fn_table_entry->llvm_value)
409422 return fn_table_entry->llvm_value;
......@@ -483,7 +496,8 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) {
483496 LLVMSetUnnamedAddr(fn_table_entry->llvm_value, true);
484497 }
485498
486 if (fn_type->data.fn.fn_type_id.return_type->id == TypeTableEntryIdUnreachable) {
499 TypeTableEntry *return_type = fn_type->data.fn.fn_type_id.return_type;
500 if (return_type->id == TypeTableEntryIdUnreachable) {
487501 addLLVMFnAttr(fn_table_entry->llvm_value, "noreturn");
488502 }
489503
......@@ -520,13 +534,11 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) {
520534 // use the ABI alignment, which is fine.
521535 }
522536
523 if (!type_has_bits(fn_type->data.fn.fn_type_id.return_type)) {
537 if (!type_has_bits(return_type)) {
524538 // nothing to do
525 } else if (fn_type->data.fn.fn_type_id.return_type->id == TypeTableEntryIdPointer ||
526 fn_type->data.fn.fn_type_id.return_type->id == TypeTableEntryIdFn)
527 {
539 } else if (return_type->id == TypeTableEntryIdPointer || return_type->id == TypeTableEntryIdFn) {
528540 addLLVMAttr(fn_table_entry->llvm_value, 0, "nonnull");
529 } else if (handle_is_ptr(fn_type->data.fn.fn_type_id.return_type) &&
541 } else if (handle_is_ptr(return_type) &&
530542 calling_convention_does_first_arg_return(fn_type->data.fn.fn_type_id.cc))
531543 {
532544 addLLVMArgAttr(fn_table_entry->llvm_value, 0, "sret");
......@@ -563,6 +575,11 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) {
563575 }
564576 }
565577
578 uint32_t err_ret_trace_arg_index = get_err_ret_trace_arg_index(g, fn_table_entry);
579 if (err_ret_trace_arg_index != UINT32_MAX) {
580 addLLVMArgAttr(fn_table_entry->llvm_value, (unsigned)err_ret_trace_arg_index, "nonnull");
581 }
582
566583 return fn_table_entry->llvm_value;
567584}
568585
......@@ -864,16 +881,25 @@ static LLVMValueRef get_panic_msg_ptr_val(CodeGen *g, PanicMsgId msg_id) {
864881 return LLVMConstBitCast(val->global_refs->llvm_global, LLVMPointerType(str_type->type_ref, 0));
865882}
866883
867static void gen_panic(CodeGen *g, LLVMValueRef msg_arg) {
884static void gen_panic(CodeGen *g, LLVMValueRef msg_arg, LLVMValueRef stack_trace_arg) {
868885 assert(g->panic_fn != nullptr);
869886 LLVMValueRef fn_val = fn_llvm_value(g, g->panic_fn);
870887 LLVMCallConv llvm_cc = get_llvm_cc(g, g->panic_fn->type_entry->data.fn.fn_type_id.cc);
871 ZigLLVMBuildCall(g->builder, fn_val, &msg_arg, 1, llvm_cc, ZigLLVM_FnInlineAuto, "");
888 if (stack_trace_arg == nullptr) {
889 TypeTableEntry *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(g);
890 stack_trace_arg = LLVMConstNull(ptr_to_stack_trace_type->type_ref);
891 }
892 LLVMValueRef args[] = {
893 msg_arg,
894 stack_trace_arg,
895 };
896 LLVMValueRef call_instruction = ZigLLVMBuildCall(g->builder, fn_val, args, 2, llvm_cc, ZigLLVM_FnInlineAuto, "");
897 LLVMSetTailCall(call_instruction, true);
872898 LLVMBuildUnreachable(g->builder);
873899}
874900
875901static void gen_debug_safety_crash(CodeGen *g, PanicMsgId msg_id) {
876 gen_panic(g, get_panic_msg_ptr_val(g, msg_id));
902 gen_panic(g, get_panic_msg_ptr_val(g, msg_id), nullptr);
877903}
878904
879905static LLVMValueRef get_memcpy_fn_val(CodeGen *g) {
......@@ -895,6 +921,87 @@ static LLVMValueRef get_memcpy_fn_val(CodeGen *g) {
895921 return g->memcpy_fn_val;
896922}
897923
924static LLVMValueRef get_return_err_fn(CodeGen *g) {
925 if (g->return_err_fn != nullptr)
926 return g->return_err_fn;
927
928 assert(g->err_tag_type != nullptr);
929
930 LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0);
931
932 LLVMTypeRef arg_types[] = {
933 // error return trace pointer
934 get_ptr_to_stack_trace_type(g)->type_ref,
935 // return address
936 ptr_u8,
937 };
938 LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMVoidType(), arg_types, 2, false);
939
940 Buf *fn_name = get_mangled_name(g, buf_create_from_str("__zig_return_error"), false);
941 LLVMValueRef fn_val = LLVMAddFunction(g->module, buf_ptr(fn_name), fn_type_ref);
942 addLLVMFnAttr(fn_val, "cold");
943 LLVMSetLinkage(fn_val, LLVMInternalLinkage);
944 LLVMSetFunctionCallConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified));
945 addLLVMFnAttr(fn_val, "nounwind");
946 add_uwtable_attr(g, fn_val);
947 addLLVMArgAttr(fn_val, (unsigned)0, "nonnull");
948 addLLVMArgAttr(fn_val, (unsigned)1, "nonnull");
949 if (g->build_mode == BuildModeDebug) {
950 ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim", "true");
951 ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim-non-leaf", nullptr);
952 }
953
954 LLVMBasicBlockRef entry_block = LLVMAppendBasicBlock(fn_val, "Entry");
955 LLVMBasicBlockRef prev_block = LLVMGetInsertBlock(g->builder);
956 LLVMValueRef prev_debug_location = LLVMGetCurrentDebugLocation(g->builder);
957 LLVMPositionBuilderAtEnd(g->builder, entry_block);
958 ZigLLVMClearCurrentDebugLocation(g->builder);
959
960 LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->type_ref;
961
962 // stack_trace.instruction_addresses[stack_trace.index % stack_trace.instruction_addresses.len] = return_address;
963
964 LLVMValueRef err_ret_trace_ptr = LLVMGetParam(fn_val, 0);
965 size_t index_field_index = g->stack_trace_type->data.structure.fields[0].gen_index;
966 LLVMValueRef index_field_ptr = LLVMBuildStructGEP(g->builder, err_ret_trace_ptr, (unsigned)index_field_index, "");
967 size_t addresses_field_index = g->stack_trace_type->data.structure.fields[1].gen_index;
968 LLVMValueRef addresses_field_ptr = LLVMBuildStructGEP(g->builder, err_ret_trace_ptr, (unsigned)addresses_field_index, "");
969
970 TypeTableEntry *slice_type = g->stack_trace_type->data.structure.fields[1].type_entry;
971 size_t ptr_field_index = slice_type->data.structure.fields[slice_ptr_index].gen_index;
972 LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, addresses_field_ptr, (unsigned)ptr_field_index, "");
973 size_t len_field_index = slice_type->data.structure.fields[slice_len_index].gen_index;
974 LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, addresses_field_ptr, (unsigned)len_field_index, "");
975
976 LLVMValueRef len_value = gen_load_untyped(g, len_field_ptr, 0, false, "");
977 LLVMValueRef index_val = gen_load_untyped(g, index_field_ptr, 0, false, "");
978 LLVMValueRef modded_val = LLVMBuildURem(g->builder, index_val, len_value, "");
979 LLVMValueRef address_indices[] = {
980 modded_val,
981 };
982
983 LLVMValueRef ptr_value = gen_load_untyped(g, ptr_field_ptr, 0, false, "");
984 LLVMValueRef address_slot = LLVMBuildInBoundsGEP(g->builder, ptr_value, address_indices, 1, "");
985
986 LLVMValueRef return_address = LLVMBuildPtrToInt(g->builder, LLVMGetParam(fn_val, 1), usize_type_ref, "");
987
988 LLVMValueRef address_value = LLVMBuildPtrToInt(g->builder, return_address, usize_type_ref, "");
989 gen_store_untyped(g, address_value, address_slot, 0, false);
990
991 // stack_trace.index += 1;
992 LLVMValueRef index_plus_one_val = LLVMBuildAdd(g->builder, index_val, LLVMConstInt(usize_type_ref, 1, false), "");
993 gen_store_untyped(g, index_plus_one_val, index_field_ptr, 0, false);
994
995 // return;
996 LLVMBuildRetVoid(g->builder);
997
998 LLVMPositionBuilderAtEnd(g->builder, prev_block);
999 LLVMSetCurrentDebugLocation(g->builder, prev_debug_location);
1000
1001 g->return_err_fn = fn_val;
1002 return fn_val;
1003}
1004
8981005static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {
8991006 if (g->safety_crash_err_fn != nullptr)
9001007 return g->safety_crash_err_fn;
......@@ -953,7 +1060,11 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {
9531060 LLVMValueRef offset_buf_ptr = LLVMConstInBoundsGEP(global_array, offset_ptr_indices, 2);
9541061
9551062 Buf *fn_name = get_mangled_name(g, buf_create_from_str("__zig_fail_unwrap"), false);
956 LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMVoidType(), &g->err_tag_type->type_ref, 1, false);
1063 LLVMTypeRef arg_types[] = {
1064 g->ptr_to_stack_trace_type->type_ref,
1065 g->err_tag_type->type_ref,
1066 };
1067 LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMVoidType(), arg_types, 2, false);
9571068 LLVMValueRef fn_val = LLVMAddFunction(g->module, buf_ptr(fn_name), fn_type_ref);
9581069 addLLVMFnAttr(fn_val, "noreturn");
9591070 addLLVMFnAttr(fn_val, "cold");
......@@ -975,7 +1086,7 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {
9751086 LLVMPositionBuilderAtEnd(g->builder, entry_block);
9761087 ZigLLVMClearCurrentDebugLocation(g->builder);
9771088
978 LLVMValueRef err_val = LLVMGetParam(fn_val, 0);
1089 LLVMValueRef err_val = LLVMGetParam(fn_val, 1);
9791090
9801091 LLVMValueRef err_table_indices[] = {
9811092 LLVMConstNull(g->builtin_types.entry_usize->type_ref),
......@@ -1005,7 +1116,7 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {
10051116 LLVMValueRef global_slice_len_field_ptr = LLVMBuildStructGEP(g->builder, global_slice, slice_len_index, "");
10061117 gen_store(g, full_buf_len, global_slice_len_field_ptr, u8_ptr_type);
10071118
1008 gen_panic(g, global_slice);
1119 gen_panic(g, global_slice, LLVMGetParam(fn_val, 0));
10091120
10101121 LLVMPositionBuilderAtEnd(g->builder, prev_block);
10111122 LLVMSetCurrentDebugLocation(g->builder, prev_debug_location);
......@@ -1016,8 +1127,18 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {
10161127
10171128static void gen_debug_safety_crash_for_err(CodeGen *g, LLVMValueRef err_val) {
10181129 LLVMValueRef safety_crash_err_fn = get_safety_crash_err_fn(g);
1019 ZigLLVMBuildCall(g->builder, safety_crash_err_fn, &err_val, 1, get_llvm_cc(g, CallingConventionUnspecified),
1130 LLVMValueRef err_ret_trace_val = g->cur_err_ret_trace_val;
1131 if (err_ret_trace_val == nullptr) {
1132 TypeTableEntry *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(g);
1133 err_ret_trace_val = LLVMConstNull(ptr_to_stack_trace_type->type_ref);
1134 }
1135 LLVMValueRef args[] = {
1136 err_ret_trace_val,
1137 err_val,
1138 };
1139 LLVMValueRef call_instruction = ZigLLVMBuildCall(g->builder, safety_crash_err_fn, args, 2, get_llvm_cc(g, CallingConventionUnspecified),
10201140 ZigLLVM_FnInlineAuto, "");
1141 LLVMSetTailCall(call_instruction, true);
10211142 LLVMBuildUnreachable(g->builder);
10221143}
10231144
......@@ -1296,6 +1417,35 @@ static LLVMValueRef ir_llvm_value(CodeGen *g, IrInstruction *instruction) {
12961417static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrInstructionReturn *return_instruction) {
12971418 LLVMValueRef value = ir_llvm_value(g, return_instruction->value);
12981419 TypeTableEntry *return_type = return_instruction->value->value.type;
1420
1421 if (g->have_err_ret_tracing) {
1422 bool is_err_return = false;
1423 if (return_type->id == TypeTableEntryIdErrorUnion) {
1424 if (return_instruction->value->value.special == ConstValSpecialStatic) {
1425 is_err_return = return_instruction->value->value.data.x_err_union.err != nullptr;
1426 } else if (return_instruction->value->value.special == ConstValSpecialRuntime) {
1427 is_err_return = return_instruction->value->value.data.rh_error_union == RuntimeHintErrorUnionError;
1428 // TODO: emit a branch to check if the return value is an error
1429 }
1430 } else if (return_type->id == TypeTableEntryIdPureError) {
1431 is_err_return = true;
1432 }
1433 if (is_err_return) {
1434 LLVMBasicBlockRef return_block = LLVMAppendBasicBlock(g->cur_fn_val, "ReturnError");
1435 LLVMValueRef block_address = LLVMBlockAddress(g->cur_fn_val, return_block);
1436
1437 LLVMValueRef return_err_fn = get_return_err_fn(g);
1438 LLVMValueRef args[] = {
1439 g->cur_err_ret_trace_val,
1440 block_address,
1441 };
1442 LLVMBuildBr(g->builder, return_block);
1443 LLVMPositionBuilderAtEnd(g->builder, return_block);
1444 LLVMValueRef call_instruction = ZigLLVMBuildCall(g->builder, return_err_fn, args, 2,
1445 get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, "");
1446 LLVMSetTailCall(call_instruction, true);
1447 }
1448 }
12991449 if (handle_is_ptr(return_type)) {
13001450 if (calling_convention_does_first_arg_return(g->cur_fn->type_entry->data.fn.fn_type_id.cc)) {
13011451 assert(g->cur_ret_ptr);
......@@ -2330,7 +2480,8 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
23302480 TypeTableEntry *src_return_type = fn_type_id->return_type;
23312481 bool ret_has_bits = type_has_bits(src_return_type);
23322482 bool first_arg_ret = ret_has_bits && handle_is_ptr(src_return_type);
2333 size_t actual_param_count = instruction->arg_count + (first_arg_ret ? 1 : 0);
2483 bool prefix_arg_err_ret_stack = g->have_err_ret_tracing && (src_return_type->id == TypeTableEntryIdErrorUnion || src_return_type->id == TypeTableEntryIdPureError);
2484 size_t actual_param_count = instruction->arg_count + (first_arg_ret ? 1 : 0) + (prefix_arg_err_ret_stack ? 1 : 0);
23342485 bool is_var_args = fn_type_id->is_var_args;
23352486 LLVMValueRef *gen_param_values = allocate<LLVMValueRef>(actual_param_count);
23362487 size_t gen_param_index = 0;
......@@ -2338,6 +2489,10 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
23382489 gen_param_values[gen_param_index] = instruction->tmp_ptr;
23392490 gen_param_index += 1;
23402491 }
2492 if (prefix_arg_err_ret_stack) {
2493 gen_param_values[gen_param_index] = g->cur_err_ret_trace_val;
2494 gen_param_index += 1;
2495 }
23412496 for (size_t call_i = 0; call_i < instruction->arg_count; call_i += 1) {
23422497 IrInstruction *param_instruction = instruction->args[call_i];
23432498 TypeTableEntry *param_type = param_instruction->value.type;
......@@ -2881,6 +3036,16 @@ static LLVMValueRef ir_render_align_cast(CodeGen *g, IrExecutable *executable, I
28813036 return target_val;
28823037}
28833038
3039static LLVMValueRef ir_render_error_return_trace(CodeGen *g, IrExecutable *executable,
3040 IrInstructionErrorReturnTrace *instruction)
3041{
3042 TypeTableEntry *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(g);
3043 if (g->cur_err_ret_trace_val == nullptr) {
3044 return LLVMConstNull(ptr_to_stack_trace_type->type_ref);
3045 }
3046 return g->cur_err_ret_trace_val;
3047}
3048
28843049static LLVMAtomicOrdering to_LLVMAtomicOrdering(AtomicOrder atomic_order) {
28853050 switch (atomic_order) {
28863051 case AtomicOrderUnordered: return LLVMAtomicOrderingUnordered;
......@@ -3474,7 +3639,7 @@ static LLVMValueRef ir_render_container_init_list(CodeGen *g, IrExecutable *exec
34743639}
34753640
34763641static LLVMValueRef ir_render_panic(CodeGen *g, IrExecutable *executable, IrInstructionPanic *instruction) {
3477 gen_panic(g, ir_llvm_value(g, instruction->msg));
3642 gen_panic(g, ir_llvm_value(g, instruction->msg), nullptr);
34783643 return nullptr;
34793644}
34803645
......@@ -3654,6 +3819,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
36543819 return ir_render_field_parent_ptr(g, executable, (IrInstructionFieldParentPtr *)instruction);
36553820 case IrInstructionIdAlignCast:
36563821 return ir_render_align_cast(g, executable, (IrInstructionAlignCast *)instruction);
3822 case IrInstructionIdErrorReturnTrace:
3823 return ir_render_error_return_trace(g, executable, (IrInstructionErrorReturnTrace *)instruction);
36573824 }
36583825 zig_unreachable();
36593826}
......@@ -4493,7 +4660,8 @@ static void do_code_gen(CodeGen *g) {
44934660 LLVMValueRef fn = fn_llvm_value(g, fn_table_entry);
44944661 g->cur_fn = fn_table_entry;
44954662 g->cur_fn_val = fn;
4496 if (handle_is_ptr(fn_table_entry->type_entry->data.fn.fn_type_id.return_type)) {
4663 TypeTableEntry *return_type = fn_table_entry->type_entry->data.fn.fn_type_id.return_type;
4664 if (handle_is_ptr(return_type)) {
44974665 g->cur_ret_ptr = LLVMGetParam(fn, 0);
44984666 } else {
44994667 g->cur_ret_ptr = nullptr;
......@@ -4502,6 +4670,42 @@ static void do_code_gen(CodeGen *g) {
45024670 build_all_basic_blocks(g, fn_table_entry);
45034671 clear_debug_source_node(g);
45044672
4673 uint32_t err_ret_trace_arg_index = get_err_ret_trace_arg_index(g, fn_table_entry);
4674 if (err_ret_trace_arg_index != UINT32_MAX) {
4675 g->cur_err_ret_trace_val = LLVMGetParam(fn, err_ret_trace_arg_index);
4676 } else if (g->have_err_ret_tracing && fn_table_entry->calls_errorable_function) {
4677 // TODO call graph analysis to find out what this number needs to be for every function
4678 static const size_t stack_trace_ptr_count = 30;
4679
4680 TypeTableEntry *usize = g->builtin_types.entry_usize;
4681 TypeTableEntry *array_type = get_array_type(g, usize, stack_trace_ptr_count);
4682 LLVMValueRef err_ret_array_val = build_alloca(g, array_type, "error_return_trace_addresses",
4683 get_abi_alignment(g, array_type));
4684 g->cur_err_ret_trace_val = build_alloca(g, g->stack_trace_type, "error_return_trace", get_abi_alignment(g, g->stack_trace_type));
4685 size_t index_field_index = g->stack_trace_type->data.structure.fields[0].gen_index;
4686 LLVMValueRef index_field_ptr = LLVMBuildStructGEP(g->builder, g->cur_err_ret_trace_val, (unsigned)index_field_index, "");
4687 gen_store_untyped(g, LLVMConstNull(usize->type_ref), index_field_ptr, 0, false);
4688
4689 size_t addresses_field_index = g->stack_trace_type->data.structure.fields[1].gen_index;
4690 LLVMValueRef addresses_field_ptr = LLVMBuildStructGEP(g->builder, g->cur_err_ret_trace_val, (unsigned)addresses_field_index, "");
4691
4692 TypeTableEntry *slice_type = g->stack_trace_type->data.structure.fields[1].type_entry;
4693 size_t ptr_field_index = slice_type->data.structure.fields[slice_ptr_index].gen_index;
4694 LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, addresses_field_ptr, (unsigned)ptr_field_index, "");
4695 LLVMValueRef zero = LLVMConstNull(usize->type_ref);
4696 LLVMValueRef indices[] = {zero, zero};
4697 LLVMValueRef err_ret_array_val_elem0_ptr = LLVMBuildInBoundsGEP(g->builder, err_ret_array_val,
4698 indices, 2, "");
4699 gen_store(g, err_ret_array_val_elem0_ptr, ptr_field_ptr,
4700 get_pointer_to_type(g, get_pointer_to_type(g, usize, false), false));
4701
4702 size_t len_field_index = slice_type->data.structure.fields[slice_len_index].gen_index;
4703 LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, addresses_field_ptr, (unsigned)len_field_index, "");
4704 gen_store(g, LLVMConstInt(usize->type_ref, stack_trace_ptr_count, false), len_field_ptr, get_pointer_to_type(g, usize, false));
4705 } else {
4706 g->cur_err_ret_trace_val = nullptr;
4707 }
4708
45054709 // allocate temporary stack data
45064710 for (size_t alloca_i = 0; alloca_i < fn_table_entry->alloca_list.length; alloca_i += 1) {
45074711 IrInstruction *instruction = fn_table_entry->alloca_list.at(alloca_i);
......@@ -5064,6 +5268,7 @@ static void define_builtin_fns(CodeGen *g) {
50645268 create_builtin_fn(g, BuiltinFnIdSetAlignStack, "setAlignStack", 1);
50655269 create_builtin_fn(g, BuiltinFnIdArgType, "ArgType", 2);
50665270 create_builtin_fn(g, BuiltinFnIdExport, "export", 3);
5271 create_builtin_fn(g, BuiltinFnIdErrorReturnTrace, "errorReturnTrace", 0);
50675272}
50685273
50695274static const char *bool_to_str(bool b) {
......@@ -5088,6 +5293,12 @@ static void define_builtin_compile_vars(CodeGen *g) {
50885293 os_path_join(g->cache_dir, buf_create_from_str(builtin_zig_basename), builtin_zig_path);
50895294 Buf *contents = buf_alloc();
50905295
5296 buf_append_str(contents,
5297 "pub const StackTrace = struct {\n"
5298 " index: usize,\n"
5299 " instruction_addresses: []usize,\n"
5300 "};\n\n");
5301
50915302 const char *cur_os = nullptr;
50925303 {
50935304 buf_appendf(contents, "pub const Os = enum {\n");
......@@ -5233,6 +5444,7 @@ static void define_builtin_compile_vars(CodeGen *g) {
52335444 buf_appendf(contents, "pub const object_format = ObjectFormat.%s;\n", cur_obj_fmt);
52345445 buf_appendf(contents, "pub const mode = %s;\n", build_mode_to_str(g->build_mode));
52355446 buf_appendf(contents, "pub const link_libc = %s;\n", bool_to_str(g->libc_link_lib != nullptr));
5447 buf_appendf(contents, "pub const have_error_return_tracing = %s;\n", bool_to_str(g->have_err_ret_tracing));
52365448
52375449 buf_appendf(contents, "pub const __zig_test_fn_slice = {}; // overwritten later\n");
52385450
......@@ -5251,6 +5463,7 @@ static void define_builtin_compile_vars(CodeGen *g) {
52515463 g->root_package->package_table.put(buf_create_from_str("builtin"), g->compile_var_package);
52525464 g->std_package->package_table.put(buf_create_from_str("builtin"), g->compile_var_package);
52535465 g->compile_var_import = add_source_file(g, g->compile_var_package, abs_full_path, contents);
5466 scan_import(g, g->compile_var_import);
52545467}
52555468
52565469static void init(CodeGen *g) {
......@@ -5359,6 +5572,8 @@ static void init(CodeGen *g) {
53595572 }
53605573 }
53615574
5575 g->have_err_ret_tracing = g->build_mode != BuildModeFastRelease;
5576
53625577 define_builtin_fns(g);
53635578 define_builtin_compile_vars(g);
53645579}
src/ir.cpp+49-12
......@@ -572,6 +572,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionArgType *) {
572572 return IrInstructionIdArgType;
573573}
574574
575static constexpr IrInstructionId ir_instruction_id(IrInstructionErrorReturnTrace *) {
576 return IrInstructionIdErrorReturnTrace;
577}
578
575579template<typename T>
576580static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {
577581 T *special_instruction = allocate<T>(1);
......@@ -2305,6 +2309,12 @@ static IrInstruction *ir_build_arg_type(IrBuilder *irb, Scope *scope, AstNode *s
23052309 return &instruction->base;
23062310}
23072311
2312static IrInstruction *ir_build_error_return_trace(IrBuilder *irb, Scope *scope, AstNode *source_node) {
2313 IrInstructionErrorReturnTrace *instruction = ir_build_instruction<IrInstructionErrorReturnTrace>(irb, scope, source_node);
2314
2315 return &instruction->base;
2316}
2317
23082318static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) {
23092319 results[ReturnKindUnconditional] = 0;
23102320 results[ReturnKindError] = 0;
......@@ -3731,6 +3741,10 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
37313741
37323742 return ir_build_export(irb, scope, node, arg0_value, arg1_value, arg2_value);
37333743 }
3744 case BuiltinFnIdErrorReturnTrace:
3745 {
3746 return ir_build_error_return_trace(irb, scope, node);
3747 }
37343748 }
37353749 zig_unreachable();
37363750}
......@@ -8230,16 +8244,6 @@ static bool ir_resolve_comptime(IrAnalyze *ira, IrInstruction *value, bool *out)
82308244 return ir_resolve_bool(ira, value, out);
82318245}
82328246
8233static ConstExprValue *get_builtin_value(CodeGen *codegen, const char *name) {
8234 Tld *tld = codegen->compile_var_import->decls_scope->decl_table.get(buf_create_from_str(name));
8235 resolve_top_level_decl(codegen, tld, false, nullptr);
8236 assert(tld->id == TldIdVar);
8237 TldVar *tld_var = (TldVar *)tld;
8238 ConstExprValue *var_value = tld_var->var->value;
8239 assert(var_value != nullptr);
8240 return var_value;
8241}
8242
82438247static bool ir_resolve_atomic_order(IrAnalyze *ira, IrInstruction *value, AtomicOrder *out) {
82448248 if (type_is_invalid(value->value.type))
82458249 return false;
......@@ -9578,6 +9582,24 @@ static TypeTableEntry *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructi
95789582 return ira->codegen->builtin_types.entry_void;
95799583}
95809584
9585static TypeTableEntry *ir_analyze_instruction_error_return_trace(IrAnalyze *ira,
9586 IrInstructionErrorReturnTrace *instruction)
9587{
9588 FnTableEntry *fn_entry = exec_fn_entry(ira->new_irb.exec);
9589 TypeTableEntry *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(ira->codegen);
9590 TypeTableEntry *nullable_type = get_maybe_type(ira->codegen, ptr_to_stack_trace_type);
9591 if (fn_entry == nullptr || !fn_entry->calls_errorable_function || !ira->codegen->have_err_ret_tracing) {
9592 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
9593 out_val->data.x_maybe = nullptr;
9594 return nullable_type;
9595 }
9596
9597 IrInstruction *new_instruction = ir_build_error_return_trace(&ira->new_irb, instruction->base.scope,
9598 instruction->base.source_node);
9599 ir_link_new_instruction(new_instruction, &instruction->base);
9600 return nullable_type;
9601}
9602
95819603static bool ir_analyze_fn_call_inline_arg(IrAnalyze *ira, AstNode *fn_proto_node,
95829604 IrInstruction *arg, Scope **exec_scope, size_t *next_proto_i)
95839605{
......@@ -9836,7 +9858,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
98369858
98379859 if (fn_proto_node->data.fn_proto.is_var_args) {
98389860 ir_add_error(ira, &call_instruction->base,
9839 buf_sprintf("compiler bug: unable to call var args function at compile time. https://github.com/andrewrk/zig/issues/313"));
9861 buf_sprintf("compiler bug: unable to call var args function at compile time. https://github.com/zig-lang/zig/issues/313"));
98409862 return ira->codegen->builtin_types.entry_invalid;
98419863 }
98429864
......@@ -10053,9 +10075,21 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
1005310075 TypeTableEntry *return_type = impl_fn->type_entry->data.fn.fn_type_id.return_type;
1005410076 ir_add_alloca(ira, new_call_instruction, return_type);
1005510077
10078 if (return_type->id == TypeTableEntryIdPureError || return_type->id == TypeTableEntryIdErrorUnion) {
10079 parent_fn_entry->calls_errorable_function = true;
10080 }
10081
1005610082 return ir_finish_anal(ira, return_type);
1005710083 }
1005810084
10085 FnTableEntry *parent_fn_entry = exec_fn_entry(ira->new_irb.exec);
10086 assert(fn_type_id->return_type != nullptr);
10087 assert(parent_fn_entry != nullptr);
10088 if (fn_type_id->return_type->id == TypeTableEntryIdPureError || fn_type_id->return_type->id == TypeTableEntryIdErrorUnion) {
10089 parent_fn_entry->calls_errorable_function = true;
10090 }
10091
10092
1005910093 IrInstruction **casted_args = allocate<IrInstruction *>(call_param_count);
1006010094 size_t next_arg_index = 0;
1006110095 if (first_arg_ptr) {
......@@ -13977,7 +14011,7 @@ static TypeTableEntry *ir_analyze_instruction_align_of(IrAnalyze *ira, IrInstruc
1397714011 return ira->codegen->builtin_types.entry_invalid;
1397814012 TypeTableEntry *type_entry = ir_resolve_type(ira, type_value);
1397914013
13980 ensure_complete_type(ira->codegen, type_entry);
14014 type_ensure_zero_bits_known(ira->codegen, type_entry);
1398114015 if (type_is_invalid(type_entry))
1398214016 return ira->codegen->builtin_types.entry_invalid;
1398314017
......@@ -15322,6 +15356,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
1532215356 return ir_analyze_instruction_tag_type(ira, (IrInstructionTagType *)instruction);
1532315357 case IrInstructionIdExport:
1532415358 return ir_analyze_instruction_export(ira, (IrInstructionExport *)instruction);
15359 case IrInstructionIdErrorReturnTrace:
15360 return ir_analyze_instruction_error_return_trace(ira, (IrInstructionErrorReturnTrace *)instruction);
1532515361 }
1532615362 zig_unreachable();
1532715363}
......@@ -15505,6 +15541,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
1550515541 case IrInstructionIdOpaqueType:
1550615542 case IrInstructionIdArgType:
1550715543 case IrInstructionIdTagType:
15544 case IrInstructionIdErrorReturnTrace:
1550815545 return false;
1550915546 case IrInstructionIdAsm:
1551015547 {
src/ir_print.cpp+7
......@@ -996,6 +996,10 @@ static void ir_print_export(IrPrint *irp, IrInstructionExport *instruction) {
996996 }
997997}
998998
999static void ir_print_error_return_trace(IrPrint *irp, IrInstructionErrorReturnTrace *instruction) {
1000 fprintf(irp->f, "@errorReturnTrace()");
1001}
1002
9991003
10001004static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
10011005 ir_print_prefix(irp, instruction);
......@@ -1308,6 +1312,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
13081312 case IrInstructionIdExport:
13091313 ir_print_export(irp, (IrInstructionExport *)instruction);
13101314 break;
1315 case IrInstructionIdErrorReturnTrace:
1316 ir_print_error_return_trace(irp, (IrInstructionErrorReturnTrace *)instruction);
1317 break;
13111318 }
13121319 fprintf(irp->f, "\n");
13131320}
src/translate_c.cpp+83-7
......@@ -1964,6 +1964,8 @@ static int trans_local_declaration(Context *c, TransScope *scope, const DeclStmt
19641964 if (init_node == nullptr)
19651965 return ErrorUnexpected;
19661966
1967 } else {
1968 init_node = trans_create_node(c, NodeTypeUndefinedLiteral);
19671969 }
19681970 AstNode *type_node = trans_qual_type(c, qual_type, stmt->getLocStart());
19691971 if (type_node == nullptr)
......@@ -2224,12 +2226,6 @@ static AstNode *trans_if_statement(Context *c, TransScope *scope, const IfStmt *
22242226 // if (c) t else e
22252227 AstNode *if_node = trans_create_node(c, NodeTypeIfBoolExpr);
22262228
2227 // TODO: condition != 0
2228 AstNode *condition_node = trans_expr(c, ResultUsedYes, scope, stmt->getCond(), TransRValue);
2229 if (condition_node == nullptr)
2230 return nullptr;
2231 if_node->data.if_bool_expr.condition = condition_node;
2232
22332229 TransScope *then_scope = trans_stmt(c, scope, stmt->getThen(), &if_node->data.if_bool_expr.then_block);
22342230 if (then_scope == nullptr)
22352231 return nullptr;
......@@ -2240,7 +2236,87 @@ static AstNode *trans_if_statement(Context *c, TransScope *scope, const IfStmt *
22402236 return nullptr;
22412237 }
22422238
2243 return if_node;
2239 AstNode *condition_node = trans_expr(c, ResultUsedYes, scope, stmt->getCond(), TransRValue);
2240 if (condition_node == nullptr)
2241 return nullptr;
2242
2243 switch (condition_node->type) {
2244 case NodeTypeBinOpExpr:
2245 switch (condition_node->data.bin_op_expr.bin_op) {
2246 case BinOpTypeBoolOr:
2247 case BinOpTypeBoolAnd:
2248 case BinOpTypeCmpEq:
2249 case BinOpTypeCmpNotEq:
2250 case BinOpTypeCmpLessThan:
2251 case BinOpTypeCmpGreaterThan:
2252 case BinOpTypeCmpLessOrEq:
2253 case BinOpTypeCmpGreaterOrEq:
2254 if_node->data.if_bool_expr.condition = condition_node;
2255 return if_node;
2256 default:
2257 goto convert_to_bitcast;
2258 }
2259
2260 case NodeTypePrefixOpExpr:
2261 switch (condition_node->data.prefix_op_expr.prefix_op) {
2262 case PrefixOpBoolNot:
2263 if_node->data.if_bool_expr.condition = condition_node;
2264 return if_node;
2265 default:
2266 goto convert_to_bitcast;
2267 }
2268
2269 case NodeTypeBoolLiteral:
2270 if_node->data.if_bool_expr.condition = condition_node;
2271 return if_node;
2272
2273 default: {
2274 // In Zig, float, int and pointer does not work in if statements.
2275 // To make it work, we bitcast any value we get to an int of the right size
2276 // and comp it to 0
2277 // TODO: This doesn't work for pointers, as they become nullable on
2278 // translate
2279 // c: if (cond) { }
2280 // zig: {
2281 // zig: const _tmp = cond;
2282 // zig: if (@bitCast(@IntType(false, @sizeOf(@typeOf(_tmp)) * 8), _tmp) != 0) { }
2283 // zig: }
2284 convert_to_bitcast:
2285 TransScopeBlock *child_scope = trans_scope_block_create(c, scope);
2286
2287 // const _tmp = cond;
2288 // TODO: avoid name collisions with generated variable names
2289 Buf* tmp_var_name = buf_create_from_str("_tmp");
2290 AstNode *tmp_var_decl = trans_create_node_var_decl_local(c, true, tmp_var_name, nullptr, condition_node);
2291 child_scope->node->data.block.statements.append(tmp_var_decl);
2292
2293 // @sizeOf(@typeOf(_tmp)) * 8
2294 AstNode *typeof_tmp = trans_create_node_builtin_fn_call_str(c, "typeOf");
2295 typeof_tmp->data.fn_call_expr.params.append(trans_create_node_symbol(c, tmp_var_name));
2296 AstNode *sizeof_tmp = trans_create_node_builtin_fn_call_str(c, "sizeOf");
2297 sizeof_tmp->data.fn_call_expr.params.append(typeof_tmp);
2298 AstNode *sizeof_tmp_in_bits = trans_create_node_bin_op(
2299 c, sizeof_tmp, BinOpTypeMult,
2300 trans_create_node_unsigned_negative(c, 8, false));
2301
2302 // @IntType(false, @sizeOf(@typeOf(_tmp)) * 8)
2303 AstNode *int_type = trans_create_node_builtin_fn_call_str(c, "IntType");
2304 int_type->data.fn_call_expr.params.append(trans_create_node_bool(c, false));
2305 int_type->data.fn_call_expr.params.append(sizeof_tmp_in_bits);
2306
2307 // @bitCast(@IntType(false, @sizeOf(@typeOf(_tmp)) * 8), _tmp)
2308 AstNode *bit_cast = trans_create_node_builtin_fn_call_str(c, "bitCast");
2309 bit_cast->data.fn_call_expr.params.append(int_type);
2310 bit_cast->data.fn_call_expr.params.append(trans_create_node_symbol(c, tmp_var_name));
2311
2312 // if (@bitCast(@IntType(false, @sizeOf(@typeOf(_tmp)) * 8), _tmp) != 0) { }
2313 AstNode *not_eql_zero = trans_create_node_bin_op(c, bit_cast, BinOpTypeCmpNotEq, trans_create_node_unsigned_negative(c, 0, false));
2314 if_node->data.if_bool_expr.condition = not_eql_zero;
2315 child_scope->node->data.block.statements.append(if_node);
2316
2317 return child_scope->node;
2318 }
2319 }
22442320}
22452321
22462322static AstNode *trans_call_expr(Context *c, ResultUsed result_used, TransScope *scope, const CallExpr *stmt) {
std/build.zig+4-6
......@@ -247,11 +247,11 @@ pub const Builder = struct {
247247 defer wanted_steps.deinit();
248248
249249 if (step_names.len == 0) {
250 wanted_steps.append(&self.default_step) catch unreachable;
250 try wanted_steps.append(&self.default_step);
251251 } else {
252252 for (step_names) |step_name| {
253253 const s = try self.getTopLevelStepByName(step_name);
254 wanted_steps.append(s) catch unreachable;
254 try wanted_steps.append(s);
255255 }
256256 }
257257
......@@ -721,11 +721,9 @@ pub const Builder = struct {
721721 return error.FileNotFound;
722722 }
723723
724 pub fn exec(self: &Builder, argv: []const []const u8) -> []u8 {
724 pub fn exec(self: &Builder, argv: []const []const u8) -> %[]u8 {
725725 const max_output_size = 100 * 1024;
726 const result = os.ChildProcess.exec(self.allocator, argv, null, null, max_output_size) catch |err| {
727 std.debug.panic("Unable to spawn {}: {}", argv[0], @errorName(err));
728 };
726 const result = try os.ChildProcess.exec(self.allocator, argv, null, null, max_output_size);
729727 switch (result.term) {
730728 os.ChildProcess.Term.Exited => |code| {
731729 if (code != 0) {
std/crypto/blake2.zig created+445
......@@ -0,0 +1,445 @@
1const mem = @import("../mem.zig");
2const math = @import("../math/index.zig");
3const endian = @import("../endian.zig");
4const debug = @import("../debug/index.zig");
5const builtin = @import("builtin");
6const htest = @import("test.zig");
7
8const RoundParam = struct {
9 a: usize, b: usize, c: usize, d: usize, x: usize, y: usize,
10};
11
12fn Rp(a: usize, b: usize, c: usize, d: usize, x: usize, y: usize) -> RoundParam {
13 return RoundParam { .a = a, .b = b, .c = c, .d = d, .x = x, .y = y, };
14}
15
16/////////////////////
17// Blake2s
18
19pub const Blake2s224 = Blake2s(224);
20pub const Blake2s256 = Blake2s(256);
21
22fn Blake2s(comptime out_len: usize) -> type { return struct {
23 const Self = this;
24
25 const iv = [8]u32 {
26 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A,
27 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19,
28 };
29
30 const sigma = [10][16]u8 {
31 []const u8 { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
32 []const u8 { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 },
33 []const u8 { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 },
34 []const u8 { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 },
35 []const u8 { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 },
36 []const u8 { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 },
37 []const u8 { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 },
38 []const u8 { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 },
39 []const u8 { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 },
40 []const u8 { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0 },
41 };
42
43 h: [8]u32,
44 t: u64,
45 // Streaming cache
46 buf: [64]u8,
47 buf_len: u8,
48
49 pub fn init() -> Self {
50 debug.assert(8 <= out_len and out_len <= 512);
51
52 var s: Self = undefined;
53 s.reset();
54 return s;
55 }
56
57 pub fn reset(d: &Self) {
58 mem.copy(u32, d.h[0..], iv[0..]);
59
60 // No key plus default parameters
61 d.h[0] ^= 0x01010000 ^ u32(out_len >> 3);
62 d.t = 0;
63 d.buf_len = 0;
64 }
65
66 pub fn hash(b: []const u8, out: []u8) {
67 var d = Self.init();
68 d.update(b);
69 d.final(out);
70 }
71
72 pub fn update(d: &Self, b: []const u8) {
73 var off: usize = 0;
74
75 // Partial buffer exists from previous update. Copy into buffer then hash.
76 if (d.buf_len != 0 and d.buf_len + b.len > 64) {
77 off += 64 - d.buf_len;
78 mem.copy(u8, d.buf[d.buf_len..], b[0..off]);
79 d.t += 64;
80 d.round(d.buf[0..], false);
81 d.buf_len = 0;
82 }
83
84 // Full middle blocks.
85 while (off + 64 < b.len) : (off += 64) {
86 d.t += 64;
87 d.round(b[off..off + 64], false);
88 }
89
90 // Copy any remainder for next pass.
91 mem.copy(u8, d.buf[d.buf_len..], b[off..]);
92 d.buf_len += u8(b[off..].len);
93 }
94
95 pub fn final(d: &Self, out: []u8) {
96 debug.assert(out.len >= out_len / 8);
97
98 mem.set(u8, d.buf[d.buf_len..], 0);
99 d.t += d.buf_len;
100 d.round(d.buf[0..], true);
101
102 const rr = d.h[0 .. out_len / 32];
103
104 for (rr) |s, j| {
105 mem.writeInt(out[4*j .. 4*j + 4], s, builtin.Endian.Little);
106 }
107 }
108
109 fn round(d: &Self, b: []const u8, last: bool) {
110 debug.assert(b.len == 64);
111
112 var m: [16]u32 = undefined;
113 var v: [16]u32 = undefined;
114
115 for (m) |*r, i| {
116 *r = mem.readIntLE(u32, b[4*i .. 4*i + 4]);
117 }
118
119 var k: usize = 0;
120 while (k < 8) : (k += 1) {
121 v[k] = d.h[k];
122 v[k+8] = iv[k];
123 }
124
125 v[12] ^= @truncate(u32, d.t);
126 v[13] ^= u32(d.t >> 32);
127 if (last) v[14] = ~v[14];
128
129 const rounds = comptime []RoundParam {
130 Rp(0, 4, 8, 12, 0, 1),
131 Rp(1, 5, 9, 13, 2, 3),
132 Rp(2, 6, 10, 14, 4, 5),
133 Rp(3, 7, 11, 15, 6, 7),
134 Rp(0, 5, 10, 15, 8, 9),
135 Rp(1, 6, 11, 12, 10, 11),
136 Rp(2, 7, 8, 13, 12, 13),
137 Rp(3, 4, 9, 14, 14, 15),
138 };
139
140 comptime var j: usize = 0;
141 inline while (j < 10) : (j += 1) {
142 inline for (rounds) |r| {
143 v[r.a] = v[r.a] +% v[r.b] +% m[sigma[j][r.x]];
144 v[r.d] = math.rotr(u32, v[r.d] ^ v[r.a], usize(16));
145 v[r.c] = v[r.c] +% v[r.d];
146 v[r.b] = math.rotr(u32, v[r.b] ^ v[r.c], usize(12));
147 v[r.a] = v[r.a] +% v[r.b] +% m[sigma[j][r.y]];
148 v[r.d] = math.rotr(u32, v[r.d] ^ v[r.a], usize(8));
149 v[r.c] = v[r.c] +% v[r.d];
150 v[r.b] = math.rotr(u32, v[r.b] ^ v[r.c], usize(7));
151 }
152 }
153
154 for (d.h) |*r, i| {
155 *r ^= v[i] ^ v[i + 8];
156 }
157 }
158};}
159
160test "blake2s224 single" {
161 const h1 = "1fa1291e65248b37b3433475b2a0dd63d54a11ecc4e3e034e7bc1ef4";
162 htest.assertEqualHash(Blake2s224, h1, "");
163
164 const h2 = "0b033fc226df7abde29f67a05d3dc62cf271ef3dfea4d387407fbd55";
165 htest.assertEqualHash(Blake2s224, h2, "abc");
166
167 const h3 = "e4e5cb6c7cae41982b397bf7b7d2d9d1949823ae78435326e8db4912";
168 htest.assertEqualHash(Blake2s224, h3, "The quick brown fox jumps over the lazy dog");
169}
170
171test "blake2s224 streaming" {
172 var h = Blake2s224.init();
173 var out: [28]u8 = undefined;
174
175 const h1 = "1fa1291e65248b37b3433475b2a0dd63d54a11ecc4e3e034e7bc1ef4";
176
177 h.final(out[0..]);
178 htest.assertEqual(h1, out[0..]);
179
180 const h2 = "0b033fc226df7abde29f67a05d3dc62cf271ef3dfea4d387407fbd55";
181
182 h.reset();
183 h.update("abc");
184 h.final(out[0..]);
185 htest.assertEqual(h2, out[0..]);
186
187 h.reset();
188 h.update("a");
189 h.update("b");
190 h.update("c");
191 h.final(out[0..]);
192 htest.assertEqual(h2, out[0..]);
193}
194
195test "blake2s256 single" {
196 const h1 = "69217a3079908094e11121d042354a7c1f55b6482ca1a51e1b250dfd1ed0eef9";
197 htest.assertEqualHash(Blake2s256, h1, "");
198
199 const h2 = "508c5e8c327c14e2e1a72ba34eeb452f37458b209ed63a294d999b4c86675982";
200 htest.assertEqualHash(Blake2s256, h2, "abc");
201
202 const h3 = "606beeec743ccbeff6cbcdf5d5302aa855c256c29b88c8ed331ea1a6bf3c8812";
203 htest.assertEqualHash(Blake2s256, h3, "The quick brown fox jumps over the lazy dog");
204}
205
206test "blake2s256 streaming" {
207 var h = Blake2s256.init();
208 var out: [32]u8 = undefined;
209
210 const h1 = "69217a3079908094e11121d042354a7c1f55b6482ca1a51e1b250dfd1ed0eef9";
211
212 h.final(out[0..]);
213 htest.assertEqual(h1, out[0..]);
214
215 const h2 = "508c5e8c327c14e2e1a72ba34eeb452f37458b209ed63a294d999b4c86675982";
216
217 h.reset();
218 h.update("abc");
219 h.final(out[0..]);
220 htest.assertEqual(h2, out[0..]);
221
222 h.reset();
223 h.update("a");
224 h.update("b");
225 h.update("c");
226 h.final(out[0..]);
227 htest.assertEqual(h2, out[0..]);
228}
229
230
231/////////////////////
232// Blake2b
233
234pub const Blake2b384 = Blake2b(384);
235pub const Blake2b512 = Blake2b(512);
236
237fn Blake2b(comptime out_len: usize) -> type { return struct {
238 const Self = this;
239
240 const iv = [8]u64 {
241 0x6a09e667f3bcc908, 0xbb67ae8584caa73b,
242 0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1,
243 0x510e527fade682d1, 0x9b05688c2b3e6c1f,
244 0x1f83d9abfb41bd6b, 0x5be0cd19137e2179,
245 };
246
247 const sigma = [12][16]u8 {
248 []const u8 { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
249 []const u8 { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 },
250 []const u8 { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 },
251 []const u8 { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 },
252 []const u8 { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 },
253 []const u8 { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 },
254 []const u8 { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 },
255 []const u8 { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 },
256 []const u8 { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 },
257 []const u8 { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0 },
258 []const u8 { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
259 []const u8 { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 },
260 };
261
262 h: [8]u64,
263 t: u128,
264 // Streaming cache
265 buf: [128]u8,
266 buf_len: u8,
267
268 pub fn init() -> Self {
269 debug.assert(8 <= out_len and out_len <= 512);
270
271 var s: Self = undefined;
272 s.reset();
273 return s;
274 }
275
276 pub fn reset(d: &Self) {
277 mem.copy(u64, d.h[0..], iv[0..]);
278
279 // No key plus default parameters
280 d.h[0] ^= 0x01010000 ^ (out_len >> 3);
281 d.t = 0;
282 d.buf_len = 0;
283 }
284
285 pub fn hash(b: []const u8, out: []u8) {
286 var d = Self.init();
287 d.update(b);
288 d.final(out);
289 }
290
291 pub fn update(d: &Self, b: []const u8) {
292 var off: usize = 0;
293
294 // Partial buffer exists from previous update. Copy into buffer then hash.
295 if (d.buf_len != 0 and d.buf_len + b.len > 128) {
296 off += 128 - d.buf_len;
297 mem.copy(u8, d.buf[d.buf_len..], b[0..off]);
298 d.t += 128;
299 d.round(d.buf[0..], false);
300 d.buf_len = 0;
301 }
302
303 // Full middle blocks.
304 while (off + 128 < b.len) : (off += 128) {
305 d.t += 128;
306 d.round(b[off..off + 128], false);
307 }
308
309 // Copy any remainder for next pass.
310 mem.copy(u8, d.buf[d.buf_len..], b[off..]);
311 d.buf_len += u8(b[off..].len);
312 }
313
314 pub fn final(d: &Self, out: []u8) {
315 mem.set(u8, d.buf[d.buf_len..], 0);
316 d.t += d.buf_len;
317 d.round(d.buf[0..], true);
318
319 const rr = d.h[0 .. out_len / 64];
320
321 for (rr) |s, j| {
322 mem.writeInt(out[8*j .. 8*j + 8], s, builtin.Endian.Little);
323 }
324 }
325
326 fn round(d: &Self, b: []const u8, last: bool) {
327 debug.assert(b.len == 128);
328
329 var m: [16]u64 = undefined;
330 var v: [16]u64 = undefined;
331
332 for (m) |*r, i| {
333 *r = mem.readIntLE(u64, b[8*i .. 8*i + 8]);
334 }
335
336 var k: usize = 0;
337 while (k < 8) : (k += 1) {
338 v[k] = d.h[k];
339 v[k+8] = iv[k];
340 }
341
342 v[12] ^= @truncate(u64, d.t);
343 v[13] ^= u64(d.t >> 64);
344 if (last) v[14] = ~v[14];
345
346 const rounds = comptime []RoundParam {
347 Rp(0, 4, 8, 12, 0, 1),
348 Rp(1, 5, 9, 13, 2, 3),
349 Rp(2, 6, 10, 14, 4, 5),
350 Rp(3, 7, 11, 15, 6, 7),
351 Rp(0, 5, 10, 15, 8, 9),
352 Rp(1, 6, 11, 12, 10, 11),
353 Rp(2, 7, 8, 13, 12, 13),
354 Rp(3, 4, 9, 14, 14, 15),
355 };
356
357 comptime var j: usize = 0;
358 inline while (j < 12) : (j += 1) {
359 inline for (rounds) |r| {
360 v[r.a] = v[r.a] +% v[r.b] +% m[sigma[j][r.x]];
361 v[r.d] = math.rotr(u64, v[r.d] ^ v[r.a], usize(32));
362 v[r.c] = v[r.c] +% v[r.d];
363 v[r.b] = math.rotr(u64, v[r.b] ^ v[r.c], usize(24));
364 v[r.a] = v[r.a] +% v[r.b] +% m[sigma[j][r.y]];
365 v[r.d] = math.rotr(u64, v[r.d] ^ v[r.a], usize(16));
366 v[r.c] = v[r.c] +% v[r.d];
367 v[r.b] = math.rotr(u64, v[r.b] ^ v[r.c], usize(63));
368 }
369 }
370
371 for (d.h) |*r, i| {
372 *r ^= v[i] ^ v[i + 8];
373 }
374 }
375};}
376
377test "blake2b384 single" {
378 const h1 = "b32811423377f52d7862286ee1a72ee540524380fda1724a6f25d7978c6fd3244a6caf0498812673c5e05ef583825100";
379 htest.assertEqualHash(Blake2b384, h1, "");
380
381 const h2 = "6f56a82c8e7ef526dfe182eb5212f7db9df1317e57815dbda46083fc30f54ee6c66ba83be64b302d7cba6ce15bb556f4";
382 htest.assertEqualHash(Blake2b384, h2, "abc");
383
384 const h3 = "b7c81b228b6bd912930e8f0b5387989691c1cee1e65aade4da3b86a3c9f678fc8018f6ed9e2906720c8d2a3aeda9c03d";
385 htest.assertEqualHash(Blake2b384, h3, "The quick brown fox jumps over the lazy dog");
386}
387
388test "blake2b384 streaming" {
389 var h = Blake2b384.init();
390 var out: [48]u8 = undefined;
391
392 const h1 = "b32811423377f52d7862286ee1a72ee540524380fda1724a6f25d7978c6fd3244a6caf0498812673c5e05ef583825100";
393
394 h.final(out[0..]);
395 htest.assertEqual(h1, out[0..]);
396
397 const h2 = "6f56a82c8e7ef526dfe182eb5212f7db9df1317e57815dbda46083fc30f54ee6c66ba83be64b302d7cba6ce15bb556f4";
398
399 h.reset();
400 h.update("abc");
401 h.final(out[0..]);
402 htest.assertEqual(h2, out[0..]);
403
404 h.reset();
405 h.update("a");
406 h.update("b");
407 h.update("c");
408 h.final(out[0..]);
409 htest.assertEqual(h2, out[0..]);
410}
411
412test "blake2b512 single" {
413 const h1 = "786a02f742015903c6c6fd852552d272912f4740e15847618a86e217f71f5419d25e1031afee585313896444934eb04b903a685b1448b755d56f701afe9be2ce";
414 htest.assertEqualHash(Blake2b512, h1, "");
415
416 const h2 = "ba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac4b74b12bb6fdbffa2d17d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923";
417 htest.assertEqualHash(Blake2b512, h2, "abc");
418
419 const h3 = "a8add4bdddfd93e4877d2746e62817b116364a1fa7bc148d95090bc7333b3673f82401cf7aa2e4cb1ecd90296e3f14cb5413f8ed77be73045b13914cdcd6a918";
420 htest.assertEqualHash(Blake2b512, h3, "The quick brown fox jumps over the lazy dog");
421}
422
423test "blake2b512 streaming" {
424 var h = Blake2b512.init();
425 var out: [64]u8 = undefined;
426
427 const h1 = "786a02f742015903c6c6fd852552d272912f4740e15847618a86e217f71f5419d25e1031afee585313896444934eb04b903a685b1448b755d56f701afe9be2ce";
428
429 h.final(out[0..]);
430 htest.assertEqual(h1, out[0..]);
431
432 const h2 = "ba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac4b74b12bb6fdbffa2d17d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923";
433
434 h.reset();
435 h.update("abc");
436 h.final(out[0..]);
437 htest.assertEqual(h2, out[0..]);
438
439 h.reset();
440 h.update("a");
441 h.update("b");
442 h.update("c");
443 h.final(out[0..]);
444 htest.assertEqual(h2, out[0..]);
445}
std/crypto/index.zig created+21
......@@ -0,0 +1,21 @@
1pub const Md5 = @import("sha1.zig").Md5;
2pub const Sha1 = @import("md5.zig").Sha1;
3
4const sha2 = @import("sha2.zig");
5pub const Sha224 = sha2.Sha224;
6pub const Sha256 = sha2.Sha256;
7pub const Sha384 = sha2.Sha384;
8pub const Sha512 = sha2.Sha512;
9
10const blake2 = @import("blake2.zig");
11pub const Blake2s224 = blake2.Blake2s224;
12pub const Blake2s256 = blake2.Blake2s256;
13pub const Blake2b384 = blake2.Blake2b384;
14pub const Blake2b512 = blake2.Blake2b512;
15
16test "crypto" {
17 _ = @import("md5.zig");
18 _ = @import("sha1.zig");
19 _ = @import("sha2.zig");
20 _ = @import("blake2.zig");
21}
std/crypto/md5.zig created+260
......@@ -0,0 +1,260 @@
1const mem = @import("../mem.zig");
2const math = @import("../math/index.zig");
3const endian = @import("../endian.zig");
4const builtin = @import("builtin");
5const debug = @import("../debug/index.zig");
6const fmt = @import("../fmt/index.zig");
7
8const RoundParam = struct {
9 a: usize, b: usize, c: usize, d: usize,
10 k: usize, s: u32, t: u32
11};
12
13fn Rp(a: usize, b: usize, c: usize, d: usize, k: usize, s: u32, t: u32) -> RoundParam {
14 return RoundParam { .a = a, .b = b, .c = c, .d = d, .k = k, .s = s, .t = t };
15}
16
17/// const hash1 = Md5.hash("my input");
18///
19/// const hasher = Md5.init();
20/// hasher.update("my ");
21/// hasher.update("input");
22/// const hash2 = hasher.final();
23pub const Md5 = struct {
24 const Self = this;
25
26 s: [4]u32,
27 // Streaming Cache
28 buf: [64]u8,
29 buf_len: u8,
30 total_len: u64,
31
32 pub fn init() -> Self {
33 var d: Self = undefined;
34 d.reset();
35 return d;
36 }
37
38 pub fn reset(d: &Self) {
39 d.s[0] = 0x67452301;
40 d.s[1] = 0xEFCDAB89;
41 d.s[2] = 0x98BADCFE;
42 d.s[3] = 0x10325476;
43 d.buf_len = 0;
44 d.total_len = 0;
45 }
46
47 pub fn hash(b: []const u8, out: []u8) {
48 var d = Md5.init();
49 d.update(b);
50 d.final(out);
51 }
52
53 pub fn update(d: &Self, b: []const u8) {
54 var off: usize = 0;
55
56 // Partial buffer exists from previous update. Copy into buffer then hash.
57 if (d.buf_len != 0 and d.buf_len + b.len > 64) {
58 off += 64 - d.buf_len;
59 mem.copy(u8, d.buf[d.buf_len..], b[0..off]);
60
61 d.round(d.buf[0..]);
62 d.buf_len = 0;
63 }
64
65 // Full middle blocks.
66 while (off + 64 < b.len) : (off += 64) {
67 d.round(b[off..off + 64]);
68 }
69
70 // Copy any remainder for next pass.
71 mem.copy(u8, d.buf[d.buf_len..], b[off..]);
72 d.buf_len += u8(b[off..].len);
73
74 // Md5 uses the bottom 64-bits for length padding
75 d.total_len +%= b.len;
76 }
77
78 pub fn final(d: &Self, out: []u8) {
79 debug.assert(out.len >= 16);
80
81 // The buffer here will never be completely full.
82 mem.set(u8, d.buf[d.buf_len..], 0);
83
84 // Append padding bits.
85 d.buf[d.buf_len] = 0x80;
86 d.buf_len += 1;
87
88 // > 448 mod 512 so need to add an extra round to wrap around.
89 if (64 - d.buf_len < 8) {
90 d.round(d.buf[0..]);
91 mem.set(u8, d.buf[0..], 0);
92 }
93
94 // Append message length.
95 var i: usize = 1;
96 var len = d.total_len >> 5;
97 d.buf[56] = u8(d.total_len & 0x1f) << 3;
98 while (i < 8) : (i += 1) {
99 d.buf[56 + i] = u8(len & 0xff);
100 len >>= 8;
101 }
102
103 d.round(d.buf[0..]);
104
105 for (d.s) |s, j| {
106 mem.writeInt(out[4*j .. 4*j + 4], s, builtin.Endian.Little);
107 }
108 }
109
110 fn round(d: &Self, b: []const u8) {
111 debug.assert(b.len == 64);
112
113 var s: [16]u32 = undefined;
114
115 // ERROR: cannot unroll this at comptime
116 var i: usize = 0;
117 while (i < 16) : (i += 1) {
118 // NOTE: Performing or's separately improves perf by ~10%
119 s[i] = 0;
120 s[i] |= u32(b[i*4+0]);
121 s[i] |= u32(b[i*4+1]) << 8;
122 s[i] |= u32(b[i*4+2]) << 16;
123 s[i] |= u32(b[i*4+3]) << 24;
124 }
125
126 var v: [4]u32 = []u32 {
127 d.s[0], d.s[1], d.s[2], d.s[3],
128 };
129
130 const round0 = comptime []RoundParam {
131 Rp(0, 1, 2, 3, 0, 7, 0xD76AA478),
132 Rp(3, 0, 1, 2, 1, 12, 0xE8C7B756),
133 Rp(2, 3, 0, 1, 2, 17, 0x242070DB),
134 Rp(1, 2, 3, 0, 3, 22, 0xC1BDCEEE),
135 Rp(0, 1, 2, 3, 4, 7, 0xF57C0FAF),
136 Rp(3, 0, 1, 2, 5, 12, 0x4787C62A),
137 Rp(2, 3, 0, 1, 6, 17, 0xA8304613),
138 Rp(1, 2, 3, 0, 7, 22, 0xFD469501),
139 Rp(0, 1, 2, 3, 8, 7, 0x698098D8),
140 Rp(3, 0, 1, 2, 9, 12, 0x8B44F7AF),
141 Rp(2, 3, 0, 1, 10, 17, 0xFFFF5BB1),
142 Rp(1, 2, 3, 0, 11, 22, 0x895CD7BE),
143 Rp(0, 1, 2, 3, 12, 7, 0x6B901122),
144 Rp(3, 0, 1, 2, 13, 12, 0xFD987193),
145 Rp(2, 3, 0, 1, 14, 17, 0xA679438E),
146 Rp(1, 2, 3, 0, 15, 22, 0x49B40821),
147 };
148 inline for (round0) |r| {
149 v[r.a] = v[r.a] +% (v[r.d] ^ (v[r.b] & (v[r.c] ^ v[r.d]))) +% r.t +% s[r.k];
150 v[r.a] = v[r.b] +% math.rotl(u32, v[r.a], r.s);
151 }
152
153 const round1 = comptime []RoundParam {
154 Rp(0, 1, 2, 3, 1, 5, 0xF61E2562),
155 Rp(3, 0, 1, 2, 6, 9, 0xC040B340),
156 Rp(2, 3, 0, 1, 11, 14, 0x265E5A51),
157 Rp(1, 2, 3, 0, 0, 20, 0xE9B6C7AA),
158 Rp(0, 1, 2, 3, 5, 5, 0xD62F105D),
159 Rp(3, 0, 1, 2, 10, 9, 0x02441453),
160 Rp(2, 3, 0, 1, 15, 14, 0xD8A1E681),
161 Rp(1, 2, 3, 0, 4, 20, 0xE7D3FBC8),
162 Rp(0, 1, 2, 3, 9, 5, 0x21E1CDE6),
163 Rp(3, 0, 1, 2, 14, 9, 0xC33707D6),
164 Rp(2, 3, 0, 1, 3, 14, 0xF4D50D87),
165 Rp(1, 2, 3, 0, 8, 20, 0x455A14ED),
166 Rp(0, 1, 2, 3, 13, 5, 0xA9E3E905),
167 Rp(3, 0, 1, 2, 2, 9, 0xFCEFA3F8),
168 Rp(2, 3, 0, 1, 7, 14, 0x676F02D9),
169 Rp(1, 2, 3, 0, 12, 20, 0x8D2A4C8A),
170 };
171 inline for (round1) |r| {
172 v[r.a] = v[r.a] +% (v[r.c] ^ (v[r.d] & (v[r.b] ^ v[r.c]))) +% r.t +% s[r.k];
173 v[r.a] = v[r.b] +% math.rotl(u32, v[r.a], r.s);
174 }
175
176 const round2 = comptime []RoundParam {
177 Rp(0, 1, 2, 3, 5, 4, 0xFFFA3942),
178 Rp(3, 0, 1, 2, 8, 11, 0x8771F681),
179 Rp(2, 3, 0, 1, 11, 16, 0x6D9D6122),
180 Rp(1, 2, 3, 0, 14, 23, 0xFDE5380C),
181 Rp(0, 1, 2, 3, 1, 4, 0xA4BEEA44),
182 Rp(3, 0, 1, 2, 4, 11, 0x4BDECFA9),
183 Rp(2, 3, 0, 1, 7, 16, 0xF6BB4B60),
184 Rp(1, 2, 3, 0, 10, 23, 0xBEBFBC70),
185 Rp(0, 1, 2, 3, 13, 4, 0x289B7EC6),
186 Rp(3, 0, 1, 2, 0, 11, 0xEAA127FA),
187 Rp(2, 3, 0, 1, 3, 16, 0xD4EF3085),
188 Rp(1, 2, 3, 0, 6, 23, 0x04881D05),
189 Rp(0, 1, 2, 3, 9, 4, 0xD9D4D039),
190 Rp(3, 0, 1, 2, 12, 11, 0xE6DB99E5),
191 Rp(2, 3, 0, 1, 15, 16, 0x1FA27CF8),
192 Rp(1, 2, 3, 0, 2, 23, 0xC4AC5665),
193 };
194 inline for (round2) |r| {
195 v[r.a] = v[r.a] +% (v[r.b] ^ v[r.c] ^ v[r.d]) +% r.t +% s[r.k];
196 v[r.a] = v[r.b] +% math.rotl(u32, v[r.a], r.s);
197 }
198
199 const round3 = comptime []RoundParam {
200 Rp(0, 1, 2, 3, 0, 6, 0xF4292244),
201 Rp(3, 0, 1, 2, 7, 10, 0x432AFF97),
202 Rp(2, 3, 0, 1, 14, 15, 0xAB9423A7),
203 Rp(1, 2, 3, 0, 5, 21, 0xFC93A039),
204 Rp(0, 1, 2, 3, 12, 6, 0x655B59C3),
205 Rp(3, 0, 1, 2, 3, 10, 0x8F0CCC92),
206 Rp(2, 3, 0, 1, 10, 15, 0xFFEFF47D),
207 Rp(1, 2, 3, 0, 1, 21, 0x85845DD1),
208 Rp(0, 1, 2, 3, 8, 6, 0x6FA87E4F),
209 Rp(3, 0, 1, 2, 15, 10, 0xFE2CE6E0),
210 Rp(2, 3, 0, 1, 6, 15, 0xA3014314),
211 Rp(1, 2, 3, 0, 13, 21, 0x4E0811A1),
212 Rp(0, 1, 2, 3, 4, 6, 0xF7537E82),
213 Rp(3, 0, 1, 2, 11, 10, 0xBD3AF235),
214 Rp(2, 3, 0, 1, 2, 15, 0x2AD7D2BB),
215 Rp(1, 2, 3, 0, 9, 21, 0xEB86D391),
216 };
217 inline for (round3) |r| {
218 v[r.a] = v[r.a] +% (v[r.c] ^ (v[r.b] | ~v[r.d])) +% r.t +% s[r.k];
219 v[r.a] = v[r.b] +% math.rotl(u32, v[r.a], r.s);
220 }
221
222 d.s[0] +%= v[0];
223 d.s[1] +%= v[1];
224 d.s[2] +%= v[2];
225 d.s[3] +%= v[3];
226 }
227};
228
229const htest = @import("test.zig");
230
231test "md5 single" {
232 htest.assertEqualHash(Md5, "d41d8cd98f00b204e9800998ecf8427e", "");
233 htest.assertEqualHash(Md5, "0cc175b9c0f1b6a831c399e269772661", "a");
234 htest.assertEqualHash(Md5, "900150983cd24fb0d6963f7d28e17f72", "abc");
235 htest.assertEqualHash(Md5, "f96b697d7cb7938d525a2f31aaf161d0", "message digest");
236 htest.assertEqualHash(Md5, "c3fcd3d76192e4007dfb496cca67e13b", "abcdefghijklmnopqrstuvwxyz");
237 htest.assertEqualHash(Md5, "d174ab98d277d9f5a5611c2c9f419d9f", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
238 htest.assertEqualHash(Md5, "57edf4a22be3c955ac49da2e2107b67a", "12345678901234567890123456789012345678901234567890123456789012345678901234567890");
239}
240
241test "md5 streaming" {
242 var h = Md5.init();
243 var out: [16]u8 = undefined;
244
245 h.final(out[0..]);
246 htest.assertEqual("d41d8cd98f00b204e9800998ecf8427e", out[0..]);
247
248 h.reset();
249 h.update("abc");
250 h.final(out[0..]);
251 htest.assertEqual("900150983cd24fb0d6963f7d28e17f72", out[0..]);
252
253 h.reset();
254 h.update("a");
255 h.update("b");
256 h.update("c");
257 h.final(out[0..]);
258
259 htest.assertEqual("900150983cd24fb0d6963f7d28e17f72", out[0..]);
260}
std/crypto/sha1.zig created+284
......@@ -0,0 +1,284 @@
1const mem = @import("../mem.zig");
2const math = @import("../math/index.zig");
3const endian = @import("../endian.zig");
4const debug = @import("../debug/index.zig");
5const builtin = @import("builtin");
6
7pub const u160 = @IntType(false, 160);
8
9const RoundParam = struct {
10 a: usize, b: usize, c: usize, d: usize, e: usize, i: u32,
11};
12
13fn Rp(a: usize, b: usize, c: usize, d: usize, e: usize, i: u32) -> RoundParam {
14 return RoundParam { .a = a, .b = b, .c = c, .d = d, .e = e, .i = i };
15}
16
17pub const Sha1 = struct {
18 const Self = this;
19
20 s: [5]u32,
21 // Streaming Cache
22 buf: [64]u8,
23 buf_len: u8,
24 total_len: u64,
25
26 pub fn init() -> Self {
27 var d: Self = undefined;
28 d.reset();
29 return d;
30 }
31
32 pub fn reset(d: &Self) {
33 d.s[0] = 0x67452301;
34 d.s[1] = 0xEFCDAB89;
35 d.s[2] = 0x98BADCFE;
36 d.s[3] = 0x10325476;
37 d.s[4] = 0xC3D2E1F0;
38 d.buf_len = 0;
39 d.total_len = 0;
40 }
41
42 pub fn hash(b: []const u8, out: []u8) {
43 var d = Sha1.init();
44 d.update(b);
45 d.final(out);
46 }
47
48 pub fn update(d: &Self, b: []const u8) {
49 var off: usize = 0;
50
51 // Partial buffer exists from previous update. Copy into buffer then hash.
52 if (d.buf_len != 0 and d.buf_len + b.len > 64) {
53 off += 64 - d.buf_len;
54 mem.copy(u8, d.buf[d.buf_len..], b[0..off]);
55
56 d.round(d.buf[0..]);
57 d.buf_len = 0;
58 }
59
60 // Full middle blocks.
61 while (off + 64 < b.len) : (off += 64) {
62 d.round(b[off..off + 64]);
63 }
64
65 // Copy any remainder for next pass.
66 mem.copy(u8, d.buf[d.buf_len..], b[off..]);
67 d.buf_len += u8(b[off..].len);
68
69 d.total_len += b.len;
70 }
71
72 pub fn final(d: &Self, out: []u8) {
73 debug.assert(out.len >= 20);
74
75 // The buffer here will never be completely full.
76 mem.set(u8, d.buf[d.buf_len..], 0);
77
78 // Append padding bits.
79 d.buf[d.buf_len] = 0x80;
80 d.buf_len += 1;
81
82 // > 448 mod 512 so need to add an extra round to wrap around.
83 if (64 - d.buf_len < 8) {
84 d.round(d.buf[0..]);
85 mem.set(u8, d.buf[0..], 0);
86 }
87
88 // Append message length.
89 var i: usize = 1;
90 var len = d.total_len >> 5;
91 d.buf[63] = u8(d.total_len & 0x1f) << 3;
92 while (i < 8) : (i += 1) {
93 d.buf[63 - i] = u8(len & 0xff);
94 len >>= 8;
95 }
96
97 d.round(d.buf[0..]);
98
99 for (d.s) |s, j| {
100 mem.writeInt(out[4*j .. 4*j + 4], s, builtin.Endian.Big);
101 }
102 }
103
104 fn round(d: &Self, b: []const u8) {
105 debug.assert(b.len == 64);
106
107 var s: [16]u32 = undefined;
108
109 var v: [5]u32 = []u32 {
110 d.s[0], d.s[1], d.s[2], d.s[3], d.s[4],
111 };
112
113 const round0a = comptime []RoundParam {
114 Rp(0, 1, 2, 3, 4, 0),
115 Rp(4, 0, 1, 2, 3, 1),
116 Rp(3, 4, 0, 1, 2, 2),
117 Rp(2, 3, 4, 0, 1, 3),
118 Rp(1, 2, 3, 4, 0, 4),
119 Rp(0, 1, 2, 3, 4, 5),
120 Rp(4, 0, 1, 2, 3, 6),
121 Rp(3, 4, 0, 1, 2, 7),
122 Rp(2, 3, 4, 0, 1, 8),
123 Rp(1, 2, 3, 4, 0, 9),
124 Rp(0, 1, 2, 3, 4, 10),
125 Rp(4, 0, 1, 2, 3, 11),
126 Rp(3, 4, 0, 1, 2, 12),
127 Rp(2, 3, 4, 0, 1, 13),
128 Rp(1, 2, 3, 4, 0, 14),
129 Rp(0, 1, 2, 3, 4, 15),
130 };
131 inline for (round0a) |r| {
132 s[r.i] = (u32(b[r.i * 4 + 0]) << 24) |
133 (u32(b[r.i * 4 + 1]) << 16) |
134 (u32(b[r.i * 4 + 2]) << 8) |
135 (u32(b[r.i * 4 + 3]) << 0);
136
137 v[r.e] = v[r.e] +% math.rotl(u32, v[r.a], u32(5)) +% 0x5A827999 +% s[r.i & 0xf]
138 +% ((v[r.b] & v[r.c]) | (~v[r.b] & v[r.d]));
139 v[r.b] = math.rotl(u32, v[r.b], u32(30));
140 }
141
142 const round0b = comptime []RoundParam {
143 Rp(4, 0, 1, 2, 3, 16),
144 Rp(3, 4, 0, 1, 2, 17),
145 Rp(2, 3, 4, 0, 1, 18),
146 Rp(1, 2, 3, 4, 0, 19),
147 };
148 inline for (round0b) |r| {
149 const t = s[(r.i-3) & 0xf] ^ s[(r.i-8) & 0xf] ^ s[(r.i-14) & 0xf] ^ s[(r.i-16) & 0xf];
150 s[r.i & 0xf] = math.rotl(u32, t, u32(1));
151
152 v[r.e] = v[r.e] +% math.rotl(u32, v[r.a], u32(5)) +% 0x5A827999 +% s[r.i & 0xf]
153 +% ((v[r.b] & v[r.c]) | (~v[r.b] & v[r.d]));
154 v[r.b] = math.rotl(u32, v[r.b], u32(30));
155 }
156
157 const round1 = comptime []RoundParam {
158 Rp(0, 1, 2, 3, 4, 20),
159 Rp(4, 0, 1, 2, 3, 21),
160 Rp(3, 4, 0, 1, 2, 22),
161 Rp(2, 3, 4, 0, 1, 23),
162 Rp(1, 2, 3, 4, 0, 24),
163 Rp(0, 1, 2, 3, 4, 25),
164 Rp(4, 0, 1, 2, 3, 26),
165 Rp(3, 4, 0, 1, 2, 27),
166 Rp(2, 3, 4, 0, 1, 28),
167 Rp(1, 2, 3, 4, 0, 29),
168 Rp(0, 1, 2, 3, 4, 30),
169 Rp(4, 0, 1, 2, 3, 31),
170 Rp(3, 4, 0, 1, 2, 32),
171 Rp(2, 3, 4, 0, 1, 33),
172 Rp(1, 2, 3, 4, 0, 34),
173 Rp(0, 1, 2, 3, 4, 35),
174 Rp(4, 0, 1, 2, 3, 36),
175 Rp(3, 4, 0, 1, 2, 37),
176 Rp(2, 3, 4, 0, 1, 38),
177 Rp(1, 2, 3, 4, 0, 39),
178 };
179 inline for (round1) |r| {
180 const t = s[(r.i-3) & 0xf] ^ s[(r.i-8) & 0xf] ^ s[(r.i-14) & 0xf] ^ s[(r.i-16) & 0xf];
181 s[r.i & 0xf] = math.rotl(u32, t, u32(1));
182
183 v[r.e] = v[r.e] +% math.rotl(u32, v[r.a], u32(5)) +% 0x6ED9EBA1 +% s[r.i & 0xf]
184 +% (v[r.b] ^ v[r.c] ^ v[r.d]);
185 v[r.b] = math.rotl(u32, v[r.b], u32(30));
186 }
187
188 const round2 = comptime []RoundParam {
189 Rp(0, 1, 2, 3, 4, 40),
190 Rp(4, 0, 1, 2, 3, 41),
191 Rp(3, 4, 0, 1, 2, 42),
192 Rp(2, 3, 4, 0, 1, 43),
193 Rp(1, 2, 3, 4, 0, 44),
194 Rp(0, 1, 2, 3, 4, 45),
195 Rp(4, 0, 1, 2, 3, 46),
196 Rp(3, 4, 0, 1, 2, 47),
197 Rp(2, 3, 4, 0, 1, 48),
198 Rp(1, 2, 3, 4, 0, 49),
199 Rp(0, 1, 2, 3, 4, 50),
200 Rp(4, 0, 1, 2, 3, 51),
201 Rp(3, 4, 0, 1, 2, 52),
202 Rp(2, 3, 4, 0, 1, 53),
203 Rp(1, 2, 3, 4, 0, 54),
204 Rp(0, 1, 2, 3, 4, 55),
205 Rp(4, 0, 1, 2, 3, 56),
206 Rp(3, 4, 0, 1, 2, 57),
207 Rp(2, 3, 4, 0, 1, 58),
208 Rp(1, 2, 3, 4, 0, 59),
209 };
210 inline for (round2) |r| {
211 const t = s[(r.i-3) & 0xf] ^ s[(r.i-8) & 0xf] ^ s[(r.i-14) & 0xf] ^ s[(r.i-16) & 0xf];
212 s[r.i & 0xf] = math.rotl(u32, t, u32(1));
213
214 v[r.e] = v[r.e] +% math.rotl(u32, v[r.a], u32(5)) +% 0x8F1BBCDC +% s[r.i & 0xf]
215 +% ((v[r.b] & v[r.c]) ^ (v[r.b] & v[r.d]) ^ (v[r.c] & v[r.d]));
216 v[r.b] = math.rotl(u32, v[r.b], u32(30));
217 }
218
219 const round3 = comptime []RoundParam {
220 Rp(0, 1, 2, 3, 4, 60),
221 Rp(4, 0, 1, 2, 3, 61),
222 Rp(3, 4, 0, 1, 2, 62),
223 Rp(2, 3, 4, 0, 1, 63),
224 Rp(1, 2, 3, 4, 0, 64),
225 Rp(0, 1, 2, 3, 4, 65),
226 Rp(4, 0, 1, 2, 3, 66),
227 Rp(3, 4, 0, 1, 2, 67),
228 Rp(2, 3, 4, 0, 1, 68),
229 Rp(1, 2, 3, 4, 0, 69),
230 Rp(0, 1, 2, 3, 4, 70),
231 Rp(4, 0, 1, 2, 3, 71),
232 Rp(3, 4, 0, 1, 2, 72),
233 Rp(2, 3, 4, 0, 1, 73),
234 Rp(1, 2, 3, 4, 0, 74),
235 Rp(0, 1, 2, 3, 4, 75),
236 Rp(4, 0, 1, 2, 3, 76),
237 Rp(3, 4, 0, 1, 2, 77),
238 Rp(2, 3, 4, 0, 1, 78),
239 Rp(1, 2, 3, 4, 0, 79),
240 };
241 inline for (round3) |r| {
242 const t = s[(r.i-3) & 0xf] ^ s[(r.i-8) & 0xf] ^ s[(r.i-14) & 0xf] ^ s[(r.i-16) & 0xf];
243 s[r.i & 0xf] = math.rotl(u32, t, u32(1));
244
245 v[r.e] = v[r.e] +% math.rotl(u32, v[r.a], u32(5)) +% 0xCA62C1D6 +% s[r.i & 0xf]
246 +% (v[r.b] ^ v[r.c] ^ v[r.d]);
247 v[r.b] = math.rotl(u32, v[r.b], u32(30));
248 }
249
250 d.s[0] +%= v[0];
251 d.s[1] +%= v[1];
252 d.s[2] +%= v[2];
253 d.s[3] +%= v[3];
254 d.s[4] +%= v[4];
255 }
256};
257
258const htest = @import("test.zig");
259
260test "sha1 single" {
261 htest.assertEqualHash(Sha1, "da39a3ee5e6b4b0d3255bfef95601890afd80709", "");
262 htest.assertEqualHash(Sha1, "a9993e364706816aba3e25717850c26c9cd0d89d", "abc");
263 htest.assertEqualHash(Sha1, "a49b2446a02c645bf419f995b67091253a04a259", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu");
264}
265
266test "sha1 streaming" {
267 var h = Sha1.init();
268 var out: [20]u8 = undefined;
269
270 h.final(out[0..]);
271 htest.assertEqual("da39a3ee5e6b4b0d3255bfef95601890afd80709", out[0..]);
272
273 h.reset();
274 h.update("abc");
275 h.final(out[0..]);
276 htest.assertEqual("a9993e364706816aba3e25717850c26c9cd0d89d", out[0..]);
277
278 h.reset();
279 h.update("a");
280 h.update("b");
281 h.update("c");
282 h.final(out[0..]);
283 htest.assertEqual("a9993e364706816aba3e25717850c26c9cd0d89d", out[0..]);
284}
std/crypto/sha2.zig created+670
......@@ -0,0 +1,670 @@
1const mem = @import("../mem.zig");
2const math = @import("../math/index.zig");
3const endian = @import("../endian.zig");
4const debug = @import("../debug/index.zig");
5const builtin = @import("builtin");
6const htest = @import("test.zig");
7
8/////////////////////
9// Sha224 + Sha256
10
11const RoundParam256 = struct {
12 a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, g: usize, h: usize,
13 i: usize, k: u32,
14};
15
16fn Rp256(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, g: usize, h: usize, i: usize, k: u32) -> RoundParam256 {
17 return RoundParam256 { .a = a, .b = b, .c = c, .d = d, .e = e, .f = f, .g = g, .h = h, .i = i, .k = k };
18}
19
20const Sha2Params32 = struct {
21 iv0: u32,
22 iv1: u32,
23 iv2: u32,
24 iv3: u32,
25 iv4: u32,
26 iv5: u32,
27 iv6: u32,
28 iv7: u32,
29 out_len: usize,
30};
31
32const Sha224Params = Sha2Params32 {
33 .iv0 = 0xC1059ED8,
34 .iv1 = 0x367CD507,
35 .iv2 = 0x3070DD17,
36 .iv3 = 0xF70E5939,
37 .iv4 = 0xFFC00B31,
38 .iv5 = 0x68581511,
39 .iv6 = 0x64F98FA7,
40 .iv7 = 0xBEFA4FA4,
41 .out_len = 224,
42};
43
44const Sha256Params = Sha2Params32 {
45 .iv0 = 0x6A09E667,
46 .iv1 = 0xBB67AE85,
47 .iv2 = 0x3C6EF372,
48 .iv3 = 0xA54FF53A,
49 .iv4 = 0x510E527F,
50 .iv5 = 0x9B05688C,
51 .iv6 = 0x1F83D9AB,
52 .iv7 = 0x5BE0CD19,
53 .out_len = 256,
54};
55
56pub const Sha224 = Sha2_32(Sha224Params);
57pub const Sha256 = Sha2_32(Sha256Params);
58
59fn Sha2_32(comptime params: Sha2Params32) -> type { return struct {
60 const Self = this;
61
62 s: [8]u32,
63 // Streaming Cache
64 buf: [64]u8,
65 buf_len: u8,
66 total_len: u64,
67
68 pub fn init() -> Self {
69 var d: Self = undefined;
70 d.reset();
71 return d;
72 }
73
74 pub fn reset(d: &Self) {
75 d.s[0] = params.iv0;
76 d.s[1] = params.iv1;
77 d.s[2] = params.iv2;
78 d.s[3] = params.iv3;
79 d.s[4] = params.iv4;
80 d.s[5] = params.iv5;
81 d.s[6] = params.iv6;
82 d.s[7] = params.iv7;
83 d.buf_len = 0;
84 d.total_len = 0;
85 }
86
87 pub fn hash(b: []const u8, out: []u8) {
88 var d = Self.init();
89 d.update(b);
90 d.final(out);
91 }
92
93 pub fn update(d: &Self, b: []const u8) {
94 var off: usize = 0;
95
96 // Partial buffer exists from previous update. Copy into buffer then hash.
97 if (d.buf_len != 0 and d.buf_len + b.len > 64) {
98 off += 64 - d.buf_len;
99 mem.copy(u8, d.buf[d.buf_len..], b[0..off]);
100
101 d.round(d.buf[0..]);
102 d.buf_len = 0;
103 }
104
105 // Full middle blocks.
106 while (off + 64 < b.len) : (off += 64) {
107 d.round(b[off..off + 64]);
108 }
109
110 // Copy any remainder for next pass.
111 mem.copy(u8, d.buf[d.buf_len..], b[off..]);
112 d.buf_len += u8(b[off..].len);
113
114 d.total_len += b.len;
115 }
116
117 pub fn final(d: &Self, out: []u8) {
118 debug.assert(out.len >= params.out_len / 8);
119
120 // The buffer here will never be completely full.
121 mem.set(u8, d.buf[d.buf_len..], 0);
122
123 // Append padding bits.
124 d.buf[d.buf_len] = 0x80;
125 d.buf_len += 1;
126
127 // > 448 mod 512 so need to add an extra round to wrap around.
128 if (64 - d.buf_len < 8) {
129 d.round(d.buf[0..]);
130 mem.set(u8, d.buf[0..], 0);
131 }
132
133 // Append message length.
134 var i: usize = 1;
135 var len = d.total_len >> 5;
136 d.buf[63] = u8(d.total_len & 0x1f) << 3;
137 while (i < 8) : (i += 1) {
138 d.buf[63 - i] = u8(len & 0xff);
139 len >>= 8;
140 }
141
142 d.round(d.buf[0..]);
143
144 // May truncate for possible 224 output
145 const rr = d.s[0 .. params.out_len / 32];
146
147 for (rr) |s, j| {
148 mem.writeInt(out[4*j .. 4*j + 4], s, builtin.Endian.Big);
149 }
150 }
151
152 fn round(d: &Self, b: []const u8) {
153 debug.assert(b.len == 64);
154
155 var s: [64]u32 = undefined;
156
157 // ERROR: Cannot unroll at compile-time.
158 var i: usize = 0;
159 while (i < 16) : (i += 1) {
160 s[i] = 0;
161 s[i] |= u32(b[i*4+0]) << 24;
162 s[i] |= u32(b[i*4+1]) << 16;
163 s[i] |= u32(b[i*4+2]) << 8;
164 s[i] |= u32(b[i*4+3]) << 0;
165 }
166 while (i < 64) : (i += 1) {
167 s[i] =
168 s[i-16] +% s[i-7] +%
169 (math.rotr(u32, s[i-15], u32(7)) ^ math.rotr(u32, s[i-15], u32(18)) ^ (s[i-15] >> 3)) +%
170 (math.rotr(u32, s[i-2], u32(17)) ^ math.rotr(u32, s[i-2], u32(19)) ^ (s[i-2] >> 10));
171 }
172
173 var v: [8]u32 = []u32 {
174 d.s[0], d.s[1], d.s[2], d.s[3], d.s[4], d.s[5], d.s[6], d.s[7],
175 };
176
177 const round0 = comptime []RoundParam256 {
178 Rp256(0, 1, 2, 3, 4, 5, 6, 7, 0, 0x428A2F98),
179 Rp256(7, 0, 1, 2, 3, 4, 5, 6, 1, 0x71374491),
180 Rp256(6, 7, 0, 1, 2, 3, 4, 5, 2, 0xB5C0FBCF),
181 Rp256(5, 6, 7, 0, 1, 2, 3, 4, 3, 0xE9B5DBA5),
182 Rp256(4, 5, 6, 7, 0, 1, 2, 3, 4, 0x3956C25B),
183 Rp256(3, 4, 5, 6, 7, 0, 1, 2, 5, 0x59F111F1),
184 Rp256(2, 3, 4, 5, 6, 7, 0, 1, 6, 0x923F82A4),
185 Rp256(1, 2, 3, 4, 5, 6, 7, 0, 7, 0xAB1C5ED5),
186 Rp256(0, 1, 2, 3, 4, 5, 6, 7, 8, 0xD807AA98),
187 Rp256(7, 0, 1, 2, 3, 4, 5, 6, 9, 0x12835B01),
188 Rp256(6, 7, 0, 1, 2, 3, 4, 5, 10, 0x243185BE),
189 Rp256(5, 6, 7, 0, 1, 2, 3, 4, 11, 0x550C7DC3),
190 Rp256(4, 5, 6, 7, 0, 1, 2, 3, 12, 0x72BE5D74),
191 Rp256(3, 4, 5, 6, 7, 0, 1, 2, 13, 0x80DEB1FE),
192 Rp256(2, 3, 4, 5, 6, 7, 0, 1, 14, 0x9BDC06A7),
193 Rp256(1, 2, 3, 4, 5, 6, 7, 0, 15, 0xC19BF174),
194 Rp256(0, 1, 2, 3, 4, 5, 6, 7, 16, 0xE49B69C1),
195 Rp256(7, 0, 1, 2, 3, 4, 5, 6, 17, 0xEFBE4786),
196 Rp256(6, 7, 0, 1, 2, 3, 4, 5, 18, 0x0FC19DC6),
197 Rp256(5, 6, 7, 0, 1, 2, 3, 4, 19, 0x240CA1CC),
198 Rp256(4, 5, 6, 7, 0, 1, 2, 3, 20, 0x2DE92C6F),
199 Rp256(3, 4, 5, 6, 7, 0, 1, 2, 21, 0x4A7484AA),
200 Rp256(2, 3, 4, 5, 6, 7, 0, 1, 22, 0x5CB0A9DC),
201 Rp256(1, 2, 3, 4, 5, 6, 7, 0, 23, 0x76F988DA),
202 Rp256(0, 1, 2, 3, 4, 5, 6, 7, 24, 0x983E5152),
203 Rp256(7, 0, 1, 2, 3, 4, 5, 6, 25, 0xA831C66D),
204 Rp256(6, 7, 0, 1, 2, 3, 4, 5, 26, 0xB00327C8),
205 Rp256(5, 6, 7, 0, 1, 2, 3, 4, 27, 0xBF597FC7),
206 Rp256(4, 5, 6, 7, 0, 1, 2, 3, 28, 0xC6E00BF3),
207 Rp256(3, 4, 5, 6, 7, 0, 1, 2, 29, 0xD5A79147),
208 Rp256(2, 3, 4, 5, 6, 7, 0, 1, 30, 0x06CA6351),
209 Rp256(1, 2, 3, 4, 5, 6, 7, 0, 31, 0x14292967),
210 Rp256(0, 1, 2, 3, 4, 5, 6, 7, 32, 0x27B70A85),
211 Rp256(7, 0, 1, 2, 3, 4, 5, 6, 33, 0x2E1B2138),
212 Rp256(6, 7, 0, 1, 2, 3, 4, 5, 34, 0x4D2C6DFC),
213 Rp256(5, 6, 7, 0, 1, 2, 3, 4, 35, 0x53380D13),
214 Rp256(4, 5, 6, 7, 0, 1, 2, 3, 36, 0x650A7354),
215 Rp256(3, 4, 5, 6, 7, 0, 1, 2, 37, 0x766A0ABB),
216 Rp256(2, 3, 4, 5, 6, 7, 0, 1, 38, 0x81C2C92E),
217 Rp256(1, 2, 3, 4, 5, 6, 7, 0, 39, 0x92722C85),
218 Rp256(0, 1, 2, 3, 4, 5, 6, 7, 40, 0xA2BFE8A1),
219 Rp256(7, 0, 1, 2, 3, 4, 5, 6, 41, 0xA81A664B),
220 Rp256(6, 7, 0, 1, 2, 3, 4, 5, 42, 0xC24B8B70),
221 Rp256(5, 6, 7, 0, 1, 2, 3, 4, 43, 0xC76C51A3),
222 Rp256(4, 5, 6, 7, 0, 1, 2, 3, 44, 0xD192E819),
223 Rp256(3, 4, 5, 6, 7, 0, 1, 2, 45, 0xD6990624),
224 Rp256(2, 3, 4, 5, 6, 7, 0, 1, 46, 0xF40E3585),
225 Rp256(1, 2, 3, 4, 5, 6, 7, 0, 47, 0x106AA070),
226 Rp256(0, 1, 2, 3, 4, 5, 6, 7, 48, 0x19A4C116),
227 Rp256(7, 0, 1, 2, 3, 4, 5, 6, 49, 0x1E376C08),
228 Rp256(6, 7, 0, 1, 2, 3, 4, 5, 50, 0x2748774C),
229 Rp256(5, 6, 7, 0, 1, 2, 3, 4, 51, 0x34B0BCB5),
230 Rp256(4, 5, 6, 7, 0, 1, 2, 3, 52, 0x391C0CB3),
231 Rp256(3, 4, 5, 6, 7, 0, 1, 2, 53, 0x4ED8AA4A),
232 Rp256(2, 3, 4, 5, 6, 7, 0, 1, 54, 0x5B9CCA4F),
233 Rp256(1, 2, 3, 4, 5, 6, 7, 0, 55, 0x682E6FF3),
234 Rp256(0, 1, 2, 3, 4, 5, 6, 7, 56, 0x748F82EE),
235 Rp256(7, 0, 1, 2, 3, 4, 5, 6, 57, 0x78A5636F),
236 Rp256(6, 7, 0, 1, 2, 3, 4, 5, 58, 0x84C87814),
237 Rp256(5, 6, 7, 0, 1, 2, 3, 4, 59, 0x8CC70208),
238 Rp256(4, 5, 6, 7, 0, 1, 2, 3, 60, 0x90BEFFFA),
239 Rp256(3, 4, 5, 6, 7, 0, 1, 2, 61, 0xA4506CEB),
240 Rp256(2, 3, 4, 5, 6, 7, 0, 1, 62, 0xBEF9A3F7),
241 Rp256(1, 2, 3, 4, 5, 6, 7, 0, 63, 0xC67178F2),
242 };
243 inline for (round0) |r| {
244 v[r.h] =
245 v[r.h] +%
246 (math.rotr(u32, v[r.e], u32(6)) ^ math.rotr(u32, v[r.e], u32(11)) ^ math.rotr(u32, v[r.e], u32(25))) +%
247 (v[r.g] ^ (v[r.e] & (v[r.f] ^ v[r.g]))) +%
248 r.k +% s[r.i];
249
250 v[r.d] = v[r.d] +% v[r.h];
251
252 v[r.h] =
253 v[r.h] +%
254 (math.rotr(u32, v[r.a], u32(2)) ^ math.rotr(u32, v[r.a], u32(13)) ^ math.rotr(u32, v[r.a], u32(22))) +%
255 ((v[r.a] & (v[r.b] | v[r.c])) | (v[r.b] & v[r.c]));
256 }
257
258 d.s[0] +%= v[0];
259 d.s[1] +%= v[1];
260 d.s[2] +%= v[2];
261 d.s[3] +%= v[3];
262 d.s[4] +%= v[4];
263 d.s[5] +%= v[5];
264 d.s[6] +%= v[6];
265 d.s[7] +%= v[7];
266 }
267};}
268
269test "sha224 single" {
270 htest.assertEqualHash(Sha224, "d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f", "");
271 htest.assertEqualHash(Sha224, "23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7", "abc");
272 htest.assertEqualHash(Sha224, "c97ca9a559850ce97a04a96def6d99a9e0e0e2ab14e6b8df265fc0b3", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu");
273}
274
275test "sha224 streaming" {
276 var h = Sha224.init();
277 var out: [28]u8 = undefined;
278
279 h.final(out[0..]);
280 htest.assertEqual("d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f", out[0..]);
281
282 h.reset();
283 h.update("abc");
284 h.final(out[0..]);
285 htest.assertEqual("23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7", out[0..]);
286
287 h.reset();
288 h.update("a");
289 h.update("b");
290 h.update("c");
291 h.final(out[0..]);
292 htest.assertEqual("23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7", out[0..]);
293}
294
295test "sha256 single" {
296 htest.assertEqualHash(Sha256, "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "");
297 htest.assertEqualHash(Sha256, "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", "abc");
298 htest.assertEqualHash(Sha256, "cf5b16a778af8380036ce59e7b0492370b249b11e8f07a51afac45037afee9d1", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu");
299}
300
301test "sha256 streaming" {
302 var h = Sha256.init();
303 var out: [32]u8 = undefined;
304
305 h.final(out[0..]);
306 htest.assertEqual("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", out[0..]);
307
308 h.reset();
309 h.update("abc");
310 h.final(out[0..]);
311 htest.assertEqual("ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", out[0..]);
312
313 h.reset();
314 h.update("a");
315 h.update("b");
316 h.update("c");
317 h.final(out[0..]);
318 htest.assertEqual("ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", out[0..]);
319}
320
321
322/////////////////////
323// Sha384 + Sha512
324
325const RoundParam512 = struct {
326 a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, g: usize, h: usize,
327 i: usize, k: u64,
328};
329
330fn Rp512(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, g: usize, h: usize, i: usize, k: u64) -> RoundParam512 {
331 return RoundParam512 { .a = a, .b = b, .c = c, .d = d, .e = e, .f = f, .g = g, .h = h, .i = i, .k = k };
332}
333
334const Sha2Params64 = struct {
335 iv0: u64,
336 iv1: u64,
337 iv2: u64,
338 iv3: u64,
339 iv4: u64,
340 iv5: u64,
341 iv6: u64,
342 iv7: u64,
343 out_len: usize,
344};
345
346const Sha384Params = Sha2Params64 {
347 .iv0 = 0xCBBB9D5DC1059ED8,
348 .iv1 = 0x629A292A367CD507,
349 .iv2 = 0x9159015A3070DD17,
350 .iv3 = 0x152FECD8F70E5939,
351 .iv4 = 0x67332667FFC00B31,
352 .iv5 = 0x8EB44A8768581511,
353 .iv6 = 0xDB0C2E0D64F98FA7,
354 .iv7 = 0x47B5481DBEFA4FA4,
355 .out_len = 384,
356};
357
358const Sha512Params = Sha2Params64 {
359 .iv0 = 0x6A09E667F3BCC908,
360 .iv1 = 0xBB67AE8584CAA73B,
361 .iv2 = 0x3C6EF372FE94F82B,
362 .iv3 = 0xA54FF53A5F1D36F1,
363 .iv4 = 0x510E527FADE682D1,
364 .iv5 = 0x9B05688C2B3E6C1F,
365 .iv6 = 0x1F83D9ABFB41BD6B,
366 .iv7 = 0x5BE0CD19137E2179,
367 .out_len = 512
368};
369
370pub const Sha384 = Sha2_64(Sha384Params);
371pub const Sha512 = Sha2_64(Sha512Params);
372
373fn Sha2_64(comptime params: Sha2Params64) -> type { return struct {
374 const Self = this;
375 const u9 = @IntType(false, 9);
376
377 s: [8]u64,
378 // Streaming Cache
379 buf: [128]u8,
380 buf_len: u8,
381 total_len: u128,
382
383 pub fn init() -> Self {
384 var d: Self = undefined;
385 d.reset();
386 return d;
387 }
388
389 pub fn reset(d: &Self) {
390 d.s[0] = params.iv0;
391 d.s[1] = params.iv1;
392 d.s[2] = params.iv2;
393 d.s[3] = params.iv3;
394 d.s[4] = params.iv4;
395 d.s[5] = params.iv5;
396 d.s[6] = params.iv6;
397 d.s[7] = params.iv7;
398 d.buf_len = 0;
399 d.total_len = 0;
400 }
401
402 pub fn hash(b: []const u8, out: []u8) {
403 var d = Self.init();
404 d.update(b);
405 d.final(out);
406 }
407
408 pub fn update(d: &Self, b: []const u8) {
409 var off: usize = 0;
410
411 // Partial buffer exists from previous update. Copy into buffer then hash.
412 if (d.buf_len != 0 and d.buf_len + b.len > 128) {
413 off += 128 - d.buf_len;
414 mem.copy(u8, d.buf[d.buf_len..], b[0..off]);
415
416 d.round(d.buf[0..]);
417 d.buf_len = 0;
418 }
419
420 // Full middle blocks.
421 while (off + 128 < b.len) : (off += 128) {
422 d.round(b[off..off + 128]);
423 }
424
425 // Copy any remainder for next pass.
426 mem.copy(u8, d.buf[d.buf_len..], b[off..]);
427 d.buf_len += u8(b[off..].len);
428
429 d.total_len += b.len;
430 }
431
432 pub fn final(d: &Self, out: []u8) {
433 debug.assert(out.len >= params.out_len / 8);
434
435 // The buffer here will never be completely full.
436 mem.set(u8, d.buf[d.buf_len..], 0);
437
438 // Append padding bits.
439 d.buf[d.buf_len] = 0x80;
440 d.buf_len += 1;
441
442 // > 896 mod 1024 so need to add an extra round to wrap around.
443 if (128 - d.buf_len < 16) {
444 d.round(d.buf[0..]);
445 mem.set(u8, d.buf[0..], 0);
446 }
447
448 // Append message length.
449 var i: usize = 1;
450 var len = d.total_len >> 5;
451 d.buf[127] = u8(d.total_len & 0x1f) << 3;
452 while (i < 16) : (i += 1) {
453 d.buf[127 - i] = u8(len & 0xff);
454 len >>= 8;
455 }
456
457 d.round(d.buf[0..]);
458
459 // May truncate for possible 384 output
460 const rr = d.s[0 .. params.out_len / 64];
461
462 for (rr) |s, j| {
463 mem.writeInt(out[8*j .. 8*j + 8], s, builtin.Endian.Big);
464 }
465 }
466
467 fn round(d: &Self, b: []const u8) {
468 debug.assert(b.len == 128);
469
470 var s: [80]u64 = undefined;
471
472 // ERROR: Cannot unroll at compile-time.
473 var i: usize = 0;
474 while (i < 16) : (i += 1) {
475 s[i] = 0;
476 s[i] |= u64(b[i*8+0]) << 56;
477 s[i] |= u64(b[i*8+1]) << 48;
478 s[i] |= u64(b[i*8+2]) << 40;
479 s[i] |= u64(b[i*8+3]) << 32;
480 s[i] |= u64(b[i*8+4]) << 24;
481 s[i] |= u64(b[i*8+5]) << 16;
482 s[i] |= u64(b[i*8+6]) << 8;
483 s[i] |= u64(b[i*8+7]) << 0;
484 }
485 while (i < 80) : (i += 1) {
486 s[i] =
487 s[i-16] +% s[i-7] +%
488 (math.rotr(u64, s[i-15], u64(1)) ^ math.rotr(u64, s[i-15], u64(8)) ^ (s[i-15] >> 7)) +%
489 (math.rotr(u64, s[i-2], u64(19)) ^ math.rotr(u64, s[i-2], u64(61)) ^ (s[i-2] >> 6));
490 }
491
492 var v: [8]u64 = []u64 {
493 d.s[0], d.s[1], d.s[2], d.s[3], d.s[4], d.s[5], d.s[6], d.s[7],
494 };
495
496 const round0 = comptime []RoundParam512 {
497 Rp512(0, 1, 2, 3, 4, 5, 6, 7, 0, 0x428A2F98D728AE22),
498 Rp512(7, 0, 1, 2, 3, 4, 5, 6, 1, 0x7137449123EF65CD),
499 Rp512(6, 7, 0, 1, 2, 3, 4, 5, 2, 0xB5C0FBCFEC4D3B2F),
500 Rp512(5, 6, 7, 0, 1, 2, 3, 4, 3, 0xE9B5DBA58189DBBC),
501 Rp512(4, 5, 6, 7, 0, 1, 2, 3, 4, 0x3956C25BF348B538),
502 Rp512(3, 4, 5, 6, 7, 0, 1, 2, 5, 0x59F111F1B605D019),
503 Rp512(2, 3, 4, 5, 6, 7, 0, 1, 6, 0x923F82A4AF194F9B),
504 Rp512(1, 2, 3, 4, 5, 6, 7, 0, 7, 0xAB1C5ED5DA6D8118),
505 Rp512(0, 1, 2, 3, 4, 5, 6, 7, 8, 0xD807AA98A3030242),
506 Rp512(7, 0, 1, 2, 3, 4, 5, 6, 9, 0x12835B0145706FBE),
507 Rp512(6, 7, 0, 1, 2, 3, 4, 5, 10, 0x243185BE4EE4B28C),
508 Rp512(5, 6, 7, 0, 1, 2, 3, 4, 11, 0x550C7DC3D5FFB4E2),
509 Rp512(4, 5, 6, 7, 0, 1, 2, 3, 12, 0x72BE5D74F27B896F),
510 Rp512(3, 4, 5, 6, 7, 0, 1, 2, 13, 0x80DEB1FE3B1696B1),
511 Rp512(2, 3, 4, 5, 6, 7, 0, 1, 14, 0x9BDC06A725C71235),
512 Rp512(1, 2, 3, 4, 5, 6, 7, 0, 15, 0xC19BF174CF692694),
513 Rp512(0, 1, 2, 3, 4, 5, 6, 7, 16, 0xE49B69C19EF14AD2),
514 Rp512(7, 0, 1, 2, 3, 4, 5, 6, 17, 0xEFBE4786384F25E3),
515 Rp512(6, 7, 0, 1, 2, 3, 4, 5, 18, 0x0FC19DC68B8CD5B5),
516 Rp512(5, 6, 7, 0, 1, 2, 3, 4, 19, 0x240CA1CC77AC9C65),
517 Rp512(4, 5, 6, 7, 0, 1, 2, 3, 20, 0x2DE92C6F592B0275),
518 Rp512(3, 4, 5, 6, 7, 0, 1, 2, 21, 0x4A7484AA6EA6E483),
519 Rp512(2, 3, 4, 5, 6, 7, 0, 1, 22, 0x5CB0A9DCBD41FBD4),
520 Rp512(1, 2, 3, 4, 5, 6, 7, 0, 23, 0x76F988DA831153B5),
521 Rp512(0, 1, 2, 3, 4, 5, 6, 7, 24, 0x983E5152EE66DFAB),
522 Rp512(7, 0, 1, 2, 3, 4, 5, 6, 25, 0xA831C66D2DB43210),
523 Rp512(6, 7, 0, 1, 2, 3, 4, 5, 26, 0xB00327C898FB213F),
524 Rp512(5, 6, 7, 0, 1, 2, 3, 4, 27, 0xBF597FC7BEEF0EE4),
525 Rp512(4, 5, 6, 7, 0, 1, 2, 3, 28, 0xC6E00BF33DA88FC2),
526 Rp512(3, 4, 5, 6, 7, 0, 1, 2, 29, 0xD5A79147930AA725),
527 Rp512(2, 3, 4, 5, 6, 7, 0, 1, 30, 0x06CA6351E003826F),
528 Rp512(1, 2, 3, 4, 5, 6, 7, 0, 31, 0x142929670A0E6E70),
529 Rp512(0, 1, 2, 3, 4, 5, 6, 7, 32, 0x27B70A8546D22FFC),
530 Rp512(7, 0, 1, 2, 3, 4, 5, 6, 33, 0x2E1B21385C26C926),
531 Rp512(6, 7, 0, 1, 2, 3, 4, 5, 34, 0x4D2C6DFC5AC42AED),
532 Rp512(5, 6, 7, 0, 1, 2, 3, 4, 35, 0x53380D139D95B3DF),
533 Rp512(4, 5, 6, 7, 0, 1, 2, 3, 36, 0x650A73548BAF63DE),
534 Rp512(3, 4, 5, 6, 7, 0, 1, 2, 37, 0x766A0ABB3C77B2A8),
535 Rp512(2, 3, 4, 5, 6, 7, 0, 1, 38, 0x81C2C92E47EDAEE6),
536 Rp512(1, 2, 3, 4, 5, 6, 7, 0, 39, 0x92722C851482353B),
537 Rp512(0, 1, 2, 3, 4, 5, 6, 7, 40, 0xA2BFE8A14CF10364),
538 Rp512(7, 0, 1, 2, 3, 4, 5, 6, 41, 0xA81A664BBC423001),
539 Rp512(6, 7, 0, 1, 2, 3, 4, 5, 42, 0xC24B8B70D0F89791),
540 Rp512(5, 6, 7, 0, 1, 2, 3, 4, 43, 0xC76C51A30654BE30),
541 Rp512(4, 5, 6, 7, 0, 1, 2, 3, 44, 0xD192E819D6EF5218),
542 Rp512(3, 4, 5, 6, 7, 0, 1, 2, 45, 0xD69906245565A910),
543 Rp512(2, 3, 4, 5, 6, 7, 0, 1, 46, 0xF40E35855771202A),
544 Rp512(1, 2, 3, 4, 5, 6, 7, 0, 47, 0x106AA07032BBD1B8),
545 Rp512(0, 1, 2, 3, 4, 5, 6, 7, 48, 0x19A4C116B8D2D0C8),
546 Rp512(7, 0, 1, 2, 3, 4, 5, 6, 49, 0x1E376C085141AB53),
547 Rp512(6, 7, 0, 1, 2, 3, 4, 5, 50, 0x2748774CDF8EEB99),
548 Rp512(5, 6, 7, 0, 1, 2, 3, 4, 51, 0x34B0BCB5E19B48A8),
549 Rp512(4, 5, 6, 7, 0, 1, 2, 3, 52, 0x391C0CB3C5C95A63),
550 Rp512(3, 4, 5, 6, 7, 0, 1, 2, 53, 0x4ED8AA4AE3418ACB),
551 Rp512(2, 3, 4, 5, 6, 7, 0, 1, 54, 0x5B9CCA4F7763E373),
552 Rp512(1, 2, 3, 4, 5, 6, 7, 0, 55, 0x682E6FF3D6B2B8A3),
553 Rp512(0, 1, 2, 3, 4, 5, 6, 7, 56, 0x748F82EE5DEFB2FC),
554 Rp512(7, 0, 1, 2, 3, 4, 5, 6, 57, 0x78A5636F43172F60),
555 Rp512(6, 7, 0, 1, 2, 3, 4, 5, 58, 0x84C87814A1F0AB72),
556 Rp512(5, 6, 7, 0, 1, 2, 3, 4, 59, 0x8CC702081A6439EC),
557 Rp512(4, 5, 6, 7, 0, 1, 2, 3, 60, 0x90BEFFFA23631E28),
558 Rp512(3, 4, 5, 6, 7, 0, 1, 2, 61, 0xA4506CEBDE82BDE9),
559 Rp512(2, 3, 4, 5, 6, 7, 0, 1, 62, 0xBEF9A3F7B2C67915),
560 Rp512(1, 2, 3, 4, 5, 6, 7, 0, 63, 0xC67178F2E372532B),
561 Rp512(0, 1, 2, 3, 4, 5, 6, 7, 64, 0xCA273ECEEA26619C),
562 Rp512(7, 0, 1, 2, 3, 4, 5, 6, 65, 0xD186B8C721C0C207),
563 Rp512(6, 7, 0, 1, 2, 3, 4, 5, 66, 0xEADA7DD6CDE0EB1E),
564 Rp512(5, 6, 7, 0, 1, 2, 3, 4, 67, 0xF57D4F7FEE6ED178),
565 Rp512(4, 5, 6, 7, 0, 1, 2, 3, 68, 0x06F067AA72176FBA),
566 Rp512(3, 4, 5, 6, 7, 0, 1, 2, 69, 0x0A637DC5A2C898A6),
567 Rp512(2, 3, 4, 5, 6, 7, 0, 1, 70, 0x113F9804BEF90DAE),
568 Rp512(1, 2, 3, 4, 5, 6, 7, 0, 71, 0x1B710B35131C471B),
569 Rp512(0, 1, 2, 3, 4, 5, 6, 7, 72, 0x28DB77F523047D84),
570 Rp512(7, 0, 1, 2, 3, 4, 5, 6, 73, 0x32CAAB7B40C72493),
571 Rp512(6, 7, 0, 1, 2, 3, 4, 5, 74, 0x3C9EBE0A15C9BEBC),
572 Rp512(5, 6, 7, 0, 1, 2, 3, 4, 75, 0x431D67C49C100D4C),
573 Rp512(4, 5, 6, 7, 0, 1, 2, 3, 76, 0x4CC5D4BECB3E42B6),
574 Rp512(3, 4, 5, 6, 7, 0, 1, 2, 77, 0x597F299CFC657E2A),
575 Rp512(2, 3, 4, 5, 6, 7, 0, 1, 78, 0x5FCB6FAB3AD6FAEC),
576 Rp512(1, 2, 3, 4, 5, 6, 7, 0, 79, 0x6C44198C4A475817),
577 };
578 inline for (round0) |r| {
579 v[r.h] =
580 v[r.h] +%
581 (math.rotr(u64, v[r.e], u64(14)) ^ math.rotr(u64, v[r.e], u64(18)) ^ math.rotr(u64, v[r.e], u64(41))) +%
582 (v[r.g] ^ (v[r.e] & (v[r.f] ^ v[r.g]))) +%
583 r.k +% s[r.i];
584
585 v[r.d] = v[r.d] +% v[r.h];
586
587 v[r.h] =
588 v[r.h] +%
589 (math.rotr(u64, v[r.a], u64(28)) ^ math.rotr(u64, v[r.a], u64(34)) ^ math.rotr(u64, v[r.a], u64(39))) +%
590 ((v[r.a] & (v[r.b] | v[r.c])) | (v[r.b] & v[r.c]));
591 }
592
593 d.s[0] +%= v[0];
594 d.s[1] +%= v[1];
595 d.s[2] +%= v[2];
596 d.s[3] +%= v[3];
597 d.s[4] +%= v[4];
598 d.s[5] +%= v[5];
599 d.s[6] +%= v[6];
600 d.s[7] +%= v[7];
601 }
602};}
603
604test "sha384 single" {
605 const h1 = "38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b";
606 htest.assertEqualHash(Sha384, h1, "");
607
608 const h2 = "cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7";
609 htest.assertEqualHash(Sha384, h2, "abc");
610
611 const h3 = "09330c33f71147e83d192fc782cd1b4753111b173b3b05d22fa08086e3b0f712fcc7c71a557e2db966c3e9fa91746039";
612 htest.assertEqualHash(Sha384, h3, "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu");
613}
614
615test "sha384 streaming" {
616 var h = Sha384.init();
617 var out: [48]u8 = undefined;
618
619 const h1 = "38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b";
620 h.final(out[0..]);
621 htest.assertEqual(h1, out[0..]);
622
623 const h2 = "cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7";
624
625 h.reset();
626 h.update("abc");
627 h.final(out[0..]);
628 htest.assertEqual(h2, out[0..]);
629
630 h.reset();
631 h.update("a");
632 h.update("b");
633 h.update("c");
634 h.final(out[0..]);
635 htest.assertEqual(h2, out[0..]);
636}
637
638test "sha512 single" {
639 const h1 = "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e";
640 htest.assertEqualHash(Sha512, h1, "");
641
642 const h2 = "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f";
643 htest.assertEqualHash(Sha512, h2, "abc");
644
645 const h3 = "8e959b75dae313da8cf4f72814fc143f8f7779c6eb9f7fa17299aeadb6889018501d289e4900f7e4331b99dec4b5433ac7d329eeb6dd26545e96e55b874be909";
646 htest.assertEqualHash(Sha512, h3, "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu");
647}
648
649test "sha512 streaming" {
650 var h = Sha512.init();
651 var out: [64]u8 = undefined;
652
653 const h1 = "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e";
654 h.final(out[0..]);
655 htest.assertEqual(h1, out[0..]);
656
657 const h2 = "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f";
658
659 h.reset();
660 h.update("abc");
661 h.final(out[0..]);
662 htest.assertEqual(h2, out[0..]);
663
664 h.reset();
665 h.update("a");
666 h.update("b");
667 h.update("c");
668 h.final(out[0..]);
669 htest.assertEqual(h2, out[0..]);
670}
std/crypto/test.zig created+22
......@@ -0,0 +1,22 @@
1const debug = @import("../debug/index.zig");
2const mem = @import("../mem.zig");
3const fmt = @import("../fmt/index.zig");
4
5// Hash using the specified hasher `H` asserting `expected == H(input)`.
6pub fn assertEqualHash(comptime Hasher: var, comptime expected: []const u8, input: []const u8) {
7 var h: [expected.len / 2]u8 = undefined;
8 Hasher.hash(input, h[0..]);
9
10 assertEqual(expected, h);
11}
12
13// Assert `expected` == `input` where `input` is a bytestring.
14pub fn assertEqual(comptime expected: []const u8, input: []const u8) {
15 var expected_bytes: [expected.len / 2]u8 = undefined;
16 for (expected_bytes) |*r, i| {
17 *r = fmt.parseInt(u8, expected[2*i .. 2*i+2], 16) catch unreachable;
18 }
19
20 debug.assert(mem.eql(u8, expected_bytes, input));
21}
22
std/debug/index.zig+149-63
......@@ -13,6 +13,10 @@ pub const FailingAllocator = @import("failing_allocator.zig").FailingAllocator;
1313error MissingDebugInfo;
1414error InvalidDebugInfo;
1515error UnsupportedDebugInfo;
16error UnknownObjectFormat;
17error TodoSupportCoffDebugInfo;
18error TodoSupportMachoDebugInfo;
19error TodoSupportCOFFDebugInfo;
1620
1721
1822/// Tries to write to stderr, unbuffered, and ignores any error returned.
......@@ -37,10 +41,43 @@ fn getStderrStream() -> %&io.OutStream {
3741 }
3842}
3943
44var self_debug_info: ?&ElfStackTrace = null;
45pub fn getSelfDebugInfo() -> %&ElfStackTrace {
46 if (self_debug_info) |info| {
47 return info;
48 } else {
49 const info = try openSelfDebugInfo(global_allocator);
50 self_debug_info = info;
51 return info;
52 }
53}
54
55/// Tries to print the current stack trace to stderr, unbuffered, and ignores any error returned.
56pub fn dumpCurrentStackTrace() {
57 const stderr = getStderrStream() catch return;
58 const debug_info = getSelfDebugInfo() catch |err| {
59 stderr.print("Unable to open debug info: {}\n", @errorName(err)) catch return;
60 return;
61 };
62 defer debug_info.close();
63 writeCurrentStackTrace(stderr, global_allocator, debug_info, stderr_file.isTty(), 1) catch |err| {
64 stderr.print("Unable to dump stack trace: {}\n", @errorName(err)) catch return;
65 return;
66 };
67}
68
4069/// Tries to print a stack trace to stderr, unbuffered, and ignores any error returned.
41pub fn dumpStackTrace() {
70pub fn dumpStackTrace(stack_trace: &const builtin.StackTrace) {
4271 const stderr = getStderrStream() catch return;
43 writeStackTrace(stderr, global_allocator, stderr_file.isTty(), 1) catch return;
72 const debug_info = getSelfDebugInfo() catch |err| {
73 stderr.print("Unable to open debug info: {}\n", @errorName(err)) catch return;
74 return;
75 };
76 defer debug_info.close();
77 writeStackTrace(stack_trace, stderr, global_allocator, debug_info, stderr_file.isTty()) catch |err| {
78 stderr.print("Unable to dump stack trace: {}\n", @errorName(err)) catch return;
79 return;
80 };
4481}
4582
4683/// This function invokes undefined behavior when `ok` is `false`.
......@@ -88,7 +125,21 @@ pub fn panic(comptime format: []const u8, args: ...) -> noreturn {
88125
89126 const stderr = getStderrStream() catch os.abort();
90127 stderr.print(format ++ "\n", args) catch os.abort();
91 writeStackTrace(stderr, global_allocator, stderr_file.isTty(), 1) catch os.abort();
128 dumpCurrentStackTrace();
129
130 os.abort();
131}
132
133pub fn panicWithTrace(trace: &const builtin.StackTrace, comptime format: []const u8, args: ...) -> noreturn {
134 if (panicking) {
135 os.abort();
136 } else {
137 panicking = true;
138 }
139 const stderr = getStderrStream() catch os.abort();
140 stderr.print(format ++ "\n", args) catch os.abort();
141 dumpStackTrace(trace);
142 dumpCurrentStackTrace();
92143
93144 os.abort();
94145}
......@@ -101,12 +152,91 @@ const RESET = "\x1b[0m";
101152error PathNotFound;
102153error InvalidDebugInfo;
103154
104pub fn writeStackTrace(out_stream: &io.OutStream, allocator: &mem.Allocator, tty_color: bool,
105 ignore_frame_count: usize) -> %void
155pub fn writeStackTrace(stack_trace: &const builtin.StackTrace, out_stream: &io.OutStream, allocator: &mem.Allocator,
156 debug_info: &ElfStackTrace, tty_color: bool) -> %void
106157{
158 var frame_index: usize = undefined;
159 var frames_left: usize = undefined;
160 if (stack_trace.index < stack_trace.instruction_addresses.len) {
161 frame_index = 0;
162 frames_left = stack_trace.index;
163 } else {
164 frame_index = (stack_trace.index + 1) % stack_trace.instruction_addresses.len;
165 frames_left = stack_trace.instruction_addresses.len;
166 }
167
168 while (frames_left != 0) : ({
169 frames_left -= 1;
170 frame_index = (frame_index + 1) % stack_trace.instruction_addresses.len;
171 }) {
172 const return_address = stack_trace.instruction_addresses[frame_index];
173 try printSourceAtAddress(debug_info, out_stream, return_address);
174 }
175}
176
177pub fn writeCurrentStackTrace(out_stream: &io.OutStream, allocator: &mem.Allocator,
178 debug_info: &ElfStackTrace, tty_color: bool, ignore_frame_count: usize) -> %void
179{
180 var ignored_count: usize = 0;
181
182 var fp = @ptrToInt(@frameAddress());
183 while (fp != 0) : (fp = *@intToPtr(&const usize, fp)) {
184 if (ignored_count < ignore_frame_count) {
185 ignored_count += 1;
186 continue;
187 }
188
189 const return_address = *@intToPtr(&const usize, fp + @sizeOf(usize));
190 try printSourceAtAddress(debug_info, out_stream, return_address);
191 }
192}
193
194fn printSourceAtAddress(debug_info: &ElfStackTrace, out_stream: &io.OutStream, address: usize) -> %void {
195 if (builtin.os == builtin.Os.windows) {
196 return error.UnsupportedDebugInfo;
197 }
198 // TODO we really should be able to convert @sizeOf(usize) * 2 to a string literal
199 // at compile time. I'll call it issue #313
200 const ptr_hex = if (@sizeOf(usize) == 4) "0x{x8}" else "0x{x16}";
201
202 const compile_unit = findCompileUnit(debug_info, address) catch {
203 try out_stream.print("???:?:?: " ++ DIM ++ ptr_hex ++ " in ??? (???)" ++ RESET ++ "\n ???\n\n",
204 address);
205 return;
206 };
207 const compile_unit_name = try compile_unit.die.getAttrString(debug_info, DW.AT_name);
208 if (getLineNumberInfo(debug_info, compile_unit, address - 1)) |line_info| {
209 defer line_info.deinit();
210 try out_stream.print(WHITE ++ "{}:{}:{}" ++ RESET ++ ": " ++
211 DIM ++ ptr_hex ++ " in ??? ({})" ++ RESET ++ "\n",
212 line_info.file_name, line_info.line, line_info.column,
213 address, compile_unit_name);
214 if (printLineFromFile(debug_info.allocator(), out_stream, line_info)) {
215 if (line_info.column == 0) {
216 try out_stream.write("\n");
217 } else {
218 {var col_i: usize = 1; while (col_i < line_info.column) : (col_i += 1) {
219 try out_stream.writeByte(' ');
220 }}
221 try out_stream.write(GREEN ++ "^" ++ RESET ++ "\n");
222 }
223 } else |err| switch (err) {
224 error.EndOfFile, error.PathNotFound => {},
225 else => return err,
226 }
227 } else |err| switch (err) {
228 error.MissingDebugInfo, error.InvalidDebugInfo => {
229 try out_stream.print(ptr_hex ++ " in ??? ({})\n", address, compile_unit_name);
230 },
231 else => return err,
232 }
233}
234
235pub fn openSelfDebugInfo(allocator: &mem.Allocator) -> %&ElfStackTrace {
107236 switch (builtin.object_format) {
108237 builtin.ObjectFormat.elf => {
109 var stack_trace = ElfStackTrace {
238 const st = try allocator.create(ElfStackTrace);
239 *st = ElfStackTrace {
110240 .self_exe_file = undefined,
111241 .elf = undefined,
112242 .debug_info = undefined,
......@@ -117,12 +247,11 @@ pub fn writeStackTrace(out_stream: &io.OutStream, allocator: &mem.Allocator, tty
117247 .abbrev_table_list = ArrayList(AbbrevTableHeader).init(allocator),
118248 .compile_unit_list = ArrayList(CompileUnit).init(allocator),
119249 };
120 const st = &stack_trace;
121250 st.self_exe_file = try os.openSelfExe();
122 defer st.self_exe_file.close();
251 %defer st.self_exe_file.close();
123252
124253 try st.elf.openFile(allocator, &st.self_exe_file);
125 defer st.elf.close();
254 %defer st.elf.close();
126255
127256 st.debug_info = (try st.elf.findSection(".debug_info")) ?? return error.MissingDebugInfo;
128257 st.debug_abbrev = (try st.elf.findSection(".debug_abbrev")) ?? return error.MissingDebugInfo;
......@@ -130,67 +259,19 @@ pub fn writeStackTrace(out_stream: &io.OutStream, allocator: &mem.Allocator, tty
130259 st.debug_line = (try st.elf.findSection(".debug_line")) ?? return error.MissingDebugInfo;
131260 st.debug_ranges = (try st.elf.findSection(".debug_ranges"));
132261 try scanAllCompileUnits(st);
133
134 var ignored_count: usize = 0;
135
136 var fp = @ptrToInt(@frameAddress());
137 while (fp != 0) : (fp = *@intToPtr(&const usize, fp)) {
138 if (ignored_count < ignore_frame_count) {
139 ignored_count += 1;
140 continue;
141 }
142
143 const return_address = *@intToPtr(&const usize, fp + @sizeOf(usize));
144
145 // TODO we really should be able to convert @sizeOf(usize) * 2 to a string literal
146 // at compile time. I'll call it issue #313
147 const ptr_hex = if (@sizeOf(usize) == 4) "0x{x8}" else "0x{x16}";
148
149 const compile_unit = findCompileUnit(st, return_address) catch {
150 try out_stream.print("???:?:?: " ++ DIM ++ ptr_hex ++ " in ??? (???)" ++ RESET ++ "\n ???\n\n",
151 return_address);
152 continue;
153 };
154 const compile_unit_name = try compile_unit.die.getAttrString(st, DW.AT_name);
155 if (getLineNumberInfo(st, compile_unit, usize(return_address) - 1)) |line_info| {
156 defer line_info.deinit();
157 try out_stream.print(WHITE ++ "{}:{}:{}" ++ RESET ++ ": " ++
158 DIM ++ ptr_hex ++ " in ??? ({})" ++ RESET ++ "\n",
159 line_info.file_name, line_info.line, line_info.column,
160 return_address, compile_unit_name);
161 if (printLineFromFile(st.allocator(), out_stream, line_info)) {
162 if (line_info.column == 0) {
163 try out_stream.write("\n");
164 } else {
165 {var col_i: usize = 1; while (col_i < line_info.column) : (col_i += 1) {
166 try out_stream.writeByte(' ');
167 }}
168 try out_stream.write(GREEN ++ "^" ++ RESET ++ "\n");
169 }
170 } else |err| switch (err) {
171 error.EndOfFile, error.PathNotFound => {},
172 else => return err,
173 }
174 } else |err| switch (err) {
175 error.MissingDebugInfo, error.InvalidDebugInfo => {
176 try out_stream.print(ptr_hex ++ " in ??? ({})\n",
177 return_address, compile_unit_name);
178 },
179 else => return err,
180 }
181 }
262 return st;
182263 },
183264 builtin.ObjectFormat.coff => {
184 try out_stream.write("(stack trace unavailable for COFF object format)\n");
265 return error.TodoSupportCoffDebugInfo;
185266 },
186267 builtin.ObjectFormat.macho => {
187 try out_stream.write("(stack trace unavailable for Mach-O object format)\n");
268 return error.TodoSupportMachoDebugInfo;
188269 },
189270 builtin.ObjectFormat.wasm => {
190 try out_stream.write("(stack trace unavailable for WASM object format)\n");
271 return error.TodoSupportCOFFDebugInfo;
191272 },
192273 builtin.ObjectFormat.unknown => {
193 try out_stream.write("(stack trace unavailable for unknown object format)\n");
274 return error.UnknownObjectFormat;
194275 },
195276 }
196277}
......@@ -228,7 +309,7 @@ fn printLineFromFile(allocator: &mem.Allocator, out_stream: &io.OutStream, line_
228309 }
229310}
230311
231const ElfStackTrace = struct {
312pub const ElfStackTrace = struct {
232313 self_exe_file: io.File,
233314 elf: elf.Elf,
234315 debug_info: &elf.SectionHeader,
......@@ -248,6 +329,11 @@ const ElfStackTrace = struct {
248329 const in_stream = &in_file_stream.stream;
249330 return readStringRaw(self.allocator(), in_stream);
250331 }
332
333 pub fn close(self: &ElfStackTrace) {
334 self.self_exe_file.close();
335 self.elf.close();
336 }
251337};
252338
253339const PcRange = struct {
std/index.zig+2
......@@ -10,6 +10,7 @@ pub const LinkedList = @import("linked_list.zig").LinkedList;
1010pub const base64 = @import("base64.zig");
1111pub const build = @import("build.zig");
1212pub const c = @import("c/index.zig");
13pub const crypto = @import("crypto/index.zig");
1314pub const cstr = @import("cstr.zig");
1415pub const debug = @import("debug/index.zig");
1516pub const dwarf = @import("dwarf.zig");
......@@ -39,6 +40,7 @@ test "std" {
3940 _ = @import("base64.zig");
4041 _ = @import("build.zig");
4142 _ = @import("c/index.zig");
43 _ = @import("crypto/index.zig");
4244 _ = @import("cstr.zig");
4345 _ = @import("debug/index.zig");
4446 _ = @import("dwarf.zig");
std/io.zig+1-1
......@@ -224,7 +224,7 @@ pub const File = struct {
224224 };
225225 }
226226 },
227 else => @compileError("unsupported OS"),
227 else => @compileError("unsupported OS: " ++ @tagName(builtin.os)),
228228 }
229229 }
230230
std/io_test.zig-5
......@@ -8,11 +8,6 @@ const os = std.os;
88const builtin = @import("builtin");
99
1010test "write a file, read it, then delete it" {
11 if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) {
12 // TODO get this test passing
13 // https://github.com/zig-lang/zig/issues/537
14 return;
15 }
1611 var data: [1024]u8 = undefined;
1712 var rng = Rand.init(1234);
1813 rng.fillBytes(data[0..]);
std/math/acosh.zig-5
......@@ -55,11 +55,6 @@ fn acosh64(x: f64) -> f64 {
5555}
5656
5757test "math.acosh" {
58 if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) {
59 // TODO get this test passing
60 // https://github.com/zig-lang/zig/issues/537
61 return;
62 }
6358 assert(acosh(f32(1.5)) == acosh32(1.5));
6459 assert(acosh(f64(1.5)) == acosh64(1.5));
6560}
std/math/cos.zig-5
......@@ -146,11 +146,6 @@ test "math.cos" {
146146}
147147
148148test "math.cos32" {
149 if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) {
150 // TODO get this test passing
151 // https://github.com/zig-lang/zig/issues/537
152 return;
153 }
154149 const epsilon = 0.000001;
155150
156151 assert(math.approxEq(f32, cos32(0.0), 1.0, epsilon));
std/math/cosh.zig-5
......@@ -81,11 +81,6 @@ fn cosh64(x: f64) -> f64 {
8181}
8282
8383test "math.cosh" {
84 if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) {
85 // TODO get this test passing
86 // https://github.com/zig-lang/zig/issues/537
87 return;
88 }
8984 assert(cosh(f32(1.5)) == cosh32(1.5));
9085 assert(cosh(f64(1.5)) == cosh64(1.5));
9186}
std/math/index.zig+39-15
......@@ -267,6 +267,45 @@ test "math.shr" {
267267 assert(shr(u8, 0b11111111, isize(-2)) == 0b11111100);
268268}
269269
270/// Rotates right. Only unsigned values can be rotated.
271/// Negative shift values results in shift modulo the bit count.
272pub fn rotr(comptime T: type, x: T, r: var) -> T {
273 if (T.is_signed) {
274 @compileError("cannot rotate signed integer");
275 } else {
276 const ar = @mod(r, T.bit_count);
277 return shr(T, x, ar) | shl(T, x, T.bit_count - ar);
278 }
279}
280
281test "math.rotr" {
282 assert(rotr(u8, 0b00000001, usize(0)) == 0b00000001);
283 assert(rotr(u8, 0b00000001, usize(9)) == 0b10000000);
284 assert(rotr(u8, 0b00000001, usize(8)) == 0b00000001);
285 assert(rotr(u8, 0b00000001, usize(4)) == 0b00010000);
286 assert(rotr(u8, 0b00000001, isize(-1)) == 0b00000010);
287}
288
289/// Rotates left. Only unsigned values can be rotated.
290/// Negative shift values results in shift modulo the bit count.
291pub fn rotl(comptime T: type, x: T, r: var) -> T {
292 if (T.is_signed) {
293 @compileError("cannot rotate signed integer");
294 } else {
295 const ar = @mod(r, T.bit_count);
296 return shl(T, x, ar) | shr(T, x, T.bit_count - ar);
297 }
298}
299
300test "math.rotl" {
301 assert(rotl(u8, 0b00000001, usize(0)) == 0b00000001);
302 assert(rotl(u8, 0b00000001, usize(9)) == 0b00000010);
303 assert(rotl(u8, 0b00000001, usize(8)) == 0b00000001);
304 assert(rotl(u8, 0b00000001, usize(4)) == 0b00010000);
305 assert(rotl(u8, 0b00000001, isize(-1)) == 0b10000000);
306}
307
308
270309pub fn Log2Int(comptime T: type) -> type {
271310 return @IntType(false, log2(T.bit_count));
272311}
......@@ -320,11 +359,6 @@ pub fn divTrunc(comptime T: type, numerator: T, denominator: T) -> %T {
320359}
321360
322361test "math.divTrunc" {
323 if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) {
324 // TODO get this test passing
325 // https://github.com/zig-lang/zig/issues/537
326 return;
327 }
328362 testDivTrunc();
329363 comptime testDivTrunc();
330364}
......@@ -350,11 +384,6 @@ pub fn divFloor(comptime T: type, numerator: T, denominator: T) -> %T {
350384}
351385
352386test "math.divFloor" {
353 if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) {
354 // TODO get this test passing
355 // https://github.com/zig-lang/zig/issues/537
356 return;
357 }
358387 testDivFloor();
359388 comptime testDivFloor();
360389}
......@@ -384,11 +413,6 @@ pub fn divExact(comptime T: type, numerator: T, denominator: T) -> %T {
384413}
385414
386415test "math.divExact" {
387 if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) {
388 // TODO get this test passing
389 // https://github.com/zig-lang/zig/issues/537
390 return;
391 }
392416 testDivExact();
393417 comptime testDivExact();
394418}
std/math/ln.zig-5
......@@ -147,11 +147,6 @@ pub fn ln_64(x_: f64) -> f64 {
147147}
148148
149149test "math.ln" {
150 if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) {
151 // TODO get this test passing
152 // https://github.com/zig-lang/zig/issues/537
153 return;
154 }
155150 assert(ln(f32(0.2)) == ln_32(0.2));
156151 assert(ln(f64(0.2)) == ln_64(0.2));
157152}
std/math/log.zig-5
......@@ -56,11 +56,6 @@ test "math.log float" {
5656}
5757
5858test "math.log float_special" {
59 if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) {
60 // TODO get this test passing
61 // https://github.com/zig-lang/zig/issues/537
62 return;
63 }
6459 assert(log(f32, 2, 0.2301974) == math.log2(f32(0.2301974)));
6560 assert(log(f32, 10, 0.2301974) == math.log10(f32(0.2301974)));
6661
std/math/log10.zig-5
......@@ -172,11 +172,6 @@ pub fn log10_64(x_: f64) -> f64 {
172172}
173173
174174test "math.log10" {
175 if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) {
176 // TODO get this test passing
177 // https://github.com/zig-lang/zig/issues/537
178 return;
179 }
180175 assert(log10(f32(0.2)) == log10_32(0.2));
181176 assert(log10(f64(0.2)) == log10_64(0.2));
182177}
std/math/log2.zig-5
......@@ -170,11 +170,6 @@ pub fn log2_64(x_: f64) -> f64 {
170170}
171171
172172test "math.log2" {
173 if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) {
174 // TODO get this test passing
175 // https://github.com/zig-lang/zig/issues/537
176 return;
177 }
178173 assert(log2(f32(0.2)) == log2_32(0.2));
179174 assert(log2(f64(0.2)) == log2_64(0.2));
180175}
std/math/pow.zig-6
......@@ -176,12 +176,6 @@ fn isOddInteger(x: f64) -> bool {
176176}
177177
178178test "math.pow" {
179 if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) {
180 // TODO get this test passing
181 // https://github.com/zig-lang/zig/issues/537
182 return;
183 }
184
185179 const epsilon = 0.000001;
186180
187181 assert(math.approxEq(f32, pow(f32, 0.0, 3.3), 0.0, epsilon));
std/math/round.zig-5
......@@ -98,11 +98,6 @@ test "math.round" {
9898}
9999
100100test "math.round32" {
101 if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) {
102 // TODO get this test passing
103 // https://github.com/zig-lang/zig/issues/537
104 return;
105 }
106101 assert(round32(1.3) == 1.0);
107102 assert(round32(-1.3) == -1.0);
108103 assert(round32(0.2) == 0.0);
std/math/sin.zig-5
......@@ -150,11 +150,6 @@ test "math.sin" {
150150}
151151
152152test "math.sin32" {
153 if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) {
154 // TODO get this test passing
155 // https://github.com/zig-lang/zig/issues/537
156 return;
157 }
158153 const epsilon = 0.000001;
159154
160155 assert(math.approxEq(f32, sin32(0.0), 0.0, epsilon));
std/math/sinh.zig-5
......@@ -88,11 +88,6 @@ fn sinh64(x: f64) -> f64 {
8888}
8989
9090test "math.sinh" {
91 if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) {
92 // TODO get this test passing
93 // https://github.com/zig-lang/zig/issues/537
94 return;
95 }
9691 assert(sinh(f32(1.5)) == sinh32(1.5));
9792 assert(sinh(f64(1.5)) == sinh64(1.5));
9893}
std/math/tan.zig-5
......@@ -136,11 +136,6 @@ test "math.tan" {
136136}
137137
138138test "math.tan32" {
139 if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) {
140 // TODO get this test passing
141 // https://github.com/zig-lang/zig/issues/537
142 return;
143 }
144139 const epsilon = 0.000001;
145140
146141 assert(math.approxEq(f32, tan32(0.0), 0.0, epsilon));
std/math/tanh.zig-5
......@@ -112,11 +112,6 @@ fn tanh64(x: f64) -> f64 {
112112}
113113
114114test "math.tanh" {
115 if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) {
116 // TODO get this test passing
117 // https://github.com/zig-lang/zig/issues/537
118 return;
119 }
120115 assert(tanh(f32(1.5)) == tanh32(1.5));
121116 assert(tanh(f64(1.5)) == tanh64(1.5));
122117}
std/os/index.zig+2-9
......@@ -148,7 +148,7 @@ pub coldcc fn abort() -> noreturn {
148148}
149149
150150/// Exits the program cleanly with the specified status code.
151pub coldcc fn exit(status: i32) -> noreturn {
151pub coldcc fn exit(status: u8) -> noreturn {
152152 if (builtin.link_libc) {
153153 c.exit(status);
154154 }
......@@ -157,14 +157,7 @@ pub coldcc fn exit(status: i32) -> noreturn {
157157 posix.exit(status);
158158 },
159159 Os.windows => {
160 // Map a possibly negative status code to a non-negative status for the systems default
161 // integer width.
162 const p_status = if (@sizeOf(c_uint) < @sizeOf(u32))
163 @truncate(c_uint, @bitCast(u32, status))
164 else
165 c_uint(@bitCast(u32, status));
166
167 windows.ExitProcess(p_status);
160 windows.ExitProcess(status);
168161 },
169162 else => @compileError("Unsupported OS"),
170163 }
std/rand.zig-20
......@@ -194,11 +194,6 @@ fn MersenneTwister(
194194}
195195
196196test "rand float 32" {
197 if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) {
198 // TODO get this test passing
199 // https://github.com/zig-lang/zig/issues/537
200 return;
201 }
202197 var r = Rand.init(42);
203198 var i: usize = 0;
204199 while (i < 1000) : (i += 1) {
......@@ -209,11 +204,6 @@ test "rand float 32" {
209204}
210205
211206test "rand.MT19937_64" {
212 if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) {
213 // TODO get this test passing
214 // https://github.com/zig-lang/zig/issues/537
215 return;
216 }
217207 var rng = MT19937_64.init(rand_test.mt64_seed);
218208 for (rand_test.mt64_data) |value| {
219209 assert(value == rng.get());
......@@ -221,11 +211,6 @@ test "rand.MT19937_64" {
221211}
222212
223213test "rand.MT19937_32" {
224 if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) {
225 // TODO get this test passing
226 // https://github.com/zig-lang/zig/issues/537
227 return;
228 }
229214 var rng = MT19937_32.init(rand_test.mt32_seed);
230215 for (rand_test.mt32_data) |value| {
231216 assert(value == rng.get());
......@@ -233,11 +218,6 @@ test "rand.MT19937_32" {
233218}
234219
235220test "rand.Rand.range" {
236 if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) {
237 // TODO get this test passing
238 // https://github.com/zig-lang/zig/issues/537
239 return;
240 }
241221 var r = Rand.init(42);
242222 testRange(&r, -4, 3);
243223 testRange(&r, -4, -1);
std/sort.zig-20
......@@ -1020,11 +1020,6 @@ fn cmpByValue(a: &const IdAndValue, b: &const IdAndValue) -> bool {
10201020}
10211021
10221022test "std.sort" {
1023 if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) {
1024 // TODO get this test passing
1025 // https://github.com/zig-lang/zig/issues/537
1026 return;
1027 }
10281023 const u8cases = [][]const []const u8 {
10291024 [][]const u8{"", ""},
10301025 [][]const u8{"a", "a"},
......@@ -1061,11 +1056,6 @@ test "std.sort" {
10611056}
10621057
10631058test "std.sort descending" {
1064 if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) {
1065 // TODO get this test passing
1066 // https://github.com/zig-lang/zig/issues/537
1067 return;
1068 }
10691059 const rev_cases = [][]const []const i32 {
10701060 [][]const i32{[]i32{}, []i32{}},
10711061 [][]const i32{[]i32{1}, []i32{1}},
......@@ -1085,11 +1075,6 @@ test "std.sort descending" {
10851075}
10861076
10871077test "another sort case" {
1088 if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) {
1089 // TODO get this test passing
1090 // https://github.com/zig-lang/zig/issues/537
1091 return;
1092 }
10931078 var arr = []i32{ 5, 3, 1, 2, 4 };
10941079 sort(i32, arr[0..], i32asc);
10951080
......@@ -1097,11 +1082,6 @@ test "another sort case" {
10971082}
10981083
10991084test "sort fuzz testing" {
1100 if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) {
1101 // TODO get this test passing
1102 // https://github.com/zig-lang/zig/issues/537
1103 return;
1104 }
11051085 var rng = std.rand.Rand.init(0x12345678);
11061086 const test_case_count = 10;
11071087 var i: usize = 0;
std/special/bootstrap.zig+35-10
......@@ -21,8 +21,7 @@ comptime {
2121}
2222
2323extern fn zenMain() -> noreturn {
24 root.main() catch std.os.posix.exit(1);
25 std.os.posix.exit(0);
24 std.os.posix.exit(callMain());
2625}
2726
2827nakedcc fn _start() -> noreturn {
......@@ -43,29 +42,55 @@ nakedcc fn _start() -> noreturn {
4342extern fn WinMainCRTStartup() -> noreturn {
4443 @setAlignStack(16);
4544
46 root.main() catch std.os.windows.ExitProcess(1);
47 std.os.windows.ExitProcess(0);
45 std.os.windows.ExitProcess(callMain());
4846}
4947
5048fn posixCallMainAndExit() -> noreturn {
5149 const argc = *argc_ptr;
5250 const argv = @ptrCast(&&u8, &argc_ptr[1]);
5351 const envp = @ptrCast(&?&u8, &argv[argc + 1]);
54 callMain(argc, argv, envp) catch std.os.posix.exit(1);
55 std.os.posix.exit(0);
52 std.os.posix.exit(callMainWithArgs(argc, argv, envp));
5653}
5754
58fn callMain(argc: usize, argv: &&u8, envp: &?&u8) -> %void {
55fn callMainWithArgs(argc: usize, argv: &&u8, envp: &?&u8) -> u8 {
5956 std.os.ArgIteratorPosix.raw = argv[0..argc];
6057
6158 var env_count: usize = 0;
6259 while (envp[env_count] != null) : (env_count += 1) {}
6360 std.os.posix_environ_raw = @ptrCast(&&u8, envp)[0..env_count];
6461
65 return root.main();
62 return callMain();
6663}
6764
6865extern fn main(c_argc: i32, c_argv: &&u8, c_envp: &?&u8) -> i32 {
69 callMain(usize(c_argc), c_argv, c_envp) catch return 1;
70 return 0;
66 return callMainWithArgs(usize(c_argc), c_argv, c_envp);
67}
68
69fn callMain() -> u8 {
70 switch (@typeId(@typeOf(root.main).ReturnType)) {
71 builtin.TypeId.NoReturn => {
72 root.main();
73 },
74 builtin.TypeId.Void => {
75 root.main();
76 return 0;
77 },
78 builtin.TypeId.Int => {
79 if (@typeOf(root.main).ReturnType.bit_count != 8) {
80 @compileError("expected return type of main to be 'u8', 'noreturn', 'void', or '%void'");
81 }
82 return root.main();
83 },
84 builtin.TypeId.ErrorUnion => {
85 root.main() catch |err| {
86 std.debug.warn("error: {}\n", @errorName(err));
87 if (@errorReturnTrace()) |trace| {
88 std.debug.dumpStackTrace(trace);
89 }
90 return 1;
91 };
92 return 0;
93 },
94 else => @compileError("expected return type of main to be 'u8', 'noreturn', 'void', or '%void'"),
95 }
7196}
std/special/build_runner.zig+4-4
......@@ -14,7 +14,7 @@ pub fn main() -> %void {
1414 var arg_it = os.args();
1515
1616 // TODO use a more general purpose allocator here
17 var inc_allocator = std.heap.IncrementingAllocator.init(40 * 1024 * 1024) catch unreachable;
17 var inc_allocator = try std.heap.IncrementingAllocator.init(40 * 1024 * 1024);
1818 defer inc_allocator.deinit();
1919
2020 const allocator = &inc_allocator.allocator;
......@@ -107,12 +107,12 @@ pub fn main() -> %void {
107107 return usageAndErr(&builder, false, try stderr_stream);
108108 }
109109 } else {
110 targets.append(arg) catch unreachable;
110 try targets.append(arg);
111111 }
112112 }
113113
114114 builder.setInstallPrefix(prefix);
115 root.build(&builder);
115 try root.build(&builder);
116116
117117 if (builder.validateUserInputDidItFail())
118118 return usageAndErr(&builder, true, try stderr_stream);
......@@ -129,7 +129,7 @@ fn usage(builder: &Builder, already_ran_build: bool, out_stream: &io.OutStream)
129129 // run the build script to collect the options
130130 if (!already_ran_build) {
131131 builder.setInstallPrefix(null);
132 root.build(builder);
132 try root.build(builder);
133133 }
134134
135135 // This usage text has to be synchronized with src/main.cpp
std/special/builtin.zig+1-1
......@@ -5,7 +5,7 @@ const builtin = @import("builtin");
55
66// Avoid dragging in the debug safety mechanisms into this .o file,
77// unless we're trying to test this file.
8pub coldcc fn panic(msg: []const u8) -> noreturn {
8pub coldcc fn panic(msg: []const u8, error_return_trace: ?&builtin.StackTrace) -> noreturn {
99 if (builtin.is_test) {
1010 @import("std").debug.panic("{}", msg);
1111 } else {
std/special/compiler_rt/index.zig+1-1
......@@ -74,7 +74,7 @@ const __udivmoddi4 = @import("udivmoddi4.zig").__udivmoddi4;
7474
7575// Avoid dragging in the debug safety mechanisms into this .o file,
7676// unless we're trying to test this file.
77pub coldcc fn panic(msg: []const u8) -> noreturn {
77pub coldcc fn panic(msg: []const u8, error_return_trace: ?&builtin.StackTrace) -> noreturn {
7878 if (is_test) {
7979 @import("std").debug.panic("{}", msg);
8080 } else {
std/special/panic.zig+5-1
......@@ -4,14 +4,18 @@
44// have to be added in the compiler.
55
66const builtin = @import("builtin");
7const std = @import("std");
78
8pub coldcc fn panic(msg: []const u8) -> noreturn {
9pub coldcc fn panic(msg: []const u8, error_return_trace: ?&builtin.StackTrace) -> noreturn {
910 switch (builtin.os) {
1011 // TODO: fix panic in zen.
1112 builtin.Os.freestanding, builtin.Os.zen => {
1213 while (true) {}
1314 },
1415 else => {
16 if (error_return_trace) |trace| {
17 @import("std").debug.panicWithTrace(trace, "{}", msg);
18 }
1519 @import("std").debug.panic("{}", msg);
1620 },
1721 }
std/special/test_runner.zig+1-4
......@@ -8,10 +8,7 @@ pub fn main() -> %void {
88 for (test_fn_list) |test_fn, i| {
99 warn("Test {}/{} {}...", i + 1, test_fn_list.len, test_fn.name);
1010
11 test_fn.func() catch |err| {
12 warn("{}\n", err);
13 return err;
14 };
11 try test_fn.func();
1512
1613 warn("OK\n");
1714 }
test/build_examples.zig+1
......@@ -16,4 +16,5 @@ pub fn addCases(cases: &tests.BuildExamplesContext) {
1616 cases.addBuildFile("test/standalone/issue_339/build.zig");
1717 cases.addBuildFile("test/standalone/pkg_import/build.zig");
1818 cases.addBuildFile("test/standalone/use_alias/build.zig");
19 cases.addBuildFile("test/standalone/brace_expansion/build.zig");
1920}
test/cases/math.zig+23
......@@ -26,6 +26,29 @@ fn testDivision() {
2626 assert(divTrunc(i32, -5, 3) == -1);
2727 assert(divTrunc(f32, 5.0, 3.0) == 1.0);
2828 assert(divTrunc(f32, -5.0, 3.0) == -1.0);
29
30 comptime {
31 assert(
32 1194735857077236777412821811143690633098347576 %
33 508740759824825164163191790951174292733114988 ==
34 177254337427586449086438229241342047632117600);
35 assert(@rem(-1194735857077236777412821811143690633098347576,
36 508740759824825164163191790951174292733114988) ==
37 -177254337427586449086438229241342047632117600);
38 assert(1194735857077236777412821811143690633098347576 /
39 508740759824825164163191790951174292733114988 ==
40 2);
41 assert(@divTrunc(-1194735857077236777412821811143690633098347576,
42 508740759824825164163191790951174292733114988) ==
43 -2);
44 assert(@divTrunc(1194735857077236777412821811143690633098347576,
45 -508740759824825164163191790951174292733114988) ==
46 -2);
47 assert(@divTrunc(-1194735857077236777412821811143690633098347576,
48 -508740759824825164163191790951174292733114988) ==
49 2);
50 assert(4126227191251978491697987544882340798050766755606969681711 % 10 == 1);
51 }
2952}
3053fn div(comptime T: type, a: T, b: T) -> T {
3154 return a / b;
test/compile_errors.zig+9-9
......@@ -1,6 +1,15 @@
11const tests = @import("tests.zig");
22
33pub fn addCases(cases: &tests.CompileErrorContext) {
4 cases.add("wrong return type for main",
5 \\pub fn main() -> f32 { }
6 , "error: expected return type of main to be 'u8', 'noreturn', 'void', or '%void'");
7
8 cases.add("double ?? on main return value",
9 \\pub fn main() -> ??void {
10 \\}
11 , "error: expected return type of main to be 'u8', 'noreturn', 'void', or '%void'");
12
413 cases.add("bad identifier in function with struct defined inside function which references local const",
514 \\export fn entry() {
615 \\ const BlockKind = u32;
......@@ -1059,15 +1068,6 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
10591068 ,
10601069 ".tmp_source.zig:2:5: error: expected type 'void', found 'error'");
10611070
1062 cases.add("wrong return type for main",
1063 \\pub fn main() { }
1064 , ".tmp_source.zig:1:15: error: expected return type of main to be '%void', instead is 'void'");
1065
1066 cases.add("double ?? on main return value",
1067 \\pub fn main() -> ??void {
1068 \\}
1069 , ".tmp_source.zig:1:18: error: expected return type of main to be '%void', instead is '??void'");
1070
10711071 cases.add("invalid pointer for var type",
10721072 \\extern fn ext() -> usize;
10731073 \\var bytes: [ext()]u8 = undefined;
test/debug_safety.zig+20-20
......@@ -2,7 +2,7 @@ const tests = @import("tests.zig");
22
33pub fn addCases(cases: &tests.CompareOutputContext) {
44 cases.addDebugSafety("calling panic",
5 \\pub fn panic(message: []const u8) -> noreturn {
5 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) -> noreturn {
66 \\ @import("std").os.exit(126);
77 \\}
88 \\pub fn main() -> %void {
......@@ -11,7 +11,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
1111 );
1212
1313 cases.addDebugSafety("out of bounds slice access",
14 \\pub fn panic(message: []const u8) -> noreturn {
14 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) -> noreturn {
1515 \\ @import("std").os.exit(126);
1616 \\}
1717 \\pub fn main() -> %void {
......@@ -25,7 +25,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
2525 );
2626
2727 cases.addDebugSafety("integer addition overflow",
28 \\pub fn panic(message: []const u8) -> noreturn {
28 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) -> noreturn {
2929 \\ @import("std").os.exit(126);
3030 \\}
3131 \\error Whatever;
......@@ -39,7 +39,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
3939 );
4040
4141 cases.addDebugSafety("integer subtraction overflow",
42 \\pub fn panic(message: []const u8) -> noreturn {
42 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) -> noreturn {
4343 \\ @import("std").os.exit(126);
4444 \\}
4545 \\error Whatever;
......@@ -53,7 +53,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
5353 );
5454
5555 cases.addDebugSafety("integer multiplication overflow",
56 \\pub fn panic(message: []const u8) -> noreturn {
56 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) -> noreturn {
5757 \\ @import("std").os.exit(126);
5858 \\}
5959 \\error Whatever;
......@@ -67,7 +67,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
6767 );
6868
6969 cases.addDebugSafety("integer negation overflow",
70 \\pub fn panic(message: []const u8) -> noreturn {
70 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) -> noreturn {
7171 \\ @import("std").os.exit(126);
7272 \\}
7373 \\error Whatever;
......@@ -81,7 +81,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
8181 );
8282
8383 cases.addDebugSafety("signed integer division overflow",
84 \\pub fn panic(message: []const u8) -> noreturn {
84 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) -> noreturn {
8585 \\ @import("std").os.exit(126);
8686 \\}
8787 \\error Whatever;
......@@ -95,7 +95,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
9595 );
9696
9797 cases.addDebugSafety("signed shift left overflow",
98 \\pub fn panic(message: []const u8) -> noreturn {
98 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) -> noreturn {
9999 \\ @import("std").os.exit(126);
100100 \\}
101101 \\error Whatever;
......@@ -109,7 +109,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
109109 );
110110
111111 cases.addDebugSafety("unsigned shift left overflow",
112 \\pub fn panic(message: []const u8) -> noreturn {
112 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) -> noreturn {
113113 \\ @import("std").os.exit(126);
114114 \\}
115115 \\error Whatever;
......@@ -123,7 +123,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
123123 );
124124
125125 cases.addDebugSafety("signed shift right overflow",
126 \\pub fn panic(message: []const u8) -> noreturn {
126 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) -> noreturn {
127127 \\ @import("std").os.exit(126);
128128 \\}
129129 \\error Whatever;
......@@ -137,7 +137,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
137137 );
138138
139139 cases.addDebugSafety("unsigned shift right overflow",
140 \\pub fn panic(message: []const u8) -> noreturn {
140 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) -> noreturn {
141141 \\ @import("std").os.exit(126);
142142 \\}
143143 \\error Whatever;
......@@ -151,7 +151,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
151151 );
152152
153153 cases.addDebugSafety("integer division by zero",
154 \\pub fn panic(message: []const u8) -> noreturn {
154 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) -> noreturn {
155155 \\ @import("std").os.exit(126);
156156 \\}
157157 \\error Whatever;
......@@ -164,7 +164,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
164164 );
165165
166166 cases.addDebugSafety("exact division failure",
167 \\pub fn panic(message: []const u8) -> noreturn {
167 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) -> noreturn {
168168 \\ @import("std").os.exit(126);
169169 \\}
170170 \\error Whatever;
......@@ -178,7 +178,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
178178 );
179179
180180 cases.addDebugSafety("cast []u8 to bigger slice of wrong size",
181 \\pub fn panic(message: []const u8) -> noreturn {
181 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) -> noreturn {
182182 \\ @import("std").os.exit(126);
183183 \\}
184184 \\error Whatever;
......@@ -192,7 +192,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
192192 );
193193
194194 cases.addDebugSafety("value does not fit in shortening cast",
195 \\pub fn panic(message: []const u8) -> noreturn {
195 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) -> noreturn {
196196 \\ @import("std").os.exit(126);
197197 \\}
198198 \\error Whatever;
......@@ -206,7 +206,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
206206 );
207207
208208 cases.addDebugSafety("signed integer not fitting in cast to unsigned integer",
209 \\pub fn panic(message: []const u8) -> noreturn {
209 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) -> noreturn {
210210 \\ @import("std").os.exit(126);
211211 \\}
212212 \\error Whatever;
......@@ -220,7 +220,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
220220 );
221221
222222 cases.addDebugSafety("unwrap error",
223 \\pub fn panic(message: []const u8) -> noreturn {
223 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) -> noreturn {
224224 \\ if (@import("std").mem.eql(u8, message, "attempt to unwrap error: Whatever")) {
225225 \\ @import("std").os.exit(126); // good
226226 \\ }
......@@ -236,7 +236,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
236236 );
237237
238238 cases.addDebugSafety("cast integer to error and no code matches",
239 \\pub fn panic(message: []const u8) -> noreturn {
239 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) -> noreturn {
240240 \\ @import("std").os.exit(126);
241241 \\}
242242 \\pub fn main() -> %void {
......@@ -248,7 +248,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
248248 );
249249
250250 cases.addDebugSafety("@alignCast misaligned",
251 \\pub fn panic(message: []const u8) -> noreturn {
251 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) -> noreturn {
252252 \\ @import("std").os.exit(126);
253253 \\}
254254 \\error Wrong;
......@@ -265,7 +265,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
265265 );
266266
267267 cases.addDebugSafety("bad union field access",
268 \\pub fn panic(message: []const u8) -> noreturn {
268 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) -> noreturn {
269269 \\ @import("std").os.exit(126);
270270 \\}
271271 \\
test/standalone/brace_expansion/build.zig created+9
......@@ -0,0 +1,9 @@
1const Builder = @import("std").build.Builder;
2
3pub fn build(b: &Builder) -> %void {
4 const main = b.addTest("main.zig");
5 main.setBuildMode(b.standardReleaseOptions());
6
7 const test_step = b.step("test", "Test it");
8 test_step.dependOn(&main.step);
9}
test/standalone/brace_expansion/main.zig created+254
......@@ -0,0 +1,254 @@
1const std = @import("std");
2const io = std.io;
3const mem = std.mem;
4const debug = std.debug;
5const assert = debug.assert;
6const Buffer = std.Buffer;
7const ArrayList = std.ArrayList;
8
9error InvalidInput;
10error OutOfMem;
11
12const Token = union(enum) {
13 Word: []const u8,
14 OpenBrace,
15 CloseBrace,
16 Comma,
17 Eof,
18};
19
20var global_allocator: &mem.Allocator = undefined;
21
22fn tokenize(input:[] const u8) -> %ArrayList(Token) {
23 const State = enum {
24 Start,
25 Word,
26 };
27
28 var token_list = ArrayList(Token).init(global_allocator);
29 var tok_begin: usize = undefined;
30 var state = State.Start;
31
32 for (input) |b, i| {
33 switch (state) {
34 State.Start => switch (b) {
35 'a'...'z', 'A'...'Z' => {
36 state = State.Word;
37 tok_begin = i;
38 },
39 '{' => try token_list.append(Token.OpenBrace),
40 '}' => try token_list.append(Token.CloseBrace),
41 ',' => try token_list.append(Token.Comma),
42 else => return error.InvalidInput,
43 },
44 State.Word => switch (b) {
45 'a'...'z', 'A'...'Z' => {},
46 '{', '}', ',' => {
47 try token_list.append(Token { .Word = input[tok_begin..i] });
48 switch (b) {
49 '{' => try token_list.append(Token.OpenBrace),
50 '}' => try token_list.append(Token.CloseBrace),
51 ',' => try token_list.append(Token.Comma),
52 else => unreachable,
53 }
54 state = State.Start;
55 },
56 else => return error.InvalidInput,
57 },
58 }
59 }
60 switch (state) {
61 State.Start => {},
62 State.Word => try token_list.append(Token {.Word = input[tok_begin..] }),
63 }
64 try token_list.append(Token.Eof);
65 return token_list;
66}
67
68const Node = union(enum) {
69 Scalar: []const u8,
70 List: ArrayList(Node),
71 Combine: []Node,
72};
73
74fn parse(tokens: &const ArrayList(Token), token_index: &usize) -> %Node {
75 const first_token = tokens.items[*token_index];
76 *token_index += 1;
77
78 const result_node = switch (first_token) {
79 Token.Word => |word| Node { .Scalar = word },
80 Token.OpenBrace => blk: {
81 var list = ArrayList(Node).init(global_allocator);
82 while (true) {
83 try list.append(try parse(tokens, token_index));
84
85 const token = tokens.items[*token_index];
86 *token_index += 1;
87
88 switch (token) {
89 Token.CloseBrace => break,
90 Token.Comma => continue,
91 else => return error.InvalidInput,
92 }
93 }
94 break :blk Node { .List = list };
95 },
96 else => return error.InvalidInput,
97 };
98
99 switch (tokens.items[*token_index]) {
100 Token.Word, Token.OpenBrace => {
101 const pair = try global_allocator.alloc(Node, 2);
102 pair[0] = result_node;
103 pair[1] = try parse(tokens, token_index);
104 return Node { .Combine = pair };
105 },
106 else => return result_node,
107 }
108}
109
110fn expandString(input: []const u8, output: &Buffer) -> %void {
111 const tokens = try tokenize(input);
112 if (tokens.len == 1) {
113 return output.resize(0);
114 }
115
116 var token_index: usize = 0;
117 const root = try parse(tokens, &token_index);
118 const last_token = tokens.items[token_index];
119 switch (last_token) {
120 Token.Eof => {},
121 else => return error.InvalidInput,
122 }
123
124 var result_list = ArrayList(Buffer).init(global_allocator);
125 defer result_list.deinit();
126
127 try expandNode(root, &result_list);
128
129 try output.resize(0);
130 for (result_list.toSliceConst()) |buf, i| {
131 if (i != 0) {
132 try output.appendByte(' ');
133 }
134 try output.append(buf.toSliceConst());
135 }
136}
137
138const ListOfBuffer0 = ArrayList(Buffer); // TODO this is working around a compiler bug, fix and delete this
139
140fn expandNode(node: &const Node, output: &ListOfBuffer0) -> %void {
141 assert(output.len == 0);
142 switch (*node) {
143 Node.Scalar => |scalar| {
144 try output.append(try Buffer.init(global_allocator, scalar));
145 },
146 Node.Combine => |pair| {
147 const a_node = pair[0];
148 const b_node = pair[1];
149
150 var child_list_a = ArrayList(Buffer).init(global_allocator);
151 try expandNode(a_node, &child_list_a);
152
153 var child_list_b = ArrayList(Buffer).init(global_allocator);
154 try expandNode(b_node, &child_list_b);
155
156 for (child_list_a.toSliceConst()) |buf_a| {
157 for (child_list_b.toSliceConst()) |buf_b| {
158 var combined_buf = try Buffer.initFromBuffer(buf_a);
159 try combined_buf.append(buf_b.toSliceConst());
160 try output.append(combined_buf);
161 }
162 }
163 },
164 Node.List => |list| {
165 for (list.toSliceConst()) |child_node| {
166 var child_list = ArrayList(Buffer).init(global_allocator);
167 try expandNode(child_node, &child_list);
168
169 for (child_list.toSliceConst()) |buf| {
170 try output.append(buf);
171 }
172 }
173 },
174 }
175}
176
177pub fn main() -> %void {
178 var stdin_file = try io.getStdIn();
179 var stdout_file = try io.getStdOut();
180
181 var inc_allocator = try std.heap.IncrementingAllocator.init(2 * 1024 * 1024);
182 defer inc_allocator.deinit();
183
184 global_allocator = &inc_allocator.allocator;
185
186 var stdin_buf = try Buffer.initSize(global_allocator, 0);
187 defer stdin_buf.deinit();
188
189 var stdin_adapter = io.FileInStream.init(&stdin_file);
190 try stdin_adapter.stream.readAllBuffer(&stdin_buf, @maxValue(usize));
191
192 var result_buf = try Buffer.initSize(global_allocator, 0);
193 defer result_buf.deinit();
194
195 try expandString(stdin_buf.toSlice(), &result_buf);
196 try stdout_file.write(result_buf.toSliceConst());
197}
198
199test "invalid inputs" {
200 global_allocator = std.debug.global_allocator;
201
202 expectError("}ABC", error.InvalidInput);
203 expectError("{ABC", error.InvalidInput);
204 expectError("}{", error.InvalidInput);
205 expectError("{}", error.InvalidInput);
206 expectError("A,B,C", error.InvalidInput);
207 expectError("{A{B,C}", error.InvalidInput);
208 expectError("{A,}", error.InvalidInput);
209
210 expectError("\n", error.InvalidInput);
211}
212
213fn expectError(test_input: []const u8, expected_err: error) {
214 var output_buf = Buffer.initSize(global_allocator, 0) catch unreachable;
215 defer output_buf.deinit();
216
217 if (expandString("}ABC", &output_buf)) {
218 unreachable;
219 } else |err| {
220 assert(expected_err == err);
221 }
222}
223
224test "valid inputs" {
225 global_allocator = std.debug.global_allocator;
226
227 expectExpansion("{x,y,z}", "x y z");
228 expectExpansion("{A,B}{x,y}", "Ax Ay Bx By");
229 expectExpansion("{A,B{x,y}}", "A Bx By");
230
231 expectExpansion("{ABC}", "ABC");
232 expectExpansion("{A,B,C}", "A B C");
233 expectExpansion("ABC", "ABC");
234
235 expectExpansion("", "");
236 expectExpansion("{A,B}{C,{x,y}}{g,h}", "ACg ACh Axg Axh Ayg Ayh BCg BCh Bxg Bxh Byg Byh");
237 expectExpansion("{A,B}{C,C{x,y}}{g,h}", "ACg ACh ACxg ACxh ACyg ACyh BCg BCh BCxg BCxh BCyg BCyh");
238 expectExpansion("{A,B}a", "Aa Ba");
239 expectExpansion("{C,{x,y}}", "C x y");
240 expectExpansion("z{C,{x,y}}", "zC zx zy");
241 expectExpansion("a{b,c{d,e{f,g}}}", "ab acd acef aceg");
242 expectExpansion("a{x,y}b", "axb ayb");
243 expectExpansion("z{{a,b}}", "za zb");
244 expectExpansion("a{b}", "ab");
245}
246
247fn expectExpansion(test_input: []const u8, expected_result: []const u8) {
248 var result = Buffer.initSize(global_allocator, 0) catch unreachable;
249 defer result.deinit();
250
251 expandString(test_input, &result) catch unreachable;
252
253 assert(mem.eql(u8, result.toSlice(), expected_result));
254}
test/standalone/issue_339/build.zig+1-1
......@@ -1,6 +1,6 @@
11const Builder = @import("std").build.Builder;
22
3pub fn build(b: &Builder) {
3pub fn build(b: &Builder) -> %void {
44 const obj = b.addObject("test", "test.zig");
55
66 const test_step = b.step("test", "Test the program");
test/standalone/issue_339/test.zig+2-1
......@@ -1,4 +1,5 @@
1pub fn panic(msg: []const u8) -> noreturn { @breakpoint(); while (true) {} }
1const StackTrace = @import("builtin").StackTrace;
2pub fn panic(msg: []const u8, stack_trace: ?&StackTrace) -> noreturn { @breakpoint(); while (true) {} }
23
34fn bar() -> %void {}
45
test/standalone/pkg_import/build.zig+1-1
......@@ -1,6 +1,6 @@
11const Builder = @import("std").build.Builder;
22
3pub fn build(b: &Builder) {
3pub fn build(b: &Builder) -> %void {
44 const exe = b.addExecutable("test", "test.zig");
55 exe.addPackagePath("my_pkg", "pkg.zig");
66
test/standalone/use_alias/build.zig+1-1
......@@ -1,6 +1,6 @@
11const Builder = @import("std").build.Builder;
22
3pub fn build(b: &Builder) {
3pub fn build(b: &Builder) -> %void {
44 b.addCIncludePath(".");
55
66 const main = b.addTest("main.zig");
test/tests.zig+2-7
......@@ -42,14 +42,10 @@ const test_targets = []TestTarget {
4242 .arch = builtin.Arch.x86_64,
4343 .environ = builtin.Environ.msvc,
4444 },
45 TestTarget {
46 .os = builtin.Os.windows,
47 .arch = builtin.Arch.i386,
48 .environ = builtin.Environ.msvc,
49 },
5045};
5146
5247error TestFailed;
48error CompilationIncorrectlySucceeded;
5349
5450const max_stdout_size = 1 * 1024 * 1024; // 1 MB
5551
......@@ -607,8 +603,7 @@ pub const CompileErrorContext = struct {
607603 switch (term) {
608604 Term.Exited => |code| {
609605 if (code == 0) {
610 warn("Compilation incorrectly succeeded\n");
611 return error.TestFailed;
606 return error.CompilationIncorrectlySucceeded;
612607 }
613608 },
614609 else => {
test/translate_c.zig+26-5
......@@ -408,7 +408,7 @@ pub fn addCases(cases: &tests.TranslateCContext) {
408408 \\}
409409 ,
410410 \\pub export fn s(a: c_int, b: c_int) -> c_int {
411 \\ var c: c_int;
411 \\ var c: c_int = undefined;
412412 \\ c = (a + b);
413413 \\ c = (a - b);
414414 \\ c = (a * b);
......@@ -416,7 +416,7 @@ pub fn addCases(cases: &tests.TranslateCContext) {
416416 \\ c = @rem(a, b);
417417 \\}
418418 \\pub export fn u(a: c_uint, b: c_uint) -> c_uint {
419 \\ var c: c_uint;
419 \\ var c: c_uint = undefined;
420420 \\ c = (a +% b);
421421 \\ c = (a -% b);
422422 \\ c = (a *% b);
......@@ -460,7 +460,7 @@ pub fn addCases(cases: &tests.TranslateCContext) {
460460 ,
461461 \\pub export fn max(_arg_a: c_int) -> c_int {
462462 \\ var a = _arg_a;
463 \\ var tmp: c_int;
463 \\ var tmp: c_int = undefined;
464464 \\ tmp = a;
465465 \\ a = tmp;
466466 \\}
......@@ -473,8 +473,8 @@ pub fn addCases(cases: &tests.TranslateCContext) {
473473 \\}
474474 ,
475475 \\pub export fn max(a: c_int) {
476 \\ var b: c_int;
477 \\ var c: c_int;
476 \\ var b: c_int = undefined;
477 \\ var c: c_int = undefined;
478478 \\ c = x: {
479479 \\ const _tmp = a;
480480 \\ b = _tmp;
......@@ -1114,4 +1114,25 @@ pub fn addCases(cases: &tests.TranslateCContext) {
11141114 ,
11151115 \\pub const NRF_GPIO = if (@typeId(@typeOf(NRF_GPIO_BASE)) == @import("builtin").TypeId.Pointer) @ptrCast(&NRF_GPIO_Type, NRF_GPIO_BASE) else if (@typeId(@typeOf(NRF_GPIO_BASE)) == @import("builtin").TypeId.Int) @intToPtr(&NRF_GPIO_Type, NRF_GPIO_BASE) else (&NRF_GPIO_Type)(NRF_GPIO_BASE);
11161116 );
1117
1118 cases.add("if on int",
1119 \\int if_int(int i) {
1120 \\ if (i) {
1121 \\ return 0;
1122 \\ } else {
1123 \\ return 1;
1124 \\ }
1125 \\}
1126 ,
1127 \\pub fn if_int(i: c_int) -> c_int {
1128 \\ {
1129 \\ const _tmp = i;
1130 \\ if (@bitCast(@IntType(false, @sizeOf(@typeOf(_tmp)) * 8), _tmp) != 0) {
1131 \\ return 0;
1132 \\ } else {
1133 \\ return 1;
1134 \\ };
1135 \\ };
1136 \\}
1137 );
11171138}