about summary refs log tree commit diff
diff options
context:
space:
mode:
authorGuillaume Gomez <guillaume.gomez@huawei.com>2024-06-10 18:29:33 +0200
committerGuillaume Gomez <guillaume.gomez@huawei.com>2024-08-13 20:14:54 +0200
commit7ec3cabe1776b1a3d0340b24a5a6901797836430 (patch)
treee860f65940e4b9777fb44e9b644f2ae05745c4c6
parent59a9e0986d061d095c813db1dc418ab55e9e7771 (diff)
downloadrust-7ec3cabe1776b1a3d0340b24a5a6901797836430.tar.gz
rust-7ec3cabe1776b1a3d0340b24a5a6901797836430.zip
Correctly handle doctests with invalid AST
-rw-r--r--src/librustdoc/doctest.rs13
-rw-r--r--src/librustdoc/doctest/make.rs19
-rw-r--r--src/librustdoc/doctest/tests.rs2
-rw-r--r--src/librustdoc/html/markdown.rs2
-rw-r--r--tests/rustdoc-ui/doctest/wrong-ast-2024.rs20
-rw-r--r--tests/rustdoc-ui/doctest/wrong-ast-2024.stdout35
-rw-r--r--tests/rustdoc-ui/doctest/wrong-ast.rs20
-rw-r--r--tests/rustdoc-ui/doctest/wrong-ast.stdout36
8 files changed, 138 insertions, 9 deletions
diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs
index 5586a23595d..07bdccff278 100644
--- a/src/librustdoc/doctest.rs
+++ b/src/librustdoc/doctest.rs
@@ -635,7 +635,7 @@ fn run_test(
         cmd.current_dir(run_directory);
     }
 
