aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Kelley <superjoe30@gmail.com>2018-07-04 20:43:49 -0400
committerAndrew Kelley <superjoe30@gmail.com>2018-07-04 20:43:49 -0400
commitb5d07297dec61a3993dfe91ceee2c87672db1e8e (patch)
tree519d097fcdfe121e38814a080868a85f5b1f9e64
parent9665cfe027c70a84cb6351ea6ecb833a728736aa (diff)
parent8c39cdc89f2ae7fc25c3856e7c4c6b4662ac8a80 (diff)
downloadzig-b5d07297dec61a3993dfe91ceee2c87672db1e8e.tar.gz
zig-b5d07297dec61a3993dfe91ceee2c87672db1e8e.zip
Merge remote-tracking branch 'origin/master' into llvm7
-rw-r--r--.gitattributes1
-rw-r--r--doc/langref.html.in127
-rw-r--r--src/analyze.cpp12
-rw-r--r--src/ir.cpp12
-rw-r--r--std/mem.zig2
-rw-r--r--std/special/compiler_rt/comparetf2.zig4
-rw-r--r--std/special/compiler_rt/fixuint.zig6
-rw-r--r--std/special/compiler_rt/fixunstfdi_test.zig21
-rw-r--r--std/special/compiler_rt/fixunstfsi_test.zig4
-rw-r--r--std/special/compiler_rt/floatunsitf.zig2
-rw-r--r--test/behavior.zig1
-rw-r--r--test/cases/coroutine_await_struct.zig47
-rw-r--r--test/cases/coroutines.zig4
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');