@@ -23,6 +23,7 @@ use rustc_target::spec::{Target, TargetTriple};
23
23
use tempfile:: Builder as TempFileBuilder ;
24
24
25
25
use std:: env;
26
+ use std:: fs:: File ;
26
27
use std:: io:: { self , Write } ;
27
28
use std:: panic;
28
29
use std:: path:: { Path , PathBuf } ;
@@ -31,6 +32,8 @@ use std::str;
31
32
use std:: sync:: atomic:: { AtomicUsize , Ordering } ;
32
33
use std:: sync:: { Arc , Mutex } ;
33
34
35
+ use tempfile:: tempdir;
36
+
34
37
use crate :: clean:: { types:: AttributesExt , Attributes } ;
35
38
use crate :: config:: Options as RustdocOptions ;
36
39
use crate :: html:: markdown:: { self , ErrorCodes , Ignore , LangString } ;
@@ -348,13 +351,49 @@ fn run_test(
348
351
. unwrap_or_else ( || rustc_interface:: util:: rustc_path ( ) . expect ( "found rustc" ) ) ;
349
352
let mut compiler = wrapped_rustc_command ( & rustdoc_options. test_builder_wrappers , rustc_binary) ;
350
353
compiler. arg ( "--crate-type" ) . arg ( "bin" ) ;
351
- for cfg in & rustdoc_options. cfgs {
352
- compiler. arg ( "--cfg" ) . arg ( & cfg) ;
354
+
355
+ let mut needs_unstable_options = false ;
356
+ let mut written_cfg_args = false ;
357
+ #[ allow( unused_variables) ]
358
+ let tmp_dir;
359
+
360
+ // If there are too many `cfg` arguments, instead of risking reaching `Command`'s limit on
361
+ // the number of arguments, we put them into a file which we then pass as `@` argument.
362
+ if rustdoc_options. cfgs . len ( ) + rustdoc_options. check_cfgs . len ( ) > 1_000
363
+ && let Ok ( temp_dir) = tempdir ( )
364
+ && let file_path = temp_dir. path ( ) . join ( "cfgs" )
365
+ && let Ok ( mut file) = File :: create ( & file_path)
366
+ {
367
+ let mut content = Vec :: new ( ) ;
368
+ for cfg in & rustdoc_options. cfgs {
369
+ content. push ( format ! ( "--cfg={cfg}" ) ) ;
370
+ }
371
+ if !rustdoc_options. check_cfgs . is_empty ( ) {
372
+ needs_unstable_options = true ;
373
+ for check_cfg in & rustdoc_options. check_cfgs {
374
+ content. push ( format ! ( "--check-cfg={check_cfg}" ) ) ;
375
+ }
376
+ }
377
+ let content = content. join ( "\n " ) ;
378
+ #[ allow( unused_assignments) ] // Needed for `tmp_dir = temp_dir`.
379
+ if file. write ( content. as_bytes ( ) ) . is_ok ( ) {
380
+ // To prevent removing the temporary directory too soon.
381
+ tmp_dir = temp_dir;
382
+ written_cfg_args = true ;
383
+ compiler. arg ( & format ! ( "@{}" , file_path. display( ) ) ) ;
384
+ }
353
385
}
354
- if !rustdoc_options. check_cfgs . is_empty ( ) {
355
- compiler. arg ( "-Z" ) . arg ( "unstable-options" ) ;
356
- for check_cfg in & rustdoc_options. check_cfgs {
357
- compiler. arg ( "--check-cfg" ) . arg ( & check_cfg) ;
386
+ // If there were not enough `cfg` argument to make a file, or the file creation failed,
387
+ // we use the usual `Command` API.
388
+ if !written_cfg_args {
389
+ for cfg in & rustdoc_options. cfgs {
390
+ compiler. arg ( "--cfg" ) . arg ( & cfg) ;
391
+ }
392
+ if !rustdoc_options. check_cfgs . is_empty ( ) {
393
+ needs_unstable_options = true ;
394
+ for check_cfg in & rustdoc_options. check_cfgs {
395
+ compiler. arg ( "--check-cfg" ) . arg ( & check_cfg) ;
396
+ }
358
397
}
359
398
}
360
399
if let Some ( sysroot) = rustdoc_options. maybe_sysroot {
@@ -370,9 +409,14 @@ fn run_test(
370
409
if rustdoc_options. json_unused_externs . is_enabled ( ) && !lang_string. compile_fail {
371
410
compiler. arg ( "--error-format=json" ) ;
372
411
compiler. arg ( "--json" ) . arg ( "unused-externs" ) ;
373
- compiler. arg ( "-Z" ) . arg ( "unstable-options" ) ;
374
412
compiler. arg ( "-W" ) . arg ( "unused_crate_dependencies" ) ;
413
+ needs_unstable_options = true ;
375
414
}
415
+
416
+ if needs_unstable_options {
417
+ compiler. arg ( "-Z" ) . arg ( "unstable-options" ) ;
418
+ }
419
+
376
420
for lib_str in & rustdoc_options. lib_strs {
377
421
compiler. arg ( "-L" ) . arg ( & lib_str) ;
378
422
}
0 commit comments