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

This commit is contained in:
Andrew Kelley 2018-07-04 20:43:49 -04:00
commit b5d07297de
13 changed files with 167 additions and 74 deletions

1
.gitattributes vendored
View File

@ -1 +1,2 @@
*.zig text eol=lf
langref.html.in text eol=lf

View File

@ -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>

View File

@ -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;
}

View File

@ -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) {

View File

@ -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;

View File

@ -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);

View File

@ -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);
}
}

View File

@ -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.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.0000000000000000p+63, 0);
test__fixunstfdi(-0x1.FFFFFFFFFFFFFFFCp+62, 0);
test__fixunstfdi(-0x1.FFFFFFFFFFFFFFF8p+62, 0);
}

View File

@ -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);

View File

@ -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;

View File

@ -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");

View File

@ -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;
}

View File

@ -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');