Skip to content

librustdoc: wrong span in "the main function of this doctest won't be run" diagnostic #157371

@legeana

Description

@legeana

Code

/// This part creates the doctest with a stray `;`.
///
/// ```
/// #[derive(Debug, PartialEq)]
/// struct Type {
///     left: i32,
///     right: i32,
/// };  // <- Stray `;`.
///
/// fn main () {
///     let x = Type {
///         left: 10,
///         right: 20,
///     };
///     assert_eq!(
///         x,
///         Type {
///             left: 10,
///             right: 20,
///         },
///     );
/// }
/// ```
pub fn add(left: u64, right: u64) -> u64 {
    // This code is completely unrelated to the doctest.
    left + right
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn it_works() {
        let result = add(2, 2);
        assert_eq!(result, 4);
    }
}

Current output

$ cargo test
    Finished `test` profile [unoptimized + debuginfo] target(s) in 0.04s
     Running unittests src/lib.rs (target/debug/deps/doctest_main_bug-eb79733dddb28b66)

running 1 test
test tests::it_works ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

   Doc-tests doctest_main_bug
warning: the `main` function of this doctest won't be run as it contains expressions at the top level, meaning that the whole doctest code will be wrapped in a function
  --> src/lib.rs:25:1
   |
25 |     // This code is completely unrelated to the doctest.
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

warning: 1 warning emitted


running 1 test
test src/lib.rs - add (line 3) ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.01s

all doctests ran in 1.12s; merged doctests compilation took 0.72s

Desired output

The span must highlight the semicolon in the doctest, not an unrelated comment.

 8 |     };
 9 |      ^

Rationale and extra context

  • At minimum the diagnostic should point to the rogue ;, not at an unrelated code below.
  • Better, an expression consisting of semicolon alone at the root of the doctest may benefit from a more specific diagnostic. It is clear that a semicolon by itself isn't doing anything, and in my opinion it is more likely that someone with a C++ background accidentally put it after a struct than meant it as a genuine expression.

Other cases

Rust Version

Reproducible on both stable and nightly.

$ rustc --version --verbose
rustc 1.96.0 (ac68faa20 2026-05-25)
binary: rustc
commit-hash: ac68faa20c58cbccd01ee7208bf3b6e93a7d7f96
commit-date: 2026-05-25
host: aarch64-apple-darwin
release: 1.96.0
LLVM version: 22.1.2

$ rustc +nightly --version --verbose
rustc 1.98.0-nightly (d595fce01 2026-06-02)
binary: rustc
commit-hash: d595fce01043347bf7f80e85b76dcc41b59a3e6e
commit-date: 2026-06-02
host: aarch64-apple-darwin
release: 1.98.0-nightly
LLVM version: 22.1.6

Anything else?

This seems to be some sort of a span miscalculation issue. If I add more lines before or inside fn add, the error always points to the same line.

Source code of the error message:

"the `main` function of this doctest won't be run as it contains \
expressions at the top level, meaning that the whole doctest code will be \
wrapped in a function",

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-diagnosticsArea: Messages for errors, warnings, and lintsA-doctestsArea: Documentation tests, run by rustdocD-imprecise-spansDiagnostics: spans don't point to exactly the erroneous codeT-rustdocRelevant to the rustdoc team, which will review and decide on the PR/issue.

    Type

    No type
    No fields configured for issues without a type.

    Projects

    Status
    Done

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions