@@ -51,20 +51,38 @@ pub fn add_configuration(cfg: &mut Cfg, sess: &mut Session, codegen_backend: &dy
51
51
pub static STACK_SIZE : OnceLock < usize > = OnceLock :: new ( ) ;
52
52
pub const DEFAULT_STACK_SIZE : usize = 8 * 1024 * 1024 ;
53
53
54
- fn init_stack_size ( ) -> usize {
54
+ fn init_stack_size ( early_dcx : & EarlyDiagCtxt ) -> usize {
55
55
// Obey the environment setting or default
56
56
* STACK_SIZE . get_or_init ( || {
57
57
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
+ } )
62
79
// otherwise pick a consistent default
63
80
. unwrap_or ( DEFAULT_STACK_SIZE )
64
81
} )
65
82
}
66
83
67
84
fn run_in_thread_with_globals < F : FnOnce ( CurrentGcx ) -> R + Send , R : Send > (
85
+ thread_stack_size : usize ,
68
86
edition : Edition ,
69
87
sm_inputs : SourceMapInputs ,
70
88
f : F ,
@@ -75,7 +93,7 @@ fn run_in_thread_with_globals<F: FnOnce(CurrentGcx) -> R + Send, R: Send>(
75
93
// the parallel compiler, in particular to ensure there is no accidental
76
94
// sharing of data between the main thread and the compilation thread
77
95
// (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 ) ;
79
97
80
98
// We build the session globals and run `f` on the spawned thread, because
81
99
// `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>(
100
118
101
119
#[ cfg( not( parallel_compiler) ) ]
102
120
pub ( crate ) fn run_in_thread_pool_with_globals < F : FnOnce ( CurrentGcx ) -> R + Send , R : Send > (
121
+ thread_builder_diag : & EarlyDiagCtxt ,
103
122
edition : Edition ,
104
123
_threads : usize ,
105
124
sm_inputs : SourceMapInputs ,
106
125
f : F ,
107
126
) -> 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)
109
129
}
110
130
111
131
#[ cfg( parallel_compiler) ]
112
132
pub ( crate ) fn run_in_thread_pool_with_globals < F : FnOnce ( CurrentGcx ) -> R + Send , R : Send > (
133
+ thread_builder_diag : & EarlyDiagCtxt ,
113
134
edition : Edition ,
114
135
threads : usize ,
115
136
sm_inputs : SourceMapInputs ,
@@ -121,10 +142,12 @@ pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce(CurrentGcx) -> R + Send,
121
142
use rustc_query_system:: query:: { break_query_cycles, QueryContext } ;
122
143
use std:: process;
123
144
145
+ let thread_stack_size = init_stack_size ( thread_builder_diag) ;
146
+
124
147
let registry = sync:: Registry :: new ( std:: num:: NonZero :: new ( threads) . unwrap ( ) ) ;
125
148
126
149
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| {
128
151
// Register the thread for use with the `WorkerLocal` type.
129
152
registry. register ( ) ;
130
153
@@ -167,7 +190,7 @@ pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce(CurrentGcx) -> R + Send,
167
190
} )
168
191
. unwrap ( ) ;
169
192
} )
170
- . stack_size ( init_stack_size ( ) ) ;
193
+ . stack_size ( thread_stack_size ) ;
171
194
172
195
// We create the session globals on the main thread, then create the thread
173
196
// pool. Upon creation, each worker thread created gets a copy of the
0 commit comments