@@ -51,20 +51,38 @@ pub fn add_configuration(cfg: &mut Cfg, sess: &mut Session, codegen_backend: &dy
5151pub static STACK_SIZE : OnceLock < usize > = OnceLock :: new ( ) ;
5252pub const DEFAULT_STACK_SIZE : usize = 8 * 1024 * 1024 ;
5353
54- fn init_stack_size ( ) -> usize {
54+ fn init_stack_size ( early_dcx : & EarlyDiagCtxt ) -> usize {
5555 // Obey the environment setting or default
5656 * STACK_SIZE . get_or_init ( || {
5757 env:: var_os ( "RUST_MIN_STACK" )
58- . map ( |os_str| os_str. to_string_lossy ( ) . into_owned ( ) )
59- // ignore if it is set to nothing
60- . filter ( |s| s. trim ( ) != "" )
61- . map ( |s| s. trim ( ) . parse :: < usize > ( ) . unwrap ( ) )
58+ . as_ref ( )
59+ . map ( |os_str| os_str. to_string_lossy ( ) )
60+ // if someone finds out `export RUST_MIN_STACK=640000` isn't enough stack
61+ // they might try to "unset" it by running `RUST_MIN_STACK= rustc code.rs`
62+ // this is wrong, but std would nonetheless "do what they mean", so let's do likewise
63+ . filter ( |s| !s. trim ( ) . is_empty ( ) )
64+ // rustc is a batch program, so error early on inputs which are unlikely to be intended
65+ // so no one thinks we parsed them setting `RUST_MIN_STACK="64 megabytes"`
66+ // FIXME: we could accept `RUST_MIN_STACK=64MB`, perhaps?
67+ . map ( |s| {
68+ let s = s. trim ( ) ;
69+ // FIXME(workingjubilee): add proper diagnostics when we factor out "pre-run" setup
70+ #[ allow( rustc:: untranslatable_diagnostic, rustc:: diagnostic_outside_of_impl) ]
71+ s. parse :: < usize > ( ) . unwrap_or_else ( |_| {
72+ let mut err = early_dcx. early_struct_fatal ( format ! (
73+ r#"`RUST_MIN_STACK` should be a number of bytes, but was "{s}""# ,
74+ ) ) ;
75+ err. note ( "you can also unset `RUST_MIN_STACK` to use the default stack size" ) ;
76+ err. emit ( )
77+ } )
78+ } )
6279 // otherwise pick a consistent default
6380 . unwrap_or ( DEFAULT_STACK_SIZE )
6481 } )
6582}
6683
6784fn run_in_thread_with_globals < F : FnOnce ( CurrentGcx ) -> R + Send , R : Send > (
85+ thread_stack_size : usize ,
6886 edition : Edition ,
6987 sm_inputs : SourceMapInputs ,
7088 f : F ,
@@ -75,7 +93,7 @@ fn run_in_thread_with_globals<F: FnOnce(CurrentGcx) -> R + Send, R: Send>(
7593 // the parallel compiler, in particular to ensure there is no accidental
7694 // sharing of data between the main thread and the compilation thread
7795 // (which might cause problems for the parallel compiler).
78- let builder = thread:: Builder :: new ( ) . name ( "rustc" . to_string ( ) ) . stack_size ( init_stack_size ( ) ) ;
96+ let builder = thread:: Builder :: new ( ) . name ( "rustc" . to_string ( ) ) . stack_size ( thread_stack_size ) ;
7997
8098 // We build the session globals and run `f` on the spawned thread, because
8199 // `SessionGlobals` does not impl `Send` in the non-parallel compiler.
@@ -100,16 +118,19 @@ fn run_in_thread_with_globals<F: FnOnce(CurrentGcx) -> R + Send, R: Send>(
100118
101119#[ cfg( not( parallel_compiler) ) ]
102120pub ( crate ) fn run_in_thread_pool_with_globals < F : FnOnce ( CurrentGcx ) -> R + Send , R : Send > (
121+ thread_builder_diag : & EarlyDiagCtxt ,
103122 edition : Edition ,
104123 _threads : usize ,
105124 sm_inputs : SourceMapInputs ,
106125 f : F ,
107126) -> R {
108- run_in_thread_with_globals ( edition, sm_inputs, f)
127+ let thread_stack_size = init_stack_size ( thread_builder_diag) ;
128+ run_in_thread_with_globals ( thread_stack_size, edition, sm_inputs, f)
109129}
110130
111131#[ cfg( parallel_compiler) ]
112132pub ( crate ) fn run_in_thread_pool_with_globals < F : FnOnce ( CurrentGcx ) -> R + Send , R : Send > (
133+ thread_builder_diag : & EarlyDiagCtxt ,
113134 edition : Edition ,
114135 threads : usize ,
115136 sm_inputs : SourceMapInputs ,
@@ -121,10 +142,12 @@ pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce(CurrentGcx) -> R + Send,
121142 use rustc_query_system:: query:: { break_query_cycles, QueryContext } ;
122143 use std:: process;
123144
145+ let thread_stack_size = init_stack_size ( thread_builder_diag) ;
146+
124147 let registry = sync:: Registry :: new ( std:: num:: NonZero :: new ( threads) . unwrap ( ) ) ;
125148
126149 if !sync:: is_dyn_thread_safe ( ) {
127- return run_in_thread_with_globals ( edition, sm_inputs, |current_gcx| {
150+ return run_in_thread_with_globals ( thread_stack_size , edition, sm_inputs, |current_gcx| {
128151 // Register the thread for use with the `WorkerLocal` type.
129152 registry. register ( ) ;
130153
@@ -167,7 +190,7 @@ pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce(CurrentGcx) -> R + Send,
167190 } )
168191 . unwrap ( ) ;
169192 } )
170- . stack_size ( init_stack_size ( ) ) ;
193+ . stack_size ( thread_stack_size ) ;
171194
172195 // We create the session globals on the main thread, then create the thread
173196 // pool. Upon creation, each worker thread created gets a copy of the
0 commit comments