Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit b6831bb

Browse files
Don't merge doctests with #[global_allocator]
1 parent 6eabffb commit b6831bb

File tree

2 files changed

+70
-75
lines changed

2 files changed

+70
-75
lines changed

src/librustdoc/doctest/make.rs

Lines changed: 62 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -49,20 +49,26 @@ impl DocTest {
4949
has_features,
5050
has_no_std,
5151
} = partition_source(source, edition);
52-
let mut supports_color = false;
5352

5453
// Uses librustc_ast to parse the doctest and find if there's a main fn and the extern
5554
// crate already is included.
56-
let Ok((has_main_fn, already_has_extern_crate, failed_ast)) =
57-
check_for_main_and_extern_crate(
58-
crate_name,
59-
source,
60-
&everything_else,
61-
&crates,
62-
edition,
63-
&mut supports_color,
64-
can_merge_doctests,
65-
)
55+
let Ok((
56+
ParseSourceInfo {
57+
has_main_fn,
58+
found_extern_crate,
59+
supports_color,
60+
has_global_allocator,
61+
..
62+
},
63+
failed_ast,
64+
)) = check_for_main_and_extern_crate(
65+
crate_name,
66+
source,
67+
&everything_else,
68+
&crates,
69+
edition,
70+
can_merge_doctests,
71+
)
6672
else {
6773
// If the parser panicked due to a fatal error, pass the test code through unchanged.
6874
// The error will be reported during compilation.
@@ -86,12 +92,12 @@ impl DocTest {
8692
maybe_crate_attrs,
8793
crates,
8894
everything_else,
89-
already_has_extern_crate,
95+
already_has_extern_crate: found_extern_crate,
9096
test_id,
9197
failed_ast: false,
9298
// If the AST returned an error, we don't want this doctest to be merged with the
9399
// others. Same if it contains `#[feature]` or `#[no_std]`.
94-
can_be_merged: !failed_ast && !has_no_std && !has_features,
100+
can_be_merged: !failed_ast && !has_no_std && !has_features && !has_global_allocator,
95101
}
96102
}
97103

@@ -231,11 +237,8 @@ fn cancel_error_count(psess: &ParseSess) {
231237

232238
fn parse_source(
233239
source: String,
234-
has_main_fn: &mut bool,
235-
found_extern_crate: &mut bool,
236-
found_macro: &mut bool,
240+
info: &mut ParseSourceInfo,
237241
crate_name: &Option<&str>,
238-
supports_color: &mut bool,
239242
) -> ParsingResult {
240243
use rustc_errors::emitter::{Emitter, HumanEmitter};
241244
use rustc_errors::DiagCtxt;
@@ -251,7 +254,7 @@ fn parse_source(
251254
rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(),
252255
false,
253256
);
254-
*supports_color =
257+
info.supports_color =
255258
HumanEmitter::new(stderr_destination(ColorConfig::Auto), fallback_bundle.clone())
256259
.supports_color();
257260

@@ -274,53 +277,48 @@ fn parse_source(
274277
// Recurse through functions body. It is necessary because the doctest source code is
275278
// wrapped in a function to limit the number of AST errors. If we don't recurse into
276279
// functions, we would thing all top-level items (so basically nothing).
277-
fn check_item(
278-
item: &ast::Item,
279-
has_main_fn: &mut bool,
280-
found_extern_crate: &mut bool,
281-
found_macro: &mut bool,
282-
crate_name: &Option<&str>,
283-
) {
280+
fn check_item(item: &ast::Item, info: &mut ParseSourceInfo, crate_name: &Option<&str>) {
281+
if !info.has_global_allocator
282+
&& item.attrs.iter().any(|attr| attr.name_or_empty() == sym::global_allocator)
283+
{
284+
info.has_global_allocator = true;
285+
}
284286
match item.kind {
285-
ast::ItemKind::Fn(ref fn_item) if !*has_main_fn => {
287+
ast::ItemKind::Fn(ref fn_item) if !info.has_main_fn => {
286288
if item.ident.name == sym::main {
287-
*has_main_fn = true;
289+
info.has_main_fn = true;
288290
}
289291
if let Some(ref body) = fn_item.body {
290292
for stmt in &body.stmts {
291293
match stmt.kind {
292-
ast::StmtKind::Item(ref item) => check_item(
293-
item,
294-
has_main_fn,
295-
found_extern_crate,
296-
found_macro,
297-
crate_name,
298-
),
299-
ast::StmtKind::MacCall(..) => *found_macro = true,
294+
ast::StmtKind::Item(ref item) => check_item(item, info, crate_name),
295+
ast::StmtKind::MacCall(..) => info.found_macro = true,
300296
_ => {}
301297
}
302298
}
303299
}
304300
}
305301
ast::ItemKind::ExternCrate(original) => {
306-
if !*found_extern_crate && let Some(ref crate_name) = crate_name {
307-
*found_extern_crate = match original {
302+
if !info.found_extern_crate
303+
&& let Some(ref crate_name) = crate_name
304+
{
305+
info.found_extern_crate = match original {
308306
Some(name) => name.as_str() == *crate_name,
309307
None => item.ident.as_str() == *crate_name,
310308
};
311309
}
312310
}
313-
ast::ItemKind::MacCall(..) => *found_macro = true,
311+
ast::ItemKind::MacCall(..) => info.found_macro = true,
314312
_ => {}
315313
}
316314
}
317315

318316
loop {
319317
match parser.parse_item(ForceCollect::No) {
320318
Ok(Some(item)) => {
321-
check_item(&item, has_main_fn, found_extern_crate, found_macro, crate_name);
319+
check_item(&item, info, crate_name);
322320

323-
if *has_main_fn && *found_extern_crate {
321+
if info.has_main_fn && info.found_extern_crate {
324322
break;
325323
}
326324
}
@@ -341,30 +339,30 @@ fn parse_source(
341339
parsing_result
342340
}
343341

344-
/// Returns `(has_main_fn, already_has_extern_crate, failed_ast)`.
342+
#[derive(Default)]
343+
struct ParseSourceInfo {
344+
has_main_fn: bool,
345+
found_extern_crate: bool,
346+
found_macro: bool,
347+
supports_color: bool,
348+
has_global_allocator: bool,
349+
}
350+
345351
fn check_for_main_and_extern_crate(
346352
crate_name: Option<&str>,
347353
original_source_code: &str,
348354
everything_else: &str,
349355
crates: &str,
350356
edition: Edition,
351-
supports_color: &mut bool,
352357
can_merge_doctests: bool,
353-
) -> Result<(bool, bool, bool), FatalError> {
358+
) -> Result<(ParseSourceInfo, bool), FatalError> {
354359
let result = rustc_driver::catch_fatal_errors(|| {
355360
rustc_span::create_session_if_not_set_then(edition, |_| {
356-
let mut has_main_fn = false;
357-
let mut found_extern_crate = crate_name.is_none();
358-
let mut found_macro = false;
359-
360-
let mut parsing_result = parse_source(
361-
format!("{crates}{everything_else}"),
362-
&mut has_main_fn,
363-
&mut found_extern_crate,
364-
&mut found_macro,
365-
&crate_name,
366-
supports_color,
367-
);
361+
let mut info =
362+
ParseSourceInfo { found_extern_crate: crate_name.is_none(), ..Default::default() };
363+
364+
let mut parsing_result =
365+
parse_source(format!("{crates}{everything_else}"), &mut info, &crate_name);
368366
// No need to double-check this if the "merged doctests" feature isn't enabled (so
369367
// before the 2024 edition).
370368
if can_merge_doctests && parsing_result != ParsingResult::Ok {
@@ -380,30 +378,25 @@ fn check_for_main_and_extern_crate(
380378
// faster doctests run time.
381379
parsing_result = parse_source(
382380
format!("{crates}\nfn __doctest_wrap(){{{everything_else}\n}}"),
383-
&mut has_main_fn,
384-
&mut found_extern_crate,
385-
&mut found_macro,
381+
&mut info,
386382
&crate_name,
387-
supports_color,
388383
);
389384
}
390385

391-
(has_main_fn, found_extern_crate, found_macro, parsing_result)
386+
(info, parsing_result)
392387
})
393388
});
394-
let (mut has_main_fn, already_has_extern_crate, found_macro, parsing_result) = match result {
395-
Err(..) | Ok((_, _, _, ParsingResult::Failed)) => return Err(FatalError),
396-
Ok((has_main_fn, already_has_extern_crate, found_macro, parsing_result)) => {
397-
(has_main_fn, already_has_extern_crate, found_macro, parsing_result)
398-
}
389+
let (mut info, parsing_result) = match result {
390+
Err(..) | Ok((_, ParsingResult::Failed)) => return Err(FatalError),
391+
Ok((info, parsing_result)) => (info, parsing_result),
399392
};
400393

401394
// If a doctest's `fn main` is being masked by a wrapper macro, the parsing loop above won't
402395
// see it. In that case, run the old text-based scan to see if they at least have a main
403396
// function written inside a macro invocation. See
404397
// https://github.com/rust-lang/rust/issues/56898
405-
if found_macro
406-
&& !has_main_fn
398+
if info.found_macro
399+
&& !info.has_main_fn
407400
&& original_source_code
408401
.lines()
409402
.map(|line| {
@@ -412,10 +405,10 @@ fn check_for_main_and_extern_crate(
412405
})
413406
.any(|code| code.contains("fn main"))
414407
{
415-
has_main_fn = true;
408+
info.has_main_fn = true;
416409
}
417410

418-
Ok((has_main_fn, already_has_extern_crate, parsing_result != ParsingResult::Ok))
411+
Ok((info, parsing_result != ParsingResult::Ok))
419412
}
420413

421414
enum AttrKind {

src/librustdoc/doctest/runner.rs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,11 @@ impl DocTestRunner {
4545
self.crate_attrs.insert(line.to_string());
4646
}
4747
}
48-
if !self.ids.is_empty() {
49-
self.ids.push(',');
50-
}
48+
// if !self.ids.is_empty() {
49+
// self.ids.push(',');
50+
// }
5151
self.ids.push_str(&format!(
52-
"{}::TEST",
52+
"tests.push({}::TEST);\n",
5353
generate_mergeable_doctest(
5454
doctest,
5555
scraped_test,
@@ -107,9 +107,11 @@ impl DocTestRunner {
107107
#[rustc_main]
108108
#[coverage(off)]
109109
fn main() {{
110-
test::test_main_static_with_args(
110+
let mut tests = Vec::new();
111+
{ids}
112+
test::test_main(
111113
&[{test_args}],
112-
&mut [{ids}],
114+
tests,
113115
None,
114116
);
115117
}}",

0 commit comments

Comments
 (0)