1const builtin = @import("builtin");
2const std = @import("std");
3const expect = std.testing.expect;
4const expectEqual = std.testing.expectEqual;
5const expectError = std.testing.expectError;
6
7test "break and continue inside loop inside defer expression" {
8 testBreakContInDefer(10);
9 comptime testBreakContInDefer(10);
10}
11
12fn testBreakContInDefer(x: usize) void {
13 defer {
14 var i: usize = 0;
15 while (i < x) : (i += 1) {
16 if (i < 5) continue;
17 if (i == 5) break;
18 }
19 expect(i == 5) catch @panic("test failure");
20 }
21}
22
23test "defer and labeled break" {
24 var i = @as(usize, 0);
25
26 blk: {
27 defer i += 1;
28 break :blk;
29 }
30
31 try expect(i == 1);
32}
33
34test "errdefer does not apply to fn inside fn" {
35 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
36
37 if (testNestedFnErrDefer()) |_| @panic("expected error") else |e| try expect(e == error.Bad);
38}
39
40fn testNestedFnErrDefer() anyerror!void {
41 var a: i32 = 0;
42 errdefer a += 1;
43 const S = struct {
44 fn baz() anyerror {
45 return error.Bad;
46 }
47 };
48 return S.baz();
49}
50
51test "return variable while defer expression in scope to modify it" {
52 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
53 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
54
55 const S = struct {
56 fn doTheTest() !void {
57 try expect(notNull().? == 1);
58 }
59
60 fn notNull() ?u8 {
61 var res: ?u8 = 1;
62 defer res = null;
63 return res;
64 }
65 };
66
67 try S.doTheTest();
68 try comptime S.doTheTest();
69}
70
71var result: [3]u8 = undefined;
72var index: usize = undefined;
73
74fn runSomeErrorDefers(x: bool) !bool {
75 index = 0;
76 defer {
77 result[index] = 'a';
78 index += 1;
79 }
80 errdefer {
81 result[index] = 'b';
82 index += 1;
83 }
84 defer {
85 result[index] = 'c';
86 index += 1;
87 }
88 return if (x) x else error.FalseNotAllowed;
89}
90
91test "mixing normal and error defers" {
92 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
93 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
94
95 try expect(runSomeErrorDefers(true) catch unreachable);
96 try expect(result[0] == 'c');
97 try expect(result[1] == 'a');
98
99 const ok = runSomeErrorDefers(false) catch |err| x: {
100 try expect(err == error.FalseNotAllowed);
101 break :x true;
102 };
103 try expect(ok);
104 try expect(result[0] == 'c');
105 try expect(result[1] == 'b');
106 try expect(result[2] == 'a');
107}
108
109test "simple else prong doesn't emit an error for unreachable else prong" {
110 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
111 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
112 const S = struct {
113 fn foo() error{Foo}!void {
114 return error.Foo;
115 }
116 };
117 var a: u32 = 0;
118 defer a += 1;
119 S.foo() catch |err| switch (err) {
120 error.Foo => a += 1,
121 else => |e| return e,
122 };
123 try expect(a == 1);
124}
125
126test "errdefer used in function that doesn't return an error" {
127 const S = struct {
128 fn foo() u8 {
129 var a: u8 = 5;
130 errdefer a += 1;
131 return a;
132 }
133 };
134 try expect(S.foo() == 5);
135}
136
137// Originally reported at https://github.com/ziglang/zig/issues/10591
138const defer_assign = switch (block: {
139 var x = 0;
140 defer x = 1;
141 break :block x;
142}) {
143 else => |i| i,
144};
145comptime {
146 if (defer_assign != 0) @compileError("defer_assign failed!");
147}
148
149test "errdefer in test block" {
150 errdefer {}
151 var x: bool = false;
152 _ = &x;
153 if (x) return error.Something;
154}