authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-07-09 11:13:29-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-07-09 11:13:29-04:00
log2ee67b7642cfeef36d8ebbc08080202b5b1d1958
treed031afb8e49237cf040b8fe4c2af72ab86239abd
parent9eb51e20ed1a040a617541303db760f80ffd3aa1

langref: docs for invalid error set cast and incorrect pointer alignment

also add detection of incorrect pointer alignment at compile-time of pointers that were constructed with `@intToPtr`.

3 files changed, 70 insertions(+), 3 deletions(-)

doc/langref.html.in+51-3
...@@ -6649,12 +6649,60 @@ pub fn main() void {...@@ -6649,12 +6649,60 @@ pub fn main() void {
6649 {#header_close#}6649 {#header_close#}
66506650
6651 {#header_open|Invalid Error Set Cast#}6651 {#header_open|Invalid Error Set Cast#}
6652 <p>TODO</p>6652 <p>At compile-time:</p>
6653 {#code_begin|test_err|error.B not a member of error set 'Set2'#}
6654const Set1 = error{
6655 A,
6656 B,
6657};
6658const Set2 = error{
6659 A,
6660 C,
6661};
6662comptime {
6663 _ = @errSetCast(Set2, Set1.B);
6664}
6665 {#code_end#}
6666 <p>At runtime:</p>
6667 {#code_begin|exe_err#}
6668const Set1 = error{
6669 A,
6670 B,
6671};
6672const Set2 = error{
6673 A,
6674 C,
6675};
6676pub fn main() void {
6677 _ = foo(Set1.B);
6678}
6679fn foo(set1: Set1) Set2 {
6680 return @errSetCast(Set2, set1);
6681}
6682 {#code_end#}
6653 {#header_close#}6683 {#header_close#}
66546684
6655 {#header_open|Incorrect Pointer Alignment#}6685 {#header_open|Incorrect Pointer Alignment#}
6656 <p>TODO</p>6686 <p>At compile-time:</p>
66576687 {#code_begin|test_err|pointer address 0x1 is not aligned to 4 bytes#}
6688comptime {
6689 const ptr = @intToPtr(*i32, 0x1);
6690 const aligned = @alignCast(4, ptr);
6691}
6692 {#code_end#}
6693 <p>At runtime:</p>
6694 {#code_begin|exe_err#}
6695pub fn main() !void {
6696 var array align(4) = []u32{ 0x11111111, 0x11111111 };
6697 const bytes = @sliceToBytes(array[0..]);
6698 if (foo(bytes) != 0x11111111) return error.Wrong;
6699}
6700fn foo(bytes: []u8) u32 {
6701 const slice4 = bytes[1..5];
6702 const int_slice = @bytesToSlice(u32, @alignCast(4, slice4));
6703 return int_slice[0];
6704}
6705 {#code_end#}
6658 {#header_close#}6706 {#header_close#}
6659 {#header_open|Wrong Union Field Access#}6707 {#header_open|Wrong Union Field Access#}
6660 <p>TODO</p>6708 <p>TODO</p>
src/ir.cpp+9
...@@ -19370,6 +19370,15 @@ static IrInstruction *ir_align_cast(IrAnalyze *ira, IrInstruction *target, uint3...@@ -19370,6 +19370,15 @@ static IrInstruction *ir_align_cast(IrAnalyze *ira, IrInstruction *target, uint3
19370 if (!val)19370 if (!val)
19371 return ira->codegen->invalid_instruction;19371 return ira->codegen->invalid_instruction;
1937219372
19373 if (val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr &&
19374 val->data.x_ptr.data.hard_coded_addr.addr % align_bytes != 0)
19375 {
19376 ir_add_error(ira, target,
19377 buf_sprintf("pointer address 0x%lx is not aligned to %" PRIu32 " bytes",
19378 val->data.x_ptr.data.hard_coded_addr.addr, align_bytes));
19379 return ira->codegen->invalid_instruction;
19380 }
19381
19373 IrInstruction *result = ir_create_const(&ira->new_irb, target->scope, target->source_node, result_type);19382 IrInstruction *result = ir_create_const(&ira->new_irb, target->scope, target->source_node, result_type);
19374 copy_const_val(&result->value, val, false);19383 copy_const_val(&result->value, val, false);
19375 result->value.type = result_type;19384 result->value.type = result_type;
test/compile_errors.zig+10
...@@ -1,6 +1,16 @@...@@ -1,6 +1,16 @@
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.add(
5 "bad @alignCast at comptime",
6 \\comptime {
7 \\ const ptr = @intToPtr(*i32, 0x1);
8 \\ const aligned = @alignCast(4, ptr);
9 \\}
10 ,
11 ".tmp_source.zig:3:35: error: pointer address 0x1 is not aligned to 4 bytes",
12 );
13
4 cases.add(14 cases.add(
5 "@ptrToInt on *void",15 "@ptrToInt on *void",
6 \\export fn entry() bool {16 \\export fn entry() bool {