| author | |
| committer | |
| log | 47090d234ecc3e50937c918b05e6f039a53d880c |
| tree | 2870ab3c20a78ca1e2115442f9ffdb74ddf98675 |
| parent | 9ea4965ceb62ea47569d0676bb68475304aad467 |
3 files changed, 233 insertions(+), 32 deletions(-)
src-self-hosted/Module.zig+3-3| ... | ... | @@ -673,8 +673,8 @@ pub fn getAllErrorsAlloc(self: *Module) !AllErrors { |
| 673 | 673 | assert(errors.items.len == self.totalErrorCount()); |
| 674 | 674 | |
| 675 | 675 | return AllErrors{ |
| 676 | .arena = arena.state, | |
| 677 | 676 | .list = try arena.allocator.dupe(AllErrors.Message, errors.items), |
| 677 | .arena = arena.state, | |
| 678 | 678 | }; |
| 679 | 679 | } |
| 680 | 680 | |
| ... | ... | @@ -935,7 +935,7 @@ fn deleteDecl(self: *Module, decl: *Decl) !void { |
| 935 | 935 | } |
| 936 | 936 | } |
| 937 | 937 | if (self.failed_decls.remove(decl)) |entry| { |
| 938 | self.allocator.destroy(entry.value); | |
| 938 | entry.value.destroy(self.allocator); | |
| 939 | 939 | } |
| 940 | 940 | self.deleteDeclExports(decl); |
| 941 | 941 | self.bin_file.freeDecl(decl); |
| ... | ... | @@ -1104,7 +1104,7 @@ fn markOutdatedDecl(self: *Module, decl: *Decl) !void { |
| 1104 | 1104 | //std.debug.warn("mark {} outdated\n", .{decl.name}); |
| 1105 | 1105 | try self.work_queue.writeItem(.{ .re_analyze_decl = decl }); |
| 1106 | 1106 | if (self.failed_decls.remove(decl)) |entry| { |
| 1107 | self.allocator.destroy(entry.value); | |
| 1107 | entry.value.destroy(self.allocator); | |
| 1108 | 1108 | } |
| 1109 | 1109 | decl.analysis = .outdated; |
| 1110 | 1110 | } |
src-self-hosted/test.zig+111-29| ... | ... | @@ -27,9 +27,32 @@ pub const TestContext = struct { |
| 27 | 27 | |
| 28 | 28 | pub const ZIRTransformCase = struct { |
| 29 | 29 | name: []const u8, |
| 30 | src: [:0]const u8, | |
| 31 | expected_zir: []const u8, | |
| 32 | 30 | cross_target: std.zig.CrossTarget, |
| 31 | updates: std.ArrayList(Update), | |
| 32 | ||
| 33 | pub const Update = struct { | |
| 34 | expected: Expected, | |
| 35 | src: [:0]const u8, | |
| 36 | }; | |
| 37 | ||
| 38 | pub const Expected = union(enum) { | |
| 39 | zir: []const u8, | |
| 40 | errors: []const []const u8, | |
| 41 | }; | |
| 42 | ||
| 43 | pub fn addZIR(case: *ZIRTransformCase, src: [:0]const u8, zir_text: []const u8) void { | |
| 44 | case.updates.append(.{ | |
| 45 | .src = src, | |
| 46 | .expected = .{ .zir = zir_text }, | |
| 47 | }) catch unreachable; | |
| 48 | } | |
| 49 | ||
| 50 | pub fn addError(case: *ZIRTransformCase, src: [:0]const u8, errors: []const []const u8) void { | |
| 51 | case.updates.append(.{ | |
| 52 | .src = src, | |
| 53 | .expected = .{ .errors = errors }, | |
| 54 | }) catch unreachable; | |
| 55 | } | |
| 33 | 56 | }; |
| 34 | 57 | |
| 35 | 58 | pub fn addZIRCompareOutput( |
| ... | ... | @@ -52,14 +75,32 @@ pub const TestContext = struct { |
| 52 | 75 | src: [:0]const u8, |
| 53 | 76 | expected_zir: []const u8, |
| 54 | 77 | ) void { |
| 55 | ctx.zir_transform_cases.append(.{ | |
| 78 | const case = ctx.zir_transform_cases.addOne() catch unreachable; | |
| 79 | case.* = .{ | |
| 56 | 80 | .name = name, |
| 57 | .src = src, | |
| 58 | .expected_zir = expected_zir, | |
| 59 | 81 | .cross_target = cross_target, |
| 82 | .updates = std.ArrayList(ZIRTransformCase.Update).init(std.heap.page_allocator), | |
| 83 | }; | |
| 84 | case.updates.append(.{ | |
| 85 | .src = src, | |
| 86 | .expected = .{ .zir = expected_zir }, | |
| 60 | 87 | }) catch unreachable; |
| 61 | 88 | } |
| 62 | 89 | |
| 90 | pub fn addZIRMulti( | |
| 91 | ctx: *TestContext, | |
| 92 | name: []const u8, | |
| 93 | cross_target: std.zig.CrossTarget, | |
| 94 | ) *ZIRTransformCase { | |
| 95 | const case = ctx.zir_transform_cases.addOne() catch unreachable; | |
| 96 | case.* = .{ | |
| 97 | .name = name, | |
| 98 | .cross_target = cross_target, | |
| 99 | .updates = std.ArrayList(ZIRTransformCase.Update).init(std.heap.page_allocator), | |
| 100 | }; | |
| 101 | return case; | |
| 102 | } | |
| 103 | ||
| 63 | 104 | fn init(self: *TestContext) !void { |
| 64 | 105 | self.* = .{ |
| 65 | 106 | .zir_cmp_output_cases = std.ArrayList(ZIRCompareOutputCase).init(std.heap.page_allocator), |
| ... | ... | @@ -178,13 +219,11 @@ pub const TestContext = struct { |
| 178 | 219 | var tmp = std.testing.tmpDir(.{}); |
| 179 | 220 | defer tmp.cleanup(); |
| 180 | 221 | |
| 181 | var prg_node = root_node.start(case.name, 3); | |
| 182 | prg_node.activate(); | |
| 183 | defer prg_node.end(); | |
| 222 | var update_node = root_node.start(case.name, case.updates.items.len); | |
| 223 | update_node.activate(); | |
| 224 | defer update_node.end(); | |
| 184 | 225 | |
| 185 | 226 | const tmp_src_path = "test-case.zir"; |
| 186 | try tmp.dir.writeFile(tmp_src_path, case.src); | |
| 187 | ||
| 188 | 227 | const root_pkg = try Package.create(allocator, tmp.dir, ".", tmp_src_path); |
| 189 | 228 | defer root_pkg.destroy(); |
| 190 | 229 | |
| ... | ... | @@ -198,25 +237,68 @@ pub const TestContext = struct { |
| 198 | 237 | }); |
| 199 | 238 | defer module.deinit(); |
| 200 | 239 | |
| 201 | var module_node = prg_node.start("parse/analysis/codegen", null); | |
| 202 | module_node.activate(); | |
| 203 | try module.update(); | |
| 204 | module_node.end(); | |
| 205 | ||
| 206 | var emit_node = prg_node.start("emit", null); | |
| 207 | emit_node.activate(); | |
| 208 | var new_zir_module = try zir.emit(allocator, module); | |
| 209 | defer new_zir_module.deinit(allocator); | |
| 210 | emit_node.end(); | |
| 211 | ||
| 212 | var write_node = prg_node.start("write", null); | |
| 213 | write_node.activate(); | |
| 214 | var out_zir = std.ArrayList(u8).init(allocator); | |
| 215 | defer out_zir.deinit(); | |
| 216 | try new_zir_module.writeToStream(allocator, out_zir.outStream()); | |
| 217 | write_node.end(); | |
| 218 | ||
| 219 | std.testing.expectEqualSlices(u8, case.expected_zir, out_zir.items); | |
| 240 | for (case.updates.items) |update| { | |
| 241 | var prg_node = update_node.start("", 3); | |
| 242 | prg_node.activate(); | |
| 243 | defer prg_node.end(); | |
| 244 | ||
| 245 | try tmp.dir.writeFile(tmp_src_path, update.src); | |
| 246 | ||
| 247 | var module_node = prg_node.start("parse/analysis/codegen", null); | |
| 248 | module_node.activate(); | |
| 249 | try module.update(); | |
| 250 | module_node.end(); | |
| 251 | ||
| 252 | switch (update.expected) { | |
| 253 | .zir => |expected_zir| { | |
| 254 | var emit_node = prg_node.start("emit", null); | |
| 255 | emit_node.activate(); | |
| 256 | var new_zir_module = try zir.emit(allocator, module); | |
| 257 | defer new_zir_module.deinit(allocator); | |
| 258 | emit_node.end(); | |
| 259 | ||
| 260 | var write_node = prg_node.start("write", null); | |
| 261 | write_node.activate(); | |
| 262 | var out_zir = std.ArrayList(u8).init(allocator); | |
| 263 | defer out_zir.deinit(); | |
| 264 | try new_zir_module.writeToStream(allocator, out_zir.outStream()); | |
| 265 | write_node.end(); | |
| 266 | ||
| 267 | std.testing.expectEqualSlices(u8, expected_zir, out_zir.items); | |
| 268 | }, | |
| 269 | .errors => |expected_errors| { | |
| 270 | var all_errors = try module.getAllErrorsAlloc(); | |
| 271 | defer all_errors.deinit(module.allocator); | |
| 272 | for (expected_errors) |expected_error| { | |
| 273 | for (all_errors.list) |full_err_msg| { | |
| 274 | const text = try std.fmt.allocPrint(allocator, ":{}:{}: error: {}", .{ | |
| 275 | full_err_msg.line + 1, | |
| 276 | full_err_msg.column + 1, | |
| 277 | full_err_msg.msg, | |
| 278 | }); | |
| 279 | defer allocator.free(text); | |
| 280 | if (std.mem.eql(u8, text, expected_error)) { | |
| 281 | break; | |
| 282 | } | |
| 283 | } else { | |
| 284 | std.debug.warn( | |
| 285 | "{}\nExpected this error:\n================\n{}\n================\nBut found these errors:\n================\n", | |
| 286 | .{ case.name, expected_error }, | |
| 287 | ); | |
| 288 | for (all_errors.list) |full_err_msg| { | |
| 289 | std.debug.warn(":{}:{}: error: {}\n", .{ | |
| 290 | full_err_msg.line + 1, | |
| 291 | full_err_msg.column + 1, | |
| 292 | full_err_msg.msg, | |
| 293 | }); | |
| 294 | } | |
| 295 | std.debug.warn("================\nTest failed\n", .{}); | |
| 296 | std.process.exit(1); | |
| 297 | } | |
| 298 | } | |
| 299 | }, | |
| 300 | } | |
| 301 | } | |
| 220 | 302 | } |
| 221 | 303 | }; |
| 222 | 304 |
test/stage2/zir.zig+119| ... | ... | @@ -90,6 +90,125 @@ pub fn addCases(ctx: *TestContext) void { |
| 90 | 90 | \\ |
| 91 | 91 | ); |
| 92 | 92 | |
| 93 | { | |
| 94 | var case = ctx.addZIRMulti("reference cycle with compile error in the cycle", linux_x64); | |
| 95 | case.addZIR( | |
| 96 | \\@void = primitive(void) | |
| 97 | \\@fnty = fntype([], @void, cc=C) | |
| 98 | \\ | |
| 99 | \\@9 = str("entry") | |
| 100 | \\@10 = ref(@9) | |
| 101 | \\@11 = export(@10, @entry) | |
| 102 | \\ | |
| 103 | \\@entry = fn(@fnty, { | |
| 104 | \\ %0 = call(@a, []) | |
| 105 | \\ %1 = return() | |
| 106 | \\}) | |
| 107 | \\ | |
| 108 | \\@a = fn(@fnty, { | |
| 109 | \\ %0 = call(@b, []) | |
| 110 | \\ %1 = return() | |
| 111 | \\}) | |
| 112 | \\ | |
| 113 | \\@b = fn(@fnty, { | |
| 114 | \\ %0 = call(@a, []) | |
| 115 | \\ %1 = return() | |
| 116 | \\}) | |
| 117 | , | |
| 118 | \\@void = primitive(void) | |
| 119 | \\@fnty = fntype([], @void, cc=C) | |
| 120 | \\@9 = str("entry") | |
| 121 | \\@10 = ref(@9) | |
| 122 | \\@unnamed$6 = str("entry") | |
| 123 | \\@unnamed$7 = ref(@unnamed$6) | |
| 124 | \\@unnamed$8 = export(@unnamed$7, @entry) | |
| 125 | \\@unnamed$12 = fntype([], @void, cc=C) | |
| 126 | \\@entry = fn(@unnamed$12, { | |
| 127 | \\ %0 = call(@a, [], modifier=auto) | |
| 128 | \\ %1 = return() | |
| 129 | \\}) | |
| 130 | \\@unnamed$17 = fntype([], @void, cc=C) | |
| 131 | \\@a = fn(@unnamed$17, { | |
| 132 | \\ %0 = call(@b, [], modifier=auto) | |
| 133 | \\ %1 = return() | |
| 134 | \\}) | |
| 135 | \\@unnamed$22 = fntype([], @void, cc=C) | |
| 136 | \\@b = fn(@unnamed$22, { | |
| 137 | \\ %0 = call(@a, [], modifier=auto) | |
| 138 | \\ %1 = return() | |
| 139 | \\}) | |
| 140 | \\ | |
| 141 | ); | |
| 142 | // Now we introduce a compile error | |
| 143 | case.addError( | |
| 144 | \\@void = primitive(void) | |
| 145 | \\@fnty = fntype([], @void, cc=C) | |
| 146 | \\ | |
| 147 | \\@9 = str("entry") | |
| 148 | \\@10 = ref(@9) | |
| 149 | \\@11 = export(@10, @entry) | |
| 150 | \\ | |
| 151 | \\@entry = fn(@fnty, { | |
| 152 | \\ %0 = call(@a, []) | |
| 153 | \\ %1 = return() | |
| 154 | \\}) | |
| 155 | \\ | |
| 156 | \\@a = fn(@fnty, { | |
| 157 | \\ %0 = call(@b, []) | |
| 158 | \\ %1 = return() | |
| 159 | \\}) | |
| 160 | \\ | |
| 161 | \\@b = fn(@fnty, { | |
| 162 | \\ %9 = compileerror("message") | |
| 163 | \\ %0 = call(@a, []) | |
| 164 | \\ %1 = return() | |
| 165 | \\}) | |
| 166 | , | |
| 167 | &[_][]const u8{ | |
| 168 | ":19:21: error: message", | |
| 169 | }, | |
| 170 | ); | |
| 171 | // Now we remove the call to `a`. `a` and `b` form a cycle, but no entry points are | |
| 172 | // referencing either of them. This tests that the cycle is detected, and the error | |
| 173 | // goes away. | |
| 174 | case.addZIR( | |
| 175 | \\@void = primitive(void) | |
| 176 | \\@fnty = fntype([], @void, cc=C) | |
| 177 | \\ | |
| 178 | \\@9 = str("entry") | |
| 179 | \\@10 = ref(@9) | |
| 180 | \\@11 = export(@10, @entry) | |
| 181 | \\ | |
| 182 | \\@entry = fn(@fnty, { | |
| 183 | \\ %1 = return() | |
| 184 | \\}) | |
| 185 | \\ | |
| 186 | \\@a = fn(@fnty, { | |
| 187 | \\ %0 = call(@b, []) | |
| 188 | \\ %1 = return() | |
| 189 | \\}) | |
| 190 | \\ | |
| 191 | \\@b = fn(@fnty, { | |
| 192 | \\ %9 = compileerror("message") | |
| 193 | \\ %0 = call(@a, []) | |
| 194 | \\ %1 = return() | |
| 195 | \\}) | |
| 196 | , | |
| 197 | \\@void = primitive(void) | |
| 198 | \\@fnty = fntype([], @void, cc=C) | |
| 199 | \\@9 = str("entry") | |
| 200 | \\@10 = ref(@9) | |
| 201 | \\@unnamed$6 = str("entry") | |
| 202 | \\@unnamed$7 = ref(@unnamed$6) | |
| 203 | \\@unnamed$8 = export(@unnamed$7, @entry) | |
| 204 | \\@unnamed$10 = fntype([], @void, cc=C) | |
| 205 | \\@entry = fn(@unnamed$10, { | |
| 206 | \\ %0 = return() | |
| 207 | \\}) | |
| 208 | \\ | |
| 209 | ); | |
| 210 | } | |
| 211 | ||
| 93 | 212 | if (std.Target.current.os.tag != .linux or |
| 94 | 213 | std.Target.current.cpu.arch != .x86_64) |
| 95 | 214 | { |