| author | |
| committer | |
| log | 4d8a6f6fea1b6922e7904b33c5b575249213fe53 |
| tree | d2ad5906dd41a73827475157619ac36976b4092d |
| parent | 456a244d62df62940f4d860cd9f57b40d563ca96 |
| signature |
closes #30866 files changed, 57 insertions(+), 11 deletions(-)
doc/langref.html.in+9-4| ... | ... | @@ -6379,7 +6379,7 @@ comptime { |
| 6379 | 6379 | {#header_close#} |
| 6380 | 6380 | |
| 6381 | 6381 | {#header_open|@asyncCall#} |
| 6382 | <pre>{#syntax#}@asyncCall(frame_buffer: []u8, result_ptr, function_ptr, args: ...) anyframe->T{#endsyntax#}</pre> | |
| 6382 | <pre>{#syntax#}@asyncCall(frame_buffer: []align(@alignOf(@Frame(anyAsyncFunction))) u8, result_ptr, function_ptr, args: ...) anyframe->T{#endsyntax#}</pre> | |
| 6383 | 6383 | <p> |
| 6384 | 6384 | {#syntax#}@asyncCall{#endsyntax#} performs an {#syntax#}async{#endsyntax#} call on a function pointer, |
| 6385 | 6385 | which may or may not be an {#link|async function|Async Functions#}. |
| ... | ... | @@ -6405,7 +6405,7 @@ test "async fn pointer in a struct field" { |
| 6405 | 6405 | bar: async fn (*i32) void, |
| 6406 | 6406 | }; |
| 6407 | 6407 | var foo = Foo{ .bar = func }; |
| 6408 | var bytes: [64]u8 = undefined; | |
| 6408 | var bytes: [64]u8 align(@alignOf(@Frame(func))) = undefined; | |
| 6409 | 6409 | const f = @asyncCall(&bytes, {}, foo.bar, &data); |
| 6410 | 6410 | assert(data == 2); |
| 6411 | 6411 | resume f; |
| ... | ... | @@ -7322,17 +7322,22 @@ mem.set(u8, dest, c);{#endsyntax#}</pre> |
| 7322 | 7322 | {#header_close#} |
| 7323 | 7323 | |
| 7324 | 7324 | {#header_open|@newStackCall#} |
| 7325 | <pre>{#syntax#}@newStackCall(new_stack: []u8, function: var, args: ...) var{#endsyntax#}</pre> | |
| 7325 | <pre>{#syntax#}@newStackCall(new_stack: []align(target_stack_align) u8, function: var, args: ...) var{#endsyntax#}</pre> | |
| 7326 | 7326 | <p> |
| 7327 | 7327 | This calls a function, in the same way that invoking an expression with parentheses does. However, |
| 7328 | 7328 | instead of using the same stack as the caller, the function uses the stack provided in the {#syntax#}new_stack{#endsyntax#} |
| 7329 | 7329 | parameter. |
| 7330 | 7330 | </p> |
| 7331 | <p> | |
| 7332 | The new stack must be aligned to {#syntax#}target_stack_align{#endsyntax#} bytes. This is a target-specific | |
| 7333 | number. A safe value that will work on all targets is {#syntax#}16{#endsyntax#}. This value can | |
| 7334 | also be obtained by using {#link|@sizeOf#} on the {#link|@Frame#} type of {#link|Async Functions#}. | |
| 7335 | </p> | |
| 7331 | 7336 | {#code_begin|test#} |
| 7332 | 7337 | const std = @import("std"); |
| 7333 | 7338 | const assert = std.debug.assert; |
| 7334 | 7339 | |
| 7335 | var new_stack_bytes: [1024]u8 = undefined; | |
| 7340 | var new_stack_bytes: [1024]u8 align(16) = undefined; | |
| 7336 | 7341 | |
| 7337 | 7342 | test "calling a function with a new stack" { |
| 7338 | 7343 | const arg = 1234; |
src/ir.cpp+21-2| ... | ... | @@ -12110,7 +12110,26 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst |
| 12110 | 12110 | array_type->data.array.child_type, source_node, |
| 12111 | 12111 | !slice_ptr_type->data.pointer.is_const).id == ConstCastResultIdOk) |
| 12112 | 12112 | { |
| 12113 | return ir_resolve_ptr_of_array_to_slice(ira, source_instr, value, wanted_type, result_loc); | |
| 12113 | // If the pointers both have ABI align, it works. | |
| 12114 | bool ok_align = slice_ptr_type->data.pointer.explicit_alignment == 0 && | |
| 12115 | actual_type->data.pointer.explicit_alignment == 0; | |
| 12116 | if (!ok_align) { | |
| 12117 | // If either one has non ABI align, we have to resolve them both | |
| 12118 | if ((err = type_resolve(ira->codegen, actual_type->data.pointer.child_type, | |
| 12119 | ResolveStatusAlignmentKnown))) | |
| 12120 | { | |
| 12121 | return ira->codegen->invalid_instruction; | |
| 12122 | } | |
| 12123 | if ((err = type_resolve(ira->codegen, slice_ptr_type->data.pointer.child_type, | |
| 12124 | ResolveStatusAlignmentKnown))) | |
| 12125 | { | |
| 12126 | return ira->codegen->invalid_instruction; | |
| 12127 | } | |
| 12128 | ok_align = get_ptr_align(ira->codegen, actual_type) >= get_ptr_align(ira->codegen, slice_ptr_type); | |
| 12129 | } | |
| 12130 | if (ok_align) { | |
| 12131 | return ir_resolve_ptr_of_array_to_slice(ira, source_instr, value, wanted_type, result_loc); | |
| 12132 | } | |
| 12114 | 12133 | } |
| 12115 | 12134 | } |
| 12116 | 12135 | |
| ... | ... | @@ -15421,7 +15440,7 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c |
| 15421 | 15440 | IrInstruction *casted_new_stack = nullptr; |
| 15422 | 15441 | if (call_instruction->new_stack != nullptr) { |
| 15423 | 15442 | ZigType *u8_ptr = get_pointer_to_type_extra(ira->codegen, ira->codegen->builtin_types.entry_u8, |
| 15424 | false, false, PtrLenUnknown, 0, 0, 0, false); | |
| 15443 | false, false, PtrLenUnknown, target_fn_align(ira->codegen->zig_target), 0, 0, false); | |
| 15425 | 15444 | ZigType *u8_slice = get_slice_type(ira->codegen, u8_ptr); |
| 15426 | 15445 | IrInstruction *new_stack = call_instruction->new_stack->child; |
| 15427 | 15446 | if (type_is_invalid(new_stack->value.type)) |
test/compile_errors.zig+23-1| ... | ... | @@ -2,6 +2,28 @@ const tests = @import("tests.zig"); |
| 2 | 2 | const builtin = @import("builtin"); |
| 3 | 3 | |
| 4 | 4 | pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 5 | cases.add( | |
| 6 | "bad alignment in @asyncCall", | |
| 7 | \\export fn entry() void { | |
| 8 | \\ var ptr: async fn () void = func; | |
| 9 | \\ var bytes: [64]u8 = undefined; | |
| 10 | \\ _ = @asyncCall(&bytes, {}, ptr); | |
| 11 | \\} | |
| 12 | \\async fn func() void {} | |
| 13 | , | |
| 14 | "tmp.zig:4:21: error: expected type '[]align(16) u8', found '*[64]u8'", | |
| 15 | ); | |
| 16 | ||
| 17 | cases.add( | |
| 18 | "bad alignment in implicit cast from array pointer to slice", | |
| 19 | \\export fn a() void { | |
| 20 | \\ var x: [10]u8 = undefined; | |
| 21 | \\ var y: []align(16) u8 = &x; | |
| 22 | \\} | |
| 23 | , | |
| 24 | "tmp.zig:3:30: error: expected type '[]align(16) u8', found '*[10]u8'", | |
| 25 | ); | |
| 26 | ||
| 5 | 27 | cases.add( |
| 6 | 28 | "result location incompatibility mismatching handle_is_ptr (generic call)", |
| 7 | 29 | \\export fn entry() void { |
| ... | ... | @@ -164,7 +186,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 164 | 186 | "non async function pointer passed to @asyncCall", |
| 165 | 187 | \\export fn entry() void { |
| 166 | 188 | \\ var ptr = afunc; |
| 167 | \\ var bytes: [100]u8 = undefined; | |
| 189 | \\ var bytes: [100]u8 align(16) = undefined; | |
| 168 | 190 | \\ _ = @asyncCall(&bytes, {}, ptr); |
| 169 | 191 | \\} |
| 170 | 192 | \\fn afunc() void { } |
test/runtime_safety.zig+1-1| ... | ... | @@ -30,7 +30,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 30 | 30 | \\ @import("std").os.exit(126); |
| 31 | 31 | \\} |
| 32 | 32 | \\pub fn main() void { |
| 33 | \\ var bytes: [1]u8 = undefined; | |
| 33 | \\ var bytes: [1]u8 align(16) = undefined; | |
| 34 | 34 | \\ var ptr = other; |
| 35 | 35 | \\ var frame = @asyncCall(&bytes, {}, ptr); |
| 36 | 36 | \\} |
test/stage1/behavior/async_fn.zig+2-2| ... | ... | @@ -280,7 +280,7 @@ test "async fn pointer in a struct field" { |
| 280 | 280 | bar: async fn (*i32) void, |
| 281 | 281 | }; |
| 282 | 282 | var foo = Foo{ .bar = simpleAsyncFn2 }; |
| 283 | var bytes: [64]u8 = undefined; | |
| 283 | var bytes: [64]u8 align(16) = undefined; | |
| 284 | 284 | const f = @asyncCall(&bytes, {}, foo.bar, &data); |
| 285 | 285 | comptime expect(@typeOf(f) == anyframe->void); |
| 286 | 286 | expect(data == 2); |
| ... | ... | @@ -317,7 +317,7 @@ test "@asyncCall with return type" { |
| 317 | 317 | } |
| 318 | 318 | }; |
| 319 | 319 | var foo = Foo{ .bar = Foo.middle }; |
| 320 | var bytes: [150]u8 = undefined; | |
| 320 | var bytes: [150]u8 align(16) = undefined; | |
| 321 | 321 | var aresult: i32 = 0; |
| 322 | 322 | _ = @asyncCall(&bytes, &aresult, foo.bar); |
| 323 | 323 | expect(aresult == 0); |
test/stage1/behavior/new_stack_call.zig+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | const std = @import("std"); |
| 2 | 2 | const expect = std.testing.expect; |
| 3 | 3 | |
| 4 | var new_stack_bytes: [1024]u8 = undefined; | |
| 4 | var new_stack_bytes: [1024]u8 align(16) = undefined; | |
| 5 | 5 | |
| 6 | 6 | test "calling a function with a new stack" { |
| 7 | 7 | const arg = 1234; |