diff options
| author | bors <bors@rust-lang.org> | 2019-01-05 07:20:13 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2019-01-05 07:20:13 +0000 |
| commit | 2bde39b8edce6463e1c37f8a8082a875e7b536b1 (patch) | |
| tree | 0a0de57e2d21f2dba4b080ecbb2de26a2d30320b | |
| parent | e64fee6a38c27dcfbc26a276c8915f44b1091083 (diff) | |
| parent | 339148d6635215cc1b49c2e5e2841074c51d1747 (diff) | |
Auto merge of #57019 - QuietMisdreavus:semi-revert-doctest-parsing, r=GuillaumeGomez
[beta] rustdoc: semi-revert libsyntax doctest parsing if a macro is wrapping main Fixes https://github.com/rust-lang/rust/issues/56898 This is a patch to doctest parsing on beta (that i plan to "forward-port" to master) that reverts to the old text-based `fn main` scan if it found a macro invocation in the doctest but did not find a main function. This should solve situations like `allocator_api` which wrap their main functions in a macro invocation, but doesn't solve something like the initial version of `quicli` which used a macro to *generate* the main function. (Properly doing the latter involves running macro expansion before checking, which is a bit too involved for a beta fix.)
| -rw-r--r-- | src/librustdoc/test.rs | 51 |
1 files changed, 48 insertions, 3 deletions
diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index d9bab91fd0c..2aff128d756 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -395,7 +395,7 @@ pub fn make_test(s: &str, // Uses libsyntax to parse the doctest and find if there's a main fn and the extern // crate already is included. - let (already_has_main, already_has_extern_crate) = crate::syntax::with_globals(|| { + let (already_has_main, already_has_extern_crate, found_macro) = crate::syntax::with_globals(|| { use crate::syntax::{ast, parse::{self, ParseSess}, source_map::FilePathMapping}; use crate::syntax_pos::FileName; use errors::emitter::EmitterWriter; @@ -415,6 +415,7 @@ pub fn make_test(s: &str, let mut found_main = false; let mut found_extern_crate = cratename.is_none(); + let mut found_macro = false; let mut parser = match parse::maybe_new_parser_from_source_str(&sess, filename, source) { Ok(p) => p, @@ -423,7 +424,7 @@ pub fn make_test(s: &str, err.cancel(); } - return (found_main, found_extern_crate); + return (found_main, found_extern_crate, found_macro); } }; @@ -451,6 +452,12 @@ pub fn make_test(s: &str, } } + if !found_macro { + if let ast::ItemKind::Mac(..) = item.node { + found_macro = true; + } + } + if found_main && found_extern_crate { break; } @@ -463,9 +470,28 @@ pub fn make_test(s: &str, } } - (found_main, found_extern_crate) + (found_main, found_extern_crate, found_macro) }); + // If a doctest's `fn main` is being masked by a wrapper macro, the parsing loop above won't + // see it. In that case, run the old text-based scan to see if they at least have a main + // function written inside a macro invocation. See + // https://github.com/rust-lang/rust/issues/56898 + let already_has_main = if found_macro && !already_has_main { + s.lines() + .map(|line| { + let comment = line.find("//"); + if let Some(comment_begins) = comment { + &line[0..comment_begins] + } else { + line + } + }) + .any(|code| code.contains("fn main")) + } else { + already_has_main + }; + // Don't inject `extern crate std` because it's already injected by the // compiler. if !already_has_extern_crate && !opts.no_crate_inject && cratename != Some("std") { @@ -1106,4 +1132,23 @@ assert_eq!(asdf::foo, 4); let output = make_test(input, Some("asdf"), false, &opts); assert_eq!(output, (expected, 3)); } + + #[test] + fn make_test_main_in_macro() { + let opts = TestOptions::default(); + let input = +"#[macro_use] extern crate my_crate; +test_wrapper! { + fn main() {} +}"; + let expected = +"#![allow(unused)] +#[macro_use] extern crate my_crate; +test_wrapper! { + fn main() {} +}".to_string(); + + let output = make_test(input, Some("my_crate"), false, &opts); + assert_eq!(output, (expected, 1)); + } } |
