Skip to content

Commit 0a880d5

Browse files
committedJul 19, 2018
fix generation of error defers for fns inside fns
closes #878
·
0.15.10.3.0
1 parent 0736e6a commit 0a880d5

File tree

2 files changed

+74
-25
lines changed

2 files changed

+74
-25
lines changed
 

‎src/ir.cpp‎

Lines changed: 59 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2961,16 +2961,34 @@ static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_sco
29612961
results[ReturnKindUnconditional] = 0;
29622962
results[ReturnKindError] = 0;
29632963

2964-
while (inner_scope != outer_scope) {
2965-
assert(inner_scope);
2966-
if (inner_scope->id == ScopeIdDefer) {
2967-
AstNode *defer_node = inner_scope->source_node;
2968-
assert(defer_node->type == NodeTypeDefer);
2969-
ReturnKind defer_kind = defer_node->data.defer.kind;
2970-
results[defer_kind] += 1;
2964+
Scope *scope = inner_scope;
29712965

2966+
while (scope != outer_scope) {
2967+
assert(scope);
2968+
switch (scope->id) {
2969+
case ScopeIdDefer: {
2970+
AstNode *defer_node = scope->source_node;
2971+
assert(defer_node->type == NodeTypeDefer);
2972+
ReturnKind defer_kind = defer_node->data.defer.kind;
2973+
results[defer_kind] += 1;
2974+
scope = scope->parent;
2975+
continue;
2976+
}
2977+
case ScopeIdDecls:
2978+
case ScopeIdFnDef:
2979+
return;
2980+
case ScopeIdBlock:
2981+
case ScopeIdVarDecl:
2982+
case ScopeIdLoop:
2983+
case ScopeIdSuspend:
2984+
case ScopeIdCompTime:
2985+
scope = scope->parent;
2986+
continue;
2987+
case ScopeIdDeferExpr:
2988+
case ScopeIdCImport:
2989+
case ScopeIdCoroPrelude:
2990+
zig_unreachable();
29722991
}
2973-
inner_scope = inner_scope->parent;
29742992
}
29752993
}
29762994

@@ -2986,27 +3004,43 @@ static bool ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *o
29863004
if (!scope)
29873005
return is_noreturn;
29883006

2989-
if (scope->id == ScopeIdDefer) {
2990-
AstNode *defer_node = scope->source_node;
2991-
assert(defer_node->type == NodeTypeDefer);
2992-
ReturnKind defer_kind = defer_node->data.defer.kind;
2993-
if (defer_kind == ReturnKindUnconditional ||
2994-
(gen_error_defers && defer_kind == ReturnKindError))
2995-
{
2996-
AstNode *defer_expr_node = defer_node->data.defer.expr;
2997-
Scope *defer_expr_scope = defer_node->data.defer.expr_scope;
2998-
IrInstruction *defer_expr_value = ir_gen_node(irb, defer_expr_node, defer_expr_scope);
2999-
if (defer_expr_value != irb->codegen->invalid_instruction) {
3000-
if (defer_expr_value->value.type != nullptr && defer_expr_value->value.type->id == TypeTableEntryIdUnreachable) {
3001-
is_noreturn = true;
3002-
} else {
3003-
ir_mark_gen(ir_build_check_statement_is_void(irb, defer_expr_scope, defer_expr_node, defer_expr_value));
3007+
switch (scope->id) {
3008+
case ScopeIdDefer: {
3009+
AstNode *defer_node = scope->source_node;
3010+
assert(defer_node->type == NodeTypeDefer);
3011+
ReturnKind defer_kind = defer_node->data.defer.kind;
3012+
if (defer_kind == ReturnKindUnconditional ||
3013+
(gen_error_defers && defer_kind == ReturnKindError))
3014+
{
3015+
AstNode *defer_expr_node = defer_node->data.defer.expr;
3016+
Scope *defer_expr_scope = defer_node->data.defer.expr_scope;
3017+
IrInstruction *defer_expr_value = ir_gen_node(irb, defer_expr_node, defer_expr_scope);
3018+
if (defer_expr_value != irb->codegen->invalid_instruction) {
3019+
if (defer_expr_value->value.type != nullptr && defer_expr_value->value.type->id == TypeTableEntryIdUnreachable) {
3020+
is_noreturn = true;
3021+
} else {
3022+
ir_mark_gen(ir_build_check_statement_is_void(irb, defer_expr_scope, defer_expr_node, defer_expr_value));
3023+
}
30043024
}
30053025
}
3026+
scope = scope->parent;
3027+
continue;
30063028
}
3007-
3029+
case ScopeIdDecls:
3030+
case ScopeIdFnDef:
3031+
return is_noreturn;
3032+
case ScopeIdBlock:
3033+
case ScopeIdVarDecl:
3034+
case ScopeIdLoop:
3035+
case ScopeIdSuspend:
3036+
case ScopeIdCompTime:
3037+
scope = scope->parent;
3038+
continue;
3039+
case ScopeIdDeferExpr:
3040+
case ScopeIdCImport:
3041+
case ScopeIdCoroPrelude:
3042+
zig_unreachable();
30083043
}
3009-
scope = scope->parent;
30103044
}
30113045
return is_noreturn;
30123046
}

‎test/cases/defer.zig‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,3 +61,18 @@ test "defer and labeled break" {
6161

6262
assert(i == 1);
6363
}
64+
65+
test "errdefer does not apply to fn inside fn" {
66+
if (testNestedFnErrDefer()) |_| @panic("expected error") else |e| assert(e == error.Bad);
67+
}
68+
69+
fn testNestedFnErrDefer() error!void {
70+
var a: i32 = 0;
71+
errdefer a += 1;
72+
const S = struct {
73+
fn baz() error {
74+
return error.Bad;
75+
}
76+
};
77+
return S.baz();
78+
}

0 commit comments

Comments
 (0)
Please sign in to comment.