Skip to content

Commit 32567a2

Browse files
authored
Rollup merge of rust-lang#147955 - Zalathar:handlers, r=jieyouxu
compiletest: Migrate `TestProps` directive handling to a system of named handlers One of the very silly things about directive processing in compiletest is that for each directive in the test file, we proceed to check it against dozens of different directive names in linear sequence, without any kind of indexed lookup, and without any early-exit after a known directive name is found (unless a panic occurs). This PR is a big step away from that, by taking the `iter_directives` loop in `TestProps::load_from` and making all of its directive processing dispatch to a hashtable of individual name-specific handlers instead. --- The handler system is set up in a way that should allow us to add capabilities or change the implementation as needed, without having to mass-modify the existing handlers (e.g. this is why the `handler` and `multi_handler` functions are used). --- This PR is focused on mass-migrating all of the `TestProps` directive processing into handlers. Most of the resulting handlers could obviously be simplified further (e.g. by avoiding the redundant name checks that were needed in the pre-migration code), but I've avoided doing any such simplifications in this PR to keep its scope limited and make reviewing easier. The patches in this PR have been arranged so that the main migration can be inspected with `git diff --color-moved --color-moved-ws=ignore-all-space` to verify that it moves all of the relevant lines intact, without modifying or discarding any of them. r? jieyouxu
2 parents bd3781f + 33e9911 commit 32567a2

File tree

3 files changed

+409
-265
lines changed

3 files changed

+409
-265
lines changed

src/tools/compiletest/src/directives.rs

Lines changed: 17 additions & 262 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ use crate::directives::directive_names::{
1414
KNOWN_DIRECTIVE_NAMES_SET, KNOWN_HTMLDOCCK_DIRECTIVE_NAMES, KNOWN_JSONDOCCK_DIRECTIVE_NAMES,
1515
};
1616
pub(crate) use crate::directives::file::FileDirectives;
17+
use crate::directives::handlers::DIRECTIVE_HANDLERS_MAP;
1718
use crate::directives::line::{DirectiveLine, line_directive};
1819
use crate::directives::needs::CachedNeedsConditions;
1920
use crate::edition::{Edition, parse_edition};
@@ -26,6 +27,7 @@ mod auxiliary;
2627
mod cfg;
2728
mod directive_names;
2829
mod file;
30+
mod handlers;
2931
mod line;
3032
mod needs;
3133
#[cfg(test)]
@@ -359,269 +361,9 @@ impl TestProps {
359361
return;
360362
}
361363

