mirror of
https://github.com/ziglang/zig.git
synced 2026-02-13 04:48:20 +00:00
Merge pull request #4320 from fengb/while-spills
Add async spills to while captured variables
This commit is contained in:
commit
4fad16284e
12
src/ir.cpp
12
src/ir.cpp
@ -8111,6 +8111,7 @@ static IrInstSrc *ir_gen_while_expr(IrBuilderSrc *irb, Scope *scope, AstNode *no
|
||||
} else {
|
||||
payload_scope = subexpr_scope;
|
||||
}
|
||||
ScopeExpr *spill_scope = create_expr_scope(irb->codegen, node, payload_scope);
|
||||
IrInstSrc *err_val_ptr = ir_gen_node_extra(irb, node->data.while_expr.condition, subexpr_scope,
|
||||
LValPtr, nullptr);
|
||||
if (err_val_ptr == irb->codegen->invalid_inst_src)
|
||||
@ -8134,10 +8135,10 @@ static IrInstSrc *ir_gen_while_expr(IrBuilderSrc *irb, Scope *scope, AstNode *no
|
||||
|
||||
ir_set_cursor_at_end_and_append_block(irb, body_block);
|
||||
if (var_symbol) {
|
||||
IrInstSrc *payload_ptr = ir_build_unwrap_err_payload_src(irb, payload_scope, symbol_node,
|
||||
IrInstSrc *payload_ptr = ir_build_unwrap_err_payload_src(irb, &spill_scope->base, symbol_node,
|
||||
err_val_ptr, false, false);
|
||||
IrInstSrc *var_ptr = node->data.while_expr.var_is_ptr ?
|
||||
ir_build_ref_src(irb, payload_scope, symbol_node, payload_ptr, true, false) : payload_ptr;
|
||||
ir_build_ref_src(irb, &spill_scope->base, symbol_node, payload_ptr, true, false) : payload_ptr;
|
||||
ir_build_var_decl_src(irb, payload_scope, symbol_node, payload_var, nullptr, var_ptr);
|
||||
}
|
||||
|
||||
@ -8152,6 +8153,7 @@ static IrInstSrc *ir_gen_while_expr(IrBuilderSrc *irb, Scope *scope, AstNode *no
|
||||
loop_scope->incoming_values = &incoming_values;
|
||||
loop_scope->lval = lval;
|
||||
loop_scope->peer_parent = peer_parent;
|
||||
loop_scope->spill_scope = spill_scope;
|
||||
|
||||
// Note the body block of the loop is not the place that lval and result_loc are used -
|
||||
// it's actually in break statements, handled similarly to return statements.
|
||||
@ -8222,6 +8224,7 @@ static IrInstSrc *ir_gen_while_expr(IrBuilderSrc *irb, Scope *scope, AstNode *no
|
||||
ZigVar *payload_var = ir_create_var(irb, symbol_node, subexpr_scope, var_symbol,
|
||||
true, false, false, is_comptime);
|
||||
Scope *child_scope = payload_var->child_scope;
|
||||
ScopeExpr *spill_scope = create_expr_scope(irb->codegen, node, child_scope);
|
||||
IrInstSrc *maybe_val_ptr = ir_gen_node_extra(irb, node->data.while_expr.condition, subexpr_scope,
|
||||
LValPtr, nullptr);
|
||||
if (maybe_val_ptr == irb->codegen->invalid_inst_src)
|
||||
@ -8244,9 +8247,9 @@ static IrInstSrc *ir_gen_while_expr(IrBuilderSrc *irb, Scope *scope, AstNode *no
|
||||
is_comptime);
|
||||
|
||||
ir_set_cursor_at_end_and_append_block(irb, body_block);
|
||||
IrInstSrc *payload_ptr = ir_build_optional_unwrap_ptr(irb, child_scope, symbol_node, maybe_val_ptr, false, false);
|
||||
IrInstSrc *payload_ptr = ir_build_optional_unwrap_ptr(irb, &spill_scope->base, symbol_node, maybe_val_ptr, false, false);
|
||||
IrInstSrc *var_ptr = node->data.while_expr.var_is_ptr ?
|
||||
ir_build_ref_src(irb, child_scope, symbol_node, payload_ptr, true, false) : payload_ptr;
|
||||
ir_build_ref_src(irb, &spill_scope->base, symbol_node, payload_ptr, true, false) : payload_ptr;
|
||||
ir_build_var_decl_src(irb, child_scope, symbol_node, payload_var, nullptr, var_ptr);
|
||||
|
||||
ZigList<IrInstSrc *> incoming_values = {0};
|
||||
@ -8260,6 +8263,7 @@ static IrInstSrc *ir_gen_while_expr(IrBuilderSrc *irb, Scope *scope, AstNode *no
|
||||
loop_scope->incoming_values = &incoming_values;
|
||||
loop_scope->lval = lval;
|
||||
loop_scope->peer_parent = peer_parent;
|
||||
loop_scope->spill_scope = spill_scope;
|
||||
|
||||
// Note the body block of the loop is not the place that lval and result_loc are used -
|
||||
// it's actually in break statements, handled similarly to return statements.
|
||||
|
||||
@ -1182,6 +1182,42 @@ test "suspend in for loop" {
|
||||
S.doTheTest();
|
||||
}
|
||||
|
||||
test "suspend in while loop" {
|
||||
const S = struct {
|
||||
var global_frame: ?anyframe = null;
|
||||
|
||||
fn doTheTest() void {
|
||||
_ = async atest();
|
||||
while (global_frame) |f| resume f;
|
||||
}
|
||||
|
||||
fn atest() void {
|
||||
expect(optional(6) == 6);
|
||||
expect(errunion(6) == 6);
|
||||
}
|
||||
fn optional(stuff: ?u32) u32 {
|
||||
global_frame = @frame();
|
||||
defer global_frame = null;
|
||||
while (stuff) |val| {
|
||||
suspend;
|
||||
return val;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
fn errunion(stuff: anyerror!u32) u32 {
|
||||
global_frame = @frame();
|
||||
defer global_frame = null;
|
||||
while (stuff) |val| {
|
||||
suspend;
|
||||
return val;
|
||||
} else |err| {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
};
|
||||
S.doTheTest();
|
||||
}
|
||||
|
||||
test "correctly spill when returning the error union result of another async fn" {
|
||||
const S = struct {
|
||||
var global_frame: anyframe = undefined;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user