diff --git a/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs b/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs index ea8596ea28658..dbbd95408c8ab 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs @@ -120,6 +120,17 @@ impl ProvenanceMap { } } + /// Gets the provenances of all bytes (including from pointers) in a range. + pub fn get_range( + &self, + cx: &impl HasDataLayout, + range: AllocRange, + ) -> impl Iterator { + let ptr_provs = self.range_ptrs_get(range, cx).iter().map(|(_, p)| *p); + let byte_provs = self.range_bytes_get(range).iter().map(|(_, (p, _))| *p); + ptr_provs.chain(byte_provs) + } + /// Attempt to merge per-byte provenance back into ptr chunks, if the right fragments /// sit next to each other. Return `false` is that is not possible due to partial pointers. pub fn merge_bytes(&mut self, cx: &impl HasDataLayout) -> bool { diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs index 7ee0962721f5b..985e669c92d79 100644 --- a/library/core/src/char/methods.rs +++ b/library/core/src/char/methods.rs @@ -1872,28 +1872,33 @@ pub const unsafe fn encode_utf8_raw_unchecked(code: u32, dst: *mut u8) { // SAFETY: The caller must guarantee that the buffer pointed to by `dst` // is at least `len` bytes long. unsafe { - match len { - 1 => { - *dst = code as u8; - } - 2 => { - *dst = (code >> 6 & 0x1F) as u8 | TAG_TWO_B; - *dst.add(1) = (code & 0x3F) as u8 | TAG_CONT; - } - 3 => { - *dst = (code >> 12 & 0x0F) as u8 | TAG_THREE_B; - *dst.add(1) = (code >> 6 & 0x3F) as u8 | TAG_CONT; - *dst.add(2) = (code & 0x3F) as u8 | TAG_CONT; - } - 4 => { - *dst = (code >> 18 & 0x07) as u8 | TAG_FOUR_B; - *dst.add(1) = (code >> 12 & 0x3F) as u8 | TAG_CONT; - *dst.add(2) = (code >> 6 & 0x3F) as u8 | TAG_CONT; - *dst.add(3) = (code & 0x3F) as u8 | TAG_CONT; - } - // SAFETY: `char` always takes between 1 and 4 bytes to encode in UTF-8. - _ => crate::hint::unreachable_unchecked(), + if len == 1 { + *dst = code as u8; + return; + } + + let last1 = (code >> 0 & 0x3F) as u8 | TAG_CONT; + let last2 = (code >> 6 & 0x3F) as u8 | TAG_CONT; + let last3 = (code >> 12 & 0x3F) as u8 | TAG_CONT; + let last4 = (code >> 18 & 0x3F) as u8 | TAG_FOUR_B; + + if len == 2 { + *dst = last2 | TAG_TWO_B; + *dst.add(1) = last1; + return; } + + if len == 3 { + *dst = last3 | TAG_THREE_B; + *dst.add(1) = last2; + *dst.add(2) = last1; + return; + } + + *dst = last4; + *dst.add(1) = last3; + *dst.add(2) = last2; + *dst.add(3) = last1; } } diff --git a/library/std/src/sync/lazy_lock.rs b/library/std/src/sync/lazy_lock.rs index a40e29a772a9c..3231125f7a13a 100644 --- a/library/std/src/sync/lazy_lock.rs +++ b/library/std/src/sync/lazy_lock.rs @@ -244,7 +244,11 @@ impl T> LazyLock { #[inline] #[stable(feature = "lazy_cell", since = "1.80.0")] pub fn force(this: &LazyLock) -> &T { - this.once.call_once(|| { + this.once.call_once_force(|state| { + if state.is_poisoned() { + panic_poisoned(); + } + // SAFETY: `call_once` only runs this closure once, ever. let data = unsafe { &mut *this.data.get() }; let f = unsafe { ManuallyDrop::take(&mut data.f) }; @@ -257,8 +261,7 @@ impl T> LazyLock { // * the closure was called and initialized `value`. // * the closure was called and panicked, so this point is never reached. // * the closure was not called, but a previous call initialized `value`. - // * the closure was not called because the Once is poisoned, so this point - // is never reached. + // * the closure was not called because the Once is poisoned, which we handled above. // So `value` has definitely been initialized and will not be modified again. unsafe { &*(*this.data.get()).value } } diff --git a/library/std/src/sys/fd/unix.rs b/library/std/src/sys/fd/unix.rs index cdca73cdca11e..a12f692e7543b 100644 --- a/library/std/src/sys/fd/unix.rs +++ b/library/std/src/sys/fd/unix.rs @@ -37,10 +37,10 @@ pub struct FileDesc(OwnedFd); // // On Apple targets however, apparently the 64-bit libc is either buggy or // intentionally showing odd behavior by rejecting any read with a size -// larger than or equal to INT_MAX. To handle both of these the read -// size is capped on both platforms. +// larger than INT_MAX. To handle both of these the read size is capped on +// both platforms. const READ_LIMIT: usize = if cfg!(target_vendor = "apple") { - libc::c_int::MAX as usize - 1 + libc::c_int::MAX as usize } else { libc::ssize_t::MAX as usize }; diff --git a/library/std/tests/sync/lazy_lock.rs b/library/std/tests/sync/lazy_lock.rs index 6c14b79f2ce7c..68aeea834b4fa 100644 --- a/library/std/tests/sync/lazy_lock.rs +++ b/library/std/tests/sync/lazy_lock.rs @@ -33,16 +33,6 @@ fn lazy_default() { assert_eq!(CALLED.load(SeqCst), 1); } -#[test] -#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] -fn lazy_poisoning() { - let x: LazyCell = LazyCell::new(|| panic!("kaboom")); - for _ in 0..2 { - let res = panic::catch_unwind(panic::AssertUnwindSafe(|| x.len())); - assert!(res.is_err()); - } -} - #[test] #[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads fn sync_lazy_new() { @@ -123,16 +113,6 @@ fn static_sync_lazy_via_fn() { assert_eq!(xs(), &vec![1, 2, 3]); } -#[test] -#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] -fn sync_lazy_poisoning() { - let x: LazyLock = LazyLock::new(|| panic!("kaboom")); - for _ in 0..2 { - let res = panic::catch_unwind(|| x.len()); - assert!(res.is_err()); - } -} - // Check that we can infer `T` from closure's type. #[test] fn lazy_type_inference() { @@ -145,17 +125,6 @@ fn is_sync_send() { assert_traits::>(); } -#[test] -#[should_panic = "has previously been poisoned"] -fn lazy_force_mut_panic() { - let mut lazy = LazyLock::::new(|| panic!()); - panic::catch_unwind(panic::AssertUnwindSafe(|| { - let _ = LazyLock::force_mut(&mut lazy); - })) - .unwrap_err(); - let _ = &*lazy; -} - #[test] fn lazy_force_mut() { let s = "abc".to_owned(); @@ -165,3 +134,56 @@ fn lazy_force_mut() { p.clear(); LazyLock::force_mut(&mut lazy); } + +#[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] +fn lazy_poisoning() { + let x: LazyCell = LazyCell::new(|| panic!("kaboom")); + for _ in 0..2 { + let res = panic::catch_unwind(panic::AssertUnwindSafe(|| x.len())); + assert!(res.is_err()); + } +} + +/// Verifies that when a `LazyLock` is poisoned, it panics with the correct error message ("LazyLock +/// instance has previously been poisoned") instead of the underlying `Once` error message. +#[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] +#[should_panic(expected = "LazyLock instance has previously been poisoned")] +fn lazy_lock_deref_panic() { + let lazy: LazyLock = LazyLock::new(|| panic!("initialization failed")); + + // First access will panic during initialization. + let _ = panic::catch_unwind(panic::AssertUnwindSafe(|| { + let _ = &*lazy; + })); + + // Second access should panic with the poisoned message. + let _ = &*lazy; +} + +#[test] +#[should_panic(expected = "LazyLock instance has previously been poisoned")] +fn lazy_lock_deref_mut_panic() { + let mut lazy: LazyLock = LazyLock::new(|| panic!("initialization failed")); + + // First access will panic during initialization. + let _ = panic::catch_unwind(panic::AssertUnwindSafe(|| { + let _ = LazyLock::force_mut(&mut lazy); + })); + + // Second access should panic with the poisoned message. + let _ = &*lazy; +} + +/// Verifies that when the initialization closure panics with a custom message, that message is +/// preserved and not overridden by `LazyLock`. +#[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] +#[should_panic(expected = "custom panic message from closure")] +fn lazy_lock_preserves_closure_panic_message() { + let lazy: LazyLock = LazyLock::new(|| panic!("custom panic message from closure")); + + // This should panic with the original message from the closure. + let _ = &*lazy; +} diff --git a/src/bootstrap/src/bin/main.rs b/src/bootstrap/src/bin/main.rs index 93c7faf4f0159..79369dd9cea8b 100644 --- a/src/bootstrap/src/bin/main.rs +++ b/src/bootstrap/src/bin/main.rs @@ -198,7 +198,8 @@ fn check_version(config: &Config) -> Option { Some(ChangeId::Id(id)) if id == latest_change_id => return None, Some(ChangeId::Ignore) => return None, Some(ChangeId::Id(id)) => id, - None => { + // The warning is only useful for development, not release tarballs + None if !config.rust_info.is_from_tarball() => { msg.push_str("WARNING: The `change-id` is missing in the `bootstrap.toml`. This means that you will not be able to track the major changes made to the bootstrap configurations.\n"); msg.push_str("NOTE: to silence this warning, "); msg.push_str(&format!( @@ -206,6 +207,7 @@ fn check_version(config: &Config) -> Option { )); return Some(msg); } + None => return None, }; // Always try to use `change-id` from .last-warned-change-id first. If it doesn't exist, diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index f579bdd847f66..84c9f9cc4d209 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -327,59 +327,6 @@ pub struct Config { } impl Config { - #[cfg_attr( - feature = "tracing", - instrument(target = "CONFIG_HANDLING", level = "trace", name = "Config::default_opts") - )] - pub fn default_opts() -> Config { - #[cfg(feature = "tracing")] - span!(target: "CONFIG_HANDLING", tracing::Level::TRACE, "constructing default config"); - - Config { - bypass_bootstrap_lock: false, - llvm_optimize: true, - ninja_in_file: true, - llvm_static_stdcpp: false, - llvm_libzstd: false, - backtrace: true, - rust_optimize: RustOptimize::Bool(true), - rust_optimize_tests: true, - rust_randomize_layout: false, - submodules: None, - docs: true, - docs_minification: true, - rust_rpath: true, - rust_strip: false, - channel: "dev".to_string(), - codegen_tests: true, - rust_dist_src: true, - rust_codegen_backends: vec![CodegenBackendKind::Llvm], - deny_warnings: true, - bindir: "bin".into(), - dist_include_mingw_linker: true, - dist_compression_profile: "fast".into(), - - stdout_is_tty: std::io::stdout().is_terminal(), - stderr_is_tty: std::io::stderr().is_terminal(), - - // set by build.rs - host_target: get_host_target(), - - src: { - let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - // Undo `src/bootstrap` - manifest_dir.parent().unwrap().parent().unwrap().to_owned() - }, - out: PathBuf::from("build"), - - // This is needed by codegen_ssa on macOS to ship `llvm-objcopy` aliased to - // `rust-objcopy` to workaround bad `strip`s on macOS. - llvm_tools_enabled: true, - - ..Default::default() - } - } - pub fn set_dry_run(&mut self, dry_run: DryRun) { self.exec_ctx.set_dry_run(dry_run); } diff --git a/src/tools/clippy/Cargo.toml b/src/tools/clippy/Cargo.toml index 2add525b7e8ae..b3618932ded7d 100644 --- a/src/tools/clippy/Cargo.toml +++ b/src/tools/clippy/Cargo.toml @@ -65,13 +65,6 @@ harness = false name = "dogfood" harness = false -# quine-mc_cluskey makes up a significant part of the runtime in dogfood -# due to the number of conditions in the clippy_lints crate -# and enabling optimizations for that specific dependency helps a bit -# without increasing total build times. -[profile.dev.package.quine-mc_cluskey] -opt-level = 3 - [lints.rust.unexpected_cfgs] level = "warn" check-cfg = ['cfg(bootstrap)'] diff --git a/src/tools/miri/src/shims/native_lib/mod.rs b/src/tools/miri/src/shims/native_lib/mod.rs index e2a0bdbd9b408..74b9b704fea5e 100644 --- a/src/tools/miri/src/shims/native_lib/mod.rs +++ b/src/tools/miri/src/shims/native_lib/mod.rs @@ -242,14 +242,9 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { match evt { AccessEvent::Read(_) => { - // FIXME: ProvenanceMap should have something like get_range(). - let p_map = alloc.provenance(); - for idx in overlap { - // If a provenance was read by the foreign code, expose it. - if let Some((prov, _idx)) = p_map.get_byte(Size::from_bytes(idx), this) - { - this.expose_provenance(prov)?; - } + // If a provenance was read by the foreign code, expose it. + for prov in alloc.provenance().get_range(this, overlap.into()) { + this.expose_provenance(prov)?; } } AccessEvent::Write(_, certain) => {