Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 7ec3cab

Browse files
Correctly handle doctests with invalid AST
1 parent 59a9e09 commit 7ec3cab

File tree

8 files changed

+138
-9
lines changed

8 files changed

+138
-9
lines changed

src/librustdoc/doctest.rs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -635,7 +635,7 @@ fn run_test(
635635
cmd.current_dir(run_directory);
636636
}
637637

638-
let result = if rustdoc_options.nocapture {
638+
let result = if is_multiple_tests || rustdoc_options.nocapture {
639639
cmd.status().map(|status| process::Output {
640640
status,
641641
stdout: Vec::new(),
@@ -801,10 +801,15 @@ impl CreateRunnableDoctests {
801801
);
802802

803803
let edition = scraped_test.edition(&self.rustdoc_options);
804-
let doctest =
805-
DocTest::new(&scraped_test.text, Some(&self.opts.crate_name), edition, Some(test_id));
804+
let doctest = DocTest::new(
805+
&scraped_test.text,
806+
Some(&self.opts.crate_name),
807+
edition,
808+
self.can_merge_doctests,
809+
Some(test_id),
810+
);
806811
let is_standalone = !self.can_merge_doctests
807-
|| doctest.failed_ast
812+
|| !doctest.can_be_merged
808813
|| scraped_test.langstr.compile_fail
809814
|| scraped_test.langstr.test_harness
810815
|| scraped_test.langstr.standalone

src/librustdoc/doctest/make.rs

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,15 @@ pub(crate) struct DocTest {
2626
pub(crate) everything_else: String,
2727
pub(crate) test_id: Option<String>,
2828
pub(crate) failed_ast: bool,
29+
pub(crate) can_be_merged: bool,
2930
}
3031

3132
impl DocTest {
3233
pub(crate) fn new(
3334
source: &str,
3435
crate_name: Option<&str>,
3536
edition: Edition,
37+
can_merge_doctests: bool,
3638
// If `test_id` is `None`, it means we're generating code for a code example "run" link.
3739
test_id: Option<String>,
3840
) -> Self {
@@ -49,6 +51,7 @@ impl DocTest {
4951
&crates,
5052
edition,
5153
&mut supports_color,
54+
can_merge_doctests,
5255
)
5356
else {
5457
// If the parser panicked due to a fatal error, pass the test code through unchanged.
@@ -62,6 +65,7 @@ impl DocTest {
6265
already_has_extern_crate: false,
6366
test_id,
6467
failed_ast: true,
68+
can_be_merged: false,
6569
};
6670
};
6771
Self {
@@ -72,7 +76,10 @@ impl DocTest {
7276
everything_else,
7377
already_has_extern_crate,
7478
test_id,
75-
failed_ast,
79+
failed_ast: false,
80+
// If the AST returned an error, we don't want this doctest to be merged with the
81+
// others.
82+
can_be_merged: !failed_ast,
7683
}
7784
}
7885

@@ -85,6 +92,11 @@ impl DocTest {
8592
opts: &GlobalTestOptions,
8693
crate_name: Option<&str>,
8794
) -> (String, usize) {
95+
if self.failed_ast {
96+
// If the AST failed to compile, no need to go generate a complete doctest, the error
97+
// will be better this way.
98+
return (test_code.to_string(), 0);
99+
}
88100
let mut line_offset = 0;
89101
let mut prog = String::new();
90102
let everything_else = self.everything_else.trim();
@@ -323,6 +335,7 @@ fn check_for_main_and_extern_crate(
323335
crates: &str,
324336
edition: Edition,
325337
supports_color: &mut bool,
338+
can_merge_doctests: bool,
326339
) -> Result<(Option<Span>, bool, bool), FatalError> {
327340
let result = rustc_driver::catch_fatal_errors(|| {
328341
rustc_span::create_session_if_not_set_then(edition, |_| {
@@ -340,7 +353,7 @@ fn check_for_main_and_extern_crate(
340353
);
341354
// No need to double-check this if the "merged doctests" feature isn't enabled (so
342355
// before the 2024 edition).
343-
if edition >= Edition::Edition2024 && parsing_result != ParsingResult::Ok {
356+
if can_merge_doctests && parsing_result != ParsingResult::Ok {
344357
// If we found an AST error, we want to ensure it's because of an expression being
345358
// used outside of a function.
346359
//
@@ -525,5 +538,5 @@ fn partition_source(s: &str, edition: Edition) -> (String, String, String) {
525538
debug!("crates:\n{crates}");
526539
debug!("after:\n{after}");
527540

528-
(before, after, crates)
541+
(before, after.trim().to_owned(), crates)
529542
}

src/librustdoc/doctest/tests.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ fn make_test(
1111
test_id: Option<&str>,
1212
) -> (String, usize) {
1313
let doctest =
14-
DocTest::new(test_code, crate_name, DEFAULT_EDITION, test_id.map(|s| s.to_string()));
14+
DocTest::new(test_code, crate_name, DEFAULT_EDITION, false, test_id.map(|s| s.to_string()));
1515
let (code, line_offset) =
1616
doctest.generate_unique_doctest(test_code, dont_insert_main, opts, crate_name);
1717
(code, line_offset)

src/librustdoc/html/markdown.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,7 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'_, 'a, I> {
297297
attrs: vec![],
298298
args_file: PathBuf::new(),
299299
};
300-
let doctest = doctest::DocTest::new(&test, krate, edition, None);
300+
let doctest = doctest::DocTest::new(&test, krate, edition, false, None);
301301
let (test, _) = doctest.generate_unique_doctest(&test, false, &opts, krate);
302302
let channel = if test.contains("#![feature(") { "&amp;version=nightly" } else { "" };
303303

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
//@ compile-flags:--test --test-args=--test-threads=1 -Zunstable-options --edition 2024
2+
//@ normalize-stdout-test: "tests/rustdoc-ui/doctest" -> "$$DIR"
3+
//@ normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME"
4+
//@ normalize-stdout-test "wrong-ast.rs:\d+:\d+" -> "wrong-ast.rs:$$LINE:$$COL"
5+
//@ failure-status: 101
6+
7+
/// ```
8+
/// /* plop
9+
/// ```
10+
pub fn one() {}
11+
12+
/// ```
13+
/// } mod __doctest_1 { fn main() {
14+
/// ```
15+
pub fn two() {}
16+
17+
/// ```should_panic
18+
/// panic!()
19+
/// ```
20+
pub fn three() {}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
2+
running 2 tests
3+
test $DIR/wrong-ast-2024.rs - one (line 7) ... FAILED
4+
test $DIR/wrong-ast-2024.rs - two (line 12) ... FAILED
5+
6+
failures:
7+
8+
---- $DIR/wrong-ast-2024.rs - one (line 7) stdout ----
9+
error[E0758]: unterminated block comment
10+
--> $DIR/wrong-ast-2024.rs:8:1
11+
|
12+
LL | /* plop
13+
| ^^^^^^^^
14+
15+
error: aborting due to 1 previous error
16+
17+
For more information about this error, try `rustc --explain E0758`.
18+
Couldn't compile the test.
19+
---- $DIR/wrong-ast-2024.rs - two (line 12) stdout ----
20+
error: unexpected closing delimiter: `}`
21+
--> $DIR/wrong-ast-2024.rs:13:1
22+
|
23+
LL | } mod __doctest_1 { fn main() {
24+
| ^ unexpected closing delimiter
25+
26+
error: aborting due to 1 previous error
27+
28+
Couldn't compile the test.
29+
30+
failures:
31+
$DIR/wrong-ast-2024.rs - one (line 7)
32+
$DIR/wrong-ast-2024.rs - two (line 12)
33+
34+
test result: FAILED. 0 passed; 2 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
35+

tests/rustdoc-ui/doctest/wrong-ast.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
//@ compile-flags:--test --test-args=--test-threads=1
2+
//@ normalize-stdout-test: "tests/rustdoc-ui/doctest" -> "$$DIR"
3+
//@ normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME"
4+
//@ normalize-stdout-test "wrong-ast.rs:\d+:\d+" -> "wrong-ast.rs:$$LINE:$$COL"
5+
//@ failure-status: 101
6+
7+
/// ```
8+
/// /* plop
9+
/// ```
10+
pub fn one() {}
11+
12+
/// ```
13+
/// } mod __doctest_1 { fn main() {
14+
/// ```
15+
pub fn two() {}
16+
17+
/// ```should_panic
18+
/// panic!()
19+
/// ```
20+
pub fn three() {}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
2+
running 3 tests
3+
test $DIR/wrong-ast.rs - one (line 7) ... FAILED
4+
test $DIR/wrong-ast.rs - three (line 17) ... ok
5+
test $DIR/wrong-ast.rs - two (line 12) ... FAILED
6+
7+
failures:
8+
9+
---- $DIR/wrong-ast.rs - one (line 7) stdout ----
10+
error[E0758]: unterminated block comment
11+
--> $DIR/wrong-ast.rs:$LINE:$COL
12+
|
13+
LL | /* plop
14+
| ^^^^^^^^
15+
16+
error: aborting due to 1 previous error
17+
18+
For more information about this error, try `rustc --explain E0758`.
19+
Couldn't compile the test.
20+
---- $DIR/wrong-ast.rs - two (line 12) stdout ----
21+
error: unexpected closing delimiter: `}`
22+
--> $DIR/wrong-ast.rs:$LINE:$COL
23+
|
24+
LL | } mod __doctest_1 { fn main() {
25+
| ^ unexpected closing delimiter
26+
27+
error: aborting due to 1 previous error
28+
29+
Couldn't compile the test.
30+
31+
failures:
32+
$DIR/wrong-ast.rs - one (line 7)
33+
$DIR/wrong-ast.rs - two (line 12)
34+
35+
test result: FAILED. 1 passed; 2 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
36+

0 commit comments

Comments
 (0)