authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-07-19 18:05:01-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-07-19 18:06:41-04:00
log0a880d5e6034ab35778e4f4db33a385b2a5ad7cc
tree62e683c9fd635a07a3e61dd9018ac4eec3be3e2b
parent0736e6aa347f065c15c7acaa0a7d2cc61b85bba6

fix generation of error defers for fns inside fns

closes #878

2 files changed, 74 insertions(+), 25 deletions(-)

src/ir.cpp+59-25
......@@ -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+15
......@@ -61,3 +61,18 @@ test "defer and labeled break" {
6161
6262 assert(i == 1);
6363}
64
65test "errdefer does not apply to fn inside fn" {
66 if (testNestedFnErrDefer()) |_| @panic("expected error") else |e| assert(e == error.Bad);
67}
68
69fn 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}