Skip to content

Commit 5877e7e

Browse files
committed
Error on invalid compiletest directives in Rust test files
1 parent 3521a2f commit 5877e7e

File tree

7 files changed

+172
-31
lines changed

7 files changed

+172
-31
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+
}

0 commit comments

Comments
 (0)