diff options
| -rw-r--r-- | doc/langref.html.in | 13 | ||||
| -rw-r--r-- | src/ir.cpp | 23 | ||||
| -rw-r--r-- | test/compile_errors.zig | 24 | ||||
| -rw-r--r-- | test/runtime_safety.zig | 2 | ||||
| -rw-r--r-- | test/stage1/behavior/async_fn.zig | 4 | ||||
| -rw-r--r-- | test/stage1/behavior/new_stack_call.zig | 2 |
6 files changed, 57 insertions, 11 deletions
diff --git a/doc/langref.html.in b/doc/langref.html.in index 2e56bc6557..b2f313b234 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -6379,7 +6379,7 @@ comptime { {#header_close#} {#header_open|@asyncCall#} - <pre>{#syntax#}@asyncCall(frame_buffer: []u8, result_ptr, function_ptr, args: ...) anyframe->T{#endsyntax#}</pre> + <pre>{#syntax#}@asyncCall(frame_buffer: []align(@alignOf(@Frame(anyAsyncFunction))) u8, result_ptr, function_ptr, args: ...) anyframe->T{#endsyntax#}</pre> <p> {#syntax#}@asyncCall{#endsyntax#} performs an {#syntax#}async{#endsyntax#} call on a function pointer, which may or may not be an {#link|async function|Async Functions#}. @@ -6405,7 +6405,7 @@ test "async fn pointer in a struct field" { bar: async fn (*i32) void, }; var foo = Foo{ .bar = func }; - var bytes: [64]u8 = undefined; + var bytes: [64]u8 align(@alignOf(@Frame(func))) = undefined; const f = @asyncCall(&bytes, {}, foo.bar, &data); assert(data == 2); resume f; @@ -7322,17 +7322,22 @@ mem.set(u8, dest, c);{#endsyntax#}</pre> {#header_close#} {#header_open|@newStackCall#} - <pre>{#syntax#}@newStackCall(new_stack: []u8, function: var, args: ...) var{#endsyntax#}</pre> + <pre>{#syntax#}@newStackCall(new_stack: []align(target_stack_align) u8, function: var, args: ...) var{#endsyntax#}</pre> <p> This calls a function, in the same way that invoking an expression with parentheses does. However, instead of using the same stack as the caller, the function uses the stack provided in the {#syntax#}new_stack{#endsyntax#} parameter. </p> + <p> + The new stack must be aligned to {#syntax#}target_stack_align{#endsyntax#} bytes. This is a target-specific + number. A safe value that will work on all targets is {#syntax#}16{#endsyntax#}. This value can + also be obtained by using {#link|@sizeOf#} on the {#link|@Frame#} type of {#link|Async Functions#}. + </p> {#code_begin|test#} const std = @import("std"); const assert = std.debug.assert; -var new_stack_bytes: [1024]u8 = undefined; +var new_stack_bytes: [1024]u8 align(16) = undefined; test "calling a function with a new stack" { const arg = 1234; diff --git a/src/ir.cpp b/src/ir.cpp index 0129081e22..15c570ddd9 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -12110,7 +12110,26 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst array_type->data.array.child_type, source_node, !slice_ptr_type->data.pointer.is_const).id == ConstCastResultIdOk) { - return ir_resolve_ptr_of_array_to_slice(ira, source_instr, value, wanted_type, result_loc); + // If the pointers both have ABI align, it works. + bool ok_align = slice_ptr_type->data.pointer.explicit_alignment == 0 && + actual_type->data.pointer.explicit_alignment == 0; + if (!ok_align) { + // If either one has non ABI align, we have to resolve them both + if ((err = type_resolve(ira->codegen, actual_type->data.pointer.child_type, + ResolveStatusAlignmentKnown))) + { + return ira->codegen->invalid_instruction; + } + if ((err = type_resolve(ira->codegen, slice_ptr_type->data.pointer.child_type, + ResolveStatusAlignmentKnown))) + { + return ira->codegen->invalid_instruction; + } + ok_align = get_ptr_align(ira->codegen, actual_type) >= get_ptr_align(ira->codegen, slice_ptr_type); + } + if (ok_align) { + return ir_resolve_ptr_of_array_to_slice(ira, source_instr, value, wanted_type, result_loc); + } } } @@ -15421,7 +15440,7 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c IrInstruction *casted_new_stack = nullptr; if (call_instruction->new_stack != nullptr) { ZigType *u8_ptr = get_pointer_to_type_extra(ira->codegen, ira->codegen->builtin_types.entry_u8, - false, false, PtrLenUnknown, 0, 0, 0, false); + false, false, PtrLenUnknown, target_fn_align(ira->codegen->zig_target), 0, 0, false); ZigType *u8_slice = get_slice_type(ira->codegen, u8_ptr); IrInstruction *new_stack = call_instruction->new_stack->child; if (type_is_invalid(new_stack->value.type)) diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 5eec78fa7f..2088b32d98 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -3,6 +3,28 @@ const builtin = @import("builtin"); pub fn addCases(cases: *tests.CompileErrorContext) void { cases.add( + "bad alignment in @asyncCall", + \\export fn entry() void { + \\ var ptr: async fn () void = func; + \\ var bytes: [64]u8 = undefined; + \\ _ = @asyncCall(&bytes, {}, ptr); + \\} + \\async fn func() void {} + , + "tmp.zig:4:21: error: expected type '[]align(16) u8', found '*[64]u8'", + ); + + cases.add( + "bad alignment in implicit cast from array pointer to slice", + \\export fn a() void { + \\ var x: [10]u8 = undefined; + \\ var y: []align(16) u8 = &x; + \\} + , + "tmp.zig:3:30: error: expected type '[]align(16) u8', found '*[10]u8'", + ); + + cases.add( "result location incompatibility mismatching handle_is_ptr (generic call)", \\export fn entry() void { \\ var damn = Container{ @@ -164,7 +186,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { "non async function pointer passed to @asyncCall", \\export fn entry() void { \\ var ptr = afunc; - \\ var bytes: [100]u8 = undefined; + \\ var bytes: [100]u8 align(16) = undefined; \\ _ = @asyncCall(&bytes, {}, ptr); \\} \\fn afunc() void { } diff --git a/test/runtime_safety.zig b/test/runtime_safety.zig index 0fb593c0e2..07a8c3910a 100644 --- a/test/runtime_safety.zig +++ b/test/runtime_safety.zig @@ -30,7 +30,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { \\ @import("std").os.exit(126); \\} \\pub fn main() void { - \\ var bytes: [1]u8 = undefined; + \\ var bytes: [1]u8 align(16) = undefined; \\ var ptr = other; \\ var frame = @asyncCall(&bytes, {}, ptr); \\} diff --git a/test/stage1/behavior/async_fn.zig b/test/stage1/behavior/async_fn.zig index e1b173292b..cb9bf2c1ea 100644 --- a/test/stage1/behavior/async_fn.zig +++ b/test/stage1/behavior/async_fn.zig @@ -280,7 +280,7 @@ test "async fn pointer in a struct field" { bar: async fn (*i32) void, }; var foo = Foo{ .bar = simpleAsyncFn2 }; - var bytes: [64]u8 = undefined; + var bytes: [64]u8 align(16) = undefined; const f = @asyncCall(&bytes, {}, foo.bar, &data); comptime expect(@typeOf(f) == anyframe->void); expect(data == 2); @@ -317,7 +317,7 @@ test "@asyncCall with return type" { } }; var foo = Foo{ .bar = Foo.middle }; - var bytes: [150]u8 = undefined; + var bytes: [150]u8 align(16) = undefined; var aresult: i32 = 0; _ = @asyncCall(&bytes, &aresult, foo.bar); expect(aresult == 0); diff --git a/test/stage1/behavior/new_stack_call.zig b/test/stage1/behavior/new_stack_call.zig index 1e01a5a8a2..cbda9a2435 100644 --- a/test/stage1/behavior/new_stack_call.zig +++ b/test/stage1/behavior/new_stack_call.zig @@ -1,7 +1,7 @@ const std = @import("std"); const expect = std.testing.expect; -var new_stack_bytes: [1024]u8 = undefined; +var new_stack_bytes: [1024]u8 align(16) = undefined; test "calling a function with a new stack" { const arg = 1234; |
