authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-02-09 21:10:59-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-02-09 21:38:34-05:00
logcaf672c49586f1af5e3d41ae200aded991b8b0f7
tree76b8e9dd955342c6a7ccda3ca62eade39edb4c5f
parent31be1ddf09fafae270d9946a3f09aa25816dd153
signature Commit is signed but in an unrecognized format.

`@truncate`: comptime 0 when target type is 0 bits

also if the dest type is a comptime_int, then treat it as an implicit cast. also compile error for attempting to truncate undefined closes #1568

4 files changed, 56 insertions(+), 13 deletions(-)

doc/langref.html.in+7-4
...@@ -6381,14 +6381,14 @@ fn List(comptime T: type) type {...@@ -6381,14 +6381,14 @@ fn List(comptime T: type) type {
6381 {#header_close#}6381 {#header_close#}
63826382
6383 {#header_open|@truncate#}6383 {#header_open|@truncate#}
6384 <pre>{#syntax#}@truncate(comptime T: type, integer) T{#endsyntax#}</pre>6384 <pre>{#syntax#}@truncate(comptime T: type, integer: var) T{#endsyntax#}</pre>
6385 <p>6385 <p>
6386 This function truncates bits from an integer type, resulting in a smaller6386 This function truncates bits from an integer type, resulting in a smaller
6387 integer type.6387 integer type.
6388 </p>6388 </p>
6389 <p>6389 <p>
6390 The following produces a crash in debug mode and undefined behavior in6390 The following produces a crash in {#link|Debug#} mode and {#link|Undefined Behavior#} in
6391 release mode:6391 {#link|ReleaseFast#} mode:
6392 </p>6392 </p>
6393 <pre>{#syntax#}const a: u16 = 0xabcd;6393 <pre>{#syntax#}const a: u16 = 0xabcd;
6394const b: u8 = u8(a);{#endsyntax#}</pre>6394const b: u8 = u8(a);{#endsyntax#}</pre>
...@@ -6402,7 +6402,10 @@ const b: u8 = @truncate(u8, a);...@@ -6402,7 +6402,10 @@ const b: u8 = @truncate(u8, a);
6402 This function always truncates the significant bits of the integer, regardless6402 This function always truncates the significant bits of the integer, regardless
6403 of endianness on the target platform.6403 of endianness on the target platform.
6404 </p>6404 </p>
64056405 <p>
6406 If {#syntax#}T{#endsyntax#} is {#syntax#}comptime_int{#endsyntax#},
6407 then this is semantically equivalent to an {#link|implicit cast|Implicit Casts#}.
6408 </p>
6406 {#header_close#}6409 {#header_close#}
64076410
6408 {#header_open|@typeId#}6411 {#header_open|@typeId#}
src/ir.cpp+16-8
...@@ -18491,7 +18491,22 @@ static IrInstruction *ir_analyze_instruction_truncate(IrAnalyze *ira, IrInstruct...@@ -18491,7 +18491,22 @@ static IrInstruction *ir_analyze_instruction_truncate(IrAnalyze *ira, IrInstruct
18491 return ira->codegen->invalid_instruction;18491 return ira->codegen->invalid_instruction;
18492 }18492 }
1849318493
18494 if (src_type->data.integral.bit_count == 0) {18494 if (dest_type->id == ZigTypeIdComptimeInt) {
18495 return ir_implicit_cast(ira, target, dest_type);
18496 }
18497
18498 if (instr_is_comptime(target)) {
18499 ConstExprValue *val = ir_resolve_const(ira, target, UndefBad);
18500 if (val == nullptr)
18501 return ira->codegen->invalid_instruction;
18502
18503 IrInstruction *result = ir_const(ira, &instruction->base, dest_type);
18504 bigint_truncate(&result->value.data.x_bigint, &val->data.x_bigint,
18505 dest_type->data.integral.bit_count, dest_type->data.integral.is_signed);
18506 return result;
18507 }
18508
18509 if (src_type->data.integral.bit_count == 0 || dest_type->data.integral.bit_count == 0) {
18495 IrInstruction *result = ir_const(ira, &instruction->base, dest_type);18510 IrInstruction *result = ir_const(ira, &instruction->base, dest_type);
18496 bigint_init_unsigned(&result->value.data.x_bigint, 0);18511 bigint_init_unsigned(&result->value.data.x_bigint, 0);
18497 return result;18512 return result;
...@@ -18507,13 +18522,6 @@ static IrInstruction *ir_analyze_instruction_truncate(IrAnalyze *ira, IrInstruct...@@ -18507,13 +18522,6 @@ static IrInstruction *ir_analyze_instruction_truncate(IrAnalyze *ira, IrInstruct
18507 return ira->codegen->invalid_instruction;18522 return ira->codegen->invalid_instruction;
18508 }18523 }
1850918524
18510 if (target->value.special == ConstValSpecialStatic) {
18511 IrInstruction *result = ir_const(ira, &instruction->base, dest_type);
18512 bigint_truncate(&result->value.data.x_bigint, &target->value.data.x_bigint,
18513 dest_type->data.integral.bit_count, dest_type->data.integral.is_signed);
18514 return result;
18515 }
18516
18517 IrInstruction *new_instruction = ir_build_truncate(&ira->new_irb, instruction->base.scope,18525 IrInstruction *new_instruction = ir_build_truncate(&ira->new_irb, instruction->base.scope,
18518 instruction->base.source_node, dest_type_value, target);18526 instruction->base.source_node, dest_type_value, target);
18519 new_instruction->value.type = dest_type;18527 new_instruction->value.type = dest_type;
test/compile_errors.zig+10-1
...@@ -1,6 +1,15 @@...@@ -1,6 +1,15 @@
1const tests = @import("tests.zig");1const tests = @import("tests.zig");
22
3pub fn addCases(cases: *tests.CompileErrorContext) void {3pub fn addCases(cases: *tests.CompileErrorContext) void {
4 cases.addTest(
5 "@truncate undefined value",
6 \\export fn entry() void {
7 \\ var z = @truncate(u8, u16(undefined));
8 \\}
9 ,
10 ".tmp_source.zig:2:30: error: use of undefined value",
11 );
12
4 cases.addTest(13 cases.addTest(
5 "return invalid type from test",14 "return invalid type from test",
6 \\test "example" { return 1; }15 \\test "example" { return 1; }
...@@ -3335,7 +3344,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3335,7 +3344,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3335 cases.add(3344 cases.add(
3336 "truncate sign mismatch",3345 "truncate sign mismatch",
3337 \\fn f() i8 {3346 \\fn f() i8 {
3338 \\ const x: u32 = 10;3347 \\ var x: u32 = 10;
3339 \\ return @truncate(i8, x);3348 \\ return @truncate(i8, x);
3340 \\}3349 \\}
3341 \\3350 \\
test/stage1/behavior/truncate.zig+23
...@@ -6,3 +6,26 @@ test "truncate u0 to larger integer allowed and has comptime known result" {...@@ -6,3 +6,26 @@ test "truncate u0 to larger integer allowed and has comptime known result" {
6 const y = @truncate(u8, x);6 const y = @truncate(u8, x);
7 comptime expect(y == 0);7 comptime expect(y == 0);
8}8}
9
10test "truncate.u0.literal" {
11 var z = @truncate(u0, 0);
12 expect(z == 0);
13}
14
15test "truncate.u0.const" {
16 const c0: usize = 0;
17 var z = @truncate(u0, c0);
18 expect(z == 0);
19}
20
21test "truncate.u0.var" {
22 var d: u8 = 2;
23 var z = @truncate(u0, d);
24 expect(z == 0);
25}
26
27test "truncate sign mismatch but comptime known so it works anyway" {
28 const x: u32 = 10;
29 var result = @truncate(i8, x);
30 expect(result == 10);
31}