Skip to content

Commit af69f4c

Browse files
committed
Auto merge of rust-lang#121561 - jieyouxu:compiletest-directive-typo-check, r=onur-ozkan
Detect typos for compiletest test directives Checks directives against a known list of compiletest directives collected during migration from legacy-style compiletest directives. A suggestion for the best matching known directive will be made if an invalid directive is found. This PR does not attempt to implement checks for Makefile directives because they still have the problem of regular comments and directives sharing the same comment prefix `#`. Closes rust-lang#83551.
2 parents 9bd88ef + 64dda8c commit af69f4c

10 files changed

+180
-43
lines changed

src/tools/compiletest/src/header.rs

+97-31
Original file line numberDiff line numberDiff line change
@@ -680,7 +680,8 @@ pub fn line_directive<'line>(
680680
/// This is generated by collecting directives from ui tests and then extracting their directive
681681
/// names. This is **not** an exhaustive list of all possible directives. Instead, this is a
682682
/// best-effort approximation for diagnostics.
683-
const DIAGNOSTICS_DIRECTIVE_NAMES: &[&str] = &[
683+
const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
684+
// tidy-alphabetical-start
684685
"assembly-output",
685686
"aux-build",
686687
"aux-crate",
@@ -693,13 +694,15 @@ const DIAGNOSTICS_DIRECTIVE_NAMES: &[&str] = &[
693694
"check-stdout",
694695
"check-test-line-numbers-match",
695696
"compile-flags",
697+
"count",
696698
"dont-check-compiler-stderr",
697699
"dont-check-compiler-stdout",
698700
"dont-check-failure-status",
699701
"edition",
700702
"error-pattern",
701703
"exec-env",
702704
"failure-status",
705+
"filecheck-flags",
703706
"forbid-output",
704707
"force-host",
705708
"ignore-16bit",
@@ -716,6 +719,7 @@ const DIAGNOSTICS_DIRECTIVE_NAMES: &[&str] = &[
716719
"ignore-compare-mode-polonius",
717720
"ignore-cross-compile",
718721
"ignore-debug",
722+
"ignore-eabi",
719723
"ignore-emscripten",
720724
"ignore-endian-big",
721725
"ignore-freebsd",
@@ -731,14 +735,30 @@ const DIAGNOSTICS_DIRECTIVE_NAMES: &[&str] = &[
731735
"ignore-lldb",
732736
"ignore-llvm-version",
733737
"ignore-loongarch64",
738+
"ignore-macabi",
734739
"ignore-macos",
740+
"ignore-mode-assembly",
741+
"ignore-mode-codegen",
742+
"ignore-mode-codegen-units",
735743
"ignore-mode-coverage-map",
736744
"ignore-mode-coverage-run",
745+
"ignore-mode-debuginfo",
746+
"ignore-mode-incremental",
747+
"ignore-mode-js-doc-test",
748+
"ignore-mode-mir-opt",
749+
"ignore-mode-pretty",
750+
"ignore-mode-run-make",
751+
"ignore-mode-run-pass-valgrind",
752+
"ignore-mode-rustdoc",
753+
"ignore-mode-rustdoc-json",
754+
"ignore-mode-ui",
755+
"ignore-mode-ui-fulldeps",
737756
"ignore-msp430",
738757
"ignore-msvc",
739758
"ignore-musl",
740759
"ignore-netbsd",
741760
"ignore-nightly",
761+
"ignore-none",
742762
"ignore-nto",
743763
"ignore-nvptx64",
744764
"ignore-openbsd",
@@ -750,35 +770,47 @@ const DIAGNOSTICS_DIRECTIVE_NAMES: &[&str] = &[
750770
"ignore-spirv",
751771
"ignore-stable",
752772
"ignore-stage1",
773+
"ignore-stage2",
753774
"ignore-test",
775+
"ignore-thumb",
754776
"ignore-thumbv8m.base-none-eabi",
755777
"ignore-thumbv8m.main-none-eabi",
778+
"ignore-unix",
779+
"ignore-unknown",
756780
"ignore-uwp",
757781
"ignore-vxworks",
782+
"ignore-wasi",
758783
"ignore-wasm",
759784
"ignore-wasm32",
760785
"ignore-wasm32-bare",
786+
"ignore-wasm64",
761787
"ignore-windows",
762788
"ignore-windows-gnu",
789+
"ignore-x32",
763790
"ignore-x86",
791+
"ignore-x86_64",
764792
"ignore-x86_64-apple-darwin",
793+
"ignore-x86_64-unknown-linux-gnu",
765794
"incremental",
766795
"known-bug",
767796
"llvm-cov-flags",
768797
"min-cdb-version",
769798
"min-gdb-version",
770799
"min-lldb-version",
771800
"min-llvm-version",
801+
"min-system-llvm-version",
772802
"needs-asm-support",
773803
"needs-dlltool",
774804
"needs-dynamic-linking",
805+
"needs-git-hash",
775806
"needs-llvm-components",
776807
"needs-profiler-support",
777808
"needs-relocation-model-pic",
778809
"needs-run-enabled",
779810
"needs-rust-lldb",
780811
"needs-sanitizer-address",
781812
"needs-sanitizer-cfi",
813+
"needs-sanitizer-dataflow",
782814
"needs-sanitizer-hwaddress",
783815
"needs-sanitizer-leak",
784816
"needs-sanitizer-memory",
@@ -801,6 +833,7 @@ const DIAGNOSTICS_DIRECTIVE_NAMES: &[&str] = &[
801833
"only-aarch64",
802834
"only-arm",
803835
"only-avr",
836+
"only-beta",
804837
"only-bpf",
805838
"only-cdb",
806839
"only-gnu",
@@ -818,13 +851,15 @@ const DIAGNOSTICS_DIRECTIVE_NAMES: &[&str] = &[
818851
"only-riscv64",
819852
"only-sparc",
820853
"only-sparc64",
854+
"only-stable",
821855
"only-thumb",
822856
"only-wasm32",
823857
"only-wasm32-bare",
824858
"only-windows",
825859
"only-x86",
826860
"only-x86_64",
827861
"only-x86_64-fortanix-unknown-sgx",
862+
"only-x86_64-pc-windows-gnu",
828863
"only-x86_64-pc-windows-msvc",
829864
"only-x86_64-unknown-linux-gnu",
830865
"pp-exact",
@@ -846,6 +881,7 @@ const DIAGNOSTICS_DIRECTIVE_NAMES: &[&str] = &[
846881
"unit-test",
847882
"unset-exec-env",
848883
"unset-rustc-env",
884+
// tidy-alphabetical-end
849885
];
850886

851887
/// The broken-down contents of a line containing a test header directive,
@@ -876,6 +912,22 @@ struct HeaderLine<'ln> {
876912
directive: &'ln str,
877913
}
878914

915+
pub(crate) struct CheckDirectiveResult<'ln> {
916+
is_known_directive: bool,
917+
directive_name: &'ln str,
918+
}
919+
920+
// Returns `(is_known_directive, directive_name)`.
921+
pub(crate) fn check_directive(directive_ln: &str) -> CheckDirectiveResult<'_> {
922+
let directive_name =
923+
directive_ln.split_once([':', ' ']).map(|(pre, _)| pre).unwrap_or(directive_ln);
924+
925+
CheckDirectiveResult {
926+
is_known_directive: KNOWN_DIRECTIVE_NAMES.contains(&directive_name),
927+
directive_name: directive_ln,
928+
}
929+
}
930+
879931
fn iter_header(
880932
mode: Mode,
881933
_suite: &str,
@@ -915,6 +967,7 @@ fn iter_header(
915967
let mut ln = String::new();
916968
let mut line_number = 0;
917969

970+
// Match on error annotations like `//~ERROR`.
918971
static REVISION_MAGIC_COMMENT_RE: Lazy<Regex> =
919972
Lazy::new(|| Regex::new("//(\\[.*\\])?~.*").unwrap());
920973

@@ -933,9 +986,38 @@ fn iter_header(
933986
if ln.starts_with("fn") || ln.starts_with("mod") {
934987
return;
935988

936-
// First try to accept `ui_test` style comments
937-
} else if let Some((header_revision, directive)) = line_directive(comment, ln) {
938-
it(HeaderLine { line_number, original_line, header_revision, directive });
989+
// First try to accept `ui_test` style comments (`//@`)
990+
} else if let Some((header_revision, non_revisioned_directive_line)) =
991+
line_directive(comment, ln)
992+
{
993+
// Perform unknown directive check on Rust files.
994+
if testfile.extension().map(|e| e == "rs").unwrap_or(false) {
995+
let directive_ln = non_revisioned_directive_line.trim();
996+
997+
let CheckDirectiveResult { is_known_directive, .. } = check_directive(directive_ln);
998+
999+
if !is_known_directive {
1000+
*poisoned = true;
1001+
1002+
eprintln!(
1003+
"error: detected unknown compiletest test directive `{}` in {}:{}",
1004+
directive_ln,
1005+
testfile.display(),
1006+
line_number,
1007+
);
1008+
1009+
return;
1010+
}
1011+
}
1012+
1013+
it(HeaderLine {
1014+
line_number,
1015+
original_line,
1016+
header_revision,
1017+
directive: non_revisioned_directive_line,
1018+
});
1019+
// Then we try to check for legacy-style candidates, which are not the magic ~ERROR family
1020+
// error annotations.
9391021
} else if !REVISION_MAGIC_COMMENT_RE.is_match(ln) {
9401022
let Some((_, rest)) = line_directive("//", ln) else {
9411023
continue;
@@ -949,34 +1031,18 @@ fn iter_header(
9491031

9501032
let rest = rest.trim_start();
9511033

952-
for candidate in DIAGNOSTICS_DIRECTIVE_NAMES.iter() {
953-
if rest.starts_with(candidate) {
954-
let Some(prefix_removed) = rest.strip_prefix(candidate) else {
955-
// We have a comment that's *successfully* parsed as an legacy-style
956-
// directive. We emit an error here to warn the user.
957-
*poisoned = true;
958-
eprintln!(
959-
"error: detected legacy-style directives in compiletest test: {}:{}, please use `ui_test`-style directives `//@` instead:{:#?}",
960-
testfile.display(),
961-
line_number,
962-
line_directive("//", ln),
963-
);
964-
return;
965-
};
1034+
let CheckDirectiveResult { is_known_directive, directive_name } = check_directive(rest);
9661035

967-
if prefix_removed.starts_with([' ', ':']) {
968-
// We have a comment that's *successfully* parsed as an legacy-style
969-
// directive. We emit an error here to warn the user.
970-
*poisoned = true;
971-
eprintln!(
972-
"error: detected legacy-style directives in compiletest test: {}:{}, please use `ui_test`-style directives `//@` instead:{:#?}",
973-
testfile.display(),
974-
line_number,
975-
line_directive("//", ln),
976-
);
977-
return;
978-
}
979-
}
1036+
if is_known_directive {
1037+
*poisoned = true;
1038+
eprintln!(
1039+
"error: detected legacy-style directive {} in compiletest test: {}:{}, please use `ui_test`-style directives `//@` instead: {:#?}",
1040+
directive_name,
1041+
testfile.display(),
1042+
line_number,
1043+
line_directive("//", ln),
1044+
);
1045+
return;
9801046
}
9811047
}
9821048
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
//@ check-pass
2+
3+
//~ HELP
4+
fn main() {} //~ERROR
5+
//~^ ERROR
6+
//~| ERROR
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
//! ignore-wasm
2+
//@ ignore-wasm
3+
//@ check-pass
4+
// regular comment
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
// ignore-wasm
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# ignore-owo
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
//@ needs-headpat

src/tools/compiletest/src/header/tests.rs

+62
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ use std::str::FromStr;
55
use crate::common::{Config, Debugger, Mode};
66
use crate::header::{parse_normalization_string, EarlyProps, HeadersCache};
77

8+
use super::iter_header;
9+
810
fn make_test_description<R: Read>(
911
config: &Config,
1012
name: test::TestName,
@@ -612,3 +614,63 @@ fn threads_support() {
612614
assert_eq!(check_ignore(&config, "//@ needs-threads"), !has_threads)
613615
}
614616
}
617+
618+
fn run_path(poisoned: &mut bool, path: &Path, buf: &[u8]) {
619+
let rdr = std::io::Cursor::new(&buf);
620+
iter_header(Mode::Ui, "ui", poisoned, path, rdr, &mut |_| {});
621+
}
622+
623+
#[test]
624+
fn test_unknown_directive_check() {
625+
let mut poisoned = false;
626+
run_path(
627+
&mut poisoned,
628+
Path::new("a.rs"),
629+
include_bytes!("./test-auxillary/unknown_directive.rs"),
630+
);
631+
assert!(poisoned);
632+
}
633+
634+
#[test]
635+
fn test_known_legacy_directive_check() {
636+
let mut poisoned = false;
637+
run_path(
638+
&mut poisoned,
639+
Path::new("a.rs"),
640+
include_bytes!("./test-auxillary/known_legacy_directive.rs"),
641+
);
642+
assert!(poisoned);
643+
}
644+
645+
#[test]
646+
fn test_known_directive_check_no_error() {
647+
let mut poisoned = false;
648+
run_path(
649+
&mut poisoned,
650+
Path::new("a.rs"),
651+
include_bytes!("./test-auxillary/known_directive.rs"),
652+
);
653+
assert!(!poisoned);
654+
}
655+
656+
#[test]
657+
fn test_error_annotation_no_error() {
658+
let mut poisoned = false;
659+
run_path(
660+
&mut poisoned,
661+
Path::new("a.rs"),
662+
include_bytes!("./test-auxillary/error_annotation.rs"),
663+
);
664+
assert!(!poisoned);
665+
}
666+
667+
#[test]
668+
fn test_non_rs_unknown_directive_not_checked() {
669+
let mut poisoned = false;
670+
run_path(
671+
&mut poisoned,
672+
Path::new("a.Makefile"),
673+
include_bytes!("./test-auxillary/not_rs.Makefile"),
674+
);
675+
assert!(!poisoned);
676+
}

tests/ui/borrowck/two-phase-reservation-sharing-interference.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
// The nll_beyond revision is disabled due to missing support from two-phase beyond autorefs
44
//@[nll_beyond]compile-flags: -Z two-phase-beyond-autoref
5-
//[nll_beyond]should-fail
5+
//@[nll_beyond]should-fail
66

77
// This is a corner case that the current implementation is (probably)
88
// treating more conservatively than is necessary. But it also does

0 commit comments

Comments
 (0)