| ... | ... | @@ -204,10 +204,10 @@ use_llvm: ?bool, |
| 204 | 204 | use_lld: ?bool, |
| 205 | 205 | |
| 206 | 206 | /// This is an advanced setting that can change the intent of this Compile step. |
| 207 | | /// If this slice has nonzero length, it means that this Compile step exists to |
| 207 | /// If this value is non-null, it means that this Compile step exists to |
| 208 | 208 | /// check for compile errors and return *success* if they match, and failure |
| 209 | 209 | /// otherwise. |
| 210 | | expect_errors: []const []const u8 = &.{}, |
| 210 | expect_errors: ?ExpectedCompileErrors = null, |
| 211 | 211 | |
| 212 | 212 | emit_directory: ?*GeneratedFile, |
| 213 | 213 | |
| ... | ... | @@ -220,6 +220,11 @@ generated_llvm_bc: ?*GeneratedFile, |
| 220 | 220 | generated_llvm_ir: ?*GeneratedFile, |
| 221 | 221 | generated_h: ?*GeneratedFile, |
| 222 | 222 | |
| 223 | pub const ExpectedCompileErrors = union(enum) { |
| 224 | contains: []const u8, |
| 225 | exact: []const []const u8, |
| 226 | }; |
| 227 | |
| 223 | 228 | pub const CSourceFiles = struct { |
| 224 | 229 | dependency: ?*std.Build.Dependency, |
| 225 | 230 | /// If `dependency` is not null relative to it, |
| ... | ... | @@ -2131,7 +2136,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { |
| 2131 | 2136 | |
| 2132 | 2137 | const maybe_output_bin_path = step.evalZigProcess(zig_args.items, prog_node) catch |err| switch (err) { |
| 2133 | 2138 | error.NeedCompileErrorCheck => { |
| 2134 | | assert(self.expect_errors.len != 0); |
| 2139 | assert(self.expect_errors != null); |
| 2135 | 2140 | try checkCompileErrors(self); |
| 2136 | 2141 | return; |
| 2137 | 2142 | }, |
| ... | ... | @@ -2390,52 +2395,70 @@ fn checkCompileErrors(self: *Compile) !void { |
| 2390 | 2395 | |
| 2391 | 2396 | // Render the expected lines into a string that we can compare verbatim. |
| 2392 | 2397 | var expected_generated = std.ArrayList(u8).init(arena); |
| 2398 | const expect_errors = self.expect_errors.?; |
| 2393 | 2399 | |
| 2394 | 2400 | var actual_line_it = mem.splitScalar(u8, actual_stderr, '\n'); |
| 2395 | | for (self.expect_errors) |expect_line| { |
| 2396 | | const actual_line = actual_line_it.next() orelse { |
| 2397 | | try expected_generated.appendSlice(expect_line); |
| 2398 | | try expected_generated.append('\n'); |
| 2399 | | continue; |
| 2400 | | }; |
| 2401 | | if (mem.endsWith(u8, actual_line, expect_line)) { |
| 2402 | | try expected_generated.appendSlice(actual_line); |
| 2403 | | try expected_generated.append('\n'); |
| 2404 | | continue; |
| 2405 | | } |
| 2406 | | if (mem.startsWith(u8, expect_line, ":?:?: ")) { |
| 2407 | | if (mem.endsWith(u8, actual_line, expect_line[":?:?: ".len..])) { |
| 2408 | | try expected_generated.appendSlice(actual_line); |
| 2409 | | try expected_generated.append('\n'); |
| 2410 | | continue; |
| 2401 | |
| 2402 | // TODO merge this with the testing.expectEqualStrings logic, and also CheckFile |
| 2403 | switch (expect_errors) { |
| 2404 | .contains => |expect_line| { |
| 2405 | while (actual_line_it.next()) |actual_line| { |
| 2406 | if (!matchCompileError(actual_line, expect_line)) continue; |
| 2407 | return; |
| 2411 | 2408 | } |
| 2412 | | } |
| 2413 | | // We scan for /?/ in expected line and if there is a match, we match everything |
| 2414 | | // up to and after /?/. |
| 2415 | | const expect_line_trim = mem.trim(u8, expect_line, " "); |
| 2416 | | if (mem.indexOf(u8, expect_line_trim, "/?/")) |exp_index| { |
| 2417 | | const actual_line_trim = mem.trim(u8, actual_line, " "); |
| 2418 | | const exp_lhs = expect_line_trim[0..exp_index]; |
| 2419 | | const exp_rhs = expect_line_trim[exp_index + "/?/".len ..]; |
| 2420 | | if (mem.startsWith(u8, actual_line_trim, exp_lhs) and mem.endsWith(u8, actual_line_trim, exp_rhs)) { |
| 2421 | | try expected_generated.appendSlice(actual_line); |
| 2409 | |
| 2410 | return self.step.fail( |
| 2411 | \\ |
| 2412 | \\========= should contain: =============== |
| 2413 | \\{s} |
| 2414 | \\========= but not found: ================ |
| 2415 | \\{s} |
| 2416 | \\========================================= |
| 2417 | , .{ expect_line, actual_stderr }); |
| 2418 | }, |
| 2419 | .exact => |expect_lines| { |
| 2420 | for (expect_lines) |expect_line| { |
| 2421 | const actual_line = actual_line_it.next() orelse { |
| 2422 | try expected_generated.appendSlice(expect_line); |
| 2423 | try expected_generated.append('\n'); |
| 2424 | continue; |
| 2425 | }; |
| 2426 | if (matchCompileError(actual_line, expect_line)) { |
| 2427 | try expected_generated.appendSlice(actual_line); |
| 2428 | try expected_generated.append('\n'); |
| 2429 | continue; |
| 2430 | } |
| 2431 | try expected_generated.appendSlice(expect_line); |
| 2422 | 2432 | try expected_generated.append('\n'); |
| 2423 | | continue; |
| 2424 | 2433 | } |
| 2425 | | } |
| 2426 | | try expected_generated.appendSlice(expect_line); |
| 2427 | | try expected_generated.append('\n'); |
| 2428 | | } |
| 2429 | 2434 | |
| 2430 | | if (mem.eql(u8, expected_generated.items, actual_stderr)) return; |
| 2435 | if (mem.eql(u8, expected_generated.items, actual_stderr)) return; |
| 2431 | 2436 | |
| 2432 | | // TODO merge this with the testing.expectEqualStrings logic, and also CheckFile |
| 2433 | | return self.step.fail( |
| 2434 | | \\ |
| 2435 | | \\========= expected: ===================== |
| 2436 | | \\{s} |
| 2437 | | \\========= but found: ==================== |
| 2438 | | \\{s} |
| 2439 | | \\========================================= |
| 2440 | | , .{ expected_generated.items, actual_stderr }); |
| 2437 | return self.step.fail( |
| 2438 | \\ |
| 2439 | \\========= expected: ===================== |
| 2440 | \\{s} |
| 2441 | \\========= but found: ==================== |
| 2442 | \\{s} |
| 2443 | \\========================================= |
| 2444 | , .{ expected_generated.items, actual_stderr }); |
| 2445 | }, |
| 2446 | } |
| 2447 | } |
| 2448 | |
| 2449 | fn matchCompileError(actual: []const u8, expected: []const u8) bool { |
| 2450 | if (mem.endsWith(u8, actual, expected)) return true; |
| 2451 | if (mem.startsWith(u8, expected, ":?:?: ")) { |
| 2452 | if (mem.endsWith(u8, actual, expected[":?:?: ".len..])) return true; |
| 2453 | } |
| 2454 | // We scan for /?/ in expected line and if there is a match, we match everything |
| 2455 | // up to and after /?/. |
| 2456 | const expected_trim = mem.trim(u8, expected, " "); |
| 2457 | if (mem.indexOf(u8, expected_trim, "/?/")) |index| { |
| 2458 | const actual_trim = mem.trim(u8, actual, " "); |
| 2459 | const lhs = expected_trim[0..index]; |
| 2460 | const rhs = expected_trim[index + "/?/".len ..]; |
| 2461 | if (mem.startsWith(u8, actual_trim, lhs) and mem.endsWith(u8, actual_trim, rhs)) return true; |
| 2462 | } |
| 2463 | return false; |
| 2441 | 2464 | } |