mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 14:55:26 +00:00
Rollup merge of #125302 - workingjubilee:prefer-my-stack-neat, r=compiler-errors
defrost `RUST_MIN_STACK=ice rustc hello.rs` I didn't think too hard about testing my previous PR rust-lang/rust#122847 which makes our stack overflow handler assist people in discovering the `RUST_MIN_STACK` variable (which apparently is surprisingly useful for Really Big codebases). After it was merged, some useful comments left in a drive-by review led me to discover I had added an ICE. This reworks the code a bit to explain the rationale, remove the ICE that I introduced, and properly test one of the diagnostics.
This commit is contained in:
commit
ecbd110c7e
@ -389,6 +389,7 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se
|
|||||||
let hash_kind = config.opts.unstable_opts.src_hash_algorithm(&target);
|
let hash_kind = config.opts.unstable_opts.src_hash_algorithm(&target);
|
||||||
|
|
||||||
util::run_in_thread_pool_with_globals(
|
util::run_in_thread_pool_with_globals(
|
||||||
|
&early_dcx,
|
||||||
config.opts.edition,
|
config.opts.edition,
|
||||||
config.opts.unstable_opts.threads,
|
config.opts.unstable_opts.threads,
|
||||||
SourceMapInputs { file_loader, path_mapping, hash_kind },
|
SourceMapInputs { file_loader, path_mapping, hash_kind },
|
||||||
|
@ -51,20 +51,38 @@ pub fn add_configuration(cfg: &mut Cfg, sess: &mut Session, codegen_backend: &dy
|
|||||||
pub static STACK_SIZE: OnceLock<usize> = OnceLock::new();
|
pub static STACK_SIZE: OnceLock<usize> = OnceLock::new();
|
||||||
pub const DEFAULT_STACK_SIZE: usize = 8 * 1024 * 1024;
|
pub const DEFAULT_STACK_SIZE: usize = 8 * 1024 * 1024;
|
||||||
|
|
||||||
fn init_stack_size() -> usize {
|
fn init_stack_size(early_dcx: &EarlyDiagCtxt) -> usize {
|
||||||
// Obey the environment setting or default
|
// Obey the environment setting or default
|
||||||
*STACK_SIZE.get_or_init(|| {
|
*STACK_SIZE.get_or_init(|| {
|
||||||
env::var_os("RUST_MIN_STACK")
|
env::var_os("RUST_MIN_STACK")
|
||||||
.map(|os_str| os_str.to_string_lossy().into_owned())
|
.as_ref()
|
||||||
// ignore if it is set to nothing
|
.map(|os_str| os_str.to_string_lossy())
|
||||||
.filter(|s| s.trim() != "")
|
// if someone finds out `export RUST_MIN_STACK=640000` isn't enough stack
|
||||||
.map(|s| s.trim().parse::<usize>().unwrap())
|
// they might try to "unset" it by running `RUST_MIN_STACK= rustc code.rs`
|
||||||
|
// this is wrong, but std would nonetheless "do what they mean", so let's do likewise
|
||||||
|
.filter(|s| !s.trim().is_empty())
|
||||||
|
// rustc is a batch program, so error early on inputs which are unlikely to be intended
|
||||||
|
// so no one thinks we parsed them setting `RUST_MIN_STACK="64 megabytes"`
|
||||||
|
// FIXME: we could accept `RUST_MIN_STACK=64MB`, perhaps?
|
||||||
|
.map(|s| {
|
||||||
|
let s = s.trim();
|
||||||
|
// FIXME(workingjubilee): add proper diagnostics when we factor out "pre-run" setup
|
||||||
|
#[allow(rustc::untranslatable_diagnostic, rustc::diagnostic_outside_of_impl)]
|
||||||
|
s.parse::<usize>().unwrap_or_else(|_| {
|
||||||
|
let mut err = early_dcx.early_struct_fatal(format!(
|
||||||
|
r#"`RUST_MIN_STACK` should be a number of bytes, but was "{s}""#,
|
||||||
|
));
|
||||||
|
err.note("you can also unset `RUST_MIN_STACK` to use the default stack size");
|
||||||
|
err.emit()
|
||||||
|
})
|
||||||
|
})
|
||||||
// otherwise pick a consistent default
|
// otherwise pick a consistent default
|
||||||
.unwrap_or(DEFAULT_STACK_SIZE)
|
.unwrap_or(DEFAULT_STACK_SIZE)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_in_thread_with_globals<F: FnOnce(CurrentGcx) -> R + Send, R: Send>(
|
fn run_in_thread_with_globals<F: FnOnce(CurrentGcx) -> R + Send, R: Send>(
|
||||||
|
thread_stack_size: usize,
|
||||||
edition: Edition,
|
edition: Edition,
|
||||||
sm_inputs: SourceMapInputs,
|
sm_inputs: SourceMapInputs,
|
||||||
f: F,
|
f: F,
|
||||||
@ -75,7 +93,7 @@ fn run_in_thread_with_globals<F: FnOnce(CurrentGcx) -> R + Send, R: Send>(
|
|||||||
// the parallel compiler, in particular to ensure there is no accidental
|
// the parallel compiler, in particular to ensure there is no accidental
|
||||||
// sharing of data between the main thread and the compilation thread
|
// sharing of data between the main thread and the compilation thread
|
||||||
// (which might cause problems for the parallel compiler).
|
// (which might cause problems for the parallel compiler).
|
||||||
let builder = thread::Builder::new().name("rustc".to_string()).stack_size(init_stack_size());
|
let builder = thread::Builder::new().name("rustc".to_string()).stack_size(thread_stack_size);
|
||||||
|
|
||||||
// We build the session globals and run `f` on the spawned thread, because
|
// We build the session globals and run `f` on the spawned thread, because
|
||||||
// `SessionGlobals` does not impl `Send` in the non-parallel compiler.
|
// `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>(
|
|||||||
|
|
||||||
#[cfg(not(parallel_compiler))]
|
#[cfg(not(parallel_compiler))]
|
||||||
pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce(CurrentGcx) -> R + Send, R: Send>(
|
pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce(CurrentGcx) -> R + Send, R: Send>(
|
||||||
|
thread_builder_diag: &EarlyDiagCtxt,
|
||||||
edition: Edition,
|
edition: Edition,
|
||||||
_threads: usize,
|
_threads: usize,
|
||||||
sm_inputs: SourceMapInputs,
|
sm_inputs: SourceMapInputs,
|
||||||
f: F,
|
f: F,
|
||||||
) -> R {
|
) -> R {
|
||||||
run_in_thread_with_globals(edition, sm_inputs, f)
|
let thread_stack_size = init_stack_size(thread_builder_diag);
|
||||||
|
run_in_thread_with_globals(thread_stack_size, edition, sm_inputs, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(parallel_compiler)]
|
#[cfg(parallel_compiler)]
|
||||||
pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce(CurrentGcx) -> R + Send, R: Send>(
|
pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce(CurrentGcx) -> R + Send, R: Send>(
|
||||||
|
thread_builder_diag: &EarlyDiagCtxt,
|
||||||
edition: Edition,
|
edition: Edition,
|
||||||
threads: usize,
|
threads: usize,
|
||||||
sm_inputs: SourceMapInputs,
|
sm_inputs: SourceMapInputs,
|
||||||
@ -121,10 +142,12 @@ pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce(CurrentGcx) -> R + Send,
|
|||||||
use rustc_query_system::query::{break_query_cycles, QueryContext};
|
use rustc_query_system::query::{break_query_cycles, QueryContext};
|
||||||
use std::process;
|
use std::process;
|
||||||
|
|
||||||
|
let thread_stack_size = init_stack_size(thread_builder_diag);
|
||||||
|
|
||||||
let registry = sync::Registry::new(std::num::NonZero::new(threads).unwrap());
|
let registry = sync::Registry::new(std::num::NonZero::new(threads).unwrap());
|
||||||
|
|
||||||
if !sync::is_dyn_thread_safe() {
|
if !sync::is_dyn_thread_safe() {
|
||||||
return run_in_thread_with_globals(edition, sm_inputs, |current_gcx| {
|
return run_in_thread_with_globals(thread_stack_size, edition, sm_inputs, |current_gcx| {
|
||||||
// Register the thread for use with the `WorkerLocal` type.
|
// Register the thread for use with the `WorkerLocal` type.
|
||||||
registry.register();
|
registry.register();
|
||||||
|
|
||||||
@ -167,7 +190,7 @@ pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce(CurrentGcx) -> R + Send,
|
|||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
})
|
})
|
||||||
.stack_size(init_stack_size());
|
.stack_size(thread_stack_size);
|
||||||
|
|
||||||
// We create the session globals on the main thread, then create the thread
|
// We create the session globals on the main thread, then create the thread
|
||||||
// pool. Upon creation, each worker thread created gets a copy of the
|
// pool. Upon creation, each worker thread created gets a copy of the
|
||||||
|
6
tests/ui/rustc-env/README.md
Normal file
6
tests/ui/rustc-env/README.md
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
Some environment variables affect rustc's behavior not because they are major compiler interfaces
|
||||||
|
but rather because rustc is, ultimately, a Rust program, with debug logging, stack control, etc.
|
||||||
|
|
||||||
|
Prefer to group tests that use environment variables to control something about rustc's core UX,
|
||||||
|
like "can we parse this number of parens if we raise RUST_MIN_STACK?" with related code for that
|
||||||
|
compiler feature.
|
2
tests/ui/rustc-env/min-stack-banana.rs
Normal file
2
tests/ui/rustc-env/min-stack-banana.rs
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
//@ rustc-env:RUST_MIN_STACK=banana
|
||||||
|
fn main() {}
|
4
tests/ui/rustc-env/min-stack-banana.stderr
Normal file
4
tests/ui/rustc-env/min-stack-banana.stderr
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
error: `RUST_MIN_STACK` should be a number of bytes, but was "banana"
|
||||||
|
|
|
||||||
|
= note: you can also unset `RUST_MIN_STACK` to use the default stack size
|
||||||
|
|
@ -5,7 +5,7 @@
|
|||||||
//@ dont-check-compiler-stdout
|
//@ dont-check-compiler-stdout
|
||||||
//@ dont-check-compiler-stderr
|
//@ dont-check-compiler-stderr
|
||||||
//@ compile-flags: --error-format human
|
//@ compile-flags: --error-format human
|
||||||
//@ aux-build: rustc-rust-log-aux.rs
|
//@ aux-build: rust-log-aux.rs
|
||||||
//@ rustc-env:RUSTC_LOG=debug
|
//@ rustc-env:RUSTC_LOG=debug
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
Loading…
Reference in New Issue
Block a user