From b4ffb2d9498560557821714e2d4651279dd6817c Mon Sep 17 00:00:00 2001 From: _ov4 Date: Wed, 21 Oct 2026 14:03:31 +0000 Subject: feat(diagnostics): print source diagnostics in gcc file:line: layout Lexer, parser, driver and codegen diagnostics now read ":: error: " instead of "error: at line N in ". The path is always printed as given on the command line. Call sites pass the bare message to cps::sourceError/sourceWarning, which carry printf format checking; reportError routes through the same helper. The suite iii harness parses the new layout and matches the reason against the message only. iii/template-class-pack-field passed only because its reason regex matched the case path, so it is now case-insensitive. Co-Authored-By: Claude Opus 5.5 --- tests/iii/template-class-pack-field/case.json | 2 +- tests/run.pl | 13 ++++++++----- tests/test_runner.pl | 27 ++++++++++++++++++--------- 3 files changed, 27 insertions(+), 15 deletions(-) (limited to 'tests') diff --git a/tests/iii/template-class-pack-field/case.json b/tests/iii/template-class-pack-field/case.json index 2ad0199..1196e7b 100644 --- a/tests/iii/template-class-pack-field/case.json +++ b/tests/iii/template-class-pack-field/case.json @@ -1,5 +1,5 @@ { "errors": [ - {"reason": "pack.*field|field.*pack", "line": 3} + {"reason": "(?i)pack.*field|field.*pack", "line": 3} ] } diff --git a/tests/run.pl b/tests/run.pl index 86eff4f..2835d5e 100644 --- a/tests/run.pl +++ b/tests/run.pl @@ -113,18 +113,21 @@ sub check_diagnostics { if (length($result->{stdout})) { push @errors, 'unexpected stdout: ' . show_bytes(substr($result->{stdout}, 0, 1000)); } - # ASCII markers (error:, line N) are matched on raw bytes; the compiler - # emits UTF-8 and ASCII patterns are unaffected by decoding. + # Diagnostics use the gcc layout ":: error: " and are + # matched on raw bytes; the compiler emits UTF-8 and ASCII patterns are + # unaffected by decoding. The non-greedy path keeps Windows "D:/" intact. my @lines = split_records(normalized($result->{stderr})); for my $expectation (@{$expectations}) { my $reason = $expectation->{reason}; my $line_no = $expectation->{line}; + my $file = $expectation->{file}; my @matching = grep { /error:/ && /$reason/ } @lines; my $found = 0; for my $line (@matching) { - my $file = $expectation->{file}; - if ($line =~ /\bline $line_no\b/ && - (!defined($file) || $line =~ /\bline $line_no in \Q$file\E(?:\s|$)/)) { + next unless $line =~ /^(.+?):(\d+): error: (.*)$/; + my ($path, $number, $message) = ($1, $2, $3); + if ($number == $line_no && $message =~ /$reason/ && + (!defined($file) || $path eq $file)) { $found = 1; last; } diff --git a/tests/test_runner.pl b/tests/test_runner.pl index 16a0e35..a074f98 100644 --- a/tests/test_runner.pl +++ b/tests/test_runner.pl @@ -29,7 +29,7 @@ for my $case ([1, ''], [-11, ''], [0, 'unexpected']) { my $good = { returncode => 1, stdout => '', - stderr => "error: Expected ':' at line 3\ncompilation terminated.\n", + stderr => "/fixtures/program.cps:3: error: Expected ':'\ncompilation terminated.\n", }; my $accepted = eval { check_diagnostics($good, [{reason => "Expected ':'", line => 3}]); @@ -37,9 +37,10 @@ my $accepted = eval { }; ok($accepted, 'matching reason and location accepted'); for my $bad ( - "error: Expected ':' at line 4", - "error: Expected ':'", - "error: Expected ':' at line 30\nerror: unrelated at line 3", + "/fixtures/program.cps:4: error: Expected ':'", + "/fixtures/program.cps: error: Expected ':'", + "error: Expected ':' at line 3", + "/fixtures/program.cps:30: error: Expected ':'\n/fixtures/program.cps:3: error: unrelated", ) { my $ok = eval { @@ -54,11 +55,11 @@ for my $bad ( my $file_expectation = [{reason => "Expected ':'", line => 3, file => '/fixtures/lib.cps'}]; for my $sample ( - ["error: Expected ':' at line 3 in /fixtures/lib.cps", 1], - ["error: Expected ':' at line 3 in /fixtures/program.cps", 0], - ["error: Expected ':' at line 3 in /fixtures/lib.cps.extra", 0], - ["error: Expected ':' at line 30 in /fixtures/lib.cps", 0], - ["error: Expected ':' at line 3\nerror: unrelated at line 3 in /fixtures/lib.cps", 0], + ["/fixtures/lib.cps:3: error: Expected ':'", 1], + ["/fixtures/program.cps:3: error: Expected ':'", 0], + ["/fixtures/lib.cps.extra:3: error: Expected ':'", 0], + ["/fixtures/lib.cps:30: error: Expected ':'", 0], + ["/fixtures/program.cps:3: error: Expected ':'\n/fixtures/lib.cps:3: error: unrelated", 0], ) { my ($diagnostic, $expected) = @{$sample}; my $ok = eval { @@ -69,6 +70,14 @@ for my $sample ( is($ok ? 1 : 0, $expected, 'file-qualified diagnostic: ' . show_bytes($diagnostic)); } +my $drive_ok = eval { + check_diagnostics({returncode => 1, stdout => '', + stderr => "D:/fixtures/lib.cps:3: error: Expected ':'\ncompilation terminated.\n"}, + [{reason => "Expected ':'", line => 3, file => 'D:/fixtures/lib.cps'}]); + 1; +}; +ok($drive_ok, 'drive-letter path keeps its colon'); + my $dir = tempdir(CLEANUP => 1); my $state = commands_new($dir); my $ran = eval { run_command($state, [$^X, '-e', 'sleep 5'], $dir, '', 1); 1; }; -- cgit v1.3.1-4-g156e