-    let result = if rustdoc_options.nocapture {
+    let result = if is_multiple_tests || rustdoc_options.nocapture {
         cmd.status().map(|status| process::Output {
             status,
             stdout: Vec::new(),
@@ -801,10 +801,15 @@ impl CreateRunnableDoctests {
         );
 
         let edition = scraped_test.edition(&self.rustdoc_options);
-        let doctest =
-            DocTest::new(&scraped_test.text, Some(&self.opts.crate_name), edition, Some(test_id));
+        let doctest = DocTest::new(
+            &scraped_test.text,
+            Some(&self.opts.crate_name),
+            edition,
+            self.can_merge_doctests,
+            Some(test_id),
+        );
         let is_standalone = !self.can_merge_doctests
-            || doctest.failed_ast
+            || !doctest.can_be_merged
             || scraped_test.langstr.compile_fail
             || scraped_test.langstr.test_harness
             || scraped_test.langstr.standalone
diff --git a/src/librustdoc/doctest/make.rs b/src/librustdoc/doctest/make.rs
index 492a9a6e38d..c95dace1a81 100644
--- a/src/librustdoc/doctest/make.rs
+++ b/src/librustdoc/doctest/make.rs
@@ -26,6 +26,7 @@ pub(crate) struct DocTest {
     pub(crate) everything_else: String,
     pub(crate) test_id: Option<String>,
     pub(crate) failed_ast: bool,
+    pub(crate) can_be_merged: bool,
 }
 
 impl DocTest {
@@ -33,6 +34,7 @@ impl DocTest {
         source: &str,
         crate_name: Option<&str>,
         edition: Edition,
+        can_merge_doctests: bool,
         // If `test_id` is `None`, it means we're generating code for a code example "run" link.
         test_id: Option<String>,
     ) -> Self {
@@ -49,6 +51,7 @@ impl DocTest {
                 &crates,
                 edition,
                 &mut supports_color,
+                can_merge_doctests,
             )
         else {
             // If the parser panicked due to a fatal error, pass the test code through unchanged.
@@ -62,6 +65,7 @@ impl DocTest {
                 already_has_extern_crate: false,
                 test_id,
                 failed_ast: true,
+                can_be_merged: false,
             };
         };
         Self {
@@ -72,7 +76,10 @@ impl DocTest {
             everything_else,
             already_has_extern_crate,
             test_id,
-            failed_ast,
+            failed_ast: false,
+            // If the AST returned an error, we don't want this doctest to be merged with the
+            // others.
+            can_be_merged: !failed_ast,
         }
     }
 
@@ -85,6 +92,11 @@ impl DocTest {
         opts: &GlobalTestOptions,
         crate_name: Option<&str>,
     ) -> (String, usize) {
+        if self.failed_ast {
+            // If the AST failed to compile, no need to go generate a complete doctest, the error
+            // will be better this way.
+            return (test_code.to_string(), 0);
+        }
         let mut line_offset = 0;
         let mut prog = String::new();
         let everything_else = self.everything_else.trim();
@@ -323,6 +335,7 @@ fn check_for_main_and_extern_crate(
     crates: &str,
     edition: Edition,
     supports_color: &mut bool,
+    can_merge_doctests: bool,
 ) -> Result<(Option<Span>, bool, bool), FatalError> {
     let result = rustc_driver::catch_fatal_errors(|| {
         rustc_span::create_session_if_not_set_then(edition, |_| {
@@ -340,7 +353,7 @@ fn check_for_main_and_extern_crate(
             );
             // No need to double-check this if the "merged doctests" feature isn't enabled (so
             // before the 2024 edition).
-            if edition >= Edition::Edition2024 && parsing_result != ParsingResult::Ok {
+            if can_merge_doctests && parsing_result != ParsingResult::Ok {
                 // If we found an AST error, we want to ensure it's because of an expression being
                 // used outside of a function.
                 //
@@ -525,5 +538,5 @@ fn partition_source(s: &str, edition: Edition) -> (String, String, String) {
     debug!("crates:\n{crates}");
     debug!("after:\n{after}");
 
-    (before, after, crates)
+    (before, after.trim().to_owned(), crates)
 }
diff --git a/src/librustdoc/doctest/tests.rs b/src/librustdoc/doctest/tests.rs
index 533fc3a56ed..982bfae5883 100644
--- a/src/librustdoc/doctest/tests.rs
+++ b/src/librustdoc/doctest/tests.rs
@@ -11,7 +11,7 @@ fn make_test(
     test_id: Option<&str>,
 ) -> (String, usize) {
     let doctest =
-        DocTest::new(test_code, crate_name, DEFAULT_EDITION, test_id.map(|s| s.to_string()));
+        DocTest::new(test_code, crate_name, DEFAULT_EDITION, false, test_id.map(|s| s.to_string()));
     let (code, line_offset) =
         doctest.generate_unique_doctest(test_code, dont_insert_main, opts, crate_name);
     (code, line_offset)
diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs
index da6aa47fff2..879e44c1712 100644
--- a/src/librustdoc/html/markdown.rs
+++ b/src/librustdoc/html/markdown.rs
@@ -297,7 +297,7 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'_, 'a, I> {
                 attrs: vec![],
                 args_file: PathBuf::new(),
             };
-            let doctest = doctest::DocTest::new(&test, krate, edition, None);
+            let doctest = doctest::DocTest::new(&test, krate, edition, false, None);
             let (test, _) = doctest.generate_unique_doctest(&test, false, &opts, krate);
             let channel = if test.contains("#![feature(") { "&amp;version=nightly" } else { "" };
 
diff --git a/tests/rustdoc-ui/doctest/wrong-ast-2024.rs b/tests/rustdoc-ui/doctest/wrong-ast-2024.rs
new file mode 100644
index 00000000000..b0a700477b2
--- /dev/null
+++ b/tests/rustdoc-ui/doctest/wrong-ast-2024.rs
@@ -0,0 +1,20 @@
+//@ compile-flags:--test --test-args=--test-threads=1 -Zunstable-options --edition 2024
+//@ normalize-stdout-test: "tests/rustdoc-ui/doctest" -> "$$DIR"
+//@ normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME"
+//@ normalize-stdout-test "wrong-ast.rs:\d+:\d+" -> "wrong-ast.rs:$$LINE:$$COL"
+//@ failure-status: 101
+
+/// ```
+/// /* plop
+/// ```
+pub fn one() {}
+
+/// ```
+/// } mod __doctest_1 { fn main() {
+/// ```
+pub fn two() {}
+
+/// ```should_panic
+/// panic!()
+/// ```
+pub fn three() {}
diff --git a/tests/rustdoc-ui/doctest/wrong-ast-2024.stdout b/tests/rustdoc-ui/doctest/wrong-ast-2024.stdout
new file mode 100644
index 00000000000..1dea2719399
--- /dev/null
+++ b/tests/rustdoc-ui/doctest/wrong-ast-2024.stdout
@@ -0,0 +1,35 @@
+
+running 2 tests
+test $DIR/wrong-ast-2024.rs - one (line 7) ... FAILED
+test $DIR/wrong-ast-2024.rs - two (line 12) ... FAILED
+
+failures:
+
+---- $DIR/wrong-ast-2024.rs - one (line 7) stdout ----
+error[E0758]: unterminated block comment
+  --> $DIR/wrong-ast-2024.rs:8:1
+   |
+LL | /* plop
+   | ^^^^^^^^
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0758`.
+Couldn't compile the test.
+---- $DIR/wrong-ast-2024.rs - two (line 12) stdout ----
+error: unexpected closing delimiter: `}`
+  --> $DIR/wrong-ast-2024.rs:13:1
+   |
+LL | } mod __doctest_1 { fn main() {
+   | ^ unexpected closing delimiter
+
+error: aborting due to 1 previous error
+
+Couldn't compile the test.
+
+failures:
+    $DIR/wrong-ast-2024.rs - one (line 7)
+    $DIR/wrong-ast-2024.rs - two (line 12)
+
+test result: FAILED. 0 passed; 2 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
+
diff --git a/tests/rustdoc-ui/doctest/wrong-ast.rs b/tests/rustdoc-ui/doctest/wrong-ast.rs
new file mode 100644
index 00000000000..b3fbf630c32
--- /dev/null
+++ b/tests/rustdoc-ui/doctest/wrong-ast.rs
@@ -0,0 +1,20 @@
+//@ compile-flags:--test --test-args=--test-threads=1
+//@ normalize-stdout-test: "tests/rustdoc-ui/doctest" -> "$$DIR"
+//@ normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME"
+//@ normalize-stdout-test "wrong-ast.rs:\d+:\d+" -> "wrong-ast.rs:$$LINE:$$COL"
+//@ failure-status: 101
+
+/// ```
+/// /* plop
+/// ```
+pub fn one() {}
+
+/// ```
+/// } mod __doctest_1 { fn main() {
+/// ```
+pub fn two() {}
+
+/// ```should_panic
+/// panic!()
+/// ```
+pub fn three() {}
diff --git a/tests/rustdoc-ui/doctest/wrong-ast.stdout b/tests/rustdoc-ui/doctest/wrong-ast.stdout
new file mode 100644
index 00000000000..b50999d17d7
--- /dev/null
+++ b/tests/rustdoc-ui/doctest/wrong-ast.stdout
@@ -0,0 +1,36 @@
+
+running 3 tests
+test $DIR/wrong-ast.rs - one (line 7) ... FAILED
+test $DIR/wrong-ast.rs - three (line 17) ... ok
+test $DIR/wrong-ast.rs - two (line 12) ... FAILED
+
+failures:
+
+---- $DIR/wrong-ast.rs - one (line 7) stdout ----
+error[E0758]: unterminated block comment
+  --> $DIR/wrong-ast.rs:$LINE:$COL
+   |
+LL | /* plop
+   | ^^^^^^^^
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0758`.
+Couldn't compile the test.
+---- $DIR/wrong-ast.rs - two (line 12) stdout ----
+error: unexpected closing delimiter: `}`
+  --> $DIR/wrong-ast.rs:$LINE:$COL
+   |
+LL | } mod __doctest_1 { fn main() {
+   | ^ unexpected closing delimiter
+
+error: aborting due to 1 previous error
+
+Couldn't compile the test.
+
+failures:
+    $DIR/wrong-ast.rs - one (line 7)
+    $DIR/wrong-ast.rs - two (line 12)
+
+test result: FAILED. 1 passed; 2 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
+