authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-05-28 17:29:56-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-05-28 17:29:56-07:00
log3f5ca3920a58d44a018ff2a2e277e60813e20d5a
treeff156147167ab13852411e5b2e9a6eed51ab88d0
parent54f774f7966e48a8419dbe2d3b37ae974ec03a83

AstGen: properly restore previous state after temporary changes

Before this, if a compile error occurred, it would cause the previous value for e.g. the function scope to not get reset. If the AstGen process continued, it would result in a violation of the data guarantees that it relies on. This commit takes advantage of defer to ensure the previous value is always reset, even in the case of an error. Closes #8920

2 files changed, 24 insertions(+), 14 deletions(-)

src/AstGen.zig+10-12
...@@ -249,9 +249,9 @@ pub const bool_rl: ResultLoc = .{ .ty = .bool_type };...@@ -249,9 +249,9 @@ pub const bool_rl: ResultLoc = .{ .ty = .bool_type };
249fn typeExpr(gz: *GenZir, scope: *Scope, type_node: ast.Node.Index) InnerError!Zir.Inst.Ref {249fn typeExpr(gz: *GenZir, scope: *Scope, type_node: ast.Node.Index) InnerError!Zir.Inst.Ref {
250 const prev_force_comptime = gz.force_comptime;250 const prev_force_comptime = gz.force_comptime;
251 gz.force_comptime = true;251 gz.force_comptime = true;
252 const e = expr(gz, scope, .{ .ty = .type_type }, type_node);252 defer gz.force_comptime = prev_force_comptime;
253 gz.force_comptime = prev_force_comptime;253
254 return e;254 return expr(gz, scope, .{ .ty = .type_type }, type_node);
255}255}
256256
257fn lvalExpr(gz: *GenZir, scope: *Scope, node: ast.Node.Index) InnerError!Zir.Inst.Ref {257fn lvalExpr(gz: *GenZir, scope: *Scope, node: ast.Node.Index) InnerError!Zir.Inst.Ref {
...@@ -1465,9 +1465,9 @@ fn comptimeExpr(...@@ -1465,9 +1465,9 @@ fn comptimeExpr(
1465) InnerError!Zir.Inst.Ref {1465) InnerError!Zir.Inst.Ref {
1466 const prev_force_comptime = gz.force_comptime;1466 const prev_force_comptime = gz.force_comptime;
1467 gz.force_comptime = true;1467 gz.force_comptime = true;
1468 const result = try expr(gz, scope, rl, node);1468 defer gz.force_comptime = prev_force_comptime;
1469 gz.force_comptime = prev_force_comptime;1469
1470 return result;1470 return expr(gz, scope, rl, node);
1471}1471}
14721472
1473/// This one is for an actual `comptime` syntax, and will emit a compile error if1473/// This one is for an actual `comptime` syntax, and will emit a compile error if
...@@ -2121,8 +2121,8 @@ fn genDefers(...@@ -2121,8 +2121,8 @@ fn genDefers(
2121 const expr_node = node_datas[defer_scope.defer_node].rhs;2121 const expr_node = node_datas[defer_scope.defer_node].rhs;
2122 const prev_in_defer = gz.in_defer;2122 const prev_in_defer = gz.in_defer;
2123 gz.in_defer = true;2123 gz.in_defer = true;
2124 defer gz.in_defer = prev_in_defer;
2124 try unusedResultExpr(gz, defer_scope.parent, expr_node);2125 try unusedResultExpr(gz, defer_scope.parent, expr_node);
2125 gz.in_defer = prev_in_defer;
2126 },2126 },
2127 .defer_error => {2127 .defer_error => {
2128 const defer_scope = scope.cast(Scope.Defer).?;2128 const defer_scope = scope.cast(Scope.Defer).?;
...@@ -2131,8 +2131,8 @@ fn genDefers(...@@ -2131,8 +2131,8 @@ fn genDefers(
2131 const expr_node = node_datas[defer_scope.defer_node].rhs;2131 const expr_node = node_datas[defer_scope.defer_node].rhs;
2132 const prev_in_defer = gz.in_defer;2132 const prev_in_defer = gz.in_defer;
2133 gz.in_defer = true;2133 gz.in_defer = true;
2134 defer gz.in_defer = prev_in_defer;
2134 try unusedResultExpr(gz, defer_scope.parent, expr_node);2135 try unusedResultExpr(gz, defer_scope.parent, expr_node);
2135 gz.in_defer = prev_in_defer;
2136 },2136 },
2137 .namespace => unreachable,2137 .namespace => unreachable,
2138 .top => unreachable,2138 .top => unreachable,
...@@ -2887,6 +2887,7 @@ fn fnDecl(...@@ -2887,6 +2887,7 @@ fn fnDecl(
28872887
2888 const prev_fn_block = astgen.fn_block;2888 const prev_fn_block = astgen.fn_block;
2889 astgen.fn_block = &fn_gz;2889 astgen.fn_block = &fn_gz;
2890 defer astgen.fn_block = prev_fn_block;
28902891
2891 // Iterate over the parameters. We put the param names as the first N2892 // Iterate over the parameters. We put the param names as the first N
2892 // items inside `extra` so that debug info later can refer to the parameter names2893 // items inside `extra` so that debug info later can refer to the parameter names
...@@ -2938,8 +2939,6 @@ fn fnDecl(...@@ -2938,8 +2939,6 @@ fn fnDecl(
2938 _ = try fn_gz.addUnTok(.ret_coerce, .void_value, tree.lastToken(body_node));2939 _ = try fn_gz.addUnTok(.ret_coerce, .void_value, tree.lastToken(body_node));
2939 }2940 }
29402941
2941 astgen.fn_block = prev_fn_block;
2942
2943 break :func try decl_gz.addFunc(.{2942 break :func try decl_gz.addFunc(.{
2944 .src_node = decl_node,2943 .src_node = decl_node,
2945 .ret_ty = return_type_inst,2944 .ret_ty = return_type_inst,
...@@ -3276,6 +3275,7 @@ fn testDecl(...@@ -3276,6 +3275,7 @@ fn testDecl(
32763275
3277 const prev_fn_block = astgen.fn_block;3276 const prev_fn_block = astgen.fn_block;
3278 astgen.fn_block = &fn_block;3277 astgen.fn_block = &fn_block;
3278 defer astgen.fn_block = prev_fn_block;
32793279
3280 const block_result = try expr(&fn_block, &fn_block.base, .none, body_node);3280 const block_result = try expr(&fn_block, &fn_block.base, .none, body_node);
3281 if (fn_block.instructions.items.len == 0 or !fn_block.refIsNoReturn(block_result)) {3281 if (fn_block.instructions.items.len == 0 or !fn_block.refIsNoReturn(block_result)) {
...@@ -3284,8 +3284,6 @@ fn testDecl(...@@ -3284,8 +3284,6 @@ fn testDecl(
3284 _ = try fn_block.addUnTok(.ret_coerce, .void_value, tree.lastToken(body_node));3284 _ = try fn_block.addUnTok(.ret_coerce, .void_value, tree.lastToken(body_node));
3285 }3285 }
32863286
3287 astgen.fn_block = prev_fn_block;
3288
3289 const func_inst = try decl_block.addFunc(.{3287 const func_inst = try decl_block.addFunc(.{
3290 .src_node = node,3288 .src_node = node,
3291 .ret_ty = .void_type,3289 .ret_ty = .void_type,
test/stage2/test.zig+14-2
...@@ -938,8 +938,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -938,8 +938,7 @@ pub fn addCases(ctx: *TestContext) !void {
938 \\pub fn b() !void {938 \\pub fn b() !void {
939 \\ defer return a();939 \\ defer return a();
940 \\}940 \\}
941941 , &[_][]const u8{
942 , &[_][]const u8{
943 ":7:8: error: try is not allowed inside defer expression",942 ":7:8: error: try is not allowed inside defer expression",
944 ":10:8: error: cannot return from defer expression",943 ":10:8: error: cannot return from defer expression",
945 });944 });
...@@ -979,6 +978,19 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -979,6 +978,19 @@ pub fn addCases(ctx: *TestContext) !void {
979 ":3:9: error: local shadows declaration of 'testing'",978 ":3:9: error: local shadows declaration of 'testing'",
980 ":1:1: note: declared here",979 ":1:1: note: declared here",
981 });980 });
981 case.addError(
982 \\fn a() type {
983 \\ return struct {
984 \\ pub fn b() void {
985 \\ const c = 6;
986 \\ const c = 69;
987 \\ }
988 \\ };
989 \\}
990 , &[_][]const u8{
991 ":5:19: error: redeclaration of 'c'",
992 ":4:19: note: previously declared here",
993 });
982 }994 }
983995
984 {996 {