362-
use directives::*;
363-
364-
config.push_name_value_directive(
365-
ln,
366-
ERROR_PATTERN,
367-
&mut self.error_patterns,
368-
|r| r,
369-
);
370-
config.push_name_value_directive(
371-
ln,
372-
REGEX_ERROR_PATTERN,
373-
&mut self.regex_error_patterns,
374-
|r| r,
375-
);
376-
377-
config.push_name_value_directive(ln, DOC_FLAGS, &mut self.doc_flags, |r| r);
378-
379-
fn split_flags(flags: &str) -> Vec<String> {
380-
// Individual flags can be single-quoted to preserve spaces; see
381-
// <https://github.com/rust-lang/rust/pull/115948/commits/957c5db6>.
382-
flags
383-
.split('\'')
384-
.enumerate()
385-
.flat_map(|(i, f)| {
386-
if i % 2 == 1 { vec![f] } else { f.split_whitespace().collect() }
387-
})
388-
.map(move |s| s.to_owned())
389-
.collect::<Vec<_>>()
390-
}
391-
392-
if let Some(flags) = config.parse_name_value_directive(ln, COMPILE_FLAGS) {
393-
let flags = split_flags(&flags);
394-
for (i, flag) in flags.iter().enumerate() {
395-
if flag == "--edition" || flag.starts_with("--edition=") {
396-
panic!("you must use `//@ edition` to configure the edition");
397-
}
398-
if (flag == "-C"
399-
&& flags.get(i + 1).is_some_and(|v| v.starts_with("incremental=")))
400-
|| flag.starts_with("-Cincremental=")
401-
{
402-
panic!(
403-
"you must use `//@ incremental` to enable incremental compilation"
404-
);
405-
}
406-
}
407-
self.compile_flags.extend(flags);
408-
}
409-
410-
if let Some(range) = parse_edition_range(config, ln) {
411-
self.edition = Some(range.edition_to_test(config.edition));
412-
}
413-
414-
config.parse_and_update_revisions(ln, &mut self.revisions);
415-
416-
if let Some(flags) = config.parse_name_value_directive(ln, RUN_FLAGS) {
417-
self.run_flags.extend(split_flags(&flags));
418-
}
419-
420-
if self.pp_exact.is_none() {
421-
self.pp_exact = config.parse_pp_exact(ln);
422-
}
423-
424-
config.set_name_directive(ln, SHOULD_ICE, &mut self.should_ice);
425-
config.set_name_directive(ln, BUILD_AUX_DOCS, &mut self.build_aux_docs);
426-
config.set_name_directive(ln, UNIQUE_DOC_OUT_DIR, &mut self.unique_doc_out_dir);
427-
428-
config.set_name_directive(ln, FORCE_HOST, &mut self.force_host);
429-
config.set_name_directive(ln, CHECK_STDOUT, &mut self.check_stdout);
430-
config.set_name_directive(ln, CHECK_RUN_RESULTS, &mut self.check_run_results);
431-
config.set_name_directive(
432-
ln,
433-
DONT_CHECK_COMPILER_STDOUT,
434-
&mut self.dont_check_compiler_stdout,
435-
);
436-
config.set_name_directive(
437-
ln,
438-
DONT_CHECK_COMPILER_STDERR,
439-
&mut self.dont_check_compiler_stderr,
440-
);
441-
config.set_name_directive(ln, NO_PREFER_DYNAMIC, &mut self.no_prefer_dynamic);
442-
443-
if let Some(m) = config.parse_name_value_directive(ln, PRETTY_MODE) {
444-
self.pretty_mode = m;
445-
}
446-
447-
config.set_name_directive(
448-
ln,
449-
PRETTY_COMPARE_ONLY,
450-
&mut self.pretty_compare_only,
451-
);
452-
453-
// Call a helper method to deal with aux-related directives.
454-
parse_and_update_aux(config, ln, &mut self.aux);
455-
456-
config.push_name_value_directive(
457-
ln,
458-
EXEC_ENV,
459-
&mut self.exec_env,
460-
Config::parse_env,
461-
);
462-
config.push_name_value_directive(
463-
ln,
464-
UNSET_EXEC_ENV,
465-
&mut self.unset_exec_env,
466-
|r| r.trim().to_owned(),
467-
);
468-
config.push_name_value_directive(
469-
ln,
470-
RUSTC_ENV,
471-
&mut self.rustc_env,
472-
Config::parse_env,
473-
);
474-
config.push_name_value_directive(
475-
ln,
476-
UNSET_RUSTC_ENV,
477-
&mut self.unset_rustc_env,
478-
|r| r.trim().to_owned(),
479-
);
480-
config.push_name_value_directive(
481-
ln,
482-
FORBID_OUTPUT,
483-
&mut self.forbid_output,
484-
|r| r,
485-
);
486-
config.set_name_directive(
487-
ln,
488-
CHECK_TEST_LINE_NUMBERS_MATCH,
489-
&mut self.check_test_line_numbers_match,
490-
);
491-
492-
self.update_pass_mode(ln, config);
493-
self.update_fail_mode(ln, config);
494-
495-
config.set_name_directive(ln, IGNORE_PASS, &mut self.ignore_pass);
496-
497-
if let Some(NormalizeRule { kind, regex, replacement }) =
498-
config.parse_custom_normalization(ln)
499-
{
500-
let rule_tuple = (regex, replacement);
501-
match kind {
502-
NormalizeKind::Stdout => self.normalize_stdout.push(rule_tuple),
503-
NormalizeKind::Stderr => self.normalize_stderr.push(rule_tuple),
504-
NormalizeKind::Stderr32bit => {
505-
if config.target_cfg().pointer_width == 32 {
506-
self.normalize_stderr.push(rule_tuple);
507-
}
508-
}
509-
NormalizeKind::Stderr64bit => {
510-
if config.target_cfg().pointer_width == 64 {
511-
self.normalize_stderr.push(rule_tuple);
512-
}
513-
}
514-
}
515-
}
516-
517-
if let Some(code) = config
518-
.parse_name_value_directive(ln, FAILURE_STATUS)
519-
.and_then(|code| code.trim().parse::<i32>().ok())
520-
{
521-
self.failure_status = Some(code);
522-
}
523-
524-
config.set_name_directive(
525-
ln,
526-
DONT_CHECK_FAILURE_STATUS,
527-
&mut self.dont_check_failure_status,
528-
);
529-
530-
config.set_name_directive(ln, RUN_RUSTFIX, &mut self.run_rustfix);
531-
config.set_name_directive(
532-
ln,
533-
RUSTFIX_ONLY_MACHINE_APPLICABLE,
534-
&mut self.rustfix_only_machine_applicable,
535-
);
536-
config.set_name_value_directive(
537-
ln,
538-
ASSEMBLY_OUTPUT,
539-
&mut self.assembly_output,
540-
|r| r.trim().to_string(),
541-
);
542-
config.set_name_directive(
543-
ln,
544-
STDERR_PER_BITWIDTH,
545-
&mut self.stderr_per_bitwidth,
546-
);
547-
config.set_name_directive(ln, INCREMENTAL, &mut self.incremental);
548-
549-
// Unlike the other `name_value_directive`s this needs to be handled manually,
550-
// because it sets a `bool` flag.
551-
if let Some(known_bug) = config.parse_name_value_directive(ln, KNOWN_BUG) {
552-
let known_bug = known_bug.trim();
553-
if known_bug == "unknown"
554-
|| known_bug.split(',').all(|issue_ref| {
555-
issue_ref
556-
.trim()
557-
.split_once('#')
558-
.filter(|(_, number)| {
559-
number.chars().all(|digit| digit.is_numeric())
560-
})
561-
.is_some()
562-
})
563-
{
564-
self.known_bug = true;
565-
} else {
566-
panic!(
567-
"Invalid known-bug value: {known_bug}\nIt requires comma-separated issue references (`#000` or `chalk#000`) or `known-bug: unknown`."
568-
);
569-
}
570-
} else if config.parse_name_directive(ln, KNOWN_BUG) {
571-
panic!(
572-
"Invalid known-bug attribute, requires comma-separated issue references (`#000` or `chalk#000`) or `known-bug: unknown`."
573-
);
574-
}
575-
576-
config.set_name_value_directive(
577-
ln,
578-
TEST_MIR_PASS,
579-
&mut self.mir_unit_test,
580-
|s| s.trim().to_string(),
581-
);
582-
config.set_name_directive(ln, REMAP_SRC_BASE, &mut self.remap_src_base);
583-
584-
if let Some(flags) = config.parse_name_value_directive(ln, LLVM_COV_FLAGS) {
585-
self.llvm_cov_flags.extend(split_flags(&flags));
586-
}
587-
588-
if let Some(flags) = config.parse_name_value_directive(ln, FILECHECK_FLAGS) {
589-
self.filecheck_flags.extend(split_flags(&flags));
590-
}
591-
592-
config.set_name_directive(ln, NO_AUTO_CHECK_CFG, &mut self.no_auto_check_cfg);
593-
594-
self.update_add_minicore(ln, config);
595-
596-
if let Some(flags) =
597-
config.parse_name_value_directive(ln, MINICORE_COMPILE_FLAGS)
598-
{
599-
let flags = split_flags(&flags);
600-
for flag in &flags {
601-
if flag == "--edition" || flag.starts_with("--edition=") {
602-
panic!("you must use `//@ edition` to configure the edition");
603-
}
604-
}
605-
self.minicore_compile_flags.extend(flags);
364+
if let Some(handler) = DIRECTIVE_HANDLERS_MAP.get(ln.name) {
365+
handler.handle(config, ln, self);
606366
}
607-
608-
if let Some(err_kind) =
609-
config.parse_name_value_directive(ln, DONT_REQUIRE_ANNOTATIONS)
610-
{
611-
self.dont_require_annotations
612-
.insert(ErrorKind::expect_from_user_str(err_kind.trim()));
613-
}
614-
615-
config.set_name_directive(
616-
ln,
617-
DISABLE_GDB_PRETTY_PRINTERS,
618-
&mut self.disable_gdb_pretty_printers,
619-
);
620-
config.set_name_directive(
621-
ln,
622-
COMPARE_OUTPUT_BY_LINES,
623-
&mut self.compare_output_by_lines,
624-
);
625367
},
626368
);
627369
}
@@ -1691,3 +1433,16 @@ impl EditionRange {
16911433
}
16921434
}
16931435
}
1436+
1437+
fn split_flags(flags: &str) -> Vec<String> {
1438+
// Individual flags can be single-quoted to preserve spaces; see
1439+
// <https://github.com/rust-lang/rust/pull/115948/commits/957c5db6>.
1440+
// FIXME(#147955): Replace this ad-hoc quoting with an escape/quote system that
1441+
// is closer to what actual shells do, so that it's more flexible and familiar.
1442+
flags
1443+
.split('\'')
1444+
.enumerate()
1445+
.flat_map(|(i, f)| if i % 2 == 1 { vec![f] } else { f.split_whitespace().collect() })
1446+
.map(move |s| s.to_owned())
1447+
.collect::<Vec<_>>()
1448+
}

0 commit comments

Comments
 (0)