diff --git a/src/etc/htmldocck.py b/src/etc/htmldocck.py
index 2e0f832192fdc..970dfc467634c 100755
--- a/src/etc/htmldocck.py
+++ b/src/etc/htmldocck.py
@@ -241,11 +241,236 @@ def concat_multi_lines(f):
LINE_PATTERN = re.compile(r'''
- (?<=(?!?)@(?P!?)
- (?P[A-Za-z]+(?:-[A-Za-z]+)*)
+ //@\s+
+ (?P!?)(?P[A-Za-z]+(?:-[A-Za-z]+)*)
(?P.*)$
''', re.X | re.UNICODE)
+# Equivalent to `src/tools/compiletest/src/header.rs` constant of the same name.
+KNOWN_DIRECTIVE_NAMES = [
+ # tidy-alphabetical-start
+ "assembly-output",
+ "aux-bin",
+ "aux-build",
+ "aux-codegen-backend",
+ "aux-crate",
+ "build-aux-docs",
+ "build-fail",
+ "build-pass",
+ "check-fail",
+ "check-pass",
+ "check-run-results",
+ "check-stdout",
+ "check-test-line-numbers-match",
+ "compare-output-lines-by-subset",
+ "compile-flags",
+ "dont-check-compiler-stderr",
+ "dont-check-compiler-stdout",
+ "dont-check-failure-status",
+ "edition",
+ "error-pattern",
+ "exec-env",
+ "failure-status",
+ "filecheck-flags",
+ "forbid-output",
+ "force-host",
+ "ignore-16bit",
+ "ignore-32bit",
+ "ignore-64bit",
+ "ignore-aarch64",
+ "ignore-aarch64-unknown-linux-gnu",
+ "ignore-android",
+ "ignore-apple",
+ "ignore-arm",
+ "ignore-avr",
+ "ignore-beta",
+ "ignore-cdb",
+ "ignore-compare-mode-next-solver",
+ "ignore-compare-mode-polonius",
+ "ignore-cross-compile",
+ "ignore-debug",
+ "ignore-eabi",
+ "ignore-emscripten",
+ "ignore-endian-big",
+ "ignore-freebsd",
+ "ignore-fuchsia",
+ "ignore-gdb",
+ "ignore-gdb-version",
+ "ignore-gnu",
+ "ignore-haiku",
+ "ignore-horizon",
+ "ignore-i686-pc-windows-msvc",
+ "ignore-ios",
+ "ignore-linux",
+ "ignore-lldb",
+ "ignore-llvm-version",
+ "ignore-loongarch64",
+ "ignore-macabi",
+ "ignore-macos",
+ "ignore-mode-assembly",
+ "ignore-mode-codegen",
+ "ignore-mode-codegen-units",
+ "ignore-mode-coverage-map",
+ "ignore-mode-coverage-run",
+ "ignore-mode-crashes",
+ "ignore-mode-debuginfo",
+ "ignore-mode-incremental",
+ "ignore-mode-js-doc-test",
+ "ignore-mode-mir-opt",
+ "ignore-mode-pretty",
+ "ignore-mode-run-make",
+ "ignore-mode-run-pass-valgrind",
+ "ignore-mode-rustdoc",
+ "ignore-mode-rustdoc-json",
+ "ignore-mode-ui",
+ "ignore-mode-ui-fulldeps",
+ "ignore-msp430",
+ "ignore-msvc",
+ "ignore-musl",
+ "ignore-netbsd",
+ "ignore-nightly",
+ "ignore-none",
+ "ignore-nto",
+ "ignore-nvptx64",
+ "ignore-nvptx64-nvidia-cuda",
+ "ignore-openbsd",
+ "ignore-pass",
+ "ignore-remote",
+ "ignore-riscv64",
+ "ignore-s390x",
+ "ignore-sgx",
+ "ignore-spirv",
+ "ignore-stable",
+ "ignore-stage1",
+ "ignore-stage2",
+ "ignore-test",
+ "ignore-thumb",
+ "ignore-thumbv8m.base-none-eabi",
+ "ignore-thumbv8m.main-none-eabi",
+ "ignore-tvos",
+ "ignore-unix",
+ "ignore-unknown",
+ "ignore-uwp",
+ "ignore-visionos",
+ "ignore-vxworks",
+ "ignore-wasi",
+ "ignore-wasm",
+ "ignore-wasm32",
+ "ignore-wasm32-bare",
+ "ignore-wasm64",
+ "ignore-watchos",
+ "ignore-windows",
+ "ignore-windows-gnu",
+ "ignore-x32",
+ "ignore-x86",
+ "ignore-x86_64",
+ "ignore-x86_64-unknown-linux-gnu",
+ "incremental",
+ "known-bug",
+ "llvm-cov-flags",
+ "min-cdb-version",
+ "min-gdb-version",
+ "min-lldb-version",
+ "min-llvm-version",
+ "min-system-llvm-version",
+ "needs-asm-support",
+ "needs-dlltool",
+ "needs-dynamic-linking",
+ "needs-force-clang-based-tests",
+ "needs-git-hash",
+ "needs-llvm-components",
+ "needs-profiler-support",
+ "needs-relocation-model-pic",
+ "needs-run-enabled",
+ "needs-rust-lld",
+ "needs-rust-lldb",
+ "needs-sanitizer-address",
+ "needs-sanitizer-cfi",
+ "needs-sanitizer-dataflow",
+ "needs-sanitizer-hwaddress",
+ "needs-sanitizer-kcfi",
+ "needs-sanitizer-leak",
+ "needs-sanitizer-memory",
+ "needs-sanitizer-memtag",
+ "needs-sanitizer-safestack",
+ "needs-sanitizer-shadow-call-stack",
+ "needs-sanitizer-support",
+ "needs-sanitizer-thread",
+ "needs-threads",
+ "needs-unwind",
+ "needs-wasmtime",
+ "needs-xray",
+ "no-auto-check-cfg",
+ "no-prefer-dynamic",
+ "normalize-stderr-32bit",
+ "normalize-stderr-64bit",
+ "normalize-stderr-test",
+ "normalize-stdout-test",
+ "only-16bit",
+ "only-32bit",
+ "only-64bit",
+ "only-aarch64",
+ "only-apple",
+ "only-arm",
+ "only-avr",
+ "only-beta",
+ "only-bpf",
+ "only-cdb",
+ "only-gnu",
+ "only-i686-pc-windows-msvc",
+ "only-ios",
+ "only-linux",
+ "only-loongarch64",
+ "only-loongarch64-unknown-linux-gnu",
+ "only-macos",
+ "only-mips",
+ "only-mips64",
+ "only-msp430",
+ "only-msvc",
+ "only-nightly",
+ "only-nvptx64",
+ "only-riscv64",
+ "only-sparc",
+ "only-sparc64",
+ "only-stable",
+ "only-thumb",
+ "only-tvos",
+ "only-unix",
+ "only-visionos",
+ "only-wasm32",
+ "only-wasm32-bare",
+ "only-wasm32-wasip1",
+ "only-watchos",
+ "only-windows",
+ "only-x86",
+ "only-x86_64",
+ "only-x86_64-fortanix-unknown-sgx",
+ "only-x86_64-pc-windows-gnu",
+ "only-x86_64-pc-windows-msvc",
+ "only-x86_64-unknown-linux-gnu",
+ "pp-exact",
+ "pretty-compare-only",
+ "pretty-expanded",
+ "pretty-mode",
+ "regex-error-pattern",
+ "remap-src-base",
+ "revisions",
+ "run-fail",
+ "run-flags",
+ "run-pass",
+ "run-rustfix",
+ "rustc-env",
+ "rustfix-only-machine-applicable",
+ "should-fail",
+ "should-ice",
+ "stderr-per-bitwidth",
+ "test-mir-pass",
+ "unset-exec-env",
+ "unset-rustc-env",
+ # Used by the tidy check `unknown_revision`.
+ "unused-revision-names",
+ # tidy-alphabetical-end
+]
def get_commands(template):
with io.open(template, encoding='utf-8') as f:
@@ -254,17 +479,9 @@ def get_commands(template):
if not m:
continue
- negated = (m.group('negated') == '!')
cmd = m.group('cmd')
- if m.group('invalid') == '!':
- print_err(
- lineno,
- line,
- 'Invalid command: `!@{0}{1}`, (help: try with `@!{1}`)'.format(
- '!' if negated else '',
- cmd,
- ),
- )
+ negated = (m.group('negated') == '!')
+ if not negated and cmd in KNOWN_DIRECTIVE_NAMES:
continue
args = m.group('args')
if args and not args[:1].isspace():
@@ -549,7 +766,7 @@ def get_nb_matching_elements(cache, c, regexp, stop_at_first):
def check_files_in_folder(c, cache, folder, files):
files = files.strip()
if not files.startswith('[') or not files.endswith(']'):
- raise InvalidCheck("Expected list as second argument of @{} (ie '[]')".format(c.cmd))
+ raise InvalidCheck("Expected list as second argument of {} (ie '[]')".format(c.cmd))
folder = cache.get_absolute_path(folder)
@@ -558,7 +775,7 @@ def check_files_in_folder(c, cache, folder, files):
files_set = set()
for file in files:
if file in files_set:
- raise InvalidCheck("Duplicated file `{}` in @{}".format(file, c.cmd))
+ raise InvalidCheck("Duplicated file `{}` in {}".format(file, c.cmd))
files_set.add(file)
folder_set = set([f for f in os.listdir(folder) if f != "." and f != ".."])
@@ -590,7 +807,7 @@ def check_command(c, cache):
if c.cmd in ['has', 'hasraw', 'matches', 'matchesraw']: # string test
regexp = c.cmd.startswith('matches')
- # @has = file existence
+ # has = file existence
if len(c.args) == 1 and not regexp and 'raw' not in c.cmd:
try:
cache.get_file(c.args[0])
@@ -598,40 +815,40 @@ def check_command(c, cache):
except FailedCheck as err:
cerr = str(err)
ret = False
- # @hasraw/matchesraw = string test
+ # hasraw/matchesraw = string test
elif len(c.args) == 2 and 'raw' in c.cmd:
cerr = "`PATTERN` did not match"
ret = check_string(cache.get_file(c.args[0]), c.args[1], regexp)
- # @has/matches = XML tree test
+ # has/matches = XML tree test
elif len(c.args) == 3 and 'raw' not in c.cmd:
cerr = "`XPATH PATTERN` did not match"
ret = get_nb_matching_elements(cache, c, regexp, True) != 0
else:
- raise InvalidCheck('Invalid number of @{} arguments'.format(c.cmd))
+ raise InvalidCheck('Invalid number of {} arguments'.format(c.cmd))
elif c.cmd == 'files': # check files in given folder
- if len(c.args) != 2: # @files
- raise InvalidCheck("Invalid number of @{} arguments".format(c.cmd))
+ if len(c.args) != 2: # files
+ raise InvalidCheck("Invalid number of {} arguments".format(c.cmd))
elif c.negated:
- raise InvalidCheck("@{} doesn't support negative check".format(c.cmd))
+ raise InvalidCheck("{} doesn't support negative check".format(c.cmd))
ret = check_files_in_folder(c, cache, c.args[0], c.args[1])
elif c.cmd == 'count': # count test
- if len(c.args) == 3: # @count = count test
+ if len(c.args) == 3: # count = count test
expected = int(c.args[2])
found = get_tree_count(cache.get_tree(c.args[0]), c.args[1])
cerr = "Expected {} occurrences but found {}".format(expected, found)
ret = expected == found
- elif len(c.args) == 4: # @count = count test
+ elif len(c.args) == 4: # count = count test
expected = int(c.args[3])
found = get_nb_matching_elements(cache, c, False, False)
cerr = "Expected {} occurrences but found {}".format(expected, found)
ret = found == expected
else:
- raise InvalidCheck('Invalid number of @{} arguments'.format(c.cmd))
+ raise InvalidCheck('Invalid number of {} arguments'.format(c.cmd))
elif c.cmd == 'snapshot': # snapshot test
- if len(c.args) == 3: # @snapshot
+ if len(c.args) == 3: # snapshot
[snapshot_name, html_path, pattern] = c.args
tree = cache.get_tree(html_path)
xpath = normalize_xpath(pattern)
@@ -654,10 +871,10 @@ def check_command(c, cache):
else:
raise FailedCheck('Expected 1 match, but found {}'.format(len(subtrees)))
else:
- raise InvalidCheck('Invalid number of @{} arguments'.format(c.cmd))
+ raise InvalidCheck('Invalid number of {} arguments'.format(c.cmd))
elif c.cmd == 'has-dir': # has-dir test
- if len(c.args) == 1: # @has-dir = has-dir test
+ if len(c.args) == 1: # has-dir = has-dir test
try:
cache.get_dir(c.args[0])
ret = True
@@ -665,22 +882,22 @@ def check_command(c, cache):
cerr = str(err)
ret = False
else:
- raise InvalidCheck('Invalid number of @{} arguments'.format(c.cmd))
+ raise InvalidCheck('Invalid number of {} arguments'.format(c.cmd))
elif c.cmd == 'valid-html':
- raise InvalidCheck('Unimplemented @valid-html')
+ raise InvalidCheck('Unimplemented valid-html')
elif c.cmd == 'valid-links':
- raise InvalidCheck('Unimplemented @valid-links')
+ raise InvalidCheck('Unimplemented valid-links')
else:
- raise InvalidCheck('Unrecognized @{}'.format(c.cmd))
+ raise InvalidCheck('Unrecognized {}'.format(c.cmd))
if ret == c.negated:
raise FailedCheck(cerr)
except FailedCheck as err:
- message = '@{}{} check failed'.format('!' if c.negated else '', c.cmd)
+ message = '{}{} check failed'.format('!' if c.negated else '', c.cmd)
print_err(c.lineno, c.context, str(err), message)
except InvalidCheck as err:
print_err(c.lineno, c.context, str(err))
diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs
index 31ae0deb7ec3c..6780c593a5a36 100644
--- a/src/tools/compiletest/src/header.rs
+++ b/src/tools/compiletest/src/header.rs
@@ -954,6 +954,25 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
// tidy-alphabetical-end
];
+const KNOWN_RUSTDOC_DIRECTIVE_NAMES: &[&str] = &[
+ "count",
+ "!count",
+ "files",
+ "!files",
+ "has",
+ "!has",
+ "has-dir",
+ "!has-dir",
+ "hasraw",
+ "!hasraw",
+ "matches",
+ "!matches",
+ "matchesraw",
+ "!matchesraw",
+ "snapshot",
+ "!snapshot",
+];
+
/// The broken-down contents of a line containing a test header directive,
/// which [`iter_header`] passes to its callback function.
///
@@ -988,20 +1007,30 @@ pub(crate) struct CheckDirectiveResult<'ln> {
trailing_directive: Option<&'ln str>,
}
-pub(crate) fn check_directive(directive_ln: &str) -> CheckDirectiveResult<'_> {
+pub(crate) fn check_directive<'a>(
+ directive_ln: &'a str,
+ is_rustdoc: bool,
+ original_line: &str,
+) -> CheckDirectiveResult<'a> {
let (directive_name, post) = directive_ln.split_once([':', ' ']).unwrap_or((directive_ln, ""));
let trailing = post.trim().split_once(' ').map(|(pre, _)| pre).unwrap_or(post);
+ let is_known = |s: &str| {
+ KNOWN_DIRECTIVE_NAMES.contains(&s)
+ || (is_rustdoc
+ && original_line.starts_with("//@")
+ && KNOWN_RUSTDOC_DIRECTIVE_NAMES.contains(&s))
+ };
let trailing_directive = {
// 1. is the directive name followed by a space? (to exclude `:`)
matches!(directive_ln.get(directive_name.len()..), Some(s) if s.starts_with(' '))
// 2. is what is after that directive also a directive (ex: "only-x86 only-arm")
- && KNOWN_DIRECTIVE_NAMES.contains(&trailing)
+ && is_known(trailing)
}
.then_some(trailing);
CheckDirectiveResult {
- is_known_directive: KNOWN_DIRECTIVE_NAMES.contains(&directive_name),
+ is_known_directive: is_known(&directive_name),
directive_name: directive_ln,
trailing_directive,
}
@@ -1072,7 +1101,7 @@ fn iter_header(
let directive_ln = non_revisioned_directive_line.trim();
let CheckDirectiveResult { is_known_directive, trailing_directive, .. } =
- check_directive(directive_ln);
+ check_directive(directive_ln, mode == Mode::Rustdoc, ln);
if !is_known_directive {
*poisoned = true;
@@ -1125,7 +1154,7 @@ fn iter_header(
let rest = rest.trim_start();
let CheckDirectiveResult { is_known_directive, directive_name, .. } =
- check_directive(rest);
+ check_directive(rest, mode == Mode::Rustdoc, ln);
if is_known_directive {
*poisoned = true;