diff --git a/compiler/rustc_data_structures/src/sync.rs b/compiler/rustc_data_structures/src/sync.rs index 8a778866a77e2..afd43a8fe6189 100644 --- a/compiler/rustc_data_structures/src/sync.rs +++ b/compiler/rustc_data_structures/src/sync.rs @@ -143,6 +143,11 @@ cfg_if! { self.0.set(val); result } + pub fn fetch_and(&self, val: bool, _: Ordering) -> bool { + let result = self.0.get() & val; + self.0.set(val); + result + } } impl Atomic { diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index fe8c630666bb2..57e55752027c7 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -338,7 +338,7 @@ declare_features! ( /// Allow conditional compilation depending on rust version (active, cfg_version, "1.45.0", Some(64796), None), /// Allows to use the `#[cfi_encoding = ""]` attribute. - (active, cfi_encoding, "1.69.0", Some(89653), None), + (active, cfi_encoding, "CURRENT_RUSTC_VERSION", Some(89653), None), /// Allows `for<...>` on closures and generators. (active, closure_lifetime_binder, "1.64.0", Some(97362), None), /// Allows `#[track_caller]` on closures and generators. diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 9b74d1085467a..6601a80920ba0 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -611,7 +611,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc { declare_lint! { /// The `missing_copy_implementations` lint detects potentially-forgotten - /// implementations of [`Copy`]. + /// implementations of [`Copy`] for public types. /// /// [`Copy`]: https://doc.rust-lang.org/std/marker/trait.Copy.html /// @@ -729,7 +729,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations { declare_lint! { /// The `missing_debug_implementations` lint detects missing - /// implementations of [`fmt::Debug`]. + /// implementations of [`fmt::Debug`] for public types. /// /// [`fmt::Debug`]: https://doc.rust-lang.org/std/fmt/trait.Debug.html /// diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index e6e7d25773e67..d76b502ff4cb8 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -361,6 +361,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { lib: Library, dep_kind: CrateDepKind, name: Symbol, + private_dep: Option, ) -> Result { let _prof_timer = self.sess.prof.generic_activity("metadata_register_crate"); @@ -368,8 +369,13 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { let crate_root = metadata.get_root(); let host_hash = host_lib.as_ref().map(|lib| lib.metadata.get_root().hash()); - let private_dep = - self.sess.opts.externs.get(name.as_str()).map_or(false, |e| e.is_private_dep); + let private_dep = self + .sess + .opts + .externs + .get(name.as_str()) + .map_or(private_dep.unwrap_or(false), |e| e.is_private_dep) + && private_dep.unwrap_or(true); // Claim this crate number and cache it let cnum = self.cstore.intern_stable_crate_id(&crate_root)?; @@ -514,15 +520,16 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { if !name.as_str().is_ascii() { return Err(CrateError::NonAsciiName(name)); } - let (root, hash, host_hash, extra_filename, path_kind) = match dep { + let (root, hash, host_hash, extra_filename, path_kind, private_dep) = match dep { Some((root, dep)) => ( Some(root), Some(dep.hash), dep.host_hash, Some(&dep.extra_filename[..]), PathKind::Dependency, + Some(dep.is_private), ), - None => (None, None, None, None, PathKind::Crate), + None => (None, None, None, None, PathKind::Crate, None), }; let result = if let Some(cnum) = self.existing_match(name, hash, path_kind) { (LoadResult::Previous(cnum), None) @@ -558,10 +565,13 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { dep_kind = CrateDepKind::MacrosOnly; } data.update_dep_kind(|data_dep_kind| cmp::max(data_dep_kind, dep_kind)); + if let Some(private_dep) = private_dep { + data.update_and_private_dep(private_dep); + } Ok(cnum) } (LoadResult::Loaded(library), host_library) => { - self.register_crate(host_library, root, library, dep_kind, name) + self.register_crate(host_library, root, library, dep_kind, name, private_dep) } _ => panic!(), } diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 1c36d5e82da7b..d677530260fdb 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -8,7 +8,7 @@ use rustc_ast as ast; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::svh::Svh; -use rustc_data_structures::sync::{AppendOnlyVec, Lock, Lrc, OnceCell}; +use rustc_data_structures::sync::{AppendOnlyVec, AtomicBool, Lock, Lrc, OnceCell}; use rustc_data_structures::unhash::UnhashMap; use rustc_expand::base::{SyntaxExtension, SyntaxExtensionKind}; use rustc_expand::proc_macro::{AttrProcMacro, BangProcMacro, DeriveProcMacro}; @@ -38,6 +38,7 @@ use proc_macro::bridge::client::ProcMacro; use std::iter::TrustedLen; use std::num::NonZeroUsize; use std::path::Path; +use std::sync::atomic::Ordering; use std::{io, iter, mem}; pub(super) use cstore_impl::provide; @@ -109,9 +110,10 @@ pub(crate) struct CrateMetadata { dep_kind: Lock, /// Filesystem location of this crate. source: Lrc, - /// Whether or not this crate should be consider a private dependency - /// for purposes of the 'exported_private_dependencies' lint - private_dep: bool, + /// Whether or not this crate should be consider a private dependency. + /// Used by the 'exported_private_dependencies' lint, and for determining + /// whether to emit suggestions that reference this crate. + private_dep: AtomicBool, /// The hash for the host proc macro. Used to support `-Z dual-proc-macro`. host_hash: Option, @@ -692,12 +694,13 @@ impl MetadataBlob { writeln!(out, "=External Dependencies=")?; for (i, dep) in root.crate_deps.decode(self).enumerate() { - let CrateDep { name, extra_filename, hash, host_hash, kind } = dep; + let CrateDep { name, extra_filename, hash, host_hash, kind, is_private } = dep; let number = i + 1; writeln!( out, - "{number} {name}{extra_filename} hash {hash} host_hash {host_hash:?} kind {kind:?}" + "{number} {name}{extra_filename} hash {hash} host_hash {host_hash:?} kind {kind:?} {privacy}", + privacy = if is_private { "private" } else { "public" } )?; } write!(out, "\n")?; @@ -1627,7 +1630,7 @@ impl CrateMetadata { dependencies, dep_kind: Lock::new(dep_kind), source: Lrc::new(source), - private_dep, + private_dep: AtomicBool::new(private_dep), host_hash, extern_crate: Lock::new(None), hygiene_context: Default::default(), @@ -1675,6 +1678,10 @@ impl CrateMetadata { self.dep_kind.with_lock(|dep_kind| *dep_kind = f(*dep_kind)) } + pub(crate) fn update_and_private_dep(&self, private_dep: bool) { + self.private_dep.fetch_and(private_dep, Ordering::SeqCst); + } + pub(crate) fn required_panic_strategy(&self) -> Option { self.root.required_panic_strategy } diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 4a3b783c63670..7834f05a250e1 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -286,7 +286,13 @@ provide! { tcx, def_id, other, cdata, is_ctfe_mir_available => { cdata.is_ctfe_mir_available(def_id.index) } dylib_dependency_formats => { cdata.get_dylib_dependency_formats(tcx) } - is_private_dep => { cdata.private_dep } + is_private_dep => { + // Parallel compiler needs to synchronize type checking and linting (which use this flag) + // so that they happen strictly crate loading. Otherwise, the full list of available + // impls aren't loaded yet. + use std::sync::atomic::Ordering; + cdata.private_dep.load(Ordering::Acquire) + } is_panic_runtime => { cdata.root.panic_runtime } is_compiler_builtins => { cdata.root.compiler_builtins } has_global_allocator => { cdata.root.has_global_allocator } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 8a643b35f1555..fe4aa6aadef95 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1869,6 +1869,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { host_hash: self.tcx.crate_host_hash(cnum), kind: self.tcx.dep_kind(cnum), extra_filename: self.tcx.extra_filename(cnum).clone(), + is_private: self.tcx.is_private_dep(cnum), }; (cnum, dep) }) diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 1328d70021047..05f676783c25d 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -302,6 +302,7 @@ pub(crate) struct CrateDep { pub host_hash: Option, pub kind: CrateDepKind, pub extra_filename: String, + pub is_private: bool, } #[derive(MetadataEncodable, MetadataDecodable)] diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 9bab693156b3d..2cbdf127ee7e9 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -14,7 +14,7 @@ use rustc_data_structures::stable_hasher::{Hash64, HashStable, StableHasher}; use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind, Res}; -use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_hir::def_id::{CrateNum, DefId, LocalDefId}; use rustc_index::bit_set::GrowableBitSet; use rustc_index::{Idx, IndexVec}; use rustc_macros::HashStable; @@ -820,6 +820,26 @@ impl<'tcx> TyCtxt<'tcx> { _ => def_kind.article(), } } + + /// Return `true` if the supplied `CrateNum` is "user-visible," meaning either a [public] + /// dependency, or a [direct] private dependency. This is used to decide whether the crate can + /// be shown in `impl` suggestions. + /// + /// [public]: TyCtxt::is_private_dep + /// [direct]: rustc_session::cstore::ExternCrate::is_direct + pub fn is_user_visible_dep(self, key: CrateNum) -> bool { + // | Private | Direct | Visible | | + // |---------|--------|---------|--------------------| + // | Yes | Yes | Yes | !true || true | + // | No | Yes | Yes | !false || true | + // | Yes | No | No | !true || false | + // | No | No | Yes | !false || false | + !self.is_private_dep(key) + // If `extern_crate` is `None`, then the crate was injected (e.g., by the allocator). + // Treat that kind of crate as "indirect", since it's an implementation detail of + // the language. + || self.extern_crate(key.as_def_id()).map_or(false, |e| e.is_direct()) + } } struct OpaqueTypeExpander<'tcx> { diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index f5f2fe5421788..bf1b890358e56 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -1775,6 +1775,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { || !trait_pred .skip_binder() .is_constness_satisfied_by(self.tcx.constness(def_id)) + || !self.tcx.is_user_visible_dep(def_id.krate) { return None; } diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index 1454b00255650..95c32e82408cc 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -1,3 +1,5 @@ +cargo-features = ["public-dependency"] + [package] name = "std" version = "0.0.0" @@ -10,12 +12,12 @@ edition = "2021" crate-type = ["dylib", "rlib"] [dependencies] -alloc = { path = "../alloc" } +alloc = { path = "../alloc", public = true } cfg-if = { version = "1.0", features = ['rustc-dep-of-std'] } panic_unwind = { path = "../panic_unwind", optional = true } panic_abort = { path = "../panic_abort" } -core = { path = "../core" } -libc = { version = "0.2.143", default-features = false, features = ['rustc-dep-of-std'] } +core = { path = "../core", public = true } +libc = { version = "0.2.143", default-features = false, features = ['rustc-dep-of-std'], public = true } compiler_builtins = { version = "0.1.91" } profiler_builtins = { path = "../profiler_builtins", optional = true } unwind = { path = "../unwind" } @@ -25,7 +27,7 @@ std_detect = { path = "../stdarch/crates/std_detect", default-features = false, # Dependencies of the `backtrace` crate addr2line = { version = "0.19.0", optional = true, default-features = false } rustc-demangle = { version = "0.1.21", features = ['rustc-dep-of-std'] } -miniz_oxide = { version = "0.6.0", optional = true, default-features = false } +miniz_oxide = { version = "0.6.0", optional = true, default-features = false, public = false } [dependencies.object] version = "0.30.0" optional = true diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs index 6d59266b6f838..a6a370409c0e2 100644 --- a/library/std/src/panicking.rs +++ b/library/std/src/panicking.rs @@ -298,8 +298,18 @@ pub mod panic_count { pub const ALWAYS_ABORT_FLAG: usize = 1 << (usize::BITS - 1); - // Panic count for the current thread. - thread_local! { static LOCAL_PANIC_COUNT: Cell = const { Cell::new(0) } } + /// A reason for forcing an immediate abort on panic. + #[derive(Debug)] + pub enum MustAbort { + AlwaysAbort, + PanicInHook, + } + + // Panic count for the current thread and whether a panic hook is currently + // being executed.. + thread_local! { + static LOCAL_PANIC_COUNT: Cell<(usize, bool)> = const { Cell::new((0, false)) } + } // Sum of panic counts from all threads. The purpose of this is to have // a fast path in `count_is_zero` (which is used by `panicking`). In any particular @@ -328,34 +338,39 @@ pub mod panic_count { // panicking thread consumes at least 2 bytes of address space. static GLOBAL_PANIC_COUNT: AtomicUsize = AtomicUsize::new(0); - // Return the state of the ALWAYS_ABORT_FLAG and number of panics. + // Increases the global and local panic count, and returns whether an + // immediate abort is required. // - // If ALWAYS_ABORT_FLAG is not set, the number is determined on a per-thread - // base (stored in LOCAL_PANIC_COUNT), i.e. it is the amount of recursive calls - // of the calling thread. - // If ALWAYS_ABORT_FLAG is set, the number equals the *global* number of panic - // calls. See above why LOCAL_PANIC_COUNT is not used. - pub fn increase() -> (bool, usize) { + // This also updates thread-local state to keep track of whether a panic + // hook is currently executing. + pub fn increase(run_panic_hook: bool) -> Option { let global_count = GLOBAL_PANIC_COUNT.fetch_add(1, Ordering::Relaxed); - let must_abort = global_count & ALWAYS_ABORT_FLAG != 0; - let panics = if must_abort { - global_count & !ALWAYS_ABORT_FLAG - } else { - LOCAL_PANIC_COUNT.with(|c| { - let next = c.get() + 1; - c.set(next); - next - }) - }; - (must_abort, panics) + if global_count & ALWAYS_ABORT_FLAG != 0 { + return Some(MustAbort::AlwaysAbort); + } + + LOCAL_PANIC_COUNT.with(|c| { + let (count, in_panic_hook) = c.get(); + if in_panic_hook { + return Some(MustAbort::PanicInHook); + } + c.set((count + 1, run_panic_hook)); + None + }) + } + + pub fn finished_panic_hook() { + LOCAL_PANIC_COUNT.with(|c| { + let (count, _) = c.get(); + c.set((count, false)); + }); } pub fn decrease() { GLOBAL_PANIC_COUNT.fetch_sub(1, Ordering::Relaxed); LOCAL_PANIC_COUNT.with(|c| { - let next = c.get() - 1; - c.set(next); - next + let (count, _) = c.get(); + c.set((count - 1, false)); }); } @@ -366,7 +381,7 @@ pub mod panic_count { // Disregards ALWAYS_ABORT_FLAG #[must_use] pub fn get_count() -> usize { - LOCAL_PANIC_COUNT.with(|c| c.get()) + LOCAL_PANIC_COUNT.with(|c| c.get().0) } // Disregards ALWAYS_ABORT_FLAG @@ -394,7 +409,7 @@ pub mod panic_count { #[inline(never)] #[cold] fn is_zero_slow_path() -> bool { - LOCAL_PANIC_COUNT.with(|c| c.get() == 0) + LOCAL_PANIC_COUNT.with(|c| c.get().0 == 0) } } @@ -655,23 +670,22 @@ fn rust_panic_with_hook( location: &Location<'_>, can_unwind: bool, ) -> ! { - let (must_abort, panics) = panic_count::increase(); - - // If this is the third nested call (e.g., panics == 2, this is 0-indexed), - // the panic hook probably triggered the last panic, otherwise the - // double-panic check would have aborted the process. In this case abort the - // process real quickly as we don't want to try calling it again as it'll - // probably just panic again. - if must_abort || panics > 2 { - if panics > 2 { - // Don't try to print the message in this case - // - perhaps that is causing the recursive panics. - rtprintpanic!("thread panicked while processing panic. aborting.\n"); - } else { - // Unfortunately, this does not print a backtrace, because creating - // a `Backtrace` will allocate, which we must to avoid here. - let panicinfo = PanicInfo::internal_constructor(message, location, can_unwind); - rtprintpanic!("{panicinfo}\npanicked after panic::always_abort(), aborting.\n"); + let must_abort = panic_count::increase(true); + + // Check if we need to abort immediately. + if let Some(must_abort) = must_abort { + match must_abort { + panic_count::MustAbort::PanicInHook => { + // Don't try to print the message in this case + // - perhaps that is causing the recursive panics. + rtprintpanic!("thread panicked while processing panic. aborting.\n"); + } + panic_count::MustAbort::AlwaysAbort => { + // Unfortunately, this does not print a backtrace, because creating + // a `Backtrace` will allocate, which we must to avoid here. + let panicinfo = PanicInfo::internal_constructor(message, location, can_unwind); + rtprintpanic!("{panicinfo}\npanicked after panic::always_abort(), aborting.\n"); + } } crate::sys::abort_internal(); } @@ -697,16 +711,16 @@ fn rust_panic_with_hook( }; drop(hook); - if panics > 1 || !can_unwind { - // If a thread panics while it's already unwinding then we - // have limited options. Currently our preference is to - // just abort. In the future we may consider resuming - // unwinding or otherwise exiting the thread cleanly. - if !can_unwind { - rtprintpanic!("thread caused non-unwinding panic. aborting.\n"); - } else { - rtprintpanic!("thread panicked while panicking. aborting.\n"); - } + // Indicate that we have finished executing the panic hook. After this point + // it is fine if there is a panic while executing destructors, as long as it + // it contained within a `catch_unwind`. + panic_count::finished_panic_hook(); + + if !can_unwind { + // If a thread panics while running destructors or tries to unwind + // through a nounwind function (e.g. extern "C") then we cannot continue + // unwinding and have to abort immediately. + rtprintpanic!("thread caused non-unwinding panic. aborting.\n"); crate::sys::abort_internal(); } @@ -716,7 +730,7 @@ fn rust_panic_with_hook( /// This is the entry point for `resume_unwind`. /// It just forwards the payload to the panic runtime. pub fn rust_panic_without_hook(payload: Box) -> ! { - panic_count::increase(); + panic_count::increase(false); struct RewrapBox(Box); diff --git a/library/std/src/sync/mpmc/error.rs b/library/std/src/sync/mpmc/error.rs index 1b8a1f387974d..33b2bff853498 100644 --- a/library/std/src/sync/mpmc/error.rs +++ b/library/std/src/sync/mpmc/error.rs @@ -35,7 +35,7 @@ impl fmt::Display for SendTimeoutError { } } -impl error::Error for SendTimeoutError {} +impl error::Error for SendTimeoutError {} impl From> for SendTimeoutError { fn from(err: SendError) -> SendTimeoutError { diff --git a/library/std/src/sync/mpsc/mod.rs b/library/std/src/sync/mpsc/mod.rs index 6e3c28f10bb1b..0e0c87d1c748e 100644 --- a/library/std/src/sync/mpsc/mod.rs +++ b/library/std/src/sync/mpsc/mod.rs @@ -1124,7 +1124,7 @@ impl fmt::Display for SendError { } #[stable(feature = "rust1", since = "1.0.0")] -impl error::Error for SendError { +impl error::Error for SendError { #[allow(deprecated)] fn description(&self) -> &str { "sending on a closed channel" @@ -1152,7 +1152,7 @@ impl fmt::Display for TrySendError { } #[stable(feature = "rust1", since = "1.0.0")] -impl error::Error for TrySendError { +impl error::Error for TrySendError { #[allow(deprecated)] fn description(&self) -> &str { match *self { diff --git a/library/std/tests/common/mod.rs b/library/std/tests/common/mod.rs index fce220223a055..358c2c3f9b2f3 100644 --- a/library/std/tests/common/mod.rs +++ b/library/std/tests/common/mod.rs @@ -20,15 +20,15 @@ pub(crate) fn test_rng() -> rand_xorshift::XorShiftRng { } // Copied from std::sys_common::io -pub struct TempDir(PathBuf); +pub(crate) struct TempDir(PathBuf); impl TempDir { - pub fn join(&self, path: &str) -> PathBuf { + pub(crate) fn join(&self, path: &str) -> PathBuf { let TempDir(ref p) = *self; p.join(path) } - pub fn path(&self) -> &Path { + pub(crate) fn path(&self) -> &Path { let TempDir(ref p) = *self; p } @@ -49,7 +49,7 @@ impl Drop for TempDir { } #[track_caller] // for `test_rng` -pub fn tmpdir() -> TempDir { +pub(crate) fn tmpdir() -> TempDir { let p = env::temp_dir(); let mut r = test_rng(); let ret = p.join(&format!("rust-{}", r.next_u32())); diff --git a/src/bootstrap/metadata.rs b/src/bootstrap/metadata.rs index 8f2c3faca3a48..3b20ceac8759f 100644 --- a/src/bootstrap/metadata.rs +++ b/src/bootstrap/metadata.rs @@ -74,6 +74,9 @@ fn workspace_members(build: &Build) -> impl Iterator { let collect_metadata = |manifest_path| { let mut cargo = Command::new(&build.initial_cargo); cargo + // Will read the libstd Cargo.toml + // which uses the unstable `public-dependency` feature. + .env("RUSTC_BOOTSTRAP", "1") .arg("metadata") .arg("--format-version") .arg("1") diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 9059a145b4345..ba68b5ee9d5b4 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -428,7 +428,6 @@ impl TargetCfgs { )) .unwrap(); - let mut current = None; let mut all_targets = HashSet::new(); let mut all_archs = HashSet::new(); let mut all_oses = HashSet::new(); @@ -449,14 +448,11 @@ impl TargetCfgs { } all_pointer_widths.insert(format!("{}bit", cfg.pointer_width)); - if target == config.target { - current = Some(cfg); - } all_targets.insert(target.into()); } Self { - current: current.expect("current target not found"), + current: Self::get_current_target_config(config), all_targets, all_archs, all_oses, @@ -467,6 +463,89 @@ impl TargetCfgs { all_pointer_widths, } } + + fn get_current_target_config(config: &Config) -> TargetCfg { + let mut arch = None; + let mut os = None; + let mut env = None; + let mut abi = None; + let mut families = Vec::new(); + let mut pointer_width = None; + let mut endian = None; + let mut panic = None; + + for config in + rustc_output(config, &["--print=cfg", "--target", &config.target]).trim().lines() + { + let (name, value) = config + .split_once("=\"") + .map(|(name, value)| { + ( + name, + Some( + value + .strip_suffix("\"") + .expect("key-value pair should be properly quoted"), + ), + ) + }) + .unwrap_or_else(|| (config, None)); + + match name { + "target_arch" => { + arch = Some(value.expect("target_arch should be a key-value pair").to_string()); + } + "target_os" => { + os = Some(value.expect("target_os sould be a key-value pair").to_string()); + } + "target_env" => { + env = Some(value.expect("target_env should be a key-value pair").to_string()); + } + "target_abi" => { + abi = Some(value.expect("target_abi should be a key-value pair").to_string()); + } + "target_family" => { + families + .push(value.expect("target_family should be a key-value pair").to_string()); + } + "target_pointer_width" => { + pointer_width = Some( + value + .expect("target_pointer_width should be a key-value pair") + .parse::() + .expect("target_pointer_width should be a valid u32"), + ); + } + "target_endian" => { + endian = Some(match value.expect("target_endian should be a key-value pair") { + "big" => Endian::Big, + "little" => Endian::Little, + _ => panic!("target_endian should be either 'big' or 'little'"), + }); + } + "panic" => { + panic = Some(match value.expect("panic should be a key-value pair") { + "abort" => PanicStrategy::Abort, + "unwind" => PanicStrategy::Unwind, + _ => panic!("panic should be either 'abort' or 'unwind'"), + }); + } + _ => (), + } + } + + TargetCfg { + arch: arch.expect("target configuration should specify target_arch"), + os: os.expect("target configuration should specify target_os"), + env: env.expect("target configuration should specify target_env"), + abi: abi.expect("target configuration should specify target_abi"), + families, + pointer_width: pointer_width + .expect("target configuration should specify target_pointer_width"), + endian: endian.expect("target configuration should specify target_endian"), + panic: panic.expect("target configuration should specify panic"), + } + } } #[derive(Clone, Debug, serde::Deserialize)] diff --git a/src/tools/miri/src/concurrency/thread.rs b/src/tools/miri/src/concurrency/thread.rs index e9bbae4d50488..597fb314a12d6 100644 --- a/src/tools/miri/src/concurrency/thread.rs +++ b/src/tools/miri/src/concurrency/thread.rs @@ -132,10 +132,15 @@ pub struct Thread<'mir, 'tcx> { /// The join status. join_status: ThreadJoinStatus, - /// The temporary used for storing the argument of - /// the call to `miri_start_panic` (the panic payload) when unwinding. + /// Stack of active panic payloads for the current thread. Used for storing + /// the argument of the call to `miri_start_panic` (the panic payload) when unwinding. /// This is pointer-sized, and matches the `Payload` type in `src/libpanic_unwind/miri.rs`. - pub(crate) panic_payload: Option>, + /// + /// In real unwinding, the payload gets passed as an argument to the landing pad, + /// which then forwards it to 'Resume'. However this argument is implicit in MIR, + /// so we have to store it out-of-band. When there are multiple active unwinds, + /// the innermost one is always caught first, so we can store them as a stack. + pub(crate) panic_payloads: Vec>, /// Last OS error location in memory. It is a 32-bit integer. pub(crate) last_error: Option>, @@ -205,7 +210,7 @@ impl<'mir, 'tcx> Thread<'mir, 'tcx> { stack: Vec::new(), top_user_relevant_frame: None, join_status: ThreadJoinStatus::Joinable, - panic_payload: None, + panic_payloads: Vec::new(), last_error: None, on_stack_empty, } @@ -215,7 +220,7 @@ impl<'mir, 'tcx> Thread<'mir, 'tcx> { impl VisitTags for Thread<'_, '_> { fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) { let Thread { - panic_payload, + panic_payloads: panic_payload, last_error, stack, top_user_relevant_frame: _, @@ -225,7 +230,9 @@ impl VisitTags for Thread<'_, '_> { on_stack_empty: _, // we assume the closure captures no GC-relevant state } = self; - panic_payload.visit_tags(visit); + for payload in panic_payload { + payload.visit_tags(visit); + } last_error.visit_tags(visit); for frame in stack { frame.visit_tags(visit) diff --git a/src/tools/miri/src/shims/panic.rs b/src/tools/miri/src/shims/panic.rs index 18ae01a19f914..7aefdfcb976af 100644 --- a/src/tools/miri/src/shims/panic.rs +++ b/src/tools/miri/src/shims/panic.rs @@ -63,8 +63,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let [payload] = this.check_shim(abi, Abi::Rust, link_name, args)?; let payload = this.read_scalar(payload)?; let thread = this.active_thread_mut(); - assert!(thread.panic_payload.is_none(), "the panic runtime should avoid double-panics"); - thread.panic_payload = Some(payload); + thread.panic_payloads.push(payload); // Jump to the unwind block to begin unwinding. this.unwind_to_block(unwind)?; @@ -146,7 +145,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { // The Thread's `panic_payload` holds what was passed to `miri_start_panic`. // This is exactly the second argument we need to pass to `catch_fn`. - let payload = this.active_thread_mut().panic_payload.take().unwrap(); + let payload = this.active_thread_mut().panic_payloads.pop().unwrap(); // Push the `catch_fn` stackframe. let f_instance = this.get_ptr_fn(catch_unwind.catch_fn)?.as_instance()?; diff --git a/src/tools/miri/tests/fail/panic/double_panic.rs b/src/tools/miri/tests/fail/panic/double_panic.rs index 9378adb8609df..adb30714269e8 100644 --- a/src/tools/miri/tests/fail/panic/double_panic.rs +++ b/src/tools/miri/tests/fail/panic/double_panic.rs @@ -1,6 +1,4 @@ -//@error-in-other-file: the program aborted //@normalize-stderr-test: "\| +\^+" -> "| ^" -//@normalize-stderr-test: "unsafe \{ libc::abort\(\) \}|crate::intrinsics::abort\(\);" -> "ABORT();" //@normalize-stderr-test: "\n +[0-9]+:[^\n]+" -> "$1" //@normalize-stderr-test: "\n at [^\n]+" -> "$1" @@ -11,6 +9,7 @@ impl Drop for Foo { } } fn main() { + //~^ERROR: panic in a function that cannot unwind let _foo = Foo; panic!("first"); } diff --git a/src/tools/miri/tests/fail/panic/double_panic.stderr b/src/tools/miri/tests/fail/panic/double_panic.stderr index 77d5fc5d7ceb9..b6ac56f15d4b5 100644 --- a/src/tools/miri/tests/fail/panic/double_panic.stderr +++ b/src/tools/miri/tests/fail/panic/double_panic.stderr @@ -2,30 +2,17 @@ thread 'main' panicked at 'first', $DIR/double_panic.rs:LL:CC note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace thread 'main' panicked at 'second', $DIR/double_panic.rs:LL:CC stack backtrace: -thread panicked while panicking. aborting. -error: abnormal termination: the program aborted execution - --> RUSTLIB/std/src/sys/PLATFORM/mod.rs:LL:CC - | -LL | ABORT(); - | ^ the program aborted execution - | - = note: inside `std::sys::PLATFORM::abort_internal` at RUSTLIB/std/src/sys/PLATFORM/mod.rs:LL:CC - = note: inside `std::panicking::rust_panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC - = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC - = note: inside `std::sys_common::backtrace::__rust_end_short_backtrace::<[closure@std::panicking::begin_panic_handler::{closure#0}], !>` at RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC - = note: inside `std::panicking::begin_panic_handler` at RUSTLIB/std/src/panicking.rs:LL:CC -note: inside `::drop` +error: abnormal termination: panic in a function that cannot unwind --> $DIR/double_panic.rs:LL:CC | -LL | panic!("second"); - | ^ - = note: inside `std::ptr::drop_in_place:: - shim(Some(Foo))` at RUSTLIB/core/src/ptr/mod.rs:LL:CC -note: inside `main` - --> $DIR/double_panic.rs:LL:CC +LL | / fn main() { +LL | | +LL | | let _foo = Foo; +LL | | panic!("first"); +LL | | } + | |_^ panic in a function that cannot unwind | -LL | } - | ^ - = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: inside `main` at $DIR/double_panic.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/pass/panic/nested_panic_caught.rs b/src/tools/miri/tests/pass/panic/nested_panic_caught.rs new file mode 100644 index 0000000000000..884813150ad2a --- /dev/null +++ b/src/tools/miri/tests/pass/panic/nested_panic_caught.rs @@ -0,0 +1,25 @@ +//@normalize-stderr-test: "\| +\^+" -> "| ^" +//@normalize-stderr-test: "\n +[0-9]+:[^\n]+" -> "$1" +//@normalize-stderr-test: "\n at [^\n]+" -> "$1" + +// Checks that nested panics work correctly. + +use std::panic::catch_unwind; + +fn double() { + struct Double; + + impl Drop for Double { + fn drop(&mut self) { + let _ = catch_unwind(|| panic!("twice")); + } + } + + let _d = Double; + + panic!("once"); +} + +fn main() { + assert!(catch_unwind(|| double()).is_err()); +} diff --git a/src/tools/miri/tests/pass/panic/nested_panic_caught.stderr b/src/tools/miri/tests/pass/panic/nested_panic_caught.stderr new file mode 100644 index 0000000000000..4e2593242df75 --- /dev/null +++ b/src/tools/miri/tests/pass/panic/nested_panic_caught.stderr @@ -0,0 +1,4 @@ +thread 'main' panicked at 'once', $DIR/nested_panic_caught.rs:LL:CC +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace +thread 'main' panicked at 'twice', $DIR/nested_panic_caught.rs:LL:CC +stack backtrace: diff --git a/src/tools/rust-installer/combine-installers.sh b/src/tools/rust-installer/combine-installers.sh index bee5319fd5502..01e5a00af4a23 100755 --- a/src/tools/rust-installer/combine-installers.sh +++ b/src/tools/rust-installer/combine-installers.sh @@ -11,5 +11,9 @@ abs_path() { (unset CDPATH && cd "$path" > /dev/null && pwd) } +# Running cargo will read the libstd Cargo.toml +# which uses the unstable `public-dependency` feature. +export RUSTC_BOOTSTRAP=1 + src_dir="$(abs_path $(dirname "$0"))" $CARGO run --manifest-path="$src_dir/Cargo.toml" -- combine "$@" diff --git a/src/tools/rust-installer/gen-installer.sh b/src/tools/rust-installer/gen-installer.sh index eabd8c95cd849..cc45b5e0803f7 100755 --- a/src/tools/rust-installer/gen-installer.sh +++ b/src/tools/rust-installer/gen-installer.sh @@ -11,5 +11,9 @@ abs_path() { (unset CDPATH && cd "$path" > /dev/null && pwd) } +# Running cargo will read the libstd Cargo.toml +# which uses the unstable `public-dependency` feature. +export RUSTC_BOOTSTRAP=1 + src_dir="$(abs_path $(dirname "$0"))" $CARGO run --manifest-path="$src_dir/Cargo.toml" -- generate "$@" diff --git a/src/tools/rust-installer/make-tarballs.sh b/src/tools/rust-installer/make-tarballs.sh index e342007da373c..374e103e89ca6 100755 --- a/src/tools/rust-installer/make-tarballs.sh +++ b/src/tools/rust-installer/make-tarballs.sh @@ -11,5 +11,9 @@ abs_path() { (unset CDPATH && cd "$path" > /dev/null && pwd) } +# Running cargo will read the libstd Cargo.toml +# which uses the unstable `public-dependency` feature. +export RUSTC_BOOTSTRAP=1 + src_dir="$(abs_path $(dirname "$0"))" $CARGO run --manifest-path="$src_dir/Cargo.toml" -- tarball "$@" diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs index f59406c404bab..a9eada22fc02f 100644 --- a/src/tools/tidy/src/main.rs +++ b/src/tools/tidy/src/main.rs @@ -16,6 +16,12 @@ use std::sync::atomic::{AtomicBool, Ordering}; use std::thread::{self, scope, ScopedJoinHandle}; fn main() { + // Running Cargo will read the libstd Cargo.toml + // which uses the unstable `public-dependency` feature. + // + // `setenv` might not be thread safe, so run it before using multiple threads. + env::set_var("RUSTC_BOOTSTRAP", "1"); + let root_path: PathBuf = env::args_os().nth(1).expect("need path to root of repo").into(); let cargo: PathBuf = env::args_os().nth(2).expect("need path to cargo").into(); let output_directory: PathBuf = diff --git a/tests/ui/backtrace.rs b/tests/ui/backtrace.rs index dd73dd9886a3b..66b378f62d63c 100644 --- a/tests/ui/backtrace.rs +++ b/tests/ui/backtrace.rs @@ -104,13 +104,17 @@ fn runtest(me: &str) { "bad output3: {}", s); // Make sure a stack trace isn't printed too many times + // + // Currently it is printed 3 times ("once", "twice" and "panic in a + // function that cannot unwind") but in the future the last one may be + // removed. let p = template(me).arg("double-fail") .env("RUST_BACKTRACE", "1").spawn().unwrap(); let out = p.wait_with_output().unwrap(); assert!(!out.status.success()); let s = str::from_utf8(&out.stderr).unwrap(); let mut i = 0; - for _ in 0..2 { + for _ in 0..3 { i += s[i + 10..].find("stack backtrace").unwrap() + 10; } assert!(s[i + 10..].find("stack backtrace").is_none(), diff --git a/tests/ui/panics/nested_panic_caught.rs b/tests/ui/panics/nested_panic_caught.rs new file mode 100644 index 0000000000000..c210aa512322e --- /dev/null +++ b/tests/ui/panics/nested_panic_caught.rs @@ -0,0 +1,23 @@ +// run-pass + +// Checks that nested panics work correctly. + +use std::panic::catch_unwind; + +fn double() { + struct Double; + + impl Drop for Double { + fn drop(&mut self) { + let _ = catch_unwind(|| panic!("twice")); + } + } + + let _d = Double; + + panic!("once"); +} + +fn main() { + assert!(catch_unwind(|| double()).is_err()); +} diff --git a/tests/ui/suggestions/issue-88696.rs b/tests/ui/suggestions/issue-88696.rs new file mode 100644 index 0000000000000..745fdef154632 --- /dev/null +++ b/tests/ui/suggestions/issue-88696.rs @@ -0,0 +1,14 @@ +// This test case should ensure that miniz_oxide isn't +// suggested, since it's not a direct dependency. + +fn a() -> Result { + Err(1) +} + +fn b() -> Result { + a().into() //~ERROR [E0277] +} + +fn main() { + let _ = dbg!(b()); +} diff --git a/tests/ui/suggestions/issue-88696.stderr b/tests/ui/suggestions/issue-88696.stderr new file mode 100644 index 0000000000000..4947269d75934 --- /dev/null +++ b/tests/ui/suggestions/issue-88696.stderr @@ -0,0 +1,11 @@ +error[E0277]: the trait bound `Result: From>` is not satisfied + --> $DIR/issue-88696.rs:9:9 + | +LL | a().into() + | ^^^^ the trait `From>` is not implemented for `Result` + | + = note: required for `Result` to implement `Into>` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/triagebot.toml b/triagebot.toml index 54c8b2060c526..2e83ef202cf99 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -532,6 +532,7 @@ bootstrap = [ "@Mark-Simulacrum", "@albertlarsan68", "@ozkanonur", + "@clubby789", ] infra-ci = [ "@Mark-Simulacrum",