[PATCH] rust: doctest: fix line numbers after crate-level attributes
From: Younes Akhouayri via B4 Relay
Date: Tue Oct 27 2026 - 02:32:11 EST
From: Younes Akhouayri <git@xxxxxxxxx>
When a doctest starts with a crate-level attribute such as
`#![expect(...)]`, KUnit reports failures one line too early, and
`line!()` returns a line number that is one too low.
This happens because `rustdoc` moves those attribute lines out of the
test body and puts them above the `main` function it generates. The
generator works out where the body starts by counting the lines above
`main`, but it does not know that some of those lines were moved there
from the body. So every line after a moved attribute is mapped one line
too early (or more, if there are several such attributes).
For example, adding `assert_eq!(36, 0);` as line 36 of
`rust/kernel/init.rs` (inside the doctest that starts with
`# #![expect(clippy::undocumented_unsafe_blocks)]`) gives:
# rust_doctest_kernel_init_rs_2: ASSERTION FAILED at rust/kernel/init.rs:35
Twelve in-tree doctests start like this, e.g. in `bits.rs`, `devres.rs`,
`init.rs` and `std_vendor.rs`.
Fix it by counting the attribute lines that `rustdoc` moved (every
`#![...]` line above `main`, except the `#![allow(unused)]` that
`rustdoc` adds itself) and taking them into account when computing
where the body starts.
With this change, the example above reports `rust/kernel/init.rs:36`,
and doctests without such attributes keep reporting the same lines as
before.
Fixes: a66d733da801 ("rust: support running Rust documentation tests as KUnit ones")
Signed-off-by: Younes Akhouayri <git@xxxxxxxxx>
---
scripts/rustdoc_test_gen.rs | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/scripts/rustdoc_test_gen.rs b/scripts/rustdoc_test_gen.rs
index 754c5aafcce4..c821ec63c32d 100644
--- a/scripts/rustdoc_test_gen.rs
+++ b/scripts/rustdoc_test_gen.rs
@@ -168,6 +168,17 @@ fn main() {
.count()
+ 1;
+ // `rustdoc` moves the crate-level attributes (`#![...]`) of the test out of its body and
+ // places them before `main`, after its own `#![allow(unused)]`. Subtract the moved lines,
+ // since the rest of the body is shifted by that amount with respect to the original source.
+ let hoisted_lines = body
+ .lines()
+ .take(body_offset - 1)
+ .filter(|line| line.starts_with("#!["))
+ .count()
+ .saturating_sub(1);
+ let body_offset = body_offset - hoisted_lines;
+
use std::fmt::Write;
write!(
tests,
---
base-commit: 21a7f44fd0765fcc5194130b28767786eba1d1e7
change-id: 20261027-rust-doctest-line-fix-cb0f663629fe
Best regards,
--
Younes Akhouayri <git@xxxxxxxxx>