Commit 3f5ca3920a

Andrew Kelley <andrew@ziglang.org>
2021-05-29 02:29:56
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
1 parent 54f774f
Changed files (2)
src
test
stage2
src/AstGen.zig
@@ -249,9 +249,9 @@ pub const bool_rl: ResultLoc = .{ .ty = .bool_type };
 fn typeExpr(gz: *GenZir, scope: *Scope, type_node: ast.Node.Index) InnerError!Zir.Inst.Ref {
     const prev_force_comptime = gz.force_comptime;
     gz.force_comptime = true;
-    const e = expr(gz, scope, .{ .ty = .type_type }, type_node);
-    gz.force_comptime = prev_force_comptime;
-    return e;
+    defer gz.force_comptime = prev_force_comptime;
+
+    return expr(gz, scope, .{ .ty = .type_type }, type_node);
 }
 
 fn lvalExpr(gz: *GenZir, scope: *Scope, node: ast.Node.Index) InnerError!Zir.Inst.Ref {
@@ -1465,9 +1465,9 @@ fn comptimeExpr(
 ) InnerError!Zir.Inst.Ref {
     const prev_force_comptime = gz.force_comptime;
     gz.force_comptime = true;
-    const result = try expr(gz, scope, rl, node);
-    gz.force_comptime = prev_force_comptime;
-    return result;
+    defer gz.force_comptime = prev_force_comptime;
+
+    return expr(gz, scope, rl, node);
 }
 
 /// This one is for an actual `comptime` syntax, and will emit a compile error if
@@ -2121,8 +2121,8 @@ fn genDefers(
                 const expr_node = node_datas[defer_scope.defer_node].rhs;
                 const prev_in_defer = gz.in_defer;
                 gz.in_defer = true;
+                defer gz.in_defer = prev_in_defer;
                 try unusedResultExpr(gz, defer_scope.parent, expr_node);
-                gz.in_defer = prev_in_defer;
             },
             .defer_error => {
                 const defer_scope = scope.cast(Scope.Defer).?;
@@ -2131,8 +2131,8 @@ fn genDefers(
                 const expr_node = node_datas[defer_scope.defer_node].rhs;
                 const prev_in_defer = gz.in_defer;
                 gz.in_defer = true;
+                defer gz.in_defer = prev_in_defer;
                 try unusedResultExpr(gz, defer_scope.parent, expr_node);
-                gz.in_defer = prev_in_defer;
             },
             .namespace => unreachable,
             .top => unreachable,
@@ -2887,6 +2887,7 @@ fn fnDecl(
 
         const prev_fn_block = astgen.fn_block;
         astgen.fn_block = &fn_gz;
+        defer astgen.fn_block = prev_fn_block;
 
         // Iterate over the parameters. We put the param names as the first N
         // items inside `extra` so that debug info later can refer to the parameter names
@@ -2938,8 +2939,6 @@ fn fnDecl(
             _ = try fn_gz.addUnTok(.ret_coerce, .void_value, tree.lastToken(body_node));
         }
 
-        astgen.fn_block = prev_fn_block;
-
         break :func try decl_gz.addFunc(.{
             .src_node = decl_node,
             .ret_ty = return_type_inst,
@@ -3276,6 +3275,7 @@ fn testDecl(
 
     const prev_fn_block = astgen.fn_block;
     astgen.fn_block = &fn_block;
+    defer astgen.fn_block = prev_fn_block;
 
     const block_result = try expr(&fn_block, &fn_block.base, .none, body_node);
     if (fn_block.instructions.items.len == 0 or !fn_block.refIsNoReturn(block_result)) {
@@ -3284,8 +3284,6 @@ fn testDecl(
         _ = try fn_block.addUnTok(.ret_coerce, .void_value, tree.lastToken(body_node));
     }
 
-    astgen.fn_block = prev_fn_block;
-
     const func_inst = try decl_block.addFunc(.{
         .src_node = node,
         .ret_ty = .void_type,
test/stage2/test.zig
@@ -938,8 +938,7 @@ pub fn addCases(ctx: *TestContext) !void {
         \\pub fn b() !void {
         \\	defer return a();
         \\}
-
-     , &[_][]const u8{
+    , &[_][]const u8{
         ":7:8: error: try is not allowed inside defer expression",
         ":10:8: error: cannot return from defer expression",
     });
@@ -979,6 +978,19 @@ pub fn addCases(ctx: *TestContext) !void {
             ":3:9: error: local shadows declaration of 'testing'",
             ":1:1: note: declared here",
         });
+        case.addError(
+            \\fn a() type {
+            \\    return struct {
+            \\        pub fn b() void {
+            \\            const c = 6;
+            \\            const c = 69;
+            \\        }
+            \\    };
+            \\}
+        , &[_][]const u8{
+            ":5:19: error: redeclaration of 'c'",
+            ":4:19: note: previously declared here",
+        });
     }
 
     {