zig

fork of https://codeberg.org/ziglang/zig
Log | Files | Refs | README | LICENSE

commit bcbcb2e9ffbfef63d3692ea45eea2e2babacc3a9 (tree)
parent 1864acd32608ae917f8afc11b11f08a4bb362cef
Author: Andrew Kelley <andrew@ziglang.org>
Date:   Sun, 10 Feb 2019 11:03:17 -0500

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

Diffstat:
Mdoc/langref.html.in | 16++++++++++------
Msrc/analyze.cpp | 3+++
Msrc/ir.cpp | 24++++++++++++++++--------
Mstd/testing.zig | 6+-----
Mtest/compile_errors.zig | 11++++++++++-
Mtest/stage1/behavior/error.zig | 5+++++
Mtest/stage1/behavior/truncate.zig | 23+++++++++++++++++++++++
7 files changed, 68 insertions(+), 20 deletions(-)

diff --git a/doc/langref.html.in b/doc/langref.html.in @@ -6381,14 +6381,14 @@ fn List(comptime T: type) type { {#header_close#} {#header_open|@truncate#} - <pre>{#syntax#}@truncate(comptime T: type, integer) T{#endsyntax#}</pre> + <pre>{#syntax#}@truncate(comptime T: type, integer: var) T{#endsyntax#}</pre> <p> This function truncates bits from an integer type, resulting in a smaller integer type. </p> <p> - The following produces a crash in debug mode and undefined behavior in - release mode: + The following produces a crash in {#link|Debug#} mode and {#link|Undefined Behavior#} in + {#link|ReleaseFast#} mode: </p> <pre>{#syntax#}const a: u16 = 0xabcd; const b: u8 = u8(a);{#endsyntax#}</pre> @@ -6402,7 +6402,10 @@ const b: u8 = @truncate(u8, a); This function always truncates the significant bits of the integer, regardless of endianness on the target platform. </p> - + <p> + If {#syntax#}T{#endsyntax#} is {#syntax#}comptime_int{#endsyntax#}, + then this is semantically equivalent to an {#link|implicit cast|Implicit Casts#}. + </p> {#header_close#} {#header_open|@typeId#} @@ -7870,7 +7873,7 @@ TopLevelComptime &lt;- KEYWORD_comptime BlockExpr TopLevelDecl &lt;- (KEYWORD_export / KEYWORD_extern STRINGLITERAL? / KEYWORD_inline)? FnProto (SEMICOLON / Block) - / (KEYWORD_export / KEYWORD_extern STRINGLITERAL?)? VarDecl + / (KEYWORD_export / KEYWORD_extern STRINGLITERAL?)? KEYWORD_threadlocal? VarDecl / KEYWORD_use Expr SEMICOLON FnProto &lt;- FnCC? KEYWORD_fn IDENTIFIER? LPAREN ParamDeclList RPAREN ByteAlign? LinkSection? EXCLAMATIONMARK? (KEYWORD_var / TypeExpr) @@ -8330,6 +8333,7 @@ KEYWORD_struct &lt;- 'struct' end_of_word KEYWORD_suspend &lt;- 'suspend' end_of_word KEYWORD_switch &lt;- 'switch' end_of_word KEYWORD_test &lt;- 'test' end_of_word +KEYWORD_threadlocal &lt;- 'threadlocal' end_of_word KEYWORD_true &lt;- 'true' end_of_word KEYWORD_try &lt;- 'try' end_of_word KEYWORD_undefined &lt;- 'undefined' end_of_word @@ -8350,7 +8354,7 @@ keyword &lt;- KEYWORD_align / KEYWORD_and / KEYWORD_anyerror / KEYWORD_asm / KEYWORD_orelse / KEYWORD_packed / KEYWORD_promise / KEYWORD_pub / KEYWORD_resume / KEYWORD_return / KEYWORD_linksection / KEYWORD_stdcallcc / KEYWORD_struct / KEYWORD_suspend - / KEYWORD_switch / KEYWORD_test / KEYWORD_true / KEYWORD_try + / KEYWORD_switch / KEYWORD_test / KEYWORD_threadlocal / KEYWORD_true / KEYWORD_try / KEYWORD_undefined / KEYWORD_union / KEYWORD_unreachable / KEYWORD_use / KEYWORD_var / KEYWORD_volatile / KEYWORD_while</code></pre> {#header_close#} diff --git a/src/analyze.cpp b/src/analyze.cpp @@ -594,6 +594,9 @@ ZigType *get_optional_type(CodeGen *g, ZigType *child_type) { // function types are technically pointers entry->type_ref = child_type->type_ref; entry->di_type = child_type->di_type; + if (entry->di_type == g->builtin_types.entry_global_error_set->di_type) { + g->error_di_types.append(&entry->di_type); + } } else { assert(child_type->di_type); // create a struct with a boolean whether this is the null value diff --git a/src/ir.cpp b/src/ir.cpp @@ -18491,7 +18491,22 @@ static IrInstruction *ir_analyze_instruction_truncate(IrAnalyze *ira, IrInstruct return ira->codegen->invalid_instruction; } - if (src_type->data.integral.bit_count == 0) { + if (dest_type->id == ZigTypeIdComptimeInt) { + return ir_implicit_cast(ira, target, dest_type); + } + + if (instr_is_comptime(target)) { + ConstExprValue *val = ir_resolve_const(ira, target, UndefBad); + if (val == nullptr) + return ira->codegen->invalid_instruction; + + IrInstruction *result = ir_const(ira, &instruction->base, dest_type); + bigint_truncate(&result->value.data.x_bigint, &val->data.x_bigint, + dest_type->data.integral.bit_count, dest_type->data.integral.is_signed); + return result; + } + + if (src_type->data.integral.bit_count == 0 || dest_type->data.integral.bit_count == 0) { IrInstruction *result = ir_const(ira, &instruction->base, dest_type); bigint_init_unsigned(&result->value.data.x_bigint, 0); return result; @@ -18507,13 +18522,6 @@ static IrInstruction *ir_analyze_instruction_truncate(IrAnalyze *ira, IrInstruct return ira->codegen->invalid_instruction; } - if (target->value.special == ConstValSpecialStatic) { - IrInstruction *result = ir_const(ira, &instruction->base, dest_type); - bigint_truncate(&result->value.data.x_bigint, &target->value.data.x_bigint, - dest_type->data.integral.bit_count, dest_type->data.integral.is_signed); - return result; - } - IrInstruction *new_instruction = ir_build_truncate(&ira->new_irb, instruction->base.scope, instruction->base.source_node, dest_type_value, target); new_instruction->value.type = dest_type; diff --git a/std/testing.zig b/std/testing.zig @@ -24,11 +24,7 @@ pub fn expectError(expected_error: anyerror, actual_error_union: var) void { /// equal, prints diagnostics to stderr to show exactly how they are not equal, /// then aborts. /// The types must match exactly. -pub fn expectEqual(expected: var, actual: var) void { - if (@typeOf(actual) != @typeOf(expected)) { - @compileError("type mismatch. expected " ++ @typeName(@typeOf(expected)) ++ ", found " ++ @typeName(@typeOf(actual))); - } - +pub fn expectEqual(expected: var, actual: @typeOf(expected)) void { switch (@typeInfo(@typeOf(actual))) { TypeId.NoReturn, TypeId.BoundFn, diff --git a/test/compile_errors.zig b/test/compile_errors.zig @@ -2,6 +2,15 @@ const tests = @import("tests.zig"); pub fn addCases(cases: *tests.CompileErrorContext) void { cases.addTest( + "@truncate undefined value", + \\export fn entry() void { + \\ var z = @truncate(u8, u16(undefined)); + \\} + , + ".tmp_source.zig:2:30: error: use of undefined value", + ); + + cases.addTest( "return invalid type from test", \\test "example" { return 1; } , @@ -3335,7 +3344,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { cases.add( "truncate sign mismatch", \\fn f() i8 { - \\ const x: u32 = 10; + \\ var x: u32 = 10; \\ return @truncate(i8, x); \\} \\ diff --git a/test/stage1/behavior/error.zig b/test/stage1/behavior/error.zig @@ -330,3 +330,8 @@ test "optional error set is the same size as error set" { expect(S.returnsOptErrSet() == null); comptime expect(S.returnsOptErrSet() == null); } + +test "debug info for optional error set" { + const SomeError = error{Hello}; + var a_local_variable: ?SomeError = null; +} diff --git a/test/stage1/behavior/truncate.zig b/test/stage1/behavior/truncate.zig @@ -6,3 +6,26 @@ test "truncate u0 to larger integer allowed and has comptime known result" { const y = @truncate(u8, x); comptime expect(y == 0); } + +test "truncate.u0.literal" { + var z = @truncate(u0, 0); + expect(z == 0); +} + +test "truncate.u0.const" { + const c0: usize = 0; + var z = @truncate(u0, c0); + expect(z == 0); +} + +test "truncate.u0.var" { + var d: u8 = 2; + var z = @truncate(u0, d); + expect(z == 0); +} + +test "truncate sign mismatch but comptime known so it works anyway" { + const x: u32 = 10; + var result = @truncate(i8, x); + expect(result == 10); +}