From 98bd8fd88c3750cfc33b6ae56a0ff1078940bdc6 Mon Sep 17 00:00:00 2001 From: Dario Gonzalez Date: Fri, 26 Apr 2019 13:52:56 -0700 Subject: [PATCH 1/5] Added ability to crosscompile doctests --- src/librustdoc/config.rs | 10 ++++++ src/librustdoc/html/markdown.rs | 34 +++++++++++++++++---- src/librustdoc/html/markdown/tests.rs | 44 ++++++++++++++------------- src/librustdoc/lib.rs | 12 ++++++++ src/librustdoc/test.rs | 42 +++++++++++++++++++++---- 5 files changed, 109 insertions(+), 33 deletions(-) diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index d261408fc148a..6d1258fe3a390 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -77,6 +77,10 @@ pub struct Options { /// Optional path to persist the doctest executables to, defaults to a /// temporary directory if not set. pub persist_doctests: Option, + /// Runtool to run doctests with + pub runtool: Option, + /// Arguments to pass to the runtool + pub runtool_args: Vec, // Options that affect the documentation process @@ -140,6 +144,8 @@ impl fmt::Debug for Options { .field("show_coverage", &self.show_coverage) .field("crate_version", &self.crate_version) .field("render_options", &self.render_options) + .field("runtool", &self.runtool) + .field("runtool_args", &self.runtool_args) .finish() } } @@ -466,6 +472,8 @@ impl Options { let codegen_options_strs = matches.opt_strs("C"); let lib_strs = matches.opt_strs("L"); let extern_strs = matches.opt_strs("extern"); + let runtool = matches.opt_str("runtool"); + let runtool_args = matches.opt_strs("runtool-arg"); let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format); @@ -496,6 +504,8 @@ impl Options { show_coverage, crate_version, persist_doctests, + runtool, + runtool_args, render_options: RenderOptions { output, external_html, diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 74413a7f905d4..45f2efd411fae 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -272,7 +272,7 @@ impl<'a, I: Iterator>> Iterator for CodeBlocks<'_, 'a, I> { )) }); - let tooltip = if ignore { + let tooltip = if ignore != Ignore::None { Some(("This example is not tested".to_owned(), "ignore")) } else if compile_fail { Some(("This example deliberately fails to compile".to_owned(), "compile_fail")) @@ -286,7 +286,7 @@ impl<'a, I: Iterator>> Iterator for CodeBlocks<'_, 'a, I> { s.push_str(&highlight::render_with_highlighting( &text, Some(&format!("rust-example-rendered{}", - if ignore { " ignore" } + if ignore != Ignore::None { " ignore" } else if compile_fail { " compile_fail" } else if explicit_edition { " edition " } else { "" })), @@ -297,7 +297,7 @@ impl<'a, I: Iterator>> Iterator for CodeBlocks<'_, 'a, I> { s.push_str(&highlight::render_with_highlighting( &text, Some(&format!("rust-example-rendered{}", - if ignore { " ignore" } + if ignore != Ignore::None { " ignore" } else if compile_fail { " compile_fail" } else if explicit_edition { " edition " } else { "" })), @@ -607,7 +607,7 @@ pub struct LangString { original: String, pub should_panic: bool, pub no_run: bool, - pub ignore: bool, + pub ignore: Ignore, pub rust: bool, pub test_harness: bool, pub compile_fail: bool, @@ -616,13 +616,20 @@ pub struct LangString { pub edition: Option } +#[derive(Eq, PartialEq, Clone, Debug)] +pub enum Ignore { + All, + None, + Some(Vec), +} + impl LangString { fn all_false() -> LangString { LangString { original: String::new(), should_panic: false, no_run: false, - ignore: false, + ignore: Ignore::None, rust: true, // NB This used to be `notrust = false` test_harness: false, compile_fail: false, @@ -637,6 +644,7 @@ impl LangString { let mut seen_rust_tags = false; let mut seen_other_tags = false; let mut data = LangString::all_false(); + let mut ignores = vec![]; data.original = string.to_owned(); let tokens = string.split(|c: char| @@ -651,7 +659,11 @@ impl LangString { seen_rust_tags = seen_other_tags == false; } "no_run" => { data.no_run = true; seen_rust_tags = !seen_other_tags; } - "ignore" => { data.ignore = true; seen_rust_tags = !seen_other_tags; } + "ignore" => { data.ignore = Ignore::All; seen_rust_tags = !seen_other_tags; } + x if x.starts_with("ignore-") => { + ignores.push(x.trim_start_matches("ignore-").to_owned()); + seen_rust_tags = !seen_other_tags; + } "allow_fail" => { data.allow_fail = true; seen_rust_tags = !seen_other_tags; } "rust" => { data.rust = true; seen_rust_tags = true; } "test_harness" => { @@ -680,6 +692,16 @@ impl LangString { } } + match data.ignore { + Ignore::All => {}, + Ignore::None => { + if !ignores.is_empty() { + data.ignore = Ignore::Some(ignores); + } + }, + _ => unreachable!(), + } + data.rust &= !seen_other_tags || seen_rust_tags; data diff --git a/src/librustdoc/html/markdown/tests.rs b/src/librustdoc/html/markdown/tests.rs index a95c29038d46f..5d6811a29a3eb 100644 --- a/src/librustdoc/html/markdown/tests.rs +++ b/src/librustdoc/html/markdown/tests.rs @@ -1,4 +1,4 @@ -use super::{ErrorCodes, LangString, Markdown, MarkdownHtml, IdMap}; +use super::{ErrorCodes, LangString, Markdown, MarkdownHtml, IdMap, Ignore}; use super::plain_summary_line; use std::cell::RefCell; use syntax::edition::{Edition, DEFAULT_EDITION}; @@ -26,10 +26,10 @@ fn test_unique_id() { #[test] fn test_lang_string_parse() { fn t(s: &str, - should_panic: bool, no_run: bool, ignore: bool, rust: bool, test_harness: bool, + should_panic: bool, no_run: bool, ignore: Ignore, rust: bool, test_harness: bool, compile_fail: bool, allow_fail: bool, error_codes: Vec, - edition: Option) { - assert_eq!(LangString::parse(s, ErrorCodes::Yes), LangString { + edition: Option) { + assert_eq!(LangString::parse(s, ErrorCodes::Yes, true), LangString { should_panic, no_run, ignore, @@ -42,6 +42,7 @@ fn test_lang_string_parse() { edition, }) } + let ignore_foo = Ignore::Some(vec!("foo".to_string())); fn v() -> Vec { Vec::new() @@ -50,23 +51,24 @@ fn test_lang_string_parse() { // ignore-tidy-linelength // marker | should_panic | no_run | ignore | rust | test_harness // | compile_fail | allow_fail | error_codes | edition - t("", false, false, false, true, false, false, false, v(), None); - t("rust", false, false, false, true, false, false, false, v(), None); - t("sh", false, false, false, false, false, false, false, v(), None); - t("ignore", false, false, true, true, false, false, false, v(), None); - t("should_panic", true, false, false, true, false, false, false, v(), None); - t("no_run", false, true, false, true, false, false, false, v(), None); - t("test_harness", false, false, false, true, true, false, false, v(), None); - t("compile_fail", false, true, false, true, false, true, false, v(), None); - t("allow_fail", false, false, false, true, false, false, true, v(), None); - t("{.no_run .example}", false, true, false, true, false, false, false, v(), None); - t("{.sh .should_panic}", true, false, false, false, false, false, false, v(), None); - t("{.example .rust}", false, false, false, true, false, false, false, v(), None); - t("{.test_harness .rust}", false, false, false, true, true, false, false, v(), None); - t("text, no_run", false, true, false, false, false, false, false, v(), None); - t("text,no_run", false, true, false, false, false, false, false, v(), None); - t("edition2015", false, false, false, true, false, false, false, v(), Some(Edition::Edition2015)); - t("edition2018", false, false, false, true, false, false, false, v(), Some(Edition::Edition2018)); + t("", false, false, Ignore::None, true, false, false, false, v(), None); + t("rust", false, false, Ignore::None, true, false, false, false, v(), None); + t("sh", false, false, Ignore::None, false, false, false, false, v(), None); + t("ignore", false, false, Ignore::All, true, false, false, false, v(), None); + t("ignore-foo", false, false, ignore_foo, true, false, false, false, v(), None); + t("should_panic", true, false, Ignore::None, true, false, false, false, v(), None); + t("no_run", false, true, Ignore::None, true, false, false, false, v(), None); + t("test_harness", false, false, Ignore::None, true, true, false, false, v(), None); + t("compile_fail", false, true, Ignore::None, true, false, true, false, v(), None); + t("allow_fail", false, false, Ignore::None, true, false, false, true, v(), None); + t("{.no_run .example}", false, true, Ignore::None, true, false, false, false, v(), None); + t("{.sh .should_panic}", true, false, Ignore::None, false, false, false, false, v(), None); + t("{.example .rust}", false, false, Ignore::None, true, false, false, false, v(), None); + t("{.test_harness .rust}", false, false, Ignore::None, true, true, false, false, v(), None); + t("text, no_run", false, true, Ignore::None, false, false, false, false, v(), None); + t("text,no_run", false, true, Ignore::None, false, false, false, false, v(), None); + t("edition2015", false, false, Ignore::None, true, false, false, false, v(), Some(Edition::Edition2015)); + t("edition2018", false, false, Ignore::None, true, false, false, false, v(), Some(Edition::Edition2018)); } #[test] diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index dfa0db0d23b74..c5ac2440f6791 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -355,6 +355,18 @@ fn opts() -> Vec { "show-coverage", "calculate percentage of public items with documentation") }), + unstable("runtool", |o| { + o.optopt("", + "runtool", + "", + "The tool to run tests with when building for a different target than host") + }), + unstable("runtool-arg", |o| { + o.optmulti("", + "runtool-arg", + "", + "One (of possibly many) arguments to pass to the runtool") + }), ] } diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index adcc9930b6c33..2c9e530b9e6b1 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -1,5 +1,6 @@ use rustc_data_structures::sync::Lrc; use rustc_interface::interface; +use rustc_target::spec::TargetTriple; use rustc::hir; use rustc::hir::intravisit; use rustc::session::{self, config, DiagnosticOutput}; @@ -22,7 +23,7 @@ use testing; use crate::clean::Attributes; use crate::config::Options; -use crate::html::markdown::{self, ErrorCodes, LangString}; +use crate::html::markdown::{self, ErrorCodes, LangString, Ignore}; #[derive(Clone, Default)] pub struct TestOptions { @@ -44,7 +45,7 @@ pub fn run(options: Options) -> i32 { vec![config::CrateType::Dylib] }; - let sessopts = config::Options { + let mut sessopts = config::Options { maybe_sysroot: options.maybe_sysroot.clone(), search_paths: options.libs.clone(), crate_types, @@ -59,7 +60,7 @@ pub fn run(options: Options) -> i32 { edition: options.edition, ..config::Options::default() }; - + options.target.as_ref().map(|t| { sessopts.target_triple = t.clone() }); let config = interface::Config { opts: sessopts, crate_cfg: config::parse_cfgspecs(options.cfgs.clone()), @@ -181,6 +182,9 @@ fn run_test( should_panic: bool, no_run: bool, as_test_harness: bool, + runtool: Option, + runtool_args: Vec, + target: Option, compile_fail: bool, mut error_codes: Vec, opts: &TestOptions, @@ -315,7 +319,15 @@ fn run_test( } // Run the code! - let mut cmd = Command::new(output_file); + let mut cmd; + + if let Some(tool) = runtool { + cmd = Command::new(tool); + cmd.arg(output_file); + cmd.args(runtool_args); + }else{ + cmd = Command::new(output_file); + } match cmd.output() { Err(e) => return Err(TestFailure::ExecutionError(e)), @@ -661,12 +673,27 @@ impl Tester for Collector { let opts = self.opts.clone(); let edition = config.edition.unwrap_or(self.options.edition.clone()); let options = self.options.clone(); + let maybe_sysroot = self.maybe_sysroot.clone(); + let linker = self.linker.clone(); + let edition = config.edition.unwrap_or(self.edition); + let persist_doctests = self.persist_doctests.clone(); + let runtool = self.runtool.clone(); + let runtool_args = self.runtool_args.clone(); + let target = self.target.clone(); + let target_str = target.as_ref().map(|t| t.to_string()); debug!("creating test {}: {}", name, test); self.tests.push(testing::TestDescAndFn { desc: testing::TestDesc { - name: testing::DynTestName(name), - ignore: config.ignore, + name: testing::DynTestName(name.clone()), + ignore: match config.ignore { + Ignore::All => true, + Ignore::None => false, + Ignore::Some(ref ignores) => { + target_str.map_or(false, + |s| ignores.iter().any(|t| s.contains(t))) + }, + }, // compiler failures are test failures should_panic: testing::ShouldPanic::No, allow_fail: config.allow_fail, @@ -681,6 +708,9 @@ impl Tester for Collector { config.should_panic, config.no_run, config.test_harness, + runtool, + runtool_args, + target, config.compile_fail, config.error_codes, &opts, From 3f7640884128c6d2acaa9aee3b582cc372044b6d Mon Sep 17 00:00:00 2001 From: Dario Gonzalez Date: Thu, 6 Jun 2019 16:01:53 -0700 Subject: [PATCH 2/5] added feature gate enable-per-target-ignores updated and augmented tests in html/markdown.rs --- src/librustdoc/config.rs | 7 +++++++ src/librustdoc/html/markdown.rs | 17 +++++++++++------ src/librustdoc/lib.rs | 5 +++++ src/librustdoc/markdown.rs | 2 +- src/librustdoc/passes/mod.rs | 2 +- src/librustdoc/test.rs | 7 +++++-- 6 files changed, 30 insertions(+), 10 deletions(-) diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index 6d1258fe3a390..d8fe8d6c8a362 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -81,6 +81,10 @@ pub struct Options { pub runtool: Option, /// Arguments to pass to the runtool pub runtool_args: Vec, + /// Whether to allow ignoring doctests on a per-target basis + /// For example, using ignore-foo to ignore running the doctest on any target that + /// contains "foo" as a substring + pub enable_per_target_ignores: bool, // Options that affect the documentation process @@ -146,6 +150,7 @@ impl fmt::Debug for Options { .field("render_options", &self.render_options) .field("runtool", &self.runtool) .field("runtool_args", &self.runtool_args) + .field("enable-per-target-ignores", &self.enable_per_target_ignores) .finish() } } @@ -474,6 +479,7 @@ impl Options { let extern_strs = matches.opt_strs("extern"); let runtool = matches.opt_str("runtool"); let runtool_args = matches.opt_strs("runtool-arg"); + let enable_per_target_ignores = matches.opt_present("enable-per-target-ignores"); let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format); @@ -506,6 +512,7 @@ impl Options { persist_doctests, runtool, runtool_args, + enable_per_target_ignores, render_options: RenderOptions { output, external_html, diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 45f2efd411fae..cdc6d4eda4006 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -199,7 +199,7 @@ impl<'a, I: Iterator>> Iterator for CodeBlocks<'_, 'a, I> { let ignore; let edition; if let Some(Event::Start(Tag::CodeBlock(lang))) = event { - let parse_result = LangString::parse(&lang, self.check_error_codes); + let parse_result = LangString::parse(&lang, self.check_error_codes, false); if !parse_result.rust { return Some(Event::Start(Tag::CodeBlock(lang))); } @@ -551,7 +551,8 @@ impl<'a, I: Iterator>> Iterator for Footnotes<'a, I> { } } -pub fn find_testable_code(doc: &str, tests: &mut T, error_codes: ErrorCodes) { +pub fn find_testable_code(doc: &str, tests: &mut T, error_codes: ErrorCodes, + enable_per_target_ignores: bool) { let mut parser = Parser::new(doc); let mut prev_offset = 0; let mut nb_lines = 0; @@ -564,7 +565,7 @@ pub fn find_testable_code(doc: &str, tests: &mut T, error_codes let block_info = if s.is_empty() { LangString::all_false() } else { - LangString::parse(&*s, error_codes) + LangString::parse(&*s, error_codes, enable_per_target_ignores) }; if !block_info.rust { continue; @@ -639,7 +640,11 @@ impl LangString { } } - fn parse(string: &str, allow_error_code_check: ErrorCodes) -> LangString { + fn parse( + string: &str, + allow_error_code_check: ErrorCodes, + enable_per_target_ignores: bool + ) -> LangString { let allow_error_code_check = allow_error_code_check.as_bool(); let mut seen_rust_tags = false; let mut seen_other_tags = false; @@ -660,7 +665,7 @@ impl LangString { } "no_run" => { data.no_run = true; seen_rust_tags = !seen_other_tags; } "ignore" => { data.ignore = Ignore::All; seen_rust_tags = !seen_other_tags; } - x if x.starts_with("ignore-") => { + x if enable_per_target_ignores && x.starts_with("ignore-") => { ignores.push(x.trim_start_matches("ignore-").to_owned()); seen_rust_tags = !seen_other_tags; } @@ -941,7 +946,7 @@ crate fn rust_code_blocks(md: &str) -> Vec { let lang_string = if syntax.is_empty() { LangString::all_false() } else { - LangString::parse(&*syntax, ErrorCodes::Yes) + LangString::parse(&*syntax, ErrorCodes::Yes, false) }; if lang_string.rust { diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index c5ac2440f6791..8f6067da08335 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -355,6 +355,11 @@ fn opts() -> Vec { "show-coverage", "calculate percentage of public items with documentation") }), + unstable("enable-per-target-ignores", |o| { + o.optflag("", + "enable-per-target-ignores", + "parse ignore-foo for ignoring doctests on a per-target basis") + }), unstable("runtool", |o| { o.optopt("", "runtool", diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs index a30fc05f36acd..67faec6bd3d0c 100644 --- a/src/librustdoc/markdown.rs +++ b/src/librustdoc/markdown.rs @@ -147,7 +147,7 @@ pub fn test(mut options: Options, diag: &errors::Handler) -> i32 { collector.set_position(DUMMY_SP); let codes = ErrorCodes::from(UnstableFeatures::from_environment().is_nightly_build()); - find_testable_code(&input_str, &mut collector, codes); + find_testable_code(&input_str, &mut collector, codes, options.enable_per_target_ignores); options.test_args.insert(0, "rustdoctest".to_string()); testing::test_main(&options.test_args, collector.tests, diff --git a/src/librustdoc/passes/mod.rs b/src/librustdoc/passes/mod.rs index 641a6df221446..3bb1d0deca78d 100644 --- a/src/librustdoc/passes/mod.rs +++ b/src/librustdoc/passes/mod.rs @@ -336,7 +336,7 @@ pub fn look_for_tests<'tcx>( found_tests: 0, }; - find_testable_code(&dox, &mut tests, ErrorCodes::No); + find_testable_code(&dox, &mut tests, ErrorCodes::No, false); if check_missing_code == true && tests.found_tests == 0 { let sp = span_of_attrs(&item.attrs).substitute_dummy(item.source.span()); diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index 2c9e530b9e6b1..a30ac1a512893 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -325,7 +325,7 @@ fn run_test( cmd = Command::new(tool); cmd.arg(output_file); cmd.args(runtool_args); - }else{ + } else { cmd = Command::new(output_file); } @@ -857,7 +857,10 @@ impl<'a, 'hir> HirCollector<'a, 'hir> { // anything else, this will combine them for us. if let Some(doc) = attrs.collapsed_doc_value() { self.collector.set_position(attrs.span.unwrap_or(DUMMY_SP)); - markdown::find_testable_code(&doc, self.collector, self.codes); + markdown::find_testable_code(&doc, + self.collector, + self.codes, + self.collector.enable_per_target_ignores); } nested(self); From 657e24c56b11a45ee1cc019eb0763838f4437475 Mon Sep 17 00:00:00 2001 From: Dario Gonzalez Date: Tue, 11 Jun 2019 11:06:34 -0700 Subject: [PATCH 3/5] changed target from option to plain target, populated with host triple at argument parsing time if no --target arguments --- src/librustdoc/config.rs | 8 +++++--- src/librustdoc/core.rs | 3 +-- src/librustdoc/test.rs | 8 +++----- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index d8fe8d6c8a362..995a340143f78 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -9,7 +9,7 @@ use rustc::session; use rustc::session::config::{CrateType, parse_crate_types_from_list}; use rustc::session::config::{CodegenOptions, DebuggingOptions, ErrorOutputType, Externs}; use rustc::session::config::{nightly_options, build_codegen_options, build_debugging_options, - get_cmd_lint_options, ExternEntry}; + get_cmd_lint_options, host_triple, ExternEntry}; use rustc::session::search_paths::SearchPath; use rustc_driver; use rustc_target::spec::TargetTriple; @@ -54,7 +54,7 @@ pub struct Options { /// Debugging (`-Z`) options to pass to the compiler. pub debugging_options: DebuggingOptions, /// The target used to compile the crate against. - pub target: Option, + pub target: TargetTriple, /// Edition used when reading the crate. Defaults to "2015". Also used by default when /// compiling doctests from the crate. pub edition: Edition, @@ -425,7 +425,9 @@ impl Options { } } - let target = matches.opt_str("target").map(|target| { + let target = matches.opt_str("target").map_or( + TargetTriple::from_triple(host_triple()), + |target| { if target.ends_with(".json") { TargetTriple::TargetPath(PathBuf::from(target)) } else { diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 9cfcad4271966..66a32c73e0f16 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -13,7 +13,6 @@ use rustc_interface::interface; use rustc_driver::abort_on_err; use rustc_resolve as resolve; use rustc_metadata::cstore::CStore; -use rustc_target::spec::TargetTriple; use syntax::source_map; use syntax::attr; @@ -313,7 +312,7 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt lint_cap: Some(lint_cap.unwrap_or_else(|| lint::Forbid)), cg: codegen_options, externs, - target_triple: target.unwrap_or(host_triple), + target_triple: target, // Ensure that rustdoc works even if rustc is feature-staged unstable_features: UnstableFeatures::Allow, actually_rustdoc: true, diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index a30ac1a512893..daec977810682 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -60,7 +60,6 @@ pub fn run(options: Options) -> i32 { edition: options.edition, ..config::Options::default() }; - options.target.as_ref().map(|t| { sessopts.target_triple = t.clone() }); let config = interface::Config { opts: sessopts, crate_cfg: config::parse_cfgspecs(options.cfgs.clone()), @@ -184,7 +183,7 @@ fn run_test( as_test_harness: bool, runtool: Option, runtool_args: Vec, - target: Option, + target: TargetTriple, compile_fail: bool, mut error_codes: Vec, opts: &TestOptions, @@ -680,7 +679,7 @@ impl Tester for Collector { let runtool = self.runtool.clone(); let runtool_args = self.runtool_args.clone(); let target = self.target.clone(); - let target_str = target.as_ref().map(|t| t.to_string()); + let target_str = target.to_string(); debug!("creating test {}: {}", name, test); self.tests.push(testing::TestDescAndFn { @@ -690,8 +689,7 @@ impl Tester for Collector { Ignore::All => true, Ignore::None => false, Ignore::Some(ref ignores) => { - target_str.map_or(false, - |s| ignores.iter().any(|t| s.contains(t))) + ignores.iter().any(|s| target_str.contains(s)) }, }, // compiler failures are test failures From 14110ebd936747eff905ec4e444a02a4a74f6e11 Mon Sep 17 00:00:00 2001 From: Dario Gonzalez Date: Wed, 12 Jun 2019 10:49:41 -0700 Subject: [PATCH 4/5] added rustdoc book documentation, improved behavior when unstable flag not present --- src/doc/rustdoc/src/unstable-features.md | 50 ++++++++++++++++++++++++ src/librustdoc/html/markdown.rs | 14 ++----- src/librustdoc/test.rs | 2 + 3 files changed, 56 insertions(+), 10 deletions(-) diff --git a/src/doc/rustdoc/src/unstable-features.md b/src/doc/rustdoc/src/unstable-features.md index 993fc8412836e..49d05b5038df7 100644 --- a/src/doc/rustdoc/src/unstable-features.md +++ b/src/doc/rustdoc/src/unstable-features.md @@ -471,3 +471,53 @@ Some methodology notes about what rustdoc counts in this metric: Public items that are not documented can be seen with the built-in `missing_docs` lint. Private items that are not documented can be seen with Clippy's `missing_docs_in_private_items` lint. + +### `--enable-per-target-ignores`: allow `ignore-foo` style filters for doctests + +Using this flag looks like this: + +```bash +$ rustdoc src/lib.rs -Z unstable-options --enable-per-target-ignores +``` + +This flag allows you to tag doctests with compiltest style `ignore-foo` filters that prevent +rustdoc from running that test if the target triple string contains foo. For example: + +```rust +///```ignore-foo,ignore-bar +///assert!(2 == 2); +///``` +struct Foo; +``` + +This will not be run when the build target is `super-awesome-foo` or `less-bar-awesome`. +If the flag is not enabled, then rustdoc will consume the filter, but do nothing with it, and +the above example will be run for all targets. +If you want to preserve backwards compatibility for older versions of rustdoc, you can use + +```rust +///```ignore,ignore-foo +///assert!(2 == 2); +///``` +struct Foo; +``` + +In older versions, this will be ignored on all targets, but on newer versions `ignore-gnu` will +override `ignore`. + +### `--runtool`, `--runtool-arg`: program to run tests with; args to pass to it + +Using thses options looks like this: + +```bash +$ rustdoc src/lib.rs -Z unstable-options --runtool runner --runtool-arg --do-thing --runtool-arg --do-other-thing +``` + +These options can be used to run the doctest under a program, and also pass arguments to +that program. For example, if you want to run your doctests under valgrind you might run + +```bash +$ rustdoc src/lib.rs -Z unstable-options --runtool valgrind +``` + +Another use case would be to run a test inside an emulator, or through a Virtual Machine. diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index cdc6d4eda4006..05e6c77256e7b 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -665,7 +665,7 @@ impl LangString { } "no_run" => { data.no_run = true; seen_rust_tags = !seen_other_tags; } "ignore" => { data.ignore = Ignore::All; seen_rust_tags = !seen_other_tags; } - x if enable_per_target_ignores && x.starts_with("ignore-") => { + x if x.starts_with("ignore-") => if enable_per_target_ignores { ignores.push(x.trim_start_matches("ignore-").to_owned()); seen_rust_tags = !seen_other_tags; } @@ -696,15 +696,9 @@ impl LangString { _ => { seen_other_tags = true } } } - - match data.ignore { - Ignore::All => {}, - Ignore::None => { - if !ignores.is_empty() { - data.ignore = Ignore::Some(ignores); - } - }, - _ => unreachable!(), + // ignore-foo overrides ignore + if !ignores.is_empty() { + data.ignore = Ignore::Some(ignores); } data.rust &= !seen_other_tags || seen_rust_tags; diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index daec977810682..840eeda9ad7ca 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -58,8 +58,10 @@ pub fn run(options: Options) -> i32 { ..config::basic_debugging_options() }, edition: options.edition, + target_triple: options.target.clone(), ..config::Options::default() }; + let config = interface::Config { opts: sessopts, crate_cfg: config::parse_cfgspecs(options.cfgs.clone()), From 4a2094c9f61836214d9e37fa042761948483c2d9 Mon Sep 17 00:00:00 2001 From: Dario Gonzalez Date: Tue, 27 Aug 2019 15:44:11 -0700 Subject: [PATCH 5/5] address rebase changes --- src/librustdoc/core.rs | 1 - src/librustdoc/markdown.rs | 3 ++- src/librustdoc/test.rs | 20 +++++++++++--------- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 66a32c73e0f16..57b016a08c2fe 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -293,7 +293,6 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt } }).collect(); - let host_triple = TargetTriple::from_triple(config::host_triple()); let crate_types = if proc_macro_crate { vec![config::CrateType::ProcMacro] } else { diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs index 67faec6bd3d0c..b06b368469fc1 100644 --- a/src/librustdoc/markdown.rs +++ b/src/librustdoc/markdown.rs @@ -143,7 +143,8 @@ pub fn test(mut options: Options, diag: &errors::Handler) -> i32 { opts.no_crate_inject = true; opts.display_warnings = options.display_warnings; let mut collector = Collector::new(options.input.display().to_string(), options.clone(), - true, opts, None, Some(options.input)); + true, opts, None, Some(options.input), + options.enable_per_target_ignores); collector.set_position(DUMMY_SP); let codes = ErrorCodes::from(UnstableFeatures::from_environment().is_nightly_build()); diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index 840eeda9ad7ca..aefe4d3ea3f43 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -45,7 +45,7 @@ pub fn run(options: Options) -> i32 { vec![config::CrateType::Dylib] }; - let mut sessopts = config::Options { + let sessopts = config::Options { maybe_sysroot: options.maybe_sysroot.clone(), search_paths: options.libs.clone(), crate_types, @@ -84,6 +84,7 @@ pub fn run(options: Options) -> i32 { let mut opts = scrape_test_config(lower_to_hir.peek().0.borrow().krate()); opts.display_warnings |= options.display_warnings; + let enable_per_target_ignores = options.enable_per_target_ignores; let mut collector = Collector::new( compiler.crate_name()?.peek().to_string(), options, @@ -91,6 +92,7 @@ pub fn run(options: Options) -> i32 { opts, Some(compiler.source_map().clone()), None, + enable_per_target_ignores, ); let mut global_ctxt = compiler.global_ctxt()?.take(); @@ -275,6 +277,7 @@ fn run_test( if no_run { compiler.arg("--emit=metadata"); } + compiler.arg("--target").arg(target.to_string()); compiler.arg("-"); compiler.stdin(Stdio::piped()); @@ -616,6 +619,7 @@ pub struct Collector { options: Options, use_headers: bool, + enable_per_target_ignores: bool, cratename: String, opts: TestOptions, position: Span, @@ -625,12 +629,14 @@ pub struct Collector { impl Collector { pub fn new(cratename: String, options: Options, use_headers: bool, opts: TestOptions, - source_map: Option>, filename: Option,) -> Collector { + source_map: Option>, filename: Option, + enable_per_target_ignores: bool) -> Collector { Collector { tests: Vec::new(), names: Vec::new(), options, use_headers, + enable_per_target_ignores, cratename, opts, position: DUMMY_SP, @@ -674,13 +680,9 @@ impl Tester for Collector { let opts = self.opts.clone(); let edition = config.edition.unwrap_or(self.options.edition.clone()); let options = self.options.clone(); - let maybe_sysroot = self.maybe_sysroot.clone(); - let linker = self.linker.clone(); - let edition = config.edition.unwrap_or(self.edition); - let persist_doctests = self.persist_doctests.clone(); - let runtool = self.runtool.clone(); - let runtool_args = self.runtool_args.clone(); - let target = self.target.clone(); + let runtool = self.options.runtool.clone(); + let runtool_args = self.options.runtool_args.clone(); + let target = self.options.target.clone(); let target_str = target.to_string(); debug!("creating test {}: {}", name, test);