From 02112f88364d0564346a71d4f9fcd1936547d725 Mon Sep 17 00:00:00 2001 From: Veikka Tuominen Date: Tue, 2 Aug 2022 19:15:41 +0300 Subject: AstGen: add error for break/continue out of defer expression --- src/AstGen.zig | 46 +++++++++++++++++++++- .../cannot_break_out_of_defer_expression.zig | 14 +++++++ .../cannot_continue_out_of_defer_expression.zig | 14 +++++++ .../obj/cannot_break_out_of_defer_expression.zig | 13 ------ .../cannot_continue_out_of_defer_expression.zig | 13 ------ 5 files changed, 73 insertions(+), 27 deletions(-) create mode 100644 test/cases/compile_errors/cannot_break_out_of_defer_expression.zig create mode 100644 test/cases/compile_errors/cannot_continue_out_of_defer_expression.zig delete mode 100644 test/cases/compile_errors/stage1/obj/cannot_break_out_of_defer_expression.zig delete mode 100644 test/cases/compile_errors/stage1/obj/cannot_continue_out_of_defer_expression.zig diff --git a/src/AstGen.zig b/src/AstGen.zig index b2bbb27865..051f1dace8 100644 --- a/src/AstGen.zig +++ b/src/AstGen.zig @@ -1899,6 +1899,17 @@ fn breakExpr(parent_gz: *GenZir, parent_scope: *Scope, node: Ast.Node.Index) Inn .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent, .namespace => break, .defer_normal, .defer_error => scope = scope.cast(Scope.Defer).?.parent, + .defer_gen => { + const defer_gen = scope.cast(Scope.DeferGen).?; + + return astgen.failNodeNotes(node, "cannot break out of defer expression", .{}, &.{ + try astgen.errNoteNode( + defer_gen.defer_node, + "defer expression here", + .{}, + ), + }); + }, .top => unreachable, } } @@ -1958,6 +1969,17 @@ fn continueExpr(parent_gz: *GenZir, parent_scope: *Scope, node: Ast.Node.Index) try unusedResultDeferExpr(parent_gz, defer_scope, defer_scope.parent, expr_node); }, .defer_error => scope = scope.cast(Scope.Defer).?.parent, + .defer_gen => { + const defer_gen = scope.cast(Scope.DeferGen).?; + + return astgen.failNodeNotes(node, "cannot continue out of defer expression", .{}, &.{ + try astgen.errNoteNode( + defer_gen.defer_node, + "defer expression here", + .{}, + ), + }); + }, .namespace => break, .top => unreachable, } @@ -2022,6 +2044,7 @@ fn checkLabelRedefinition(astgen: *AstGen, parent_scope: *Scope, label: Ast.Toke .local_val => scope = scope.cast(Scope.LocalVal).?.parent, .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent, .defer_normal, .defer_error => scope = scope.cast(Scope.Defer).?.parent, + .defer_gen => scope = scope.cast(Scope.DeferGen).?.parent, .namespace => break, .top => unreachable, } @@ -2206,7 +2229,13 @@ fn unusedResultDeferExpr(gz: *GenZir, defer_scope: *Scope.Defer, expr_scope: *Sc astgen.source_offset = defer_scope.source_offset; astgen.source_line = defer_scope.source_line; astgen.source_column = defer_scope.source_column; - _ = try unusedResultExpr(gz, expr_scope, expr_node); + + var defer_gen: Scope.DeferGen = .{ + .parent = expr_scope, + .defer_node = defer_scope.defer_node, + }; + + _ = try unusedResultExpr(gz, &defer_gen.base, expr_node); } /// Returns AST source node of the thing that is noreturn if the statement is @@ -2553,6 +2582,7 @@ fn countDefers(astgen: *AstGen, outer_scope: *Scope, inner_scope: *Scope) struct .gen_zir => scope = scope.cast(GenZir).?.parent, .local_val => scope = scope.cast(Scope.LocalVal).?.parent, .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent, + .defer_gen => scope = scope.cast(Scope.DeferGen).?.parent, .defer_normal => { const defer_scope = scope.cast(Scope.Defer).?; scope = defer_scope.parent; @@ -2602,6 +2632,7 @@ fn genDefers( .gen_zir => scope = scope.cast(GenZir).?.parent, .local_val => scope = scope.cast(Scope.LocalVal).?.parent, .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent, + .defer_gen => scope = scope.cast(Scope.DeferGen).?.parent, .defer_normal => { const defer_scope = scope.cast(Scope.Defer).?; scope = defer_scope.parent; @@ -2681,6 +2712,7 @@ fn checkUsed( scope = s.parent; }, .defer_normal, .defer_error => scope = scope.cast(Scope.Defer).?.parent, + .defer_gen => scope = scope.cast(Scope.DeferGen).?.parent, .namespace => unreachable, .top => unreachable, } @@ -4040,6 +4072,7 @@ fn testDecl( .local_val, .local_ptr => unreachable, // a test cannot be in a local scope .gen_zir => s = s.cast(GenZir).?.parent, .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent, + .defer_gen => s = s.cast(Scope.DeferGen).?.parent, .namespace => { const ns = s.cast(Scope.Namespace).?; if (ns.decls.get(name_str_index)) |i| { @@ -6730,6 +6763,7 @@ fn localVarRef( }, .gen_zir => s = s.cast(GenZir).?.parent, .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent, + .defer_gen => s = s.cast(Scope.DeferGen).?.parent, .namespace => { const ns = s.cast(Scope.Namespace).?; if (ns.decls.get(name_str_index)) |i| { @@ -7351,6 +7385,7 @@ fn builtinCall( }, .gen_zir => s = s.cast(GenZir).?.parent, .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent, + .defer_gen => s = s.cast(Scope.DeferGen).?.parent, .namespace => { const ns = s.cast(Scope.Namespace).?; if (ns.decls.get(decl_name)) |i| { @@ -9808,6 +9843,7 @@ const Scope = struct { local_ptr, defer_normal, defer_error, + defer_gen, namespace, top, }; @@ -9905,6 +9941,13 @@ const Scope = struct { const base_tag: Scope.Tag = .top; base: Scope = Scope{ .tag = base_tag }, }; + + const DeferGen = struct { + const base_tag: Scope.Tag = .defer_gen; + base: Scope = Scope{ .tag = base_tag }, + parent: *Scope, + defer_node: Ast.Node.Index, + }; }; /// This is a temporary structure; references to it are valid only @@ -11415,6 +11458,7 @@ fn detectLocalShadowing( }, .gen_zir => s = s.cast(GenZir).?.parent, .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent, + .defer_gen => s = s.cast(Scope.DeferGen).?.parent, .top => break, }; } diff --git a/test/cases/compile_errors/cannot_break_out_of_defer_expression.zig b/test/cases/compile_errors/cannot_break_out_of_defer_expression.zig new file mode 100644 index 0000000000..454309eb89 --- /dev/null +++ b/test/cases/compile_errors/cannot_break_out_of_defer_expression.zig @@ -0,0 +1,14 @@ +export fn foo() void { + while (true) { + defer { + break; + } + } +} + +// error +// backend=stage2 +// target=native +// +// :4:13: error: cannot break out of defer expression +// :3:9: note: defer expression here diff --git a/test/cases/compile_errors/cannot_continue_out_of_defer_expression.zig b/test/cases/compile_errors/cannot_continue_out_of_defer_expression.zig new file mode 100644 index 0000000000..74d11528eb --- /dev/null +++ b/test/cases/compile_errors/cannot_continue_out_of_defer_expression.zig @@ -0,0 +1,14 @@ +export fn foo() void { + while (true) { + defer { + continue; + } + } +} + +// error +// backend=stage2 +// target=native +// +// :4:13: error: cannot continue out of defer expression +// :3:9: note: defer expression here diff --git a/test/cases/compile_errors/stage1/obj/cannot_break_out_of_defer_expression.zig b/test/cases/compile_errors/stage1/obj/cannot_break_out_of_defer_expression.zig deleted file mode 100644 index 3c7ae4fa2f..0000000000 --- a/test/cases/compile_errors/stage1/obj/cannot_break_out_of_defer_expression.zig +++ /dev/null @@ -1,13 +0,0 @@ -export fn foo() void { - while (true) { - defer { - break; - } - } -} - -// error -// backend=stage1 -// target=native -// -// tmp.zig:4:13: error: cannot break out of defer expression diff --git a/test/cases/compile_errors/stage1/obj/cannot_continue_out_of_defer_expression.zig b/test/cases/compile_errors/stage1/obj/cannot_continue_out_of_defer_expression.zig deleted file mode 100644 index 56b8ced05b..0000000000 --- a/test/cases/compile_errors/stage1/obj/cannot_continue_out_of_defer_expression.zig +++ /dev/null @@ -1,13 +0,0 @@ -export fn foo() void { - while (true) { - defer { - continue; - } - } -} - -// error -// backend=stage1 -// target=native -// -// tmp.zig:4:13: error: cannot continue out of defer expression -- cgit v1.2.3