diff options
| author | Andrew Kelley <superjoe30@gmail.com> | 2018-07-04 20:43:49 -0400 |
|---|---|---|
| committer | Andrew Kelley <superjoe30@gmail.com> | 2018-07-04 20:43:49 -0400 |
| commit | b5d07297dec61a3993dfe91ceee2c87672db1e8e (patch) | |
| tree | 519d097fcdfe121e38814a080868a85f5b1f9e64 | |
| parent | 9665cfe027c70a84cb6351ea6ecb833a728736aa (diff) | |
| parent | 8c39cdc89f2ae7fc25c3856e7c4c6b4662ac8a80 (diff) | |
| download | zig-b5d07297dec61a3993dfe91ceee2c87672db1e8e.tar.gz zig-b5d07297dec61a3993dfe91ceee2c87672db1e8e.zip | |
Merge remote-tracking branch 'origin/master' into llvm7
| -rw-r--r-- | .gitattributes | 1 | ||||
| -rw-r--r-- | doc/langref.html.in | 127 | ||||
| -rw-r--r-- | src/analyze.cpp | 12 | ||||
| -rw-r--r-- | src/ir.cpp | 12 | ||||
| -rw-r--r-- | std/mem.zig | 2 | ||||
| -rw-r--r-- | std/special/compiler_rt/comparetf2.zig | 4 | ||||
| -rw-r--r-- | std/special/compiler_rt/fixuint.zig | 6 | ||||
| -rw-r--r-- | std/special/compiler_rt/fixunstfdi_test.zig | 21 | ||||
| -rw-r--r-- | std/special/compiler_rt/fixunstfsi_test.zig | 4 | ||||
| -rw-r--r-- | std/special/compiler_rt/floatunsitf.zig | 2 | ||||
| -rw-r--r-- | test/behavior.zig | 1 | ||||
| -rw-r--r-- | test/cases/coroutine_await_struct.zig | 47 | ||||
| -rw-r--r-- | test/cases/coroutines.zig | 4 |
13 files changed, 168 insertions, 75 deletions
diff --git a/.gitattributes b/.gitattributes index f86311554f..e4a9c93776 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1 +1,2 @@ *.zig text eol=lf
+langref.html.in text eol=lf
diff --git a/doc/langref.html.in b/doc/langref.html.in index 1da4205b89..3cdcdc6e88 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -616,6 +616,17 @@ test "init with undefined" { assert(x == 1); } {#code_end#} + <p> + <code>undefined</code> can be {#link|implicitly cast|Implicit Casts#} to any type. + Once this happens, it is no longer possible to detect that the value is <code>undefined</code>. + <code>undefined</code> means the value could be anything, even something that is nonsense + according to the type. Translated into English, <code>undefined</code> means "Not a meaningful + value. Using this value would be a bug. The value will be unused, or overwritten before being used." + </p> + <p> + In {#link|Debug#} mode, Zig writes <code>0xaa</code> bytes to undefined memory. This is to catch + bugs early, and to help detect use of undefined memory in a debugger. + </p> {#header_close#} {#header_close#} {#header_close#} @@ -2237,21 +2248,28 @@ test "switch inside function" { {#see_also|comptime|enum|@compileError|Compile Variables#} {#header_close#} {#header_open|while#} + <p> + A while loop is used to repeatedly execute an expression until + some condition is no longer true. + </p> {#code_begin|test|while#} const assert = @import("std").debug.assert; test "while basic" { - // A while loop is used to repeatedly execute an expression until - // some condition is no longer true. var i: usize = 0; while (i < 10) { i += 1; } assert(i == 10); } + {#code_end#} + <p> + Use <code>break</code> to exit a while loop early. + </p> + {#code_begin|test|while#} +const assert = @import("std").debug.assert; test "while break" { - // You can use break to exit a while loop early. var i: usize = 0; while (true) { if (i == 10) @@ -2260,9 +2278,14 @@ test "while break" { } assert(i == 10); } + {#code_end#} + <p> + Use <code>continue</code> to jump back to the beginning of the loop. + </p> + {#code_begin|test|while#} +const assert = @import("std").debug.assert; test "while continue" { - // You can use continue to jump back to the beginning of the loop. var i: usize = 0; while (true) { i += 1; @@ -2272,18 +2295,21 @@ test "while continue" { } assert(i == 10); } + {#code_end#} + <p> + While loops support a continue expression which is executed when the loop + is continued. The <code>continue</code> keyword respects this expression. + </p> + {#code_begin|test|while#} +const assert = @import("std").debug.assert; test "while loop continuation expression" { - // You can give an expression to the while loop to execute when - // the loop is continued. This is respected by the continue control flow. var i: usize = 0; while (i < 10) : (i += 1) {} assert(i == 10); } test "while loop continuation expression, more complicated" { - // More complex blocks can be used as an expression in the loop continue - // expression. var i1: usize = 1; var j1: usize = 1; while (i1 * j1 < 2000) : ({ i1 *= 2; j1 *= 3; }) { @@ -2291,6 +2317,20 @@ test "while loop continuation expression, more complicated" { assert(my_ij1 < 2000); } } + {#code_end#} + <p> + While loops are expressions. The result of the expression is the + result of the <code>else</code> clause of a while loop, which is executed when + the condition of the while loop is tested as false. + </p> + <p> + <code>break</code>, like <code>return</code>, accepts a value + parameter. This is the result of the <code>while</code> expression. + When you <code>break</code> from a while loop, the <code>else</code> branch is not + evaluated. + </p> + {#code_begin|test|while#} +const assert = @import("std").debug.assert; test "while else" { assert(rangeHasNumber(0, 10, 5)); @@ -2299,24 +2339,31 @@ test "while else" { fn rangeHasNumber(begin: usize, end: usize, number: usize) bool { var i = begin; - // While loops are expressions. The result of the expression is the - // result of the else clause of a while loop, which is executed when - // the condition of the while loop is tested as false. return while (i < end) : (i += 1) { if (i == number) { - // break expressions, like return expressions, accept a value - // parameter. This is the result of the while expression. - // When you break from a while loop, the else branch is not - // evaluated. break true; } } else false; } + {#code_end#} + {#header_open|while with Optionals#} + <p> + Just like {#link|if#} expressions, while loops can take an optional as the + condition and capture the payload. When {#link|null#} is encountered the loop + exits. + </p> + <p> + When the <code>|x|</code> syntax is present on a <code>while</code> expression, + the while condition must have an {#link|Optional Type#}. + </p> + <p> + The <code>else</code> branch is allowed on optional iteration. In this case, it will + be executed on the first null value encountered. + </p> + {#code_begin|test|while#} +const assert = @import("std").debug.assert; test "while null capture" { - // Just like if expressions, while loops can take an optional as the - // condition and capture the payload. When null is encountered the loop - // exits. var sum1: u32 = 0; numbers_left = 3; while (eventuallyNullSequence()) |value| { @@ -2324,8 +2371,6 @@ test "while null capture" { } assert(sum1 == 3); - // The else branch is allowed on optional iteration. In this case, it will - // be executed on the first null value encountered. var sum2: u32 = 0; numbers_left = 3; while (eventuallyNullSequence()) |value| { @@ -2333,18 +2378,6 @@ test "while null capture" { } else { assert(sum1 == 3); } - - // Just like if expressions, while loops can also take an error union as - // the condition and capture the payload or the error code. When the - // condition results in an error code the else branch is evaluated and - // the loop is finished. - var sum3: u32 = 0; - numbers_left = 3; - while (eventuallyErrorSequence()) |value| { - sum3 += value; - } else |err| { - assert(err == error.ReachedZero); - } } var numbers_left: u32 = undefined; @@ -2355,6 +2388,35 @@ fn eventuallyNullSequence() ?u32 { }; } + {#code_end#} + {#header_close#} + + {#header_open|while with Error Unions#} + <p> + Just like {#link|if#} expressions, while loops can take an error union as + the condition and capture the payload or the error code. When the + condition results in an error code the else branch is evaluated and + the loop is finished. + </p> + <p> + When the <code>else |x|</code> syntax is present on a <code>while</code> expression, + the while condition must have an {#link|Error Union Type#}. + </p> + {#code_begin|test|while#} +const assert = @import("std").debug.assert; + +test "while error union capture" { + var sum1: u32 = 0; + numbers_left = 3; + while (eventuallyErrorSequence()) |value| { + sum1 += value; + } else |err| { + assert(err == error.ReachedZero); + } +} + +var numbers_left: u32 = undefined; + fn eventuallyErrorSequence() error!u32 { return if (numbers_left == 0) error.ReachedZero else blk: { numbers_left -= 1; @@ -2362,6 +2424,7 @@ fn eventuallyErrorSequence() error!u32 { }; } {#code_end#} + {#header_close#} {#header_open|inline while#} <p> diff --git a/src/analyze.cpp b/src/analyze.cpp index 6f94deb9fd..ca582dfc4c 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -4417,22 +4417,14 @@ Buf *get_linux_libc_include_path(void) { } char *prev_newline = buf_ptr(out_stderr); ZigList<const char *> search_paths = {}; - bool found_search_paths = false; for (;;) { char *newline = strchr(prev_newline, '\n'); if (newline == nullptr) { - zig_panic("unable to determine libc include path: bad output from C compiler command"); + break; } *newline = 0; - if (found_search_paths) { - if (strcmp(prev_newline, "End of search list.") == 0) { - break; - } + if (prev_newline[0] == ' ') { search_paths.append(prev_newline); - } else { - if (strcmp(prev_newline, "#include <...> search starts here:") == 0) { - found_search_paths = true; - } } prev_newline = newline + 1; } diff --git a/src/ir.cpp b/src/ir.cpp index 5df5c1d676..b40c2dc36d 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -6674,7 +6674,10 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *parent_scope, Ast } Buf *result_field_name = buf_create_from_str(RESULT_FIELD_NAME); IrInstruction *promise_result_ptr = ir_build_field_ptr(irb, parent_scope, node, coro_promise_ptr, result_field_name); + // If the type of the result handle_is_ptr then this does not actually perform a load. But we need it to, + // because we're about to destroy the memory. So we store it into our result variable. IrInstruction *no_suspend_result = ir_build_load_ptr(irb, parent_scope, node, promise_result_ptr); + ir_build_store_ptr(irb, parent_scope, node, my_result_var_ptr, no_suspend_result); ir_build_cancel(irb, parent_scope, node, target_inst); ir_build_br(irb, parent_scope, node, merge_block, const_bool_false); @@ -6696,17 +6699,10 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *parent_scope, Ast ir_mark_gen(ir_build_br(irb, parent_scope, node, irb->exec->coro_final_cleanup_block, const_bool_false)); ir_set_cursor_at_end_and_append_block(irb, resume_block); - IrInstruction *yes_suspend_result = ir_build_load_ptr(irb, parent_scope, node, my_result_var_ptr); ir_build_br(irb, parent_scope, node, merge_block, const_bool_false); ir_set_cursor_at_end_and_append_block(irb, merge_block); - IrBasicBlock **incoming_blocks = allocate<IrBasicBlock *>(2); - IrInstruction **incoming_values = allocate<IrInstruction *>(2); - incoming_blocks[0] = resume_block; - incoming_values[0] = yes_suspend_result; - incoming_blocks[1] = no_suspend_block; - incoming_values[1] = no_suspend_result; - return ir_build_phi(irb, parent_scope, node, 2, incoming_blocks, incoming_values); + return ir_build_load_ptr(irb, parent_scope, node, my_result_var_ptr); } static IrInstruction *ir_gen_suspend(IrBuilder *irb, Scope *parent_scope, AstNode *node) { diff --git a/std/mem.zig b/std/mem.zig index ba59faf711..b52d3e9f68 100644 --- a/std/mem.zig +++ b/std/mem.zig @@ -34,7 +34,7 @@ pub const Allocator = struct { /// Call `destroy` with the result pub fn create(self: *Allocator, init: var) Error!*@typeOf(init) { const T = @typeOf(init); - if (@sizeOf(T) == 0) return &{}; + if (@sizeOf(T) == 0) return &(T{}); const slice = try self.alloc(T, 1); const ptr = &slice[0]; ptr.* = init; diff --git a/std/special/compiler_rt/comparetf2.zig b/std/special/compiler_rt/comparetf2.zig index 479ba51962..0912b71bd5 100644 --- a/std/special/compiler_rt/comparetf2.zig +++ b/std/special/compiler_rt/comparetf2.zig @@ -1,4 +1,4 @@ -// TODO https://github.com/ziglang/zig/issues/305 +// TODO https://github.com/ziglang/zig/issues/641 // and then make the return types of some of these functions the enum instead of c_int const LE_LESS = c_int(-1); const LE_EQUAL = c_int(0); @@ -56,7 +56,7 @@ pub extern fn __letf2(a: f128, b: f128) c_int { LE_GREATER; } -// TODO https://github.com/ziglang/zig/issues/305 +// TODO https://github.com/ziglang/zig/issues/641 // and then make the return types of some of these functions the enum instead of c_int const GE_LESS = c_int(-1); const GE_EQUAL = c_int(0); diff --git a/std/special/compiler_rt/fixuint.zig b/std/special/compiler_rt/fixuint.zig index 48d63ed914..55a113b368 100644 --- a/std/special/compiler_rt/fixuint.zig +++ b/std/special/compiler_rt/fixuint.zig @@ -44,14 +44,8 @@ pub fn fixuint(comptime fp_t: type, comptime fixuint_t: type, a: fp_t) fixuint_t // If 0 <= exponent < significandBits, right shift to get the result. // Otherwise, shift left. if (exponent < significandBits) { - // TODO this is a workaround for the mysterious "integer cast truncated bits" - // happening on the next line - @setRuntimeSafety(false); return @intCast(fixuint_t, significand >> @intCast(Log2Int(rep_t), significandBits - exponent)); } else { - // TODO this is a workaround for the mysterious "integer cast truncated bits" - // happening on the next line - @setRuntimeSafety(false); return @intCast(fixuint_t, significand) << @intCast(Log2Int(fixuint_t), exponent - significandBits); } } diff --git a/std/special/compiler_rt/fixunstfdi_test.zig b/std/special/compiler_rt/fixunstfdi_test.zig index dd0869195a..6b1b9b7bd2 100644 --- a/std/special/compiler_rt/fixunstfdi_test.zig +++ b/std/special/compiler_rt/fixunstfdi_test.zig @@ -36,15 +36,14 @@ test "fixunstfdi" { test__fixunstfdi(-0x1.FFFFFFFFFFFFFp+62, 0); test__fixunstfdi(-0x1.FFFFFFFFFFFFEp+62, 0); - // TODO enable these tests when we can parse f128 float literals - //test__fixunstfdi(0x1.FFFFFFFFFFFFFFFEp+63, 0xFFFFFFFFFFFFFFFF); - //test__fixunstfdi(0x1.0000000000000002p+63, 0x8000000000000001); - //test__fixunstfdi(0x1.0000000000000000p+63, 0x8000000000000000); - //test__fixunstfdi(0x1.FFFFFFFFFFFFFFFCp+62, 0x7FFFFFFFFFFFFFFF); - //test__fixunstfdi(0x1.FFFFFFFFFFFFFFF8p+62, 0x7FFFFFFFFFFFFFFE); - //test__fixunstfdi(0x1.p+64, 0xFFFFFFFFFFFFFFFF); - - //test__fixunstfdi(-0x1.0000000000000000p+63, 0); - //test__fixunstfdi(-0x1.FFFFFFFFFFFFFFFCp+62, 0); - //test__fixunstfdi(-0x1.FFFFFFFFFFFFFFF8p+62, 0); + test__fixunstfdi(0x1.FFFFFFFFFFFFFFFEp+63, 0xFFFFFFFFFFFFFFFF); + test__fixunstfdi(0x1.0000000000000002p+63, 0x8000000000000001); + test__fixunstfdi(0x1.0000000000000000p+63, 0x8000000000000000); + test__fixunstfdi(0x1.FFFFFFFFFFFFFFFCp+62, 0x7FFFFFFFFFFFFFFF); + test__fixunstfdi(0x1.FFFFFFFFFFFFFFF8p+62, 0x7FFFFFFFFFFFFFFE); + test__fixunstfdi(0x1.p+64, 0xFFFFFFFFFFFFFFFF); + + test__fixunstfdi(-0x1.0000000000000000p+63, 0); + test__fixunstfdi(-0x1.FFFFFFFFFFFFFFFCp+62, 0); + test__fixunstfdi(-0x1.FFFFFFFFFFFFFFF8p+62, 0); } diff --git a/std/special/compiler_rt/fixunstfsi_test.zig b/std/special/compiler_rt/fixunstfsi_test.zig index f682191994..f47fcb3c86 100644 --- a/std/special/compiler_rt/fixunstfsi_test.zig +++ b/std/special/compiler_rt/fixunstfsi_test.zig @@ -11,9 +11,9 @@ const inf128 = @bitCast(f128, u128(0x7fff0000000000000000000000000000)); test "fixunstfsi" { test__fixunstfsi(inf128, 0xffffffff); test__fixunstfsi(0, 0x0); - //TODO test__fixunstfsi(0x1.23456789abcdefp+5, 0x24); + test__fixunstfsi(0x1.23456789abcdefp+5, 0x24); test__fixunstfsi(0x1.23456789abcdefp-3, 0x0); - //TODO test__fixunstfsi(0x1.23456789abcdefp+20, 0x123456); + test__fixunstfsi(0x1.23456789abcdefp+20, 0x123456); test__fixunstfsi(0x1.23456789abcdefp+40, 0xffffffff); test__fixunstfsi(0x1.23456789abcdefp+256, 0xffffffff); test__fixunstfsi(-0x1.23456789abcdefp+3, 0x0); diff --git a/std/special/compiler_rt/floatunsitf.zig b/std/special/compiler_rt/floatunsitf.zig index 625f90a3d0..19a5918bd0 100644 --- a/std/special/compiler_rt/floatunsitf.zig +++ b/std/special/compiler_rt/floatunsitf.zig @@ -17,7 +17,7 @@ pub extern fn __floatunsitf(a: u64) f128 { const exp = (u64.bit_count - 1) - @clz(a); const shift = mantissa_bits - @intCast(u7, exp); - // TODO: @bitCast alignment error + // TODO(#1148): @bitCast alignment error var result align(16) = (@intCast(u128, a) << shift) ^ implicit_bit; result += (@intCast(u128, exp) + exponent_bias) << mantissa_bits; diff --git a/test/behavior.zig b/test/behavior.zig index 3766ed4305..d47eb8fd6c 100644 --- a/test/behavior.zig +++ b/test/behavior.zig @@ -18,6 +18,7 @@ comptime { _ = @import("cases/cast.zig"); _ = @import("cases/const_slice_child.zig"); _ = @import("cases/coroutines.zig"); + _ = @import("cases/coroutine_await_struct.zig"); _ = @import("cases/defer.zig"); _ = @import("cases/enum.zig"); _ = @import("cases/enum_with_members.zig"); diff --git a/test/cases/coroutine_await_struct.zig b/test/cases/coroutine_await_struct.zig new file mode 100644 index 0000000000..56c526092d --- /dev/null +++ b/test/cases/coroutine_await_struct.zig @@ -0,0 +1,47 @@ +const std = @import("std"); +const builtin = @import("builtin"); +const assert = std.debug.assert; + +const Foo = struct { + x: i32, +}; + +var await_a_promise: promise = undefined; +var await_final_result = Foo{ .x = 0 }; + +test "coroutine await struct" { + var da = std.heap.DirectAllocator.init(); + defer da.deinit(); + + await_seq('a'); + const p = async<&da.allocator> await_amain() catch unreachable; + await_seq('f'); + resume await_a_promise; + await_seq('i'); + assert(await_final_result.x == 1234); + assert(std.mem.eql(u8, await_points, "abcdefghi")); +} +async fn await_amain() void { + await_seq('b'); + const p = async await_another() catch unreachable; + await_seq('e'); + await_final_result = await p; + await_seq('h'); +} +async fn await_another() Foo { + await_seq('c'); + suspend |p| { + await_seq('d'); + await_a_promise = p; + } + await_seq('g'); + return Foo{ .x = 1234 }; +} + +var await_points = []u8{0} ** "abcdefghi".len; +var await_seq_index: usize = 0; + +fn await_seq(c: u8) void { + await_points[await_seq_index] = c; + await_seq_index += 1; +} diff --git a/test/cases/coroutines.zig b/test/cases/coroutines.zig index b3899b306b..f7f2af62a6 100644 --- a/test/cases/coroutines.zig +++ b/test/cases/coroutines.zig @@ -116,14 +116,14 @@ test "coroutine await early return" { defer da.deinit(); early_seq('a'); - const p = async<&da.allocator> early_amain() catch unreachable; + const p = async<&da.allocator> early_amain() catch @panic("out of memory"); early_seq('f'); assert(early_final_result == 1234); assert(std.mem.eql(u8, early_points, "abcdef")); } async fn early_amain() void { early_seq('b'); - const p = async early_another() catch unreachable; + const p = async early_another() catch @panic("out of memory"); early_seq('d'); early_final_result = await p; early_seq('e'); |
