Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stabilize flags for doctest cross compilation #137096

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions src/doc/rustdoc/src/command-line-arguments.md
Original file line number Diff line number Diff line change
@@ -222,6 +222,28 @@ For more, see [the chapter on documentation tests](write-documentation/documenta

See also `--test`.

## `--test-runtool`, `--test-runtool-arg`: program to run tests with; args to pass to it

A doctest wrapper program can be specified with the `--test-runtool` flag.
Rustdoc will execute that wrapper instead of the doctest executable when
running tests. The first arguments to the wrapper will be any arguments
specified with the `--test-runtool-arg` flag, followed by the path to the
doctest executable to run.

Using these options looks like this:

```bash
$ rustdoc src/lib.rs --test-runtool path/to/runner --test-runtool-arg --do-thing --test-runtool-arg --do-other-thing
```

For example, if you want to run your doctests under valgrind you might run:

```bash
$ rustdoc src/lib.rs --test-runtool valgrind
```

Another use case would be to run a test inside an emulator, or through a Virtual Machine.

## `--target`: generate documentation for the specified target triple

Using this flag looks like this:
54 changes: 0 additions & 54 deletions src/doc/rustdoc/src/unstable-features.md
Original file line number Diff line number Diff line change
@@ -631,60 +631,6 @@ The generated output (formatted) will look like this:
`--output-format html` has no effect, as the default output is HTML. This is
accepted on stable, even though the other options for this flag aren't.

## `--enable-per-target-ignores`: allow `ignore-foo` style filters for doctests

* Tracking issue: [#64245](https://github.com/rust-lang/rust/issues/64245)

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 compiletest 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

* Tracking issue: [#64245](https://github.com/rust-lang/rust/issues/64245)

Using these 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.

## `--with-examples`: include examples of uses of items as documentation

* Tracking issue: [#88791](https://github.com/rust-lang/rust/issues/88791)
37 changes: 37 additions & 0 deletions src/doc/rustdoc/src/write-documentation/documentation-tests.md
Original file line number Diff line number Diff line change
@@ -427,6 +427,43 @@ should not be merged with the others. So the previous code should use it:
In this case, it means that the line information will not change if you add/remove other
doctests.

### Ignoring targets

Attributes starting with `ignore-` can be used to ignore doctests for specific
targets. For example, `ignore-x86_64` will avoid building doctests when the
target name contains `x86_64`.

```rust
/// ```ignore-x86_64
/// assert!(2 == 2);
/// ```
struct Foo;
```

This doctest will not be built for targets such as `x86_64-unknown-linux-gnu`.

Multiple ignore attributes can be specified to ignore multiple targets:

```rust
/// ```ignore-x86_64,ignore-windows
/// assert!(2 == 2);
/// ```
struct Foo;
```

If you want to preserve backwards compatibility for older versions of rustdoc,
you can specify both `ignore` and `ignore-`, such as:

```rust
/// ```ignore,ignore-x86_64
/// assert!(2 == 2);
/// ```
struct Foo;
```

In older versions, this will be ignored on all targets, but starting with
version CURRENT_RUSTC_VERSION, `ignore-x86_64` will override `ignore`.

### Custom CSS classes for code blocks

```rust
23 changes: 8 additions & 15 deletions src/librustdoc/config.rs
Original file line number Diff line number Diff line change
@@ -124,13 +124,9 @@ pub(crate) struct Options {
/// temporary directory if not set.
pub(crate) persist_doctests: Option<PathBuf>,
/// Runtool to run doctests with
pub(crate) runtool: Option<String>,
pub(crate) test_runtool: Option<String>,
/// Arguments to pass to the runtool
pub(crate) runtool_args: Vec<String>,
/// 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(crate) enable_per_target_ignores: bool,
pub(crate) test_runtool_args: Vec<String>,
/// Do not run doctests, compile them if should_test is active.
pub(crate) no_run: bool,
/// What sources are being mapped.
@@ -215,9 +211,8 @@ impl fmt::Debug for Options {
.field("persist_doctests", &self.persist_doctests)
.field("show_coverage", &self.show_coverage)
.field("crate_version", &self.crate_version)
.field("runtool", &self.runtool)
.field("runtool_args", &self.runtool_args)
.field("enable-per-target-ignores", &self.enable_per_target_ignores)
.field("test_runtool", &self.test_runtool)
.field("test_runtool_args", &self.test_runtool_args)
.field("run_check", &self.run_check)
.field("no_run", &self.no_run)
.field("test_builder_wrappers", &self.test_builder_wrappers)
@@ -779,9 +774,8 @@ impl Options {
let unstable_opts_strs = matches.opt_strs("Z");
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 enable_per_target_ignores = matches.opt_present("enable-per-target-ignores");
let test_runtool = matches.opt_str("test-runtool");
let test_runtool_args = matches.opt_strs("test-runtool-arg");
let document_private = matches.opt_present("document-private-items");
let document_hidden = matches.opt_present("document-hidden-items");
let run_check = matches.opt_present("check");
@@ -843,9 +837,8 @@ impl Options {
crate_version,
test_run_directory,
persist_doctests,
runtool,
runtool_args,
enable_per_target_ignores,
test_runtool,
test_runtool_args,
test_builder,
run_check,
no_run,
6 changes: 2 additions & 4 deletions src/librustdoc/doctest.rs
Original file line number Diff line number Diff line change
@@ -218,11 +218,9 @@ pub(crate) fn run(dcx: DiagCtxtHandle<'_>, input: Input, options: RustdocOptions
let crate_name = tcx.crate_name(LOCAL_CRATE).to_string();
let crate_attrs = tcx.hir_attrs(CRATE_HIR_ID);
let opts = scrape_test_config(crate_name, crate_attrs, args_path);
let enable_per_target_ignores = options.enable_per_target_ignores;

let hir_collector = HirCollector::new(
ErrorCodes::from(compiler.sess.opts.unstable_features.is_nightly_build()),
enable_per_target_ignores,
tcx,
);
let tests = hir_collector.collect_crate();
@@ -781,10 +779,10 @@ fn run_test(
let mut cmd;

let output_file = make_maybe_absolute_path(output_file);
if let Some(tool) = &rustdoc_options.runtool {
if let Some(tool) = &rustdoc_options.test_runtool {
let tool = make_maybe_absolute_path(tool.into());
cmd = Command::new(tool);
cmd.args(&rustdoc_options.runtool_args);
cmd.args(&rustdoc_options.test_runtool_args);
cmd.arg(&output_file);
} else {
cmd = Command::new(&output_file);
8 changes: 1 addition & 7 deletions src/librustdoc/doctest/markdown.rs
Original file line number Diff line number Diff line change
@@ -104,13 +104,7 @@ pub(crate) fn test(input: &Input, options: Options) -> Result<(), String> {
};
let codes = ErrorCodes::from(options.unstable_features.is_nightly_build());

find_testable_code(
&input_str,
&mut md_collector,
codes,
options.enable_per_target_ignores,
None,
);
find_testable_code(&input_str, &mut md_collector, codes, None);

let mut collector = CreateRunnableDocTests::new(options.clone(), opts);
md_collector.tests.into_iter().for_each(|t| collector.add_test(t));
6 changes: 2 additions & 4 deletions src/librustdoc/doctest/rust.rs
Original file line number Diff line number Diff line change
@@ -63,19 +63,18 @@ impl DocTestVisitor for RustCollector {
pub(super) struct HirCollector<'tcx> {
codes: ErrorCodes,
tcx: TyCtxt<'tcx>,
enable_per_target_ignores: bool,
collector: RustCollector,
}

impl<'tcx> HirCollector<'tcx> {
pub fn new(codes: ErrorCodes, enable_per_target_ignores: bool, tcx: TyCtxt<'tcx>) -> Self {
pub fn new(codes: ErrorCodes, tcx: TyCtxt<'tcx>) -> Self {
let collector = RustCollector {
source_map: tcx.sess.psess.clone_source_map(),
cur_path: vec![],
position: DUMMY_SP,
tests: vec![],
};
Self { codes, enable_per_target_ignores, tcx, collector }
Self { codes, tcx, collector }
}

pub fn collect_crate(mut self) -> Vec<ScrapedDocTest> {
@@ -131,7 +130,6 @@ impl HirCollector<'_> {
&doc,
&mut self.collector,
self.codes,
self.enable_per_target_ignores,
Some(&crate::html::markdown::ExtraInfo::new(self.tcx, def_id, span)),
);
}
30 changes: 8 additions & 22 deletions src/librustdoc/html/markdown.rs
Original file line number Diff line number Diff line change
@@ -246,7 +246,7 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'_, 'a, I> {
match kind {
CodeBlockKind::Fenced(ref lang) => {
let parse_result =
LangString::parse_without_check(lang, self.check_error_codes, false);
LangString::parse_without_check(lang, self.check_error_codes);
if !parse_result.rust {
let added_classes = parse_result.added_classes;
let lang_string = if let Some(lang) = parse_result.unknown.first() {
@@ -707,17 +707,15 @@ pub(crate) fn find_testable_code<T: doctest::DocTestVisitor>(
doc: &str,
tests: &mut T,
error_codes: ErrorCodes,
enable_per_target_ignores: bool,
extra_info: Option<&ExtraInfo<'_>>,
) {
find_codes(doc, tests, error_codes, enable_per_target_ignores, extra_info, false)
find_codes(doc, tests, error_codes, extra_info, false)
}

pub(crate) fn find_codes<T: doctest::DocTestVisitor>(
doc: &str,
tests: &mut T,
error_codes: ErrorCodes,
enable_per_target_ignores: bool,
extra_info: Option<&ExtraInfo<'_>>,
include_non_rust: bool,
) {
@@ -733,12 +731,7 @@ pub(crate) fn find_codes<T: doctest::DocTestVisitor>(
if lang.is_empty() {
Default::default()
} else {
LangString::parse(
lang,
error_codes,
enable_per_target_ignores,
extra_info,
)
LangString::parse(lang, error_codes, extra_info)
}
}
CodeBlockKind::Indented => Default::default(),
@@ -1162,18 +1155,13 @@ impl Default for LangString {
}

impl LangString {
fn parse_without_check(
string: &str,
allow_error_code_check: ErrorCodes,
enable_per_target_ignores: bool,
) -> Self {
Self::parse(string, allow_error_code_check, enable_per_target_ignores, None)
fn parse_without_check(string: &str, allow_error_code_check: ErrorCodes) -> Self {
Self::parse(string, allow_error_code_check, None)
}

fn parse(
string: &str,
allow_error_code_check: ErrorCodes,
enable_per_target_ignores: bool,
extra: Option<&ExtraInfo<'_>>,
) -> Self {
let allow_error_code_check = allow_error_code_check.as_bool();
@@ -1203,10 +1191,8 @@ impl LangString {
LangStringToken::LangToken(x)
if let Some(ignore) = x.strip_prefix("ignore-") =>
{
if enable_per_target_ignores {
ignores.push(ignore.to_owned());
seen_rust_tags = !seen_other_tags;
}
ignores.push(ignore.to_owned());
seen_rust_tags = !seen_other_tags;
}
LangStringToken::LangToken("rust") => {
data.rust = true;
@@ -1967,7 +1953,7 @@ pub(crate) fn rust_code_blocks(md: &str, extra_info: &ExtraInfo<'_>) -> Vec<Rust
let lang_string = if syntax.is_empty() {
Default::default()
} else {
LangString::parse(syntax, ErrorCodes::Yes, false, Some(extra_info))
LangString::parse(syntax, ErrorCodes::Yes, Some(extra_info))
};
if !lang_string.rust {
continue;
4 changes: 2 additions & 2 deletions src/librustdoc/html/markdown/tests.rs
Original file line number Diff line number Diff line change
@@ -49,7 +49,7 @@ fn test_unique_id() {
fn test_lang_string_parse() {
fn t(lg: LangString) {
let s = &lg.original;
assert_eq!(LangString::parse(s, ErrorCodes::Yes, true, None), lg)
assert_eq!(LangString::parse(s, ErrorCodes::Yes, None), lg)
}

t(Default::default());
@@ -479,7 +479,7 @@ fn test_markdown_html_escape() {
fn test_find_testable_code_line() {
fn t(input: &str, expect: &[usize]) {
let mut lines = Vec::<usize>::new();
find_testable_code(input, &mut lines, ErrorCodes::No, false, None);
find_testable_code(input, &mut lines, ErrorCodes::No, None);
assert_eq!(lines, expect);
}

16 changes: 4 additions & 12 deletions src/librustdoc/lib.rs
Original file line number Diff line number Diff line change
@@ -507,26 +507,18 @@ fn opts() -> Vec<RustcOptGroup> {
"",
),
opt(
Unstable,
FlagMulti,
"",
"enable-per-target-ignores",
"parse ignore-foo for ignoring doctests on a per-target basis",
"",
),
opt(
Unstable,
Stable,
Opt,
"",
"runtool",
"test-runtool",
"",
"The tool to run tests with when building for a different target than host",
),
opt(
Unstable,
Stable,
Multi,
"",
"runtool-arg",
"test-runtool-arg",
"",
"One (of possibly many) arguments to pass to the runtool",
),
2 changes: 1 addition & 1 deletion src/librustdoc/passes/calculate_doc_coverage.rs
Original file line number Diff line number Diff line change
@@ -212,7 +212,7 @@ impl DocVisitor<'_> for CoverageCalculator<'_, '_> {
let has_docs = !i.attrs.doc_strings.is_empty();
let mut tests = Tests { found_tests: 0 };

find_testable_code(&i.doc_value(), &mut tests, ErrorCodes::No, false, None);
find_testable_code(&i.doc_value(), &mut tests, ErrorCodes::No, None);

let has_doc_example = tests.found_tests != 0;
let hir_id = DocContext::as_local_hir_id(self.ctx.tcx, i.item_id).unwrap();
Loading