Skip to content

Commit 9985821

Browse files
defrost RUST_MIN_STACK=ice rustc hello.rs
An earlier commit included the change for a suggestion here. Unfortunately, it also used unwrap instead of dying properly. Roll out the ~~rice paper~~ EarlyDiagCtxt before we do anything that might leave a mess.
1 parent def6b99 commit 9985821

File tree

5 files changed

+37
-9
lines changed

5 files changed

+37
-9
lines changed

compiler/rustc_interface/src/interface.rs

+1
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,7 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se
389389
let hash_kind = config.opts.unstable_opts.src_hash_algorithm(&target);
390390

391391
util::run_in_thread_pool_with_globals(
392+
&early_dcx,
392393
config.opts.edition,
393394
config.opts.unstable_opts.threads,
394395
SourceMapInputs { file_loader, path_mapping, hash_kind },

compiler/rustc_interface/src/util.rs

+26-9
Original file line numberDiff line numberDiff line change
@@ -51,20 +51,32 @@ pub fn add_configuration(cfg: &mut Cfg, sess: &mut Session, codegen_backend: &dy
5151
pub static STACK_SIZE: OnceLock<usize> = OnceLock::new();
5252
pub 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+
s.trim().parse::<usize>().unwrap_or_else(|_| {
69+
#[allow(rustc::untranslatable_diagnostic)]
70+
early_dcx.early_fatal("`RUST_MIN_STACK` should be unset or a number of bytes")
71+
})
72+
})
6273
// otherwise pick a consistent default
6374
.unwrap_or(DEFAULT_STACK_SIZE)
6475
})
6576
}
6677

6778
fn run_in_thread_with_globals<F: FnOnce(CurrentGcx) -> R + Send, R: Send>(
79+
thread_stack_size: usize,
6880
edition: Edition,
6981
sm_inputs: SourceMapInputs,
7082
f: F,
@@ -75,7 +87,7 @@ fn run_in_thread_with_globals<F: FnOnce(CurrentGcx) -> R + Send, R: Send>(
7587
// the parallel compiler, in particular to ensure there is no accidental
7688
// sharing of data between the main thread and the compilation thread
7789
// (which might cause problems for the parallel compiler).
78-
let builder = thread::Builder::new().name("rustc".to_string()).stack_size(init_stack_size());
90+
let builder = thread::Builder::new().name("rustc".to_string()).stack_size(thread_stack_size);
7991

8092
// We build the session globals and run `f` on the spawned thread, because
8193
// `SessionGlobals` does not impl `Send` in the non-parallel compiler.
@@ -100,16 +112,19 @@ fn run_in_thread_with_globals<F: FnOnce(CurrentGcx) -> R + Send, R: Send>(
100112

101113
#[cfg(not(parallel_compiler))]
102114
pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce(CurrentGcx) -> R + Send, R: Send>(
115+
thread_builder_diag: &EarlyDiagCtxt,
103116
edition: Edition,
104117
_threads: usize,
105118
sm_inputs: SourceMapInputs,
106119
f: F,
107120
) -> R {
108-
run_in_thread_with_globals(edition, sm_inputs, f)
121+
let thread_stack_size = init_stack_size(thread_builder_diag);
122+
run_in_thread_with_globals(thread_stack_size, edition, sm_inputs, f)
109123
}
110124

111125
#[cfg(parallel_compiler)]
112126
pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce(CurrentGcx) -> R + Send, R: Send>(
127+
thread_builder_diag: &EarlyDiagCtxt,
113128
edition: Edition,
114129
threads: usize,
115130
sm_inputs: SourceMapInputs,
@@ -121,10 +136,12 @@ pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce(CurrentGcx) -> R + Send,
121136
use rustc_query_system::query::{break_query_cycles, QueryContext};
122137
use std::process;
123138

139+
let thread_stack_size = init_stack_size(thread_builder_diag);
140+
124141
let registry = sync::Registry::new(std::num::NonZero::new(threads).unwrap());
125142

126143
if !sync::is_dyn_thread_safe() {
127-
return run_in_thread_with_globals(edition, sm_inputs, |current_gcx| {
144+
return run_in_thread_with_globals(thread_stack_size, edition, sm_inputs, |current_gcx| {
128145
// Register the thread for use with the `WorkerLocal` type.
129146
registry.register();
130147

@@ -167,7 +184,7 @@ pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce(CurrentGcx) -> R + Send,
167184
})
168185
.unwrap();
169186
})
170-
.stack_size(init_stack_size());
187+
.stack_size(thread_stack_size);
171188

172189
// We create the session globals on the main thread, then create the thread
173190
// pool. Upon creation, each worker thread created gets a copy of the

tests/ui/rustc-env/README.md

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
Some environment variables affect rustc's behavior not because they are major compiler interfaces
2+
but rather because rustc is, ultimately, a Rust program, with debug logging, stack control, etc.
3+
4+
Prefer to group tests that use environment variables to control something about rustc's core UX,
5+
like "can we parse this number of parens if we raise RUST_MIN_STACK?" with related code for that
6+
compiler feature.
+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
//@ rustc-env:RUST_MIN_STACK=banana
2+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
error: `RUST_MIN_STACK` should be unset or a number of bytes
2+

0 commit comments

Comments
 (0)