From 0e0a84ae4e656fda2becd9ba33428fff613b44cb Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 24 Oct 2024 15:02:58 +0200 Subject: [PATCH 1/2] Do not consider nested functions as `main` function even if named `main` in doctests --- src/librustdoc/doctest/make.rs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/librustdoc/doctest/make.rs b/src/librustdoc/doctest/make.rs index efbb332d12d..3ae60938749 100644 --- a/src/librustdoc/doctest/make.rs +++ b/src/librustdoc/doctest/make.rs @@ -289,7 +289,12 @@ fn parse_source( // Recurse through functions body. It is necessary because the doctest source code is // wrapped in a function to limit the number of AST errors. If we don't recurse into // functions, we would thing all top-level items (so basically nothing). - fn check_item(item: &ast::Item, info: &mut ParseSourceInfo, crate_name: &Option<&str>) { + fn check_item( + item: &ast::Item, + info: &mut ParseSourceInfo, + crate_name: &Option<&str>, + is_top_level: bool, + ) { if !info.has_global_allocator && item.attrs.iter().any(|attr| attr.name_or_empty() == sym::global_allocator) { @@ -297,13 +302,15 @@ fn parse_source( } match item.kind { ast::ItemKind::Fn(ref fn_item) if !info.has_main_fn => { - if item.ident.name == sym::main { + if item.ident.name == sym::main && is_top_level { info.has_main_fn = true; } if let Some(ref body) = fn_item.body { for stmt in &body.stmts { match stmt.kind { - ast::StmtKind::Item(ref item) => check_item(item, info, crate_name), + ast::StmtKind::Item(ref item) => { + check_item(item, info, crate_name, false) + } ast::StmtKind::MacCall(..) => info.found_macro = true, _ => {} } @@ -329,7 +336,7 @@ fn parse_source( loop { match parser.parse_item(ForceCollect::No) { Ok(Some(item)) => { - check_item(&item, info, crate_name); + check_item(&item, info, crate_name, true); if info.has_main_fn && info.found_extern_crate { break; From aab2b6747db09b8572f879bd74dbee701287536d Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 24 Oct 2024 15:05:39 +0200 Subject: [PATCH 2/2] Add regression test for #131893 --- tests/rustdoc-ui/doctest/nested-main.rs | 24 +++++++++++++++++++++ tests/rustdoc-ui/doctest/nested-main.stdout | 7 ++++++ 2 files changed, 31 insertions(+) create mode 100644 tests/rustdoc-ui/doctest/nested-main.rs create mode 100644 tests/rustdoc-ui/doctest/nested-main.stdout diff --git a/tests/rustdoc-ui/doctest/nested-main.rs b/tests/rustdoc-ui/doctest/nested-main.rs new file mode 100644 index 00000000000..e939ba81214 --- /dev/null +++ b/tests/rustdoc-ui/doctest/nested-main.rs @@ -0,0 +1,24 @@ +//@ check-pass +//@ 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" + +// Regression test for . +// It ensures that if a function called `main` is nested, it will not consider +// it as the `main` function. + +/// ``` +/// fn dox() { +/// fn main() {} +/// } +/// ``` +pub fn foo() {} + +// This one ensures that having a nested `main` doesn't prevent the +// actual `main` function to be detected. +/// ``` +/// fn main() { +/// fn main() {} +/// } +/// ``` +pub fn foo2() {} diff --git a/tests/rustdoc-ui/doctest/nested-main.stdout b/tests/rustdoc-ui/doctest/nested-main.stdout new file mode 100644 index 00000000000..af9a8f5e1d7 --- /dev/null +++ b/tests/rustdoc-ui/doctest/nested-main.stdout @@ -0,0 +1,7 @@ + +running 2 tests +test $DIR/nested-main.rs - foo (line 10) ... ok +test $DIR/nested-main.rs - foo2 (line 19) ... ok + +test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME +