@@ -49,20 +49,26 @@ impl DocTest {
49
49
has_features,
50
50
has_no_std,
51
51
} = partition_source ( source, edition) ;
52
- let mut supports_color = false ;
53
52
54
53
// Uses librustc_ast to parse the doctest and find if there's a main fn and the extern
55
54
// 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
+ )
66
72
else {
67
73
// If the parser panicked due to a fatal error, pass the test code through unchanged.
68
74
// The error will be reported during compilation.
@@ -86,12 +92,12 @@ impl DocTest {
86
92
maybe_crate_attrs,
87
93
crates,
88
94
everything_else,
89
- already_has_extern_crate,
95
+ already_has_extern_crate : found_extern_crate ,
90
96
test_id,
91
97
failed_ast : false ,
92
98
// If the AST returned an error, we don't want this doctest to be merged with the
93
99
// 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 ,
95
101
}
96
102
}
97
103
@@ -231,11 +237,8 @@ fn cancel_error_count(psess: &ParseSess) {
231
237
232
238
fn parse_source (
233
239
source : String ,
234
- has_main_fn : & mut bool ,
235
- found_extern_crate : & mut bool ,
236
- found_macro : & mut bool ,
240
+ info : & mut ParseSourceInfo ,
237
241
crate_name : & Option < & str > ,
238
- supports_color : & mut bool ,
239
242
) -> ParsingResult {
240
243
use rustc_errors:: emitter:: { Emitter , HumanEmitter } ;
241
244
use rustc_errors:: DiagCtxt ;
@@ -251,7 +254,7 @@ fn parse_source(
251
254
rustc_driver:: DEFAULT_LOCALE_RESOURCES . to_vec ( ) ,
252
255
false ,
253
256
) ;
254
- * supports_color =
257
+ info . supports_color =
255
258
HumanEmitter :: new ( stderr_destination ( ColorConfig :: Auto ) , fallback_bundle. clone ( ) )
256
259
. supports_color ( ) ;
257
260
@@ -274,53 +277,48 @@ fn parse_source(
274
277
// Recurse through functions body. It is necessary because the doctest source code is
275
278
// wrapped in a function to limit the number of AST errors. If we don't recurse into
276
279
// 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
+ }
284
286
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 => {
286
288
if item. ident . name == sym:: main {
287
- * has_main_fn = true ;
289
+ info . has_main_fn = true ;
288
290
}
289
291
if let Some ( ref body) = fn_item. body {
290
292
for stmt in & body. stmts {
291
293
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 ,
300
296
_ => { }
301
297
}
302
298
}
303
299
}
304
300
}
305
301
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 {
308
306
Some ( name) => name. as_str ( ) == * crate_name,
309
307
None => item. ident . as_str ( ) == * crate_name,
310
308
} ;
311
309
}
312
310
}
313
- ast:: ItemKind :: MacCall ( ..) => * found_macro = true ,
311
+ ast:: ItemKind :: MacCall ( ..) => info . found_macro = true ,
314
312
_ => { }
315
313
}
316
314
}
317
315
318
316
loop {
319
317
match parser. parse_item ( ForceCollect :: No ) {
320
318
Ok ( Some ( item) ) => {
321
- check_item ( & item, has_main_fn , found_extern_crate , found_macro , crate_name) ;
319
+ check_item ( & item, info , crate_name) ;
322
320
323
- if * has_main_fn && * found_extern_crate {
321
+ if info . has_main_fn && info . found_extern_crate {
324
322
break ;
325
323
}
326
324
}
@@ -341,30 +339,30 @@ fn parse_source(
341
339
parsing_result
342
340
}
343
341
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
+
345
351
fn check_for_main_and_extern_crate (
346
352
crate_name : Option < & str > ,
347
353
original_source_code : & str ,
348
354
everything_else : & str ,
349
355
crates : & str ,
350
356
edition : Edition ,
351
- supports_color : & mut bool ,
352
357
can_merge_doctests : bool ,
353
- ) -> Result < ( bool , bool , bool ) , FatalError > {
358
+ ) -> Result < ( ParseSourceInfo , bool ) , FatalError > {
354
359
let result = rustc_driver:: catch_fatal_errors ( || {
355
360
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) ;
368
366
// No need to double-check this if the "merged doctests" feature isn't enabled (so
369
367
// before the 2024 edition).
370
368
if can_merge_doctests && parsing_result != ParsingResult :: Ok {
@@ -380,30 +378,25 @@ fn check_for_main_and_extern_crate(
380
378
// faster doctests run time.
381
379
parsing_result = parse_source (
382
380
format ! ( "{crates}\n fn __doctest_wrap(){{{everything_else}\n }}" ) ,
383
- & mut has_main_fn,
384
- & mut found_extern_crate,
385
- & mut found_macro,
381
+ & mut info,
386
382
& crate_name,
387
- supports_color,
388
383
) ;
389
384
}
390
385
391
- ( has_main_fn , found_extern_crate , found_macro , parsing_result)
386
+ ( info , parsing_result)
392
387
} )
393
388
} ) ;
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) ,
399
392
} ;
400
393
401
394
// If a doctest's `fn main` is being masked by a wrapper macro, the parsing loop above won't
402
395
// see it. In that case, run the old text-based scan to see if they at least have a main
403
396
// function written inside a macro invocation. See
404
397
// 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
407
400
&& original_source_code
408
401
. lines ( )
409
402
. map ( |line| {
@@ -412,10 +405,10 @@ fn check_for_main_and_extern_crate(
412
405
} )
413
406
. any ( |code| code. contains ( "fn main" ) )
414
407
{
415
- has_main_fn = true ;
408
+ info . has_main_fn = true ;
416
409
}
417
410
418
- Ok ( ( has_main_fn , already_has_extern_crate , parsing_result != ParsingResult :: Ok ) )
411
+ Ok ( ( info , parsing_result != ParsingResult :: Ok ) )
419
412
}
420
413
421
414
enum AttrKind {
0 commit comments