diff options
103 files changed, 978 insertions, 538 deletions
diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index c4771115cac..e6c4db9e2ae 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -10,15 +10,10 @@ use crate::tokenstream::{DelimSpan, Spacing, TokenTree}; use crate::tokenstream::{LazyAttrTokenStream, TokenStream}; use crate::util::comments; use crate::util::literal::escape_string_symbol; -use rustc_data_structures::sync::WorkerLocal; use rustc_index::bit_set::GrowableBitSet; use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::Span; -use std::cell::Cell; use std::iter; -#[cfg(debug_assertions)] -use std::ops::BitXor; -#[cfg(debug_assertions)] use std::sync::atomic::{AtomicU32, Ordering}; use thin_vec::{thin_vec, ThinVec}; @@ -40,39 +35,16 @@ impl MarkedAttrs { } } -pub struct AttrIdGenerator(WorkerLocal<Cell<u32>>); - -#[cfg(debug_assertions)] -static MAX_ATTR_ID: AtomicU32 = AtomicU32::new(u32::MAX); +pub struct AttrIdGenerator(AtomicU32); impl AttrIdGenerator { pub fn new() -> Self { - // We use `(index as u32).reverse_bits()` to initialize the - // starting value of AttrId in each worker thread. - // The `index` is the index of the worker thread. - // This ensures that the AttrId generated in each thread is unique. - AttrIdGenerator(WorkerLocal::new(|index| { - let index: u32 = index.try_into().unwrap(); - - #[cfg(debug_assertions)] - { - let max_id = ((index + 1).next_power_of_two() - 1).bitxor(u32::MAX).reverse_bits(); - MAX_ATTR_ID.fetch_min(max_id, Ordering::Release); - } - - Cell::new(index.reverse_bits()) - })) + AttrIdGenerator(AtomicU32::new(0)) } pub fn mk_attr_id(&self) -> AttrId { - let id = self.0.get(); - - // Ensure the assigned attr_id does not overlap the bits - // representing the number of threads. - #[cfg(debug_assertions)] - assert!(id <= MAX_ATTR_ID.load(Ordering::Acquire)); - - self.0.set(id + 1); + let id = self.0.fetch_add(1, Ordering::Relaxed); + assert!(id != u32::MAX); AttrId::from_u32(id) } } diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 6863100d9ba..7a0a7da9695 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -858,13 +858,8 @@ impl<'hir> LoweringContext<'_, 'hir> { let awaitee_arm = self.arm(awaitee_pat, loop_expr); // `match ::std::future::IntoFuture::into_future(<expr>) { ... }` - let into_future_span = self.mark_span_with_reason( - DesugaringKind::Await, - dot_await_span, - self.allow_into_future.clone(), - ); let into_future_expr = self.expr_call_lang_item_fn( - into_future_span, + span, hir::LangItem::IntoFutureIntoFuture, arena_vec![self; expr], Some(expr_hir_id), diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index a9fd8db281b..3d154a93fb2 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -83,7 +83,6 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> { impl_trait_bounds: Vec::new(), allow_try_trait: Some([sym::try_trait_v2, sym::yeet_desugar_details][..].into()), allow_gen_future: Some([sym::gen_future, sym::closure_track_caller][..].into()), - allow_into_future: Some([sym::into_future][..].into()), generics_def_id_map: Default::default(), }; lctx.with_hir_id_owner(owner, |lctx| f(lctx)); diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index d07355a4154..b5b28bf8e31 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -136,7 +136,6 @@ struct LoweringContext<'a, 'hir> { allow_try_trait: Option<Lrc<[Symbol]>>, allow_gen_future: Option<Lrc<[Symbol]>>, - allow_into_future: Option<Lrc<[Symbol]>>, /// Mapping from generics `def_id`s to TAIT generics `def_id`s. /// For each captured lifetime (e.g., 'a), we create a new lifetime parameter that is a generic diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs index 91c085d3d69..0b4d4ecf2e4 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs @@ -70,7 +70,7 @@ pub(crate) fn get_function_sig<'tcx>( default_call_conv: CallConv, inst: Instance<'tcx>, ) -> Signature { - assert!(!inst.substs.needs_infer()); + assert!(!inst.substs.has_infer()); clif_sig_from_fn_abi( tcx, default_call_conv, diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index 98ba23c6f57..c181c73e4be 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -28,7 +28,7 @@ pub(crate) fn codegen_fn<'tcx>( module: &mut dyn Module, instance: Instance<'tcx>, ) -> CodegenedFunction { - debug_assert!(!instance.substs.needs_infer()); + debug_assert!(!instance.substs.has_infer()); let symbol_name = tcx.symbol_name(instance).name.to_string(); let _timer = tcx.prof.generic_activity_with_arg("codegen fn", &*symbol_name); diff --git a/compiler/rustc_codegen_gcc/src/callee.rs b/compiler/rustc_codegen_gcc/src/callee.rs index ba1e8656208..433b2585f82 100644 --- a/compiler/rustc_codegen_gcc/src/callee.rs +++ b/compiler/rustc_codegen_gcc/src/callee.rs @@ -17,7 +17,7 @@ use crate::context::CodegenCx; pub fn get_fn<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, instance: Instance<'tcx>) -> Function<'gcc> { let tcx = cx.tcx(); - assert!(!instance.substs.needs_infer()); + assert!(!instance.substs.has_infer()); assert!(!instance.substs.has_escaping_bound_vars()); let sym = tcx.symbol_name(instance).name; diff --git a/compiler/rustc_codegen_gcc/src/mono_item.rs b/compiler/rustc_codegen_gcc/src/mono_item.rs index c1f6340866c..342b830cedb 100644 --- a/compiler/rustc_codegen_gcc/src/mono_item.rs +++ b/compiler/rustc_codegen_gcc/src/mono_item.rs @@ -31,7 +31,7 @@ impl<'gcc, 'tcx> PreDefineMethods<'tcx> for CodegenCx<'gcc, 'tcx> { #[cfg_attr(not(feature="master"), allow(unused_variables))] fn predefine_fn(&self, instance: Instance<'tcx>, linkage: Linkage, visibility: Visibility, symbol_name: &str) { - assert!(!instance.substs.needs_infer()); + assert!(!instance.substs.has_infer()); let fn_abi = self.fn_abi_of_instance(instance, ty::List::empty()); self.linkage.set(base::linkage_to_gcc(linkage)); diff --git a/compiler/rustc_codegen_llvm/src/callee.rs b/compiler/rustc_codegen_llvm/src/callee.rs index 6ee2a05ffd7..30a0cf1d019 100644 --- a/compiler/rustc_codegen_llvm/src/callee.rs +++ b/compiler/rustc_codegen_llvm/src/callee.rs @@ -27,7 +27,7 @@ pub fn get_fn<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'tcx>) -> debug!("get_fn(instance={:?})", instance); - assert!(!instance.substs.needs_infer()); + assert!(!instance.substs.has_infer()); assert!(!instance.substs.has_escaping_bound_vars()); if let Some(&llfn) = cx.instances.borrow().get(&instance) { diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs index 824cffa28ba..2e9f89f4196 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs @@ -515,7 +515,7 @@ impl<'ll, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { ty::Adt(def, ..) if !def.is_box() => { // Again, only create type information if full debuginfo is enabled if cx.sess().opts.debuginfo == DebugInfo::Full - && !impl_self_ty.needs_subst() + && !impl_self_ty.has_param() { Some(type_di_node(cx, impl_self_ty)) } else { diff --git a/compiler/rustc_codegen_llvm/src/mono_item.rs b/compiler/rustc_codegen_llvm/src/mono_item.rs index d0ae36349df..59bdc60830f 100644 --- a/compiler/rustc_codegen_llvm/src/mono_item.rs +++ b/compiler/rustc_codegen_llvm/src/mono_item.rs @@ -48,7 +48,7 @@ impl<'tcx> PreDefineMethods<'tcx> for CodegenCx<'_, 'tcx> { visibility: Visibility, symbol_name: &str, ) { - assert!(!instance.substs.needs_infer()); + assert!(!instance.substs.has_infer()); let fn_abi = self.fn_abi_of_instance(instance, ty::List::empty()); let lldecl = self.declare_fn(symbol_name, fn_abi); diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs index e4f04b83d58..f706ecea975 100644 --- a/compiler/rustc_codegen_ssa/src/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -152,7 +152,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( cx: &'a Bx::CodegenCx, instance: Instance<'tcx>, ) { - assert!(!instance.substs.needs_infer()); + assert!(!instance.substs.has_infer()); let llfn = cx.get_fn(instance); @@ -304,7 +304,17 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( bug!("spread argument isn't a tuple?!"); }; - let place = PlaceRef::alloca(bx, bx.layout_of(arg_ty)); + let layout = bx.layout_of(arg_ty); + + // FIXME: support unsized params in "rust-call" ABI + if layout.is_unsized() { + span_bug!( + arg_decl.source_info.span, + "\"rust-call\" ABI does not support unsized params", + ); + } + + let place = PlaceRef::alloca(bx, layout); for i in 0..tupled_arg_tys.len() { let arg = &fx.fn_abi.args[idx]; idx += 1; diff --git a/compiler/rustc_const_eval/src/interpret/util.rs b/compiler/rustc_const_eval/src/interpret/util.rs index 7cb19744987..22bdd4d2c3f 100644 --- a/compiler/rustc_const_eval/src/interpret/util.rs +++ b/compiler/rustc_const_eval/src/interpret/util.rs @@ -14,7 +14,7 @@ where T: TypeVisitable<TyCtxt<'tcx>>, { debug!("ensure_monomorphic_enough: ty={:?}", ty); - if !ty.needs_subst() { + if !ty.has_param() { return Ok(()); } @@ -27,7 +27,7 @@ where type BreakTy = FoundParam; fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { - if !ty.needs_subst() { + if !ty.has_param() { return ControlFlow::Continue(()); } @@ -46,7 +46,7 @@ where // are used and require substitution. // Just in case there are closures or generators within this subst, // recurse. - if unused_params.is_used(index) && subst.needs_subst() { + if unused_params.is_used(index) && subst.has_param() { return subst.visit_with(self); } } diff --git a/compiler/rustc_data_structures/src/sharded.rs b/compiler/rustc_data_structures/src/sharded.rs index bd7a86f6780..7ed70ba1e0f 100644 --- a/compiler/rustc_data_structures/src/sharded.rs +++ b/compiler/rustc_data_structures/src/sharded.rs @@ -1,14 +1,10 @@ use crate::fx::{FxHashMap, FxHasher}; -use crate::sync::{Lock, LockGuard}; +use crate::sync::{CacheAligned, Lock, LockGuard}; use std::borrow::Borrow; use std::collections::hash_map::RawEntryMut; use std::hash::{Hash, Hasher}; use std::mem; -#[derive(Default)] -#[cfg_attr(parallel_compiler, repr(align(64)))] -struct CacheAligned<T>(T); - #[cfg(parallel_compiler)] // 32 shards is sufficient to reduce contention on an 8-core Ryzen 7 1700, // but this should be tested on higher core count CPUs. How the `Sharded` type gets used diff --git a/compiler/rustc_data_structures/src/sync.rs b/compiler/rustc_data_structures/src/sync.rs index ef1da85198f..e73ca56efa0 100644 --- a/compiler/rustc_data_structures/src/sync.rs +++ b/compiler/rustc_data_structures/src/sync.rs @@ -45,6 +45,9 @@ use std::hash::{BuildHasher, Hash}; use std::ops::{Deref, DerefMut}; use std::panic::{catch_unwind, resume_unwind, AssertUnwindSafe}; +mod worker_local; +pub use worker_local::{Registry, WorkerLocal}; + pub use std::sync::atomic::Ordering; pub use std::sync::atomic::Ordering::SeqCst; @@ -205,33 +208,6 @@ cfg_if! { use std::cell::Cell; - #[derive(Debug)] - pub struct WorkerLocal<T>(OneThread<T>); - - impl<T> WorkerLocal<T> { - /// Creates a new worker local where the `initial` closure computes the - /// value this worker local should take for each thread in the thread pool. - #[inline] - pub fn new<F: FnMut(usize) -> T>(mut f: F) -> WorkerLocal<T> { - WorkerLocal(OneThread::new(f(0))) - } - - /// Returns the worker-local value for each thread - #[inline] - pub fn into_inner(self) -> Vec<T> { - vec![OneThread::into_inner(self.0)] - } - } - - impl<T> Deref for WorkerLocal<T> { - type Target = T; - - #[inline(always)] - fn deref(&self) -> &T { - &self.0 - } - } - pub type MTLockRef<'a, T> = &'a mut MTLock<T>; #[derive(Debug, Default)] @@ -351,8 +327,6 @@ cfg_if! { }; } - pub use rayon_core::WorkerLocal; - pub use rayon::iter::ParallelIterator; use rayon::iter::IntoParallelIterator; @@ -383,6 +357,10 @@ pub fn assert_send<T: ?Sized + Send>() {} pub fn assert_send_val<T: ?Sized + Send>(_t: &T) {} pub fn assert_send_sync_val<T: ?Sized + Sync + Send>(_t: &T) {} +#[derive(Default)] +#[cfg_attr(parallel_compiler, repr(align(64)))] +pub struct CacheAligned<T>(pub T); + pub trait HashMapExt<K, V> { /// Same as HashMap::insert, but it may panic if there's already an /// entry for `key` with a value not equal to `value` diff --git a/compiler/rustc_data_structures/src/sync/worker_local.rs b/compiler/rustc_data_structures/src/sync/worker_local.rs new file mode 100644 index 00000000000..bfb04ba8a73 --- /dev/null +++ b/compiler/rustc_data_structures/src/sync/worker_local.rs @@ -0,0 +1,180 @@ +use crate::sync::Lock; +use std::cell::Cell; +use std::cell::OnceCell; +use std::ops::Deref; +use std::ptr; +use std::sync::Arc; + +#[cfg(parallel_compiler)] +use {crate::cold_path, crate::sync::CacheAligned}; + +/// A pointer to the `RegistryData` which uniquely identifies a registry. +/// This identifier can be reused if the registry gets freed. +#[derive(Clone, Copy, PartialEq)] +struct RegistryId(*const RegistryData); + +impl RegistryId { + #[inline(always)] + /// Verifies that the current thread is associated with the registry and returns its unique + /// index within the registry. This panics if the current thread is not associated with this + /// registry. + /// + /// Note that there's a race possible where the identifer in `THREAD_DATA` could be reused + /// so this can succeed from a different registry. + #[cfg(parallel_compiler)] + fn verify(self) -> usize { + let (id, index) = THREAD_DATA.with(|data| (data.registry_id.get(), data.index.get())); + + if id == self { + index + } else { + cold_path(|| panic!("Unable to verify registry association")) + } + } +} + +struct RegistryData { + thread_limit: usize, + threads: Lock<usize>, +} + +/// Represents a list of threads which can access worker locals. +#[derive(Clone)] +pub struct Registry(Arc<RegistryData>); + +thread_local! { + /// The registry associated with the thread. + /// This allows the `WorkerLocal` type to clone the registry in its constructor. + static REGISTRY: OnceCell<Registry> = OnceCell::new(); +} + +struct ThreadData { + registry_id: Cell<RegistryId>, + index: Cell<usize>, +} + +thread_local! { + /// A thread local which contains the identifer of `REGISTRY` but allows for faster access. + /// It also holds the index of the current thread. + static THREAD_DATA: ThreadData = const { ThreadData { + registry_id: Cell::new(RegistryId(ptr::null())), + index: Cell::new(0), + }}; +} + +impl Registry { + /// Creates a registry which can hold up to `thread_limit` threads. + pub fn new(thread_limit: usize) -> Self { + Registry(Arc::new(RegistryData { thread_limit, threads: Lock::new(0) })) + } + + /// Gets the registry associated with the current thread. Panics if there's no such registry. + pub fn current() -> Self { + REGISTRY.with(|registry| registry.get().cloned().expect("No assocated registry")) + } + + /// Registers the current thread with the registry so worker locals can be used on it. + /// Panics if the thread limit is hit or if the thread already has an associated registry. + pub fn register(&self) { + let mut threads = self.0.threads.lock(); + if *threads < self.0.thread_limit { + REGISTRY.with(|registry| { + if registry.get().is_some() { + drop(threads); + panic!("Thread already has a registry"); + } + registry.set(self.clone()).ok(); + THREAD_DATA.with(|data| { + data.registry_id.set(self.id()); + data.index.set(*threads); + }); + *threads += 1; + }); + } else { + drop(threads); + panic!("Thread limit reached"); + } + } + + /// Gets the identifer of this registry. + fn id(&self) -> RegistryId { + RegistryId(&*self.0) + } +} + +/// Holds worker local values for each possible thread in a registry. You can only access the +/// worker local value through the `Deref` impl on the registry associated with the thread it was +/// created on. It will panic otherwise. +pub struct WorkerLocal<T> { + #[cfg(not(parallel_compiler))] + local: T, + #[cfg(parallel_compiler)] + locals: Box<[CacheAligned<T>]>, + #[cfg(parallel_compiler)] + registry: Registry, +} + +// This is safe because the `deref` call will return a reference to a `T` unique to each thread +// or it will panic for threads without an associated local. So there isn't a need for `T` to do +// it's own synchronization. The `verify` method on `RegistryId` has an issue where the the id +// can be reused, but `WorkerLocal` has a reference to `Registry` which will prevent any reuse. +#[cfg(parallel_compiler)] +unsafe impl<T: Send> Sync for WorkerLocal<T> {} + +impl<T> WorkerLocal<T> { + /// Creates a new worker local where the `initial` closure computes the + /// value this worker local should take for each thread in the registry. + #[inline] + pub fn new<F: FnMut(usize) -> T>(mut initial: F) -> WorkerLocal<T> { + #[cfg(parallel_compiler)] + { + let registry = Registry::current(); + WorkerLocal { + locals: (0..registry.0.thread_limit).map(|i| CacheAligned(initial(i))).collect(), + registry, + } + } + #[cfg(not(parallel_compiler))] + { + WorkerLocal { local: initial(0) } + } + } + + /// Returns the worker-local values for each thread + #[inline] + pub fn into_inner(self) -> impl Iterator<Item = T> { + #[cfg(parallel_compiler)] + { + self.locals.into_vec().into_iter().map(|local| local.0) + } + #[cfg(not(parallel_compiler))] + { + std::iter::once(self.local) + } + } +} + +impl<T> WorkerLocal<Vec<T>> { + /// Joins the elements of all the worker locals into one Vec + pub fn join(self) -> Vec<T> { + self.into_inner().into_iter().flat_map(|v| v).collect() + } +} + +impl<T> Deref for WorkerLocal<T> { + type Target = T; + + #[inline(always)] + #[cfg(not(parallel_compiler))] + fn deref(&self) -> &T { + &self.local + } + + #[inline(always)] + #[cfg(parallel_compiler)] + fn deref(&self) -> &T { + // This is safe because `verify` will only return values less than + // `self.registry.thread_limit` which is the size of the `self.locals` array. + unsafe { &self.locals.get_unchecked(self.registry.id().verify()).0 } + } +} diff --git a/compiler/rustc_data_structures/src/tagged_ptr/copy.rs b/compiler/rustc_data_structures/src/tagged_ptr/copy.rs index 691e92f196a..e893a2c7813 100644 --- a/compiler/rustc_data_structures/src/tagged_ptr/copy.rs +++ b/compiler/rustc_data_structures/src/tagged_ptr/copy.rs @@ -82,11 +82,13 @@ where /// drop, use [`TaggedPtr`] instead. /// /// [`TaggedPtr`]: crate::tagged_ptr::TaggedPtr + #[inline] pub fn new(pointer: P, tag: T) -> Self { Self { packed: Self::pack(P::into_ptr(pointer), tag), tag_ghost: PhantomData } } /// Retrieves the pointer. + #[inline] pub fn pointer(self) -> P where P: Copy, @@ -123,6 +125,7 @@ where /// according to `self.packed` encoding scheme. /// /// [`P::into_ptr`]: Pointer::into_ptr + #[inline] fn pack(ptr: NonNull<P::Target>, tag: T) -> NonNull<P::Target> { // Trigger assert! let () = Self::ASSERTION; @@ -145,6 +148,7 @@ where } /// Retrieves the original raw pointer from `self.packed`. + #[inline] pub(super) fn pointer_raw(&self) -> NonNull<P::Target> { self.packed.map_addr(|addr| unsafe { NonZeroUsize::new_unchecked(addr.get() << T::BITS) }) } @@ -184,6 +188,7 @@ where P: Pointer + Copy, T: Tag, { + #[inline] fn clone(&self) -> Self { *self } @@ -196,6 +201,7 @@ where { type Target = P::Target; + #[inline] fn deref(&self) -> &Self::Target { // Safety: // `pointer_raw` returns the original pointer from `P::into_ptr` which, @@ -209,6 +215,7 @@ where P: Pointer + DerefMut, T: Tag, { + #[inline] fn deref_mut(&mut self) -> &mut Self::Target { // Safety: // `pointer_raw` returns the original pointer from `P::into_ptr` which, @@ -235,6 +242,7 @@ where P: Pointer, T: Tag, { + #[inline] fn eq(&self, other: &Self) -> bool { self.packed == other.packed } @@ -252,6 +260,7 @@ where P: Pointer, T: Tag, { + #[inline] fn hash<H: Hasher>(&self, state: &mut H) { self.packed.hash(state); } diff --git a/compiler/rustc_data_structures/src/tagged_ptr/drop.rs b/compiler/rustc_data_structures/src/tagged_ptr/drop.rs index d418c06b7eb..4e42b5b4afe 100644 --- a/compiler/rustc_data_structures/src/tagged_ptr/drop.rs +++ b/compiler/rustc_data_structures/src/tagged_ptr/drop.rs @@ -30,16 +30,19 @@ where T: Tag, { /// Tags `pointer` with `tag`. + #[inline] pub fn new(pointer: P, tag: T) -> Self { TaggedPtr { raw: CopyTaggedPtr::new(pointer, tag) } } /// Retrieves the tag. + #[inline] pub fn tag(&self) -> T { self.raw.tag() } /// Sets the tag to a new value. + #[inline] pub fn set_tag(&mut self, tag: T) { self.raw.set_tag(tag) } @@ -63,6 +66,8 @@ where T: Tag, { type Target = P::Target; + + #[inline] fn deref(&self) -> &Self::Target { self.raw.deref() } @@ -73,6 +78,7 @@ where P: Pointer + DerefMut, T: Tag, { + #[inline] fn deref_mut(&mut self) -> &mut Self::Target { self.raw.deref_mut() } @@ -108,6 +114,7 @@ where P: Pointer, T: Tag, { + #[inline] fn eq(&self, other: &Self) -> bool { self.raw.eq(&other.raw) } @@ -125,6 +132,7 @@ where P: Pointer, T: Tag, { + #[inline] fn hash<H: Hasher>(&self, state: &mut H) { self.raw.hash(state); } diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index 992316edb63..709dea43d84 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -2318,7 +2318,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let infcx = match self.infcx() { Some(infcx) => infcx, None => { - assert!(!self_ty.needs_infer()); + assert!(!self_ty.has_infer()); infcx_ = tcx.infer_ctxt().ignoring_regions().build(); &infcx_ } @@ -2489,7 +2489,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let infcx = if let Some(infcx) = self.infcx() { infcx } else { - assert!(!qself_ty.needs_infer()); + assert!(!qself_ty.has_infer()); infcx_ = tcx.infer_ctxt().build(); &infcx_ }; @@ -3039,7 +3039,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // the anon const, which is empty. This is why the // `AlwaysApplicable` impl needs a `T: ?Sized` bound for // this to compile if we were to normalize here. - if forbid_generic && ty.needs_subst() { + if forbid_generic && ty.has_param() { let mut err = tcx.sess.struct_span_err( path.span, "generic `Self` types are currently not permitted in anonymous constants", diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index aab005dacf3..c066c396766 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -1027,7 +1027,7 @@ fn check_type_defn<'tcx>(tcx: TyCtxt<'tcx>, item: &hir::Item<'tcx>, all_sized: b packed && { let ty = tcx.type_of(variant.fields.raw.last().unwrap().did).subst_identity(); let ty = tcx.erase_regions(ty); - if ty.needs_infer() { + if ty.has_infer() { tcx.sess .delay_span_bug(item.span, &format!("inference variables in {:?}", ty)); // Just treat unresolved type expression as if it needs drop. @@ -1292,7 +1292,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id // Ignore dependent defaults -- that is, where the default of one type // parameter includes another (e.g., `<T, U = T>`). In those cases, we can't // be sure if it will error or not as user might always specify the other. - if !ty.needs_subst() { + if !ty.has_param() { wfcx.register_wf_obligation( tcx.def_span(param.def_id), Some(WellFormedLoc::Ty(param.def_id.expect_local())), @@ -1308,7 +1308,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id // for `struct Foo<const N: usize, const M: usize = { 1 - 2 }>` // we should eagerly error. let default_ct = tcx.const_param_default(param.def_id).subst_identity(); - if !default_ct.needs_subst() { + if !default_ct.has_param() { wfcx.register_wf_obligation( tcx.def_span(param.def_id), None, @@ -1342,7 +1342,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id if is_our_default(param) { let default_ty = tcx.type_of(param.def_id).subst_identity(); // ... and it's not a dependent default, ... - if !default_ty.needs_subst() { + if !default_ty.has_param() { // ... then substitute it with the default. return default_ty.into(); } @@ -1355,7 +1355,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id if is_our_default(param) { let default_ct = tcx.const_param_default(param.def_id).subst_identity(); // ... and it's not a dependent default, ... - if !default_ct.needs_subst() { + if !default_ct.has_param() { // ... then substitute it with the default. return default_ct.into(); } diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs index 47c47de8ced..89175c0ef74 100644 --- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs +++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs @@ -457,7 +457,7 @@ fn emit_newtype_suggestion_for_raw_ptr( ptr_ty: &ty::TypeAndMut<'_>, diag: &mut Diagnostic, ) { - if !self_ty.needs_subst() { + if !self_ty.has_param() { let mut_key = ptr_ty.mutbl.prefix_str(); let msg_sugg = "consider introducing a new wrapper type".to_owned(); let sugg = vec![ diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs index 56f456e5557..c09457e1d65 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs @@ -366,7 +366,7 @@ fn check_predicates<'tcx>( wf::obligations(infcx, tcx.param_env(impl1_def_id), impl1_def_id, 0, arg, span) .unwrap(); - assert!(!obligations.needs_infer()); + assert!(!obligations.has_infer()); impl2_predicates .extend(traits::elaborate(tcx, obligations).map(|obligation| obligation.predicate)) } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs index 3ba679df3ed..73a7bbebb65 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -168,7 +168,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ocx.normalize(&ObligationCause::dummy(), self.param_env, fn_sig); if ocx.select_all_or_error().is_empty() { let normalized_fn_sig = self.resolve_vars_if_possible(normalized_fn_sig); - if !normalized_fn_sig.needs_infer() { + if !normalized_fn_sig.has_infer() { return normalized_fn_sig; } } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index eef2b5009c8..82fc1256bba 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -1384,7 +1384,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } let item_ty = self.tcx.type_of(item.def_id).subst_identity(); // FIXME(compiler-errors): This check is *so* rudimentary - if item_ty.needs_subst() { + if item_ty.has_param() { return false; } if self.can_coerce(item_ty, expected_ty) { diff --git a/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/record_consumed_borrow.rs b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/record_consumed_borrow.rs index fa3887362d9..5136d895f22 100644 --- a/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/record_consumed_borrow.rs +++ b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/record_consumed_borrow.rs @@ -202,7 +202,7 @@ impl<'tcx> expr_use_visitor::Delegate<'tcx> for ExprUseDelegate<'tcx> { // If the type being assigned needs dropped, then the mutation counts as a borrow // since it is essentially doing `Drop::drop(&mut x); x = new_value;`. let ty = self.tcx.erase_regions(assignee_place.place.base_ty); - if ty.needs_infer() { + if ty.has_infer() { self.tcx.sess.delay_span_bug( self.tcx.hir().span(assignee_place.hir_id), &format!("inference variables in {ty}"), diff --git a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs index 5b432475fc3..915280a5bea 100644 --- a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs +++ b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs @@ -460,7 +460,7 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> { // Avoid ICEs in needs_drop. let ty = self.fcx.resolve_vars_if_possible(ty); let ty = self.fcx.tcx.erase_regions(ty); - if ty.needs_infer() { + if ty.has_infer() { self.fcx .tcx .sess diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 4fd778910ba..1a429142e01 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -2032,7 +2032,7 @@ impl<'tcx> Candidate<'tcx> { // means they are safe to put into the // `WhereClausePick`. assert!( - !trait_ref.skip_binder().substs.needs_infer() + !trait_ref.skip_binder().substs.has_infer() && !trait_ref.skip_binder().substs.has_placeholders() ); diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index 9432a5840b2..817918257be 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -133,7 +133,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { fn write_ty_to_typeck_results(&mut self, hir_id: hir::HirId, ty: Ty<'tcx>) { debug!("write_ty_to_typeck_results({:?}, {:?})", hir_id, ty); - assert!(!ty.needs_infer() && !ty.has_placeholders() && !ty.has_free_regions()); + assert!(!ty.has_infer() && !ty.has_placeholders() && !ty.has_free_regions()); self.typeck_results.node_types_mut().insert(hir_id, ty); } @@ -508,7 +508,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { fcx_typeck_results.user_provided_types().items().map(|(local_id, c_ty)| { let hir_id = hir::HirId { owner: common_hir_owner, local_id }; - if cfg!(debug_assertions) && c_ty.needs_infer() { + if cfg!(debug_assertions) && c_ty.has_infer() { span_bug!( hir_id.to_span(self.fcx.tcx), "writeback: `{:?}` has inference variables", @@ -527,7 +527,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { self.typeck_results.user_provided_sigs.extend( fcx_typeck_results.user_provided_sigs.items().map(|(&def_id, c_sig)| { - if cfg!(debug_assertions) && c_sig.needs_infer() { + if cfg!(debug_assertions) && c_sig.has_infer() { span_bug!( self.fcx.tcx.def_span(def_id), "writeback: `{:?}` has inference variables", @@ -618,7 +618,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { if let Some(substs) = self.fcx.typeck_results.borrow().node_substs_opt(hir_id) { let substs = self.resolve(substs, &span); debug!("write_substs_to_tcx({:?}, {:?})", hir_id, substs); - assert!(!substs.needs_infer() && !substs.has_placeholders()); + assert!(!substs.has_infer() && !substs.has_placeholders()); self.typeck_results.node_substs_mut().insert(hir_id, substs); } } @@ -693,7 +693,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { { let hir_id = hir::HirId { owner: common_hir_owner, local_id }; - if cfg!(debug_assertions) && container.needs_infer() { + if cfg!(debug_assertions) && container.has_infer() { span_bug!( hir_id.to_span(self.fcx.tcx), "writeback: `{:?}` has inference variables", @@ -711,7 +711,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { { let mut resolver = Resolver::new(self.fcx, span, self.body); let x = x.fold_with(&mut resolver); - if cfg!(debug_assertions) && x.needs_infer() { + if cfg!(debug_assertions) && x.has_infer() { span_bug!(span.to_span(self.fcx.tcx), "writeback: `{:?}` has inference variables", x); } diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs index e6e1bc0393f..c29f652034f 100644 --- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs +++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs @@ -564,12 +564,12 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { let _inside_canonical_ctxt_guard = infcx.set_canonicalization_ctxt(); let needs_canonical_flags = if canonicalize_region_mode.any() { - TypeFlags::NEEDS_INFER | + TypeFlags::HAS_INFER | TypeFlags::HAS_FREE_REGIONS | // `HAS_RE_PLACEHOLDER` implies `HAS_FREE_REGIONS` TypeFlags::HAS_TY_PLACEHOLDER | TypeFlags::HAS_CT_PLACEHOLDER } else { - TypeFlags::NEEDS_INFER + TypeFlags::HAS_INFER | TypeFlags::HAS_RE_PLACEHOLDER | TypeFlags::HAS_TY_PLACEHOLDER | TypeFlags::HAS_CT_PLACEHOLDER @@ -600,7 +600,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { // Once we have canonicalized `out_value`, it should not // contain anything that ties it to this inference context // anymore. - debug_assert!(!out_value.needs_infer() && !out_value.has_placeholders()); + debug_assert!(!out_value.has_infer() && !out_value.has_placeholders()); let canonical_variables = tcx.mk_canonical_var_infos(&canonicalizer.universe_canonicalized_variables()); diff --git a/compiler/rustc_infer/src/infer/freshen.rs b/compiler/rustc_infer/src/infer/freshen.rs index d89f63e5c53..0219167f6e5 100644 --- a/compiler/rustc_infer/src/infer/freshen.rs +++ b/compiler/rustc_infer/src/infer/freshen.rs @@ -127,7 +127,7 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for TypeFreshener<'a, 'tcx> { #[inline] fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - if !t.needs_infer() && !t.has_erasable_regions() { + if !t.has_infer() && !t.has_erasable_regions() { t } else { match *t.kind() { diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 1cd09cde0fc..1cfdb791cd6 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -1327,7 +1327,7 @@ impl<'tcx> InferCtxt<'tcx> { where T: TypeFoldable<TyCtxt<'tcx>>, { - if !value.needs_infer() { + if !value.has_infer() { return value; // Avoid duplicated subst-folding. } let mut r = InferenceLiteralEraser { tcx: self.tcx }; @@ -1365,7 +1365,7 @@ impl<'tcx> InferCtxt<'tcx> { pub fn fully_resolve<T: TypeFoldable<TyCtxt<'tcx>>>(&self, value: T) -> FixupResult<'tcx, T> { let value = resolve::fully_resolve(self, value); assert!( - value.as_ref().map_or(true, |value| !value.needs_infer()), + value.as_ref().map_or(true, |value| !value.has_infer()), "`{value:?}` is not fully resolved" ); value diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs index 2f5e2e417a6..d3f7eeff997 100644 --- a/compiler/rustc_infer/src/infer/outlives/obligations.rs +++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs @@ -347,7 +347,7 @@ where let is_opaque = alias_ty.kind(self.tcx) == ty::Opaque; if approx_env_bounds.is_empty() && trait_bounds.is_empty() - && (alias_ty.needs_infer() || is_opaque) + && (alias_ty.has_infer() || is_opaque) { debug!("no declared bounds"); let opt_variances = is_opaque.then(|| self.tcx.variances_of(alias_ty.def_id)); diff --git a/compiler/rustc_infer/src/infer/resolve.rs b/compiler/rustc_infer/src/infer/resolve.rs index 4f49f416507..3c41e8b3783 100644 --- a/compiler/rustc_infer/src/infer/resolve.rs +++ b/compiler/rustc_infer/src/infer/resolve.rs @@ -213,7 +213,7 @@ impl<'a, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for FullTypeResolver<'a, 'tcx> { } fn try_fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> { - if !t.needs_infer() { + if !t.has_infer() { Ok(t) // micro-optimize -- if there is nothing in this type that this fold affects... } else { let t = self.infcx.shallow_resolve(t); @@ -243,7 +243,7 @@ impl<'a, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for FullTypeResolver<'a, 'tcx> { } fn try_fold_const(&mut self, c: ty::Const<'tcx>) -> Result<ty::Const<'tcx>, Self::Error> { - if !c.needs_infer() { + if !c.has_infer() { Ok(c) // micro-optimize -- if there is nothing in this const that this fold affects... } else { let c = self.infcx.shallow_resolve(c); diff --git a/compiler/rustc_infer/src/traits/project.rs b/compiler/rustc_infer/src/traits/project.rs index 8d0af738dd1..e375d611936 100644 --- a/compiler/rustc_infer/src/traits/project.rs +++ b/compiler/rustc_infer/src/traits/project.rs @@ -20,7 +20,7 @@ pub struct MismatchedProjectionTypes<'tcx> { pub err: ty::error::TypeError<'tcx>, } -#[derive(Clone, TypeFoldable, TypeVisitable)] +#[derive(Clone)] pub struct Normalized<'tcx, T> { pub value: T, pub obligations: Vec<PredicateObligation<'tcx>>, diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index 612903810d2..a27a1e2978a 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -4,6 +4,8 @@ use libloading::Library; use rustc_ast as ast; use rustc_codegen_ssa::traits::CodegenBackend; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +#[cfg(parallel_compiler)] +use rustc_data_structures::sync; use rustc_errors::registry::Registry; use rustc_parse::validate_attr; use rustc_session as session; @@ -170,6 +172,7 @@ pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>( use rustc_middle::ty::tls; use rustc_query_impl::{deadlock, QueryContext, QueryCtxt}; + let registry = sync::Registry::new(threads); let mut builder = rayon::ThreadPoolBuilder::new() .thread_name(|_| "rustc".to_string()) .acquire_thread_handler(jobserver::acquire_thread) @@ -200,6 +203,9 @@ pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>( .build_scoped( // Initialize each new worker thread when created. move |thread: rayon::ThreadBuilder| { + // Register the thread for use with the `WorkerLocal` type. + registry.register(); + rustc_span::set_session_globals_then(session_globals, || thread.run()) }, // Run `f` on the first thread in the thread pool. diff --git a/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs b/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs index f1ba192f2bc..2ce28f3a049 100644 --- a/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs +++ b/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs @@ -42,7 +42,7 @@ declare_lint_pass!(EnumIntrinsicsNonEnums => [ENUM_INTRINSICS_NON_ENUMS]); /// Returns `true` if we know for sure that the given type is not an enum. Note that for cases where /// the type is generic, we can't be certain if it will be an enum so we have to assume that it is. fn is_non_enum(t: Ty<'_>) -> bool { - !t.is_enum() && !t.needs_subst() + !t.is_enum() && !t.has_param() } fn enforce_mem_discriminant( diff --git a/compiler/rustc_middle/src/hir/place.rs b/compiler/rustc_middle/src/hir/place.rs index 80b4c964ce4..8a22de931c3 100644 --- a/compiler/rustc_middle/src/hir/place.rs +++ b/compiler/rustc_middle/src/hir/place.rs @@ -66,7 +66,6 @@ pub struct Place<'tcx> { /// /// This is an HIR version of [`rustc_middle::mir::Place`]. #[derive(Clone, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)] -#[derive(TypeFoldable, TypeVisitable)] pub struct PlaceWithHirId<'tcx> { /// `HirId` of the expression or pattern producing this value. pub hir_id: HirId, diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 039194284b8..2490b17aac0 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -9,7 +9,7 @@ use crate::mir::visit::MirVisitable; use crate::ty::codec::{TyDecoder, TyEncoder}; use crate::ty::fold::{FallibleTypeFolder, TypeFoldable}; use crate::ty::print::{FmtPrinter, Printer}; -use crate::ty::visit::{TypeVisitable, TypeVisitableExt, TypeVisitor}; +use crate::ty::visit::TypeVisitableExt; use crate::ty::{self, List, Ty, TyCtxt}; use crate::ty::{AdtDef, InstanceDef, ScalarInt, UserTypeAnnotationIndex}; use crate::ty::{GenericArg, InternalSubsts, SubstsRef}; @@ -36,7 +36,7 @@ use either::Either; use std::borrow::Cow; use std::fmt::{self, Debug, Display, Formatter, Write}; -use std::ops::{ControlFlow, Index, IndexMut}; +use std::ops::{Index, IndexMut}; use std::{iter, mem}; pub use self::query::*; @@ -2722,6 +2722,7 @@ impl<'tcx> UserTypeProjections { /// `field[0]` (aka `.0`), indicating that the type of `s` is /// determined by finding the type of the `.0` field from `T`. #[derive(Clone, Debug, TyEncodable, TyDecodable, Hash, HashStable, PartialEq)] +#[derive(TypeFoldable, TypeVisitable)] pub struct UserTypeProjection { pub base: UserTypeAnnotationIndex, pub projs: Vec<ProjectionKind>, @@ -2765,28 +2766,6 @@ impl UserTypeProjection { } } -impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for UserTypeProjection { - fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>( - self, - folder: &mut F, - ) -> Result<Self, F::Error> { - Ok(UserTypeProjection { - base: self.base.try_fold_with(folder)?, - projs: self.projs.try_fold_with(folder)?, - }) - } -} - -impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for UserTypeProjection { - fn visit_with<Vs: TypeVisitor<TyCtxt<'tcx>>>( - &self, - visitor: &mut Vs, - ) -> ControlFlow<Vs::BreakTy> { - self.base.visit_with(visitor) - // Note: there's nothing in `self.proj` to visit. - } -} - rustc_index::newtype_index! { #[derive(HashStable)] #[debug_format = "promoted[{}]"] diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index da86cfd4772..813e109c41e 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -234,7 +234,6 @@ pub enum StmtKind<'tcx> { } #[derive(Clone, Debug, Copy, PartialEq, Eq, Hash, HashStable, TyEncodable, TyDecodable)] -#[derive(TypeFoldable, TypeVisitable)] pub struct LocalVarId(pub hir::HirId); /// A THIR expression. diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 6a8ae525069..02433026266 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -569,7 +569,7 @@ pub struct DerivedObligationCause<'tcx> { pub parent_code: InternedObligationCauseCode<'tcx>, } -#[derive(Clone, Debug, TypeFoldable, TypeVisitable, Lift)] +#[derive(Clone, Debug, TypeVisitable, Lift)] pub enum SelectionError<'tcx> { /// The trait is not implemented. Unimplemented, diff --git a/compiler/rustc_middle/src/traits/select.rs b/compiler/rustc_middle/src/traits/select.rs index 1cc9fd526b4..f2dda003b99 100644 --- a/compiler/rustc_middle/src/traits/select.rs +++ b/compiler/rustc_middle/src/traits/select.rs @@ -103,7 +103,7 @@ pub type EvaluationCache<'tcx> = Cache< /// required for associated types to work in default impls, as the bounds /// are visible both as projection bounds and as where-clauses from the /// parameter environment. -#[derive(PartialEq, Eq, Debug, Clone, TypeFoldable, TypeVisitable)] +#[derive(PartialEq, Eq, Debug, Clone, TypeVisitable)] pub enum SelectionCandidate<'tcx> { /// A builtin implementation for some specific traits, used in cases /// where we cannot rely an ordinary library implementations. diff --git a/compiler/rustc_middle/src/traits/solve.rs b/compiler/rustc_middle/src/traits/solve.rs index fef2be133e8..6b7b910a59b 100644 --- a/compiler/rustc_middle/src/traits/solve.rs +++ b/compiler/rustc_middle/src/traits/solve.rs @@ -120,7 +120,7 @@ impl<'tcx> std::ops::Deref for ExternalConstraints<'tcx> { } /// Additional constraints returned on success. -#[derive(Debug, PartialEq, Eq, Clone, Hash, Default, TypeFoldable, TypeVisitable)] +#[derive(Debug, PartialEq, Eq, Clone, Hash, Default)] pub struct ExternalConstraintsData<'tcx> { // FIXME: implement this. pub region_constraints: QueryRegionConstraints<'tcx>, diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 7df4be263d5..830231646c6 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -215,7 +215,7 @@ impl<'tcx> CtxtInterners<'tcx> { ) -> Fingerprint { // It's impossible to hash inference variables (and will ICE), so we don't need to try to cache them. // Without incremental, we rarely stable-hash types, so let's not do it proactively. - if flags.flags.intersects(TypeFlags::NEEDS_INFER) || sess.opts.incremental.is_none() { + if flags.flags.intersects(TypeFlags::HAS_INFER) || sess.opts.incremental.is_none() { Fingerprint::ZERO } else { let mut hasher = StableHasher::new(); diff --git a/compiler/rustc_middle/src/ty/erase_regions.rs b/compiler/rustc_middle/src/ty/erase_regions.rs index 38377324832..ad930d1e6b6 100644 --- a/compiler/rustc_middle/src/ty/erase_regions.rs +++ b/compiler/rustc_middle/src/ty/erase_regions.rs @@ -40,7 +40,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for RegionEraserVisitor<'tcx> { } fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { - if ty.needs_infer() { ty.super_fold_with(self) } else { self.tcx.erase_regions_ty(ty) } + if ty.has_infer() { ty.super_fold_with(self) } else { self.tcx.erase_regions_ty(ty) } } fn fold_binder<T>(&mut self, t: ty::Binder<'tcx, T>) -> ty::Binder<'tcx, T> diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs index aff6c77e039..1be61e16dbe 100644 --- a/compiler/rustc_middle/src/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -28,7 +28,7 @@ impl<T> ExpectedFound<T> { } // Data structures used in type unification -#[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable, Lift, PartialEq, Eq)] +#[derive(Copy, Clone, Debug, TypeVisitable, Lift, PartialEq, Eq)] #[rustc_pass_by_value] pub enum TypeError<'tcx> { Mismatch, diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 1c1432ecd5a..2aced27f7bb 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -2690,7 +2690,7 @@ impl<'tcx> ty::PolyTraitPredicate<'tcx> { } } -#[derive(Debug, Copy, Clone, TypeFoldable, TypeVisitable, Lift)] +#[derive(Debug, Copy, Clone, Lift)] pub struct PrintClosureAsImpl<'tcx> { pub closure: ty::ClosureSubsts<'tcx>, } diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index b35b514d795..29a3bc8bb97 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -4,7 +4,6 @@ //! to help with the tedium. use crate::mir::interpret; -use crate::mir::ProjectionKind; use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable}; use crate::ty::print::{with_no_trimmed_paths, FmtPrinter, Printer}; use crate::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor}; @@ -373,16 +372,6 @@ impl<'a, 'tcx> Lift<'tcx> for ty::ParamEnv<'a> { /////////////////////////////////////////////////////////////////////////// // Traversal implementations. -/// AdtDefs are basically the same as a DefId. -impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for ty::AdtDef<'tcx> { - fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>( - self, - _folder: &mut F, - ) -> Result<Self, F::Error> { - Ok(self) - } -} - impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for ty::AdtDef<'tcx> { fn visit_with<V: TypeVisitor<TyCtxt<'tcx>>>( &self, @@ -445,15 +434,6 @@ impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for &'tcx ty::List<ty::Const<'tcx>> { } } -impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for &'tcx ty::List<ProjectionKind> { - fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>( - self, - folder: &mut F, - ) -> Result<Self, F::Error> { - ty::util::fold_list(self, folder, |tcx, v| tcx.mk_projs(v)) - } -} - impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for Ty<'tcx> { fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>( self, diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 82dec7d98ad..7bda20ffe9a 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -631,7 +631,7 @@ impl<'tcx> UpvarSubsts<'tcx> { /// type of the constant. The reason that `R` is represented as an extra type parameter /// is the same reason that [`ClosureSubsts`] have `CS` and `U` as type parameters: /// inline const can reference lifetimes that are internal to the creating function. -#[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable)] +#[derive(Copy, Clone, Debug)] pub struct InlineConstSubsts<'tcx> { /// Generic parameters from the enclosing item, /// concatenated with the inferred type of the constant. diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs index d05d3e2d3dc..43f95635ab0 100644 --- a/compiler/rustc_middle/src/ty/subst.rs +++ b/compiler/rustc_middle/src/ty/subst.rs @@ -761,7 +761,7 @@ impl<'tcx, T: TypeFoldable<TyCtxt<'tcx>>> ty::EarlyBinder<T> { /// Returns the inner value, but only if it contains no bound vars. pub fn no_bound_vars(self) -> Option<T> { - if !self.0.needs_subst() { Some(self.0) } else { None } + if !self.0.has_param() { Some(self.0) } else { None } } } @@ -840,7 +840,7 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for SubstFolder<'a, 'tcx> { } fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - if !t.needs_subst() { + if !t.has_param() { return t; } diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 4c346b00256..c77985c6bd6 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -1151,7 +1151,7 @@ impl<'tcx> Ty<'tcx> { // context, or *something* like that, but for now just avoid passing inference // variables to queries that can't cope with them. Instead, conservatively // return "true" (may change drop order). - if query_ty.needs_infer() { + if query_ty.has_infer() { return true; } diff --git a/compiler/rustc_middle/src/ty/visit.rs b/compiler/rustc_middle/src/ty/visit.rs index 1b07f52afca..5eaa58d69ed 100644 --- a/compiler/rustc_middle/src/ty/visit.rs +++ b/compiler/rustc_middle/src/ty/visit.rs @@ -70,7 +70,7 @@ pub trait TypeVisitableExt<'tcx>: TypeVisitable<TyCtxt<'tcx>> { } } fn has_non_region_param(&self) -> bool { - self.has_type_flags(TypeFlags::NEEDS_SUBST - TypeFlags::HAS_RE_PARAM) + self.has_type_flags(TypeFlags::HAS_PARAM - TypeFlags::HAS_RE_PARAM) } fn has_infer_regions(&self) -> bool { self.has_type_flags(TypeFlags::HAS_RE_INFER) @@ -79,10 +79,10 @@ pub trait TypeVisitableExt<'tcx>: TypeVisitable<TyCtxt<'tcx>> { self.has_type_flags(TypeFlags::HAS_TY_INFER) } fn has_non_region_infer(&self) -> bool { - self.has_type_flags(TypeFlags::NEEDS_INFER - TypeFlags::HAS_RE_INFER) + self.has_type_flags(TypeFlags::HAS_INFER - TypeFlags::HAS_RE_INFER) } - fn needs_infer(&self) -> bool { - self.has_type_flags(TypeFlags::NEEDS_INFER) + fn has_infer(&self) -> bool { + self.has_type_flags(TypeFlags::HAS_INFER) } fn has_placeholders(&self) -> bool { self.has_type_flags( @@ -94,8 +94,8 @@ pub trait TypeVisitableExt<'tcx>: TypeVisitable<TyCtxt<'tcx>> { fn has_non_region_placeholders(&self) -> bool { self.has_type_flags(TypeFlags::HAS_TY_PLACEHOLDER | TypeFlags::HAS_CT_PLACEHOLDER) } - fn needs_subst(&self) -> bool { - self.has_type_flags(TypeFlags::NEEDS_SUBST) + fn has_param(&self) -> bool { + self.has_type_flags(TypeFlags::HAS_PARAM) } /// "Free" regions in this context means that it has any region /// that is not (a) erased or (b) late-bound. diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs index 1ce7f09d8ce..880745b8f0e 100644 --- a/compiler/rustc_mir_transform/src/const_prop.rs +++ b/compiler/rustc_mir_transform/src/const_prop.rs @@ -391,7 +391,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { /// Returns the value, if any, of evaluating `c`. fn eval_constant(&mut self, c: &Constant<'tcx>) -> Option<OpTy<'tcx>> { // FIXME we need to revisit this for #67176 - if c.needs_subst() { + if c.has_param() { return None; } @@ -490,7 +490,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { } // FIXME we need to revisit this for #67176 - if rvalue.needs_subst() { + if rvalue.has_param() { return None; } if !rvalue diff --git a/compiler/rustc_mir_transform/src/const_prop_lint.rs b/compiler/rustc_mir_transform/src/const_prop_lint.rs index 3a105a2abae..a4049d08d7b 100644 --- a/compiler/rustc_mir_transform/src/const_prop_lint.rs +++ b/compiler/rustc_mir_transform/src/const_prop_lint.rs @@ -281,7 +281,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { /// Returns the value, if any, of evaluating `c`. fn eval_constant(&mut self, c: &Constant<'tcx>, location: Location) -> Option<OpTy<'tcx>> { // FIXME we need to revisit this for #67176 - if c.needs_subst() { + if c.has_param() { return None; } @@ -474,7 +474,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { } // FIXME we need to revisit this for #67176 - if rvalue.needs_subst() { + if rvalue.has_param() { return None; } if !rvalue.ty(self.local_decls(), self.tcx).is_sized(self.tcx, self.param_env) { diff --git a/compiler/rustc_mir_transform/src/inline/cycle.rs b/compiler/rustc_mir_transform/src/inline/cycle.rs index 098ce0391fc..6046c3876be 100644 --- a/compiler/rustc_mir_transform/src/inline/cycle.rs +++ b/compiler/rustc_mir_transform/src/inline/cycle.rs @@ -92,7 +92,7 @@ pub(crate) fn mir_callgraph_reachable<'tcx>( // FIXME: A not fully substituted drop shim can cause ICEs if one attempts to // have its MIR built. Likely oli-obk just screwed up the `ParamEnv`s, so this // needs some more analysis. - if callee.needs_subst() { + if callee.has_param() { continue; } } diff --git a/compiler/rustc_monomorphize/src/partitioning/default.rs b/compiler/rustc_monomorphize/src/partitioning/default.rs index bd24deb590a..03183a40660 100644 --- a/compiler/rustc_monomorphize/src/partitioning/default.rs +++ b/compiler/rustc_monomorphize/src/partitioning/default.rs @@ -305,7 +305,7 @@ fn characteristic_def_id_of_mono_item<'tcx>( // When polymorphization is enabled, methods which do not depend on their generic // parameters, but the self-type of their impl block do will fail to normalize. - if !tcx.sess.opts.unstable_opts.polymorphize || !instance.needs_subst() { + if !tcx.sess.opts.unstable_opts.polymorphize || !instance.has_param() { // This is a method within an impl, find out what the self-type is: let impl_self_ty = tcx.subst_and_normalize_erasing_regions( instance.substs, diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 055682a1509..40680150601 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -139,7 +139,6 @@ passes_doc_attr_not_crate_level = passes_attr_crate_level = this attribute can only be applied at the crate level .suggestion = to apply to the crate, use an inner attribute - .help = to apply to the crate, use an inner attribute .note = read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#at-the-crate-level> for more information passes_doc_test_unknown = @@ -724,3 +723,45 @@ passes_skipping_const_checks = skipping const checks passes_invalid_macro_export_arguments = `{$name}` isn't a valid `#[macro_export]` argument passes_invalid_macro_export_arguments_too_many_items = `#[macro_export]` can only take 1 or 0 arguments + +passes_unreachable_due_to_uninhabited = unreachable {$descr} + .label = unreachable {$descr} + .label_orig = any code following this expression is unreachable + .note = this expression has type `{$ty}`, which is uninhabited + +passes_unused_var_maybe_capture_ref = unused variable: `{$name}` + .help = did you mean to capture by reference instead? + +passes_unused_capture_maybe_capture_ref = value captured by `{$name}` is never read + .help = did you mean to capture by reference instead? + +passes_unused_var_remove_field = unused variable: `{$name}` +passes_unused_var_remove_field_suggestion = try removing the field + +passes_unused_var_assigned_only = variable `{$name}` is assigned to, but never used + .note = consider using `_{$name}` instead + +passes_unnecessary_stable_feature = the feature `{$feature}` has been stable since {$since} and no longer requires an attribute to enable + +passes_unnecessary_partial_stable_feature = the feature `{$feature}` has been partially stabilized since {$since} and is succeeded by the feature `{$implies}` + .suggestion = if you are using features which are still unstable, change to using `{$implies}` + .suggestion_remove = if you are using features which are now stable, remove this line + +passes_ineffective_unstable_impl = an `#[unstable]` annotation here has no effect + .note = see issue #55436 <https://github.com/rust-lang/rust/issues/55436> for more information + +passes_unused_assign = value assigned to `{$name}` is never read + .help = maybe it is overwritten before being read? + +passes_unused_assign_passed = value passed to `{$name}` is never read + .help = maybe it is overwritten before being read? + +passes_maybe_string_interpolation = you might have meant to use string interpolation in this string literal +passes_string_interpolation_only_works = string interpolation only works in `format!` invocations + +passes_unused_variable_try_prefix = unused variable: `{$name}` + .label = unused variable + .suggestion = if this is intentional, prefix it with an underscore + +passes_unused_variable_try_ignore = unused variable: `{$name}` + .suggestion = try ignoring the field diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 085a28626ea..3f28ac26f86 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -29,7 +29,7 @@ use rustc_session::lint::builtin::{ }; use rustc_session::parse::feature_err; use rustc_span::symbol::{kw, sym, Symbol}; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::{BytePos, Span, DUMMY_SP}; use rustc_target::spec::abi::Abi; use rustc_trait_selection::infer::{TyCtxtInferExt, ValuePairs}; use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt; @@ -927,30 +927,18 @@ impl CheckAttrVisitor<'_> { hir_id: HirId, ) -> bool { if hir_id != CRATE_HIR_ID { - self.tcx.struct_span_lint_hir( + // insert a bang between `#` and `[...` + let bang_span = attr.span.lo() + BytePos(1); + let sugg = (attr.style == AttrStyle::Outer + && self.tcx.hir().get_parent_item(hir_id) == CRATE_OWNER_ID) + .then_some(errors::AttrCrateLevelOnlySugg { + attr: attr.span.with_lo(bang_span).with_hi(bang_span), + }); + self.tcx.emit_spanned_lint( INVALID_DOC_ATTRIBUTES, hir_id, meta.span(), - fluent::passes_attr_crate_level, - |err| { - if attr.style == AttrStyle::Outer - && self.tcx.hir().get_parent_item(hir_id) == CRATE_OWNER_ID - { - if let Ok(mut src) = self.tcx.sess.source_map().span_to_snippet(attr.span) { - src.insert(1, '!'); - err.span_suggestion_verbose( - attr.span, - fluent::passes_suggestion, - src, - Applicability::MaybeIncorrect, - ); - } else { - err.span_help(attr.span, fluent::passes_help); - } - } - err.note(fluent::passes_note); - err - }, + errors::AttrCrateLevelOnly { sugg }, ); return false; } diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index e8603b3a2f1..99fc69d1bec 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -6,7 +6,8 @@ use std::{ use crate::fluent_generated as fluent; use rustc_ast::Label; use rustc_errors::{ - error_code, Applicability, DiagnosticSymbolList, ErrorGuaranteed, IntoDiagnostic, MultiSpan, + error_code, AddToDiagnostic, Applicability, Diagnostic, DiagnosticSymbolList, ErrorGuaranteed, + IntoDiagnostic, MultiSpan, }; use rustc_hir::{self as hir, ExprKind, Target}; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; @@ -1555,3 +1556,160 @@ pub struct SkippingConstChecks { #[primary_span] pub span: Span, } + +#[derive(LintDiagnostic)] +#[diag(passes_unreachable_due_to_uninhabited)] +pub struct UnreachableDueToUninhabited<'desc, 'tcx> { + pub descr: &'desc str, + #[label] + pub expr: Span, + #[label(passes_label_orig)] + #[note] + pub orig: Span, + pub ty: Ty<'tcx>, +} + +#[derive(LintDiagnostic)] +#[diag(passes_unused_var_maybe_capture_ref)] +#[help] +pub struct UnusedVarMaybeCaptureRef { + pub name: String, +} + +#[derive(LintDiagnostic)] +#[diag(passes_unused_capture_maybe_capture_ref)] +#[help] +pub struct UnusedCaptureMaybeCaptureRef { + pub name: String, +} + +#[derive(LintDiagnostic)] +#[diag(passes_unused_var_remove_field)] +pub struct UnusedVarRemoveField { + pub name: String, + #[subdiagnostic] + pub sugg: UnusedVarRemoveFieldSugg, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion( + passes_unused_var_remove_field_suggestion, + applicability = "machine-applicable" +)] +pub struct UnusedVarRemoveFieldSugg { + #[suggestion_part(code = "")] + pub spans: Vec<Span>, +} + +#[derive(LintDiagnostic)] +#[diag(passes_unused_var_assigned_only)] +#[note] +pub struct UnusedVarAssignedOnly { + pub name: String, +} + +#[derive(LintDiagnostic)] +#[diag(passes_unnecessary_stable_feature)] +pub struct UnnecessaryStableFeature { + pub feature: Symbol, + pub since: Symbol, +} + +#[derive(LintDiagnostic)] +#[diag(passes_unnecessary_partial_stable_feature)] +pub struct UnnecessaryPartialStableFeature { + #[suggestion(code = "{implies}", applicability = "maybe-incorrect")] + pub span: Span, + #[suggestion(passes_suggestion_remove, code = "", applicability = "maybe-incorrect")] + pub line: Span, + pub feature: Symbol, + pub since: Symbol, + pub implies: Symbol, +} + +#[derive(LintDiagnostic)] +#[diag(passes_ineffective_unstable_impl)] +#[note] +pub struct IneffectiveUnstableImpl; + +#[derive(LintDiagnostic)] +#[diag(passes_unused_assign)] +#[help] +pub struct UnusedAssign { + pub name: String, +} + +#[derive(LintDiagnostic)] +#[diag(passes_unused_assign_passed)] +#[help] +pub struct UnusedAssignPassed { + pub name: String, +} + +#[derive(LintDiagnostic)] +#[diag(passes_unused_variable_try_prefix)] +pub struct UnusedVariableTryPrefix { + #[label] + pub label: Option<Span>, + #[subdiagnostic] + pub string_interp: Vec<UnusedVariableStringInterp>, + #[subdiagnostic] + pub sugg: UnusedVariableTryPrefixSugg, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion(passes_suggestion, applicability = "machine-applicable")] +pub struct UnusedVariableTryPrefixSugg { + #[suggestion_part(code = "_{name}")] + pub spans: Vec<Span>, + pub name: String, +} + +pub struct UnusedVariableStringInterp { + pub lit: Span, + pub lo: Span, + pub hi: Span, +} + +impl AddToDiagnostic for UnusedVariableStringInterp { + fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F) { + diag.span_label(self.lit, crate::fluent_generated::passes_maybe_string_interpolation); + diag.multipart_suggestion( + crate::fluent_generated::passes_string_interpolation_only_works, + vec![(self.lo, String::from("format!(")), (self.hi, String::from(")"))], + Applicability::MachineApplicable, + ); + } +} + +#[derive(LintDiagnostic)] +#[diag(passes_unused_variable_try_ignore)] +pub struct UnusedVarTryIgnore { + #[subdiagnostic] + pub sugg: UnusedVarTryIgnoreSugg, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion(passes_suggestion, applicability = "machine-applicable")] +pub struct UnusedVarTryIgnoreSugg { + #[suggestion_part(code = "{name}: _")] + pub shorthands: Vec<Span>, + #[suggestion_part(code = "_")] + pub non_shorthands: Vec<Span>, + pub name: String, +} + +#[derive(LintDiagnostic)] +#[diag(passes_attr_crate_level)] +#[note] +pub struct AttrCrateLevelOnly { + #[subdiagnostic] + pub sugg: Option<AttrCrateLevelOnlySugg>, +} + +#[derive(Subdiagnostic)] +#[suggestion(passes_suggestion, applicability = "maybe-incorrect", code = "!", style = "verbose")] +pub struct AttrCrateLevelOnlySugg { + #[primary_span] + pub attr: Span, +} diff --git a/compiler/rustc_passes/src/lib.rs b/compiler/rustc_passes/src/lib.rs index eca3bae9a1c..8b7338e29aa 100644 --- a/compiler/rustc_passes/src/lib.rs +++ b/compiler/rustc_passes/src/lib.rs @@ -12,6 +12,8 @@ #![feature(min_specialization)] #![feature(try_blocks)] #![recursion_limit = "256"] +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] #[macro_use] extern crate rustc_middle; diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index 7d8f6add632..6758024419d 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -81,13 +81,13 @@ //! We generate various special nodes for various, well, special purposes. //! These are described in the `Liveness` struct. +use crate::errors; + use self::LiveNodeKind::*; use self::VarKind::*; use rustc_ast::InlineAsmOptions; use rustc_data_structures::fx::FxIndexMap; -use rustc_errors::Applicability; -use rustc_errors::Diagnostic; use rustc_hir as hir; use rustc_hir::def::*; use rustc_hir::def_id::LocalDefId; @@ -1297,13 +1297,13 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { self.exit_ln } - fn warn_about_unreachable( + fn warn_about_unreachable<'desc>( &mut self, orig_span: Span, orig_ty: Ty<'tcx>, expr_span: Span, expr_id: HirId, - descr: &str, + descr: &'desc str, ) { if !orig_ty.is_never() { // Unreachable code warnings are already emitted during type checking. @@ -1316,22 +1316,15 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { // that we do not emit the same warning twice if the uninhabited type // is indeed `!`. - let msg = format!("unreachable {}", descr); - self.ir.tcx.struct_span_lint_hir( + self.ir.tcx.emit_spanned_lint( lint::builtin::UNREACHABLE_CODE, expr_id, expr_span, - &msg, - |diag| { - diag.span_label(expr_span, &msg) - .span_label(orig_span, "any code following this expression is unreachable") - .span_note( - orig_span, - &format!( - "this expression has type `{}`, which is uninhabited", - orig_ty - ), - ) + errors::UnreachableDueToUninhabited { + expr: expr_span, + orig: orig_span, + descr, + ty: orig_ty, }, ); } @@ -1483,23 +1476,21 @@ impl<'tcx> Liveness<'_, 'tcx> { if self.used_on_entry(entry_ln, var) { if !self.live_on_entry(entry_ln, var) { if let Some(name) = self.should_warn(var) { - self.ir.tcx.struct_span_lint_hir( + self.ir.tcx.emit_spanned_lint( lint::builtin::UNUSED_ASSIGNMENTS, var_hir_id, vec![span], - format!("value captured by `{}` is never read", name), - |lint| lint.help("did you mean to capture by reference instead?"), + errors::UnusedCaptureMaybeCaptureRef { name }, ); } } } else { if let Some(name) = self.should_warn(var) { - self.ir.tcx.struct_span_lint_hir( + self.ir.tcx.emit_spanned_lint( lint::builtin::UNUSED_VARIABLES, var_hir_id, vec![span], - format!("unused variable: `{}`", name), - |lint| lint.help("did you mean to capture by reference instead?"), + errors::UnusedVarMaybeCaptureRef { name }, ); } } @@ -1514,11 +1505,14 @@ impl<'tcx> Liveness<'_, 'tcx> { Some(entry_ln), Some(body), |spans, hir_id, ln, var| { - if !self.live_on_entry(ln, var) { - self.report_unused_assign(hir_id, spans, var, |name| { - format!("value passed to `{}` is never read", name) - }); - } + if !self.live_on_entry(ln, var) + && let Some(name) = self.should_warn(var) { + self.ir.tcx.emit_spanned_lint( + lint::builtin::UNUSED_ASSIGNMENTS, + hir_id, + spans, + errors::UnusedAssignPassed { name }, + ); } }, ); } @@ -1587,39 +1581,35 @@ impl<'tcx> Liveness<'_, 'tcx> { if ln == self.exit_ln { false } else { self.assigned_on_exit(ln, var) }; if is_assigned { - self.ir.tcx.struct_span_lint_hir( + self.ir.tcx.emit_spanned_lint( lint::builtin::UNUSED_VARIABLES, first_hir_id, hir_ids_and_spans .into_iter() .map(|(_, _, ident_span)| ident_span) .collect::<Vec<_>>(), - format!("variable `{}` is assigned to, but never used", name), - |lint| lint.note(&format!("consider using `_{}` instead", name)), + errors::UnusedVarAssignedOnly { name }, ) } else if can_remove { - self.ir.tcx.struct_span_lint_hir( + let spans = hir_ids_and_spans + .iter() + .map(|(_, pat_span, _)| { + let span = self + .ir + .tcx + .sess + .source_map() + .span_extend_to_next_char(*pat_span, ',', true); + span.with_hi(BytePos(span.hi().0 + 1)) + }) + .collect(); + self.ir.tcx.emit_spanned_lint( lint::builtin::UNUSED_VARIABLES, first_hir_id, hir_ids_and_spans.iter().map(|(_, pat_span, _)| *pat_span).collect::<Vec<_>>(), - format!("unused variable: `{}`", name), - |lint| { - lint.multipart_suggestion( - "try removing the field", - hir_ids_and_spans - .iter() - .map(|(_, pat_span, _)| { - let span = self - .ir - .tcx - .sess - .source_map() - .span_extend_to_next_char(*pat_span, ',', true); - (span.with_hi(BytePos(span.hi().0 + 1)), String::new()) - }) - .collect(), - Applicability::MachineApplicable, - ) + errors::UnusedVarRemoveField { + name, + sugg: errors::UnusedVarRemoveFieldSugg { spans }, }, ); } else { @@ -1633,55 +1623,46 @@ impl<'tcx> Liveness<'_, 'tcx> { // the field" message, and suggest `_` for the non-shorthands. If we only // have non-shorthand, then prefix with an underscore instead. if !shorthands.is_empty() { - let shorthands = shorthands - .into_iter() - .map(|(_, pat_span, _)| (pat_span, format!("{}: _", name))) - .chain( - non_shorthands - .into_iter() - .map(|(_, pat_span, _)| (pat_span, "_".to_string())), - ) - .collect::<Vec<_>>(); + let shorthands = + shorthands.into_iter().map(|(_, pat_span, _)| pat_span).collect(); + let non_shorthands = + non_shorthands.into_iter().map(|(_, pat_span, _)| pat_span).collect(); - self.ir.tcx.struct_span_lint_hir( + self.ir.tcx.emit_spanned_lint( lint::builtin::UNUSED_VARIABLES, first_hir_id, hir_ids_and_spans .iter() .map(|(_, pat_span, _)| *pat_span) .collect::<Vec<_>>(), - format!("unused variable: `{}`", name), - |lint| { - lint.multipart_suggestion( - "try ignoring the field", + errors::UnusedVarTryIgnore { + sugg: errors::UnusedVarTryIgnoreSugg { shorthands, - Applicability::MachineApplicable, - ) + non_shorthands, + name, + }, }, ); } else { let non_shorthands = non_shorthands .into_iter() - .map(|(_, _, ident_span)| (ident_span, format!("_{}", name))) + .map(|(_, _, ident_span)| ident_span) .collect::<Vec<_>>(); - - self.ir.tcx.struct_span_lint_hir( + let suggestions = self.string_interp_suggestions(&name, opt_body); + self.ir.tcx.emit_spanned_lint( lint::builtin::UNUSED_VARIABLES, first_hir_id, hir_ids_and_spans .iter() .map(|(_, _, ident_span)| *ident_span) .collect::<Vec<_>>(), - format!("unused variable: `{}`", name), - |lint| { - if self.has_added_lit_match_name_span(&name, opt_body, lint) { - lint.span_label(pat.span, "unused variable"); - } - lint.multipart_suggestion( - "if this is intentional, prefix it with an underscore", - non_shorthands, - Applicability::MachineApplicable, - ) + errors::UnusedVariableTryPrefix { + label: if !suggestions.is_empty() { Some(pat.span) } else { None }, + sugg: errors::UnusedVariableTryPrefixSugg { + spans: non_shorthands, + name, + }, + string_interp: suggestions, }, ); } @@ -1689,65 +1670,40 @@ impl<'tcx> Liveness<'_, 'tcx> { } } - fn has_added_lit_match_name_span( + fn string_interp_suggestions( &self, name: &str, opt_body: Option<&hir::Body<'_>>, - err: &mut Diagnostic, - ) -> bool { - let mut has_litstring = false; - let Some(opt_body) = opt_body else {return false;}; + ) -> Vec<errors::UnusedVariableStringInterp> { + let mut suggs = Vec::new(); + let Some(opt_body) = opt_body else { return suggs; }; let mut visitor = CollectLitsVisitor { lit_exprs: vec![] }; intravisit::walk_body(&mut visitor, opt_body); for lit_expr in visitor.lit_exprs { let hir::ExprKind::Lit(litx) = &lit_expr.kind else { continue }; let rustc_ast::LitKind::Str(syb, _) = litx.node else{ continue; }; let name_str: &str = syb.as_str(); - let mut name_pa = String::from("{"); - name_pa.push_str(&name); - name_pa.push('}'); + let name_pa = format!("{{{name}}}"); if name_str.contains(&name_pa) { - err.span_label( - lit_expr.span, - "you might have meant to use string interpolation in this string literal", - ); - err.multipart_suggestion( - "string interpolation only works in `format!` invocations", - vec![ - (lit_expr.span.shrink_to_lo(), "format!(".to_string()), - (lit_expr.span.shrink_to_hi(), ")".to_string()), - ], - Applicability::MachineApplicable, - ); - has_litstring = true; + suggs.push(errors::UnusedVariableStringInterp { + lit: lit_expr.span, + lo: lit_expr.span.shrink_to_lo(), + hi: lit_expr.span.shrink_to_hi(), + }); } } - has_litstring + suggs } fn warn_about_dead_assign(&self, spans: Vec<Span>, hir_id: HirId, ln: LiveNode, var: Variable) { - if !self.live_on_exit(ln, var) { - self.report_unused_assign(hir_id, spans, var, |name| { - format!("value assigned to `{}` is never read", name) - }); - } - } - - fn report_unused_assign( - &self, - hir_id: HirId, - spans: Vec<Span>, - var: Variable, - message: impl Fn(&str) -> String, - ) { - if let Some(name) = self.should_warn(var) { - self.ir.tcx.struct_span_lint_hir( - lint::builtin::UNUSED_ASSIGNMENTS, - hir_id, - spans, - message(&name), - |lint| lint.help("maybe it is overwritten before being read?"), - ) - } + if !self.live_on_exit(ln, var) + && let Some(name) = self.should_warn(var) { + self.ir.tcx.emit_spanned_lint( + lint::builtin::UNUSED_ASSIGNMENTS, + hir_id, + spans, + errors::UnusedAssign { name }, + ); + } } } diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 4a35c679466..9615f283ff4 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -7,7 +7,6 @@ use rustc_attr::{ UnstableReason, VERSION_PLACEHOLDER, }; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; -use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID}; @@ -759,12 +758,11 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> { // do not lint when the trait isn't resolved, since resolution error should // be fixed first if t.path.res != Res::Err && c.fully_stable { - self.tcx.struct_span_lint_hir( + self.tcx.emit_spanned_lint( INEFFECTIVE_UNSTABLE_TRAIT_IMPL, item.hir_id(), span, - "an `#[unstable]` annotation here has no effect", - |lint| lint.note("see issue #55436 <https://github.com/rust-lang/rust/issues/55436> for more information") + errors::IneffectiveUnstableImpl, ); } } @@ -1095,29 +1093,16 @@ fn unnecessary_partially_stable_feature_lint( implies: Symbol, since: Symbol, ) { - tcx.struct_span_lint_hir( + tcx.emit_spanned_lint( lint::builtin::STABLE_FEATURES, hir::CRATE_HIR_ID, span, - format!( - "the feature `{feature}` has been partially stabilized since {since} and is succeeded \ - by the feature `{implies}`" - ), - |lint| { - lint.span_suggestion( - span, - &format!( - "if you are using features which are still unstable, change to using `{implies}`" - ), - implies, - Applicability::MaybeIncorrect, - ) - .span_suggestion( - tcx.sess.source_map().span_extend_to_line(span), - "if you are using features which are now stable, remove this line", - "", - Applicability::MaybeIncorrect, - ) + errors::UnnecessaryPartialStableFeature { + span, + line: tcx.sess.source_map().span_extend_to_line(span), + feature, + since, + implies, }, ); } @@ -1131,7 +1116,10 @@ fn unnecessary_stable_feature_lint( if since.as_str() == VERSION_PLACEHOLDER { since = rust_version_symbol(); } - tcx.struct_span_lint_hir(lint::builtin::STABLE_FEATURES, hir::CRATE_HIR_ID, span, format!("the feature `{feature}` has been stable since {since} and no longer requires an attribute to enable"), |lint| { - lint - }); + tcx.emit_spanned_lint( + lint::builtin::STABLE_FEATURES, + hir::CRATE_HIR_ID, + span, + errors::UnnecessaryStableFeature { feature, since }, + ); } diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index b9922b26afc..8de4d06fe78 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -354,24 +354,20 @@ impl<K: DepKind> DepGraphData<K> { - dep-node: {key:?}" ); - let task_deps = if cx.dep_context().is_eval_always(key.kind) { - None + let with_deps = |task_deps| K::with_deps(task_deps, || task(cx, arg)); + let (result, edges) = if cx.dep_context().is_eval_always(key.kind) { + (with_deps(TaskDepsRef::EvalAlways), smallvec![]) } else { - Some(Lock::new(TaskDeps { + let task_deps = Lock::new(TaskDeps { #[cfg(debug_assertions)] node: Some(key), reads: SmallVec::new(), read_set: Default::default(), phantom_data: PhantomData, - })) + }); + (with_deps(TaskDepsRef::Allow(&task_deps)), task_deps.into_inner().reads) }; - let task_deps_ref = - task_deps.as_ref().map(TaskDepsRef::Allow).unwrap_or(TaskDepsRef::EvalAlways); - - let result = K::with_deps(task_deps_ref, || task(cx, arg)); - let edges = task_deps.map_or_else(|| smallvec![], |lock| lock.into_inner().reads); - let dcx = cx.dep_context(); let hashing_timer = dcx.profiler().incr_result_hashing(); let current_fingerprint = @@ -1236,76 +1232,48 @@ impl<K: DepKind> CurrentDepGraph<K> { self.node_intern_event_id.map(|eid| profiler.generic_activity_with_event_id(eid)); if let Some(prev_index) = prev_graph.node_to_index_opt(&key) { + let get_dep_node_index = |color, fingerprint| { + if print_status { + eprintln!("[task::{color:}] {key:?}"); + } + + let mut prev_index_to_index = self.prev_index_to_index.lock(); + + let dep_node_index = match prev_index_to_index[prev_index] { + Some(dep_node_index) => dep_node_index, + None => { + let dep_node_index = + self.encoder.borrow().send(profiler, key, fingerprint, edges); + prev_index_to_index[prev_index] = Some(dep_node_index); + dep_node_index + } + }; + + #[cfg(debug_assertions)] + self.record_edge(dep_node_index, key, fingerprint); + + dep_node_index + }; + // Determine the color and index of the new `DepNode`. if let Some(fingerprint) = fingerprint { if fingerprint == prev_graph.fingerprint_by_index(prev_index) { - if print_status { - eprintln!("[task::green] {key:?}"); - } - // This is a green node: it existed in the previous compilation, // its query was re-executed, and it has the same result as before. - let mut prev_index_to_index = self.prev_index_to_index.lock(); - - let dep_node_index = match prev_index_to_index[prev_index] { - Some(dep_node_index) => dep_node_index, - None => { - let dep_node_index = - self.encoder.borrow().send(profiler, key, fingerprint, edges); - prev_index_to_index[prev_index] = Some(dep_node_index); - dep_node_index - } - }; - - #[cfg(debug_assertions)] - self.record_edge(dep_node_index, key, fingerprint); + let dep_node_index = get_dep_node_index("green", fingerprint); (dep_node_index, Some((prev_index, DepNodeColor::Green(dep_node_index)))) } else { - if print_status { - eprintln!("[task::red] {key:?}"); - } - // This is a red node: it existed in the previous compilation, its query // was re-executed, but it has a different result from before. - let mut prev_index_to_index = self.prev_index_to_index.lock(); - - let dep_node_index = match prev_index_to_index[prev_index] { - Some(dep_node_index) => dep_node_index, - None => { - let dep_node_index = - self.encoder.borrow().send(profiler, key, fingerprint, edges); - prev_index_to_index[prev_index] = Some(dep_node_index); - dep_node_index - } - }; - - #[cfg(debug_assertions)] - self.record_edge(dep_node_index, key, fingerprint); + let dep_node_index = get_dep_node_index("red", fingerprint); (dep_node_index, Some((prev_index, DepNodeColor::Red))) } } else { - if print_status { - eprintln!("[task::unknown] {key:?}"); - } - // This is a red node, effectively: it existed in the previous compilation // session, its query was re-executed, but it doesn't compute a result hash // (i.e. it represents a `no_hash` query), so we have no way of determining // whether or not the result was the same as before. - let mut prev_index_to_index = self.prev_index_to_index.lock(); - - let dep_node_index = match prev_index_to_index[prev_index] { - Some(dep_node_index) => dep_node_index, - None => { - let dep_node_index = - self.encoder.borrow().send(profiler, key, Fingerprint::ZERO, edges); - prev_index_to_index[prev_index] = Some(dep_node_index); - dep_node_index - } - }; - - #[cfg(debug_assertions)] - self.record_edge(dep_node_index, key, Fingerprint::ZERO); + let dep_node_index = get_dep_node_index("unknown", Fingerprint::ZERO); (dep_node_index, Some((prev_index, DepNodeColor::Red))) } } else { diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs index 6a0ca06f69c..a3f262905c7 100644 --- a/compiler/rustc_symbol_mangling/src/legacy.rs +++ b/compiler/rustc_symbol_mangling/src/legacy.rs @@ -108,7 +108,7 @@ fn get_symbol_hash<'tcx>( tcx.def_path_hash(def_id).hash_stable(&mut hcx, &mut hasher); // Include the main item-type. Note that, in this case, the - // assertions about `needs_subst` may not hold, but this item-type + // assertions about `has_param` may not hold, but this item-type // ought to be the same for every reference anyway. assert!(!item_type.has_erasable_regions()); hcx.while_hashing_spans(false, |hcx| { diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs index 911cc0b88c4..fcf86da08f4 100644 --- a/compiler/rustc_trait_selection/src/infer.rs +++ b/compiler/rustc_trait_selection/src/infer.rs @@ -41,7 +41,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { fn type_is_copy_modulo_regions(&self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool { let ty = self.resolve_vars_if_possible(ty); - if !(param_env, ty).needs_infer() { + if !(param_env, ty).has_infer() { return ty.is_copy_modulo_regions(self.tcx, param_env); } diff --git a/compiler/rustc_trait_selection/src/solve/canonicalize.rs b/compiler/rustc_trait_selection/src/solve/canonicalize.rs index 976849696e3..ff4bff10cc8 100644 --- a/compiler/rustc_trait_selection/src/solve/canonicalize.rs +++ b/compiler/rustc_trait_selection/src/solve/canonicalize.rs @@ -69,7 +69,7 @@ impl<'a, 'tcx> Canonicalizer<'a, 'tcx> { }; let value = value.fold_with(&mut canonicalizer); - assert!(!value.needs_infer()); + assert!(!value.has_infer()); assert!(!value.has_placeholders()); let (max_universe, variables) = canonicalizer.finalize(); diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index 20c2605f219..b7690f79933 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -582,7 +582,7 @@ fn orphan_check_trait_ref<'tcx>( trait_ref: ty::TraitRef<'tcx>, in_crate: InCrate, ) -> Result<(), OrphanCheckErr<'tcx>> { - if trait_ref.needs_infer() && trait_ref.needs_subst() { + if trait_ref.has_infer() && trait_ref.has_param() { bug!( "can't orphan check a trait ref with both params and inference variables {:?}", trait_ref diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 4c9df5d9d0a..0e8c74a6765 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -414,7 +414,7 @@ fn subst_and_check_impossible_predicates<'tcx>( predicates.push(ty::Binder::dummy(trait_ref).to_predicate(tcx)); } - predicates.retain(|predicate| !predicate.needs_subst()); + predicates.retain(|predicate| !predicate.has_param()); let result = impossible_predicates(tcx, predicates); debug!("subst_and_check_impossible_predicates(key={:?}) = {:?}", key, result); diff --git a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs index e01a57ea4fe..0db80232891 100644 --- a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs +++ b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs @@ -60,7 +60,7 @@ impl<'a, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'tcx> { // We may however encounter unconstrained lifetime variables in invalid // code. See #110161 for context. assert!(!ty.has_non_region_infer()); - if ty.needs_infer() { + if ty.has_infer() { self.tcx.sess.delay_span_bug( self.tcx.def_span(body_id), "skipped implied_outlives_bounds due to unconstrained lifetimes", diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index af61ca0c29f..863553670de 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -449,7 +449,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { debug!(?stack, ?candidates, "winnowed to {} candidates", candidates.len()); - let needs_infer = stack.obligation.predicate.has_non_region_infer(); + let has_non_region_infer = stack.obligation.predicate.has_non_region_infer(); // If there are STILL multiple candidates, we can further // reduce the list by dropping duplicates -- including @@ -461,7 +461,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.candidate_should_be_dropped_in_favor_of( &candidates[i], &candidates[j], - needs_infer, + has_non_region_infer, ) == DropVictim::Yes }); if should_drop_i { @@ -1000,7 +1000,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ) -> Result<EvaluationResult, OverflowError> { if !self.is_intercrate() && obligation.is_global() - && obligation.param_env.caller_bounds().iter().all(|bound| bound.needs_subst()) + && obligation.param_env.caller_bounds().iter().all(|bound| bound.has_param()) { // If a param env has no global bounds, global obligations do not // depend on its particular value in order to work, so we can clear @@ -1330,7 +1330,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } if self.can_use_global_caches(param_env) { - if !trait_pred.needs_infer() { + if !trait_pred.has_infer() { debug!(?trait_pred, ?result, "insert_evaluation_cache global"); // This may overwrite the cache with the same value // FIXME: Due to #50507 this overwrites the different values @@ -1516,7 +1516,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // If there are any inference variables in the `ParamEnv`, then we // always use a cache local to this particular scope. Otherwise, we // switch to a global cache. - if param_env.needs_infer() { + if param_env.has_infer() { return false; } @@ -1587,7 +1587,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { return false; } match result { - Ok(Some(SelectionCandidate::ParamCandidate(trait_ref))) => !trait_ref.needs_infer(), + Ok(Some(SelectionCandidate::ParamCandidate(trait_ref))) => !trait_ref.has_infer(), _ => true, } } @@ -1613,8 +1613,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { if self.can_use_global_caches(param_env) { if let Err(Overflow(OverflowError::Canonical)) = candidate { // Don't cache overflow globally; we only produce this in certain modes. - } else if !pred.needs_infer() { - if !candidate.needs_infer() { + } else if !pred.has_infer() { + if !candidate.has_infer() { debug!(?pred, ?candidate, "insert_candidate_cache global"); // This may overwrite the cache with the same value. tcx.selection_cache.insert((param_env, pred), dep_node, candidate); @@ -1724,7 +1724,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .map(|InferOk { obligations: _, value: () }| { // This method is called within a probe, so we can't have // inference variables and placeholders escape. - if !trait_bound.needs_infer() && !trait_bound.has_placeholders() { + if !trait_bound.has_infer() && !trait_bound.has_placeholders() { Some(trait_bound) } else { None @@ -1840,7 +1840,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { &mut self, victim: &EvaluatedCandidate<'tcx>, other: &EvaluatedCandidate<'tcx>, - needs_infer: bool, + has_non_region_infer: bool, ) -> DropVictim { if victim.candidate == other.candidate { return DropVictim::Yes; @@ -1956,7 +1956,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { | (ObjectCandidate(i), ObjectCandidate(j)) => { // Arbitrarily pick the lower numbered candidate for backwards // compatibility reasons. Don't let this affect inference. - DropVictim::drop_if(i < j && !needs_infer) + DropVictim::drop_if(i < j && !has_non_region_infer) } (ObjectCandidate(_), ProjectionCandidate(..)) | (ProjectionCandidate(..), ObjectCandidate(_)) => { @@ -2062,7 +2062,8 @@ impl<'tcx> SelectionContext<'_, 'tcx> { // existence of multiple marker trait impls tells us nothing // about which one should actually apply. DropVictim::drop_if( - !needs_infer && other.evaluation.must_apply_considering_regions(), + !has_non_region_infer + && other.evaluation.must_apply_considering_regions(), ) } None => DropVictim::No, diff --git a/compiler/rustc_trait_selection/src/traits/vtable.rs b/compiler/rustc_trait_selection/src/traits/vtable.rs index a4e9928f8b2..c56e7c7cadd 100644 --- a/compiler/rustc_trait_selection/src/traits/vtable.rs +++ b/compiler/rustc_trait_selection/src/traits/vtable.rs @@ -353,8 +353,8 @@ pub(crate) fn vtable_trait_upcasting_coercion_new_vptr_slot<'tcx>( ), ) -> Option<usize> { let (source, target) = key; - assert!(matches!(&source.kind(), &ty::Dynamic(..)) && !source.needs_infer()); - assert!(matches!(&target.kind(), &ty::Dynamic(..)) && !target.needs_infer()); + assert!(matches!(&source.kind(), &ty::Dynamic(..)) && !source.has_infer()); + assert!(matches!(&target.kind(), &ty::Dynamic(..)) && !target.has_infer()); // this has been typecked-before, so diagnostics is not really needed. let unsize_trait_did = tcx.require_lang_item(LangItem::Unsize, None); diff --git a/compiler/rustc_traits/src/normalize_erasing_regions.rs b/compiler/rustc_traits/src/normalize_erasing_regions.rs index 126a494f34f..5da0f16c2bf 100644 --- a/compiler/rustc_traits/src/normalize_erasing_regions.rs +++ b/compiler/rustc_traits/src/normalize_erasing_regions.rs @@ -47,7 +47,7 @@ fn try_normalize_after_erasing_regions<'tcx, T: TypeFoldable<TyCtxt<'tcx>> + Par // us a test case. debug_assert_eq!(normalized_value, resolved_value); let erased = infcx.tcx.erase_regions(resolved_value); - debug_assert!(!erased.needs_infer(), "{erased:?}"); + debug_assert!(!erased.has_infer(), "{erased:?}"); Ok(erased) } Err(NoSolution) => Err(NoSolution), diff --git a/compiler/rustc_transmute/src/lib.rs b/compiler/rustc_transmute/src/lib.rs index 8be02c1d988..77c0526e3aa 100644 --- a/compiler/rustc_transmute/src/lib.rs +++ b/compiler/rustc_transmute/src/lib.rs @@ -62,7 +62,7 @@ mod rustc { use rustc_hir::lang_items::LangItem; use rustc_infer::infer::InferCtxt; - use rustc_macros::{TypeFoldable, TypeVisitable}; + use rustc_macros::TypeVisitable; use rustc_middle::traits::ObligationCause; use rustc_middle::ty::Const; use rustc_middle::ty::ParamEnv; @@ -70,7 +70,7 @@ mod rustc { use rustc_middle::ty::TyCtxt; /// The source and destination types of a transmutation. - #[derive(TypeFoldable, TypeVisitable, Debug, Clone, Copy)] + #[derive(TypeVisitable, Debug, Clone, Copy)] pub struct Types<'tcx> { /// The source type. pub src: Ty<'tcx>, diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs index 21cc3c9517e..64586a6782b 100644 --- a/compiler/rustc_ty_utils/src/instance.rs +++ b/compiler/rustc_ty_utils/src/instance.rs @@ -104,8 +104,8 @@ fn resolve_associated_item<'tcx>( "resolving ImplSource::UserDefined: {:?}, {:?}, {:?}, {:?}", param_env, trait_item_id, rcvr_substs, impl_data ); - assert!(!rcvr_substs.needs_infer()); - assert!(!trait_ref.needs_infer()); + assert!(!rcvr_substs.has_infer()); + assert!(!trait_ref.has_infer()); let trait_def_id = tcx.trait_id_of_impl(impl_data.impl_def_id).unwrap(); let trait_def = tcx.trait_def(trait_def_id); diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index 95237dda8c2..1e91e26e2af 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -179,7 +179,7 @@ bitflags! { /// Does this have `ConstKind::Param`? const HAS_CT_PARAM = 1 << 2; - const NEEDS_SUBST = TypeFlags::HAS_TY_PARAM.bits + const HAS_PARAM = TypeFlags::HAS_TY_PARAM.bits | TypeFlags::HAS_RE_PARAM.bits | TypeFlags::HAS_CT_PARAM.bits; @@ -192,7 +192,7 @@ bitflags! { /// Does this have inference variables? Used to determine whether /// inference is required. - const NEEDS_INFER = TypeFlags::HAS_TY_INFER.bits + const HAS_INFER = TypeFlags::HAS_TY_INFER.bits | TypeFlags::HAS_RE_INFER.bits | TypeFlags::HAS_CT_INFER.bits; diff --git a/compiler/rustc_type_ir/src/structural_impls.rs b/compiler/rustc_type_ir/src/structural_impls.rs index 54c1ab5a275..c9675f93f95 100644 --- a/compiler/rustc_type_ir/src/structural_impls.rs +++ b/compiler/rustc_type_ir/src/structural_impls.rs @@ -6,11 +6,10 @@ use crate::fold::{FallibleTypeFolder, TypeFoldable}; use crate::visit::{TypeVisitable, TypeVisitor}; use crate::Interner; use rustc_data_structures::functor::IdFunctor; +use rustc_data_structures::sync::Lrc; use rustc_index::{Idx, IndexVec}; use std::ops::ControlFlow; -use std::rc::Rc; -use std::sync::Arc; /////////////////////////////////////////////////////////////////////////// // Atomic structs @@ -106,25 +105,13 @@ impl<I: Interner, T: TypeVisitable<I>, E: TypeVisitable<I>> TypeVisitable<I> for } } -impl<I: Interner, T: TypeFoldable<I>> TypeFoldable<I> for Rc<T> { +impl<I: Interner, T: TypeFoldable<I>> TypeFoldable<I> for Lrc<T> { fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> { self.try_map_id(|value| value.try_fold_with(folder)) } } -impl<I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for Rc<T> { - fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { - (**self).visit_with(visitor) - } -} - -impl<I: Interner, T: TypeFoldable<I>> TypeFoldable<I> for Arc<T> { - fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> { - self.try_map_id(|value| value.try_fold_with(folder)) - } -} - -impl<I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for Arc<T> { +impl<I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for Lrc<T> { fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { (**self).visit_with(visitor) } @@ -154,19 +141,11 @@ impl<I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for Vec<T> { } } -impl<I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for &[T] { - fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { - self.iter().try_for_each(|t| t.visit_with(visitor)) - } -} - -impl<I: Interner, T: TypeFoldable<I>> TypeFoldable<I> for Box<[T]> { - fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> { - self.try_map_id(|t| t.try_fold_with(folder)) - } -} +// `TypeFoldable` isn't impl'd for `&[T]`. It doesn't make sense in the general +// case, because we can't return a new slice. But note that there are a couple +// of trivial impls of `TypeFoldable` for specific slice types elsewhere. -impl<I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for Box<[T]> { +impl<I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for &[T] { fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { self.iter().try_for_each(|t| t.visit_with(visitor)) } diff --git a/library/std/src/alloc.rs b/library/std/src/alloc.rs index c5a5991cc81..ec774e62deb 100644 --- a/library/std/src/alloc.rs +++ b/library/std/src/alloc.rs @@ -93,7 +93,7 @@ pub use alloc_crate::alloc::*; /// /// ```rust /// use std::alloc::{System, GlobalAlloc, Layout}; -/// use std::sync::atomic::{AtomicUsize, Ordering::SeqCst}; +/// use std::sync::atomic::{AtomicUsize, Ordering::Relaxed}; /// /// struct Counter; /// @@ -103,14 +103,14 @@ pub use alloc_crate::alloc::*; /// unsafe fn alloc(&self, layout: Layout) -> *mut u8 { /// let ret = System.alloc(layout); /// if !ret.is_null() { -/// ALLOCATED.fetch_add(layout.size(), SeqCst); +/// ALLOCATED.fetch_add(layout.size(), Relaxed); /// } /// ret /// } /// /// unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { /// System.dealloc(ptr, layout); -/// ALLOCATED.fetch_sub(layout.size(), SeqCst); +/// ALLOCATED.fetch_sub(layout.size(), Relaxed); /// } /// } /// @@ -118,7 +118,7 @@ pub use alloc_crate::alloc::*; /// static A: Counter = Counter; /// /// fn main() { -/// println!("allocated bytes before main: {}", ALLOCATED.load(SeqCst)); +/// println!("allocated bytes before main: {}", ALLOCATED.load(Relaxed)); /// } /// ``` /// diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index 42a68496fc4..30e553f285b 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -2284,6 +2284,11 @@ pub fn remove_dir<P: AsRef<Path>>(path: P) -> io::Result<()> { /// /// See [`fs::remove_file`] and [`fs::remove_dir`]. /// +/// `remove_dir_all` will fail if `remove_dir` or `remove_file` fail on any constituent paths, including the root path. +/// As a result, the directory you are deleting must exist, meaning that this function is not idempotent. +/// +/// Consider ignoring the error if validating the removal is not required for your use case. +/// /// [`fs::remove_file`]: remove_file /// [`fs::remove_dir`]: remove_dir /// diff --git a/library/std/src/prelude/v1.rs b/library/std/src/prelude/v1.rs index 2aefd7c513d..7a7a7737635 100644 --- a/library/std/src/prelude/v1.rs +++ b/library/std/src/prelude/v1.rs @@ -91,10 +91,10 @@ pub use core::prelude::v1::cfg_eval; )] pub use core::prelude::v1::type_ascribe; -// The file so far is equivalent to src/libcore/prelude/v1.rs, -// and below to src/liballoc/prelude.rs. -// Those files are duplicated rather than using glob imports -// because we want docs to show these re-exports as pointing to within `std`. +// The file so far is equivalent to core/src/prelude/v1.rs. It is duplicated +// rather than glob imported because we want docs to show these re-exports as +// pointing to within `std`. +// Below are the items from the alloc crate. #[stable(feature = "rust1", since = "1.0.0")] #[doc(no_inline)] diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs index fa08fdc1653..3b7c31826b9 100644 --- a/library/std/src/thread/local.rs +++ b/library/std/src/thread/local.rs @@ -134,10 +134,28 @@ impl<T: 'static> fmt::Debug for LocalKey<T> { /// thread_local! { /// pub static FOO: RefCell<u32> = RefCell::new(1); /// -/// #[allow(unused)] /// static BAR: RefCell<f32> = RefCell::new(1.0); /// } -/// # fn main() {} +/// +/// FOO.with(|foo| assert_eq!(*foo.borrow(), 1)); +/// BAR.with(|bar| assert_eq!(*bar.borrow(), 1.0)); +/// ``` +/// +/// This macro supports a special `const {}` syntax that can be used +/// when the initialization expression can be evaluated as a constant. +/// This can enable a more efficient thread local implementation that +/// can avoid lazy initialization. For types that do not +/// [need to be dropped][crate::mem::needs_drop], this can enable an +/// even more efficient implementation that does not need to +/// track any additional state. +/// +/// ``` +/// use std::cell::Cell; +/// thread_local! { +/// pub static FOO: Cell<u32> = const { Cell::new(1) }; +/// } +/// +/// FOO.with(|foo| assert_eq!(foo.get(), 1)); /// ``` /// /// See [`LocalKey` documentation][`std::thread::LocalKey`] for more diff --git a/src/bootstrap/bootstrap_test.py b/src/bootstrap/bootstrap_test.py index 26bd80a008f..5ecda83ee66 100644 --- a/src/bootstrap/bootstrap_test.py +++ b/src/bootstrap/bootstrap_test.py @@ -112,6 +112,14 @@ class GenerateAndParseConfig(unittest.TestCase): build = self.serialize_and_parse(["--set", "profile=compiler"]) self.assertEqual(build.get_toml("profile"), 'compiler') + def test_set_codegen_backends(self): + build = self.serialize_and_parse(["--set", "rust.codegen-backends=cranelift"]) + self.assertNotEqual(build.config_toml.find("codegen-backends = ['cranelift']"), -1) + build = self.serialize_and_parse(["--set", "rust.codegen-backends=cranelift,llvm"]) + self.assertNotEqual(build.config_toml.find("codegen-backends = ['cranelift', 'llvm']"), -1) + build = self.serialize_and_parse(["--enable-full-tools"]) + self.assertNotEqual(build.config_toml.find("codegen-backends = ['llvm']"), -1) + if __name__ == '__main__': SUITE = unittest.TestSuite() TEST_LOADER = unittest.TestLoader() diff --git a/src/bootstrap/configure.py b/src/bootstrap/configure.py index dd1851e29a9..571062a3a6f 100755 --- a/src/bootstrap/configure.py +++ b/src/bootstrap/configure.py @@ -153,8 +153,7 @@ v("experimental-targets", "llvm.experimental-targets", "experimental LLVM targets to build") v("release-channel", "rust.channel", "the name of the release channel to build") v("release-description", "rust.description", "optional descriptive string for version output") -v("dist-compression-formats", None, - "comma-separated list of compression formats to use") +v("dist-compression-formats", None, "List of compression formats to use") # Used on systems where "cc" is unavailable v("default-linker", "rust.default-linker", "the default linker") @@ -168,8 +167,8 @@ o("extended", "build.extended", "build an extended rust tool set") v("tools", None, "List of extended tools will be installed") v("codegen-backends", None, "List of codegen backends to build") v("build", "build.build", "GNUs ./configure syntax LLVM build triple") -v("host", None, "GNUs ./configure syntax LLVM host triples") -v("target", None, "GNUs ./configure syntax LLVM target triples") +v("host", None, "List of GNUs ./configure syntax LLVM host triples") +v("target", None, "List of GNUs ./configure syntax LLVM target triples") v("set", None, "set arbitrary key/value pairs in TOML configuration") @@ -182,6 +181,11 @@ def err(msg): print("configure: error: " + msg) sys.exit(1) +def is_value_list(key): + for option in options: + if option.name == key and option.desc.startswith('List of'): + return True + return False if '--help' in sys.argv or '-h' in sys.argv: print('Usage: ./configure [options]') @@ -295,6 +299,8 @@ def set(key, value, config): parts = key.split('.') for i, part in enumerate(parts): if i == len(parts) - 1: + if is_value_list(part) and isinstance(value, str): + value = value.split(',') arr[part] = value else: if part not in arr: diff --git a/src/doc/rustdoc/src/scraped-examples.md b/src/doc/rustdoc/src/scraped-examples.md index d75f6d522e8..7197e01c8e3 100644 --- a/src/doc/rustdoc/src/scraped-examples.md +++ b/src/doc/rustdoc/src/scraped-examples.md @@ -24,14 +24,14 @@ Then this code snippet will be included in the documentation for `a_func`. This This feature is unstable, so you can enable it by calling Rustdoc with the unstable `rustdoc-scrape-examples` flag: ```bash -cargo doc -Zunstable-options -Zrustdoc-scrape-examples=examples +cargo doc -Zunstable-options -Zrustdoc-scrape-examples ``` To enable this feature on [docs.rs](https://docs.rs), add this to your Cargo.toml: ```toml [package.metadata.docs.rs] -cargo-args = ["-Zunstable-options", "-Zrustdoc-scrape-examples=examples"] +cargo-args = ["-Zunstable-options", "-Zrustdoc-scrape-examples"] ``` diff --git a/src/doc/style-guide/src/statements.md b/src/doc/style-guide/src/statements.md index 4ab1c36f976..671e6d31a57 100644 --- a/src/doc/style-guide/src/statements.md +++ b/src/doc/style-guide/src/statements.md @@ -138,18 +138,31 @@ Otherwise, the `else` keyword and opening brace should be placed on the next lin For example: ```rust -let Some(x) = abcdef() - .foo( - "abc", - some_really_really_really_long_ident, - "ident", - "123456", - ) - .bar() - .baz() - .qux("fffffffffffffffff") -else { - foo_bar() +fn main() { + let Some(x) = abcdef() + .foo( + "abc", + some_really_really_really_long_ident, + "ident", + "123456", + ) + .bar() + .baz() + .qux("fffffffffffffffff") + else { + return + }; + + let Some(x) = some_really_really_really_really_really_really_really_really_really_long_name + else { + return; + }; + + let Some(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) = + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb + else { + return; + }; } ``` diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index f2486abaaa7..7e173a171a8 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -1295,7 +1295,8 @@ impl LinkCollector<'_, '_> { } } } - resolution_failure(self, diag, path_str, disambiguator, smallvec![err]) + resolution_failure(self, diag, path_str, disambiguator, smallvec![err]); + return vec![]; } } } @@ -1331,13 +1332,14 @@ impl LinkCollector<'_, '_> { .fold(0, |acc, res| if let Ok(res) = res { acc + res.len() } else { acc }); if len == 0 { - return resolution_failure( + resolution_failure( self, diag, path_str, disambiguator, candidates.into_iter().filter_map(|res| res.err()).collect(), ); + return vec![]; } else if len == 1 { candidates.into_iter().filter_map(|res| res.ok()).flatten().collect::<Vec<_>>() } else { @@ -1642,9 +1644,8 @@ fn resolution_failure( path_str: &str, disambiguator: Option<Disambiguator>, kinds: SmallVec<[ResolutionFailure<'_>; 3]>, -) -> Vec<(Res, Option<DefId>)> { +) { let tcx = collector.cx.tcx; - let mut recovered_res = None; report_diagnostic( tcx, BROKEN_INTRA_DOC_LINKS, @@ -1736,19 +1737,25 @@ fn resolution_failure( if !path_str.contains("::") { if disambiguator.map_or(true, |d| d.ns() == MacroNS) - && let Some(&res) = collector.cx.tcx.resolutions(()).all_macro_rules - .get(&Symbol::intern(path_str)) + && collector + .cx + .tcx + .resolutions(()) + .all_macro_rules + .get(&Symbol::intern(path_str)) + .is_some() { diag.note(format!( "`macro_rules` named `{path_str}` exists in this crate, \ but it is not in scope at this link's location" )); - recovered_res = res.try_into().ok().map(|res| (res, None)); } else { // If the link has `::` in it, assume it was meant to be an // intra-doc link. Otherwise, the `[]` might be unrelated. - diag.help("to escape `[` and `]` characters, \ - add '\\' before them like `\\[` or `\\]`"); + diag.help( + "to escape `[` and `]` characters, \ + add '\\' before them like `\\[` or `\\]`", + ); } } @@ -1854,11 +1861,6 @@ fn resolution_failure( } }, ); - - match recovered_res { - Some(r) => vec![r], - None => Vec::new(), - } } fn report_multiple_anchors(cx: &DocContext<'_>, diag_info: DiagnosticInfo<'_>) { diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs index cb700126c2b..a6572011644 100644 --- a/src/tools/clippy/clippy_utils/src/ty.rs +++ b/src/tools/clippy/clippy_utils/src/ty.rs @@ -226,7 +226,7 @@ pub fn implements_trait_with_env<'tcx>( ty_params: impl IntoIterator<Item = Option<GenericArg<'tcx>>>, ) -> bool { // Clippy shouldn't have infer types - assert!(!ty.needs_infer()); + assert!(!ty.has_infer()); let ty = tcx.erase_regions(ty); if ty.has_escaping_bound_vars() { diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index f6597c72938..e03a73c4e71 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -224,6 +224,7 @@ enum Emit { Metadata, LlvmIr, Asm, + LinkArgsAsm, } impl<'test> TestCx<'test> { @@ -2035,6 +2036,9 @@ impl<'test> TestCx<'test> { Emit::Asm => { rustc.args(&["--emit", "asm"]); } + Emit::LinkArgsAsm => { + rustc.args(&["-Clink-args=--emit=asm"]); + } } if !is_rustdoc { @@ -2328,11 +2332,15 @@ impl<'test> TestCx<'test> { emit = Emit::Asm; } + Some("bpf-linker") => { + emit = Emit::LinkArgsAsm; + } + Some("ptx-linker") => { // No extra flags needed. } - Some(_) => self.fatal("unknown 'assembly-output' header"), + Some(header) => self.fatal(&format!("unknown 'assembly-output' header: {header}")), None => self.fatal("missing 'assembly-output' header"), } diff --git a/tests/debuginfo/thread.rs b/tests/debuginfo/thread.rs index 388d50c5cdc..e7e83c7aacd 100644 --- a/tests/debuginfo/thread.rs +++ b/tests/debuginfo/thread.rs @@ -1,4 +1,4 @@ -// Testing the the display of JoinHandle and Thread in cdb. +// Testing the display of JoinHandle and Thread in cdb. // cdb-only // min-cdb-version: 10.0.18317.1001 diff --git a/tests/mir-opt/building/async_await.b-{closure#0}.generator_resume.0.mir b/tests/mir-opt/building/async_await.b-{closure#0}.generator_resume.0.mir index 7cce3415fa1..9bced25a595 100644 --- a/tests/mir-opt/building/async_await.b-{closure#0}.generator_resume.0.mir +++ b/tests/mir-opt/building/async_await.b-{closure#0}.generator_resume.0.mir @@ -12,7 +12,7 @@ _1: GeneratorSavedTy { ty: impl std::future::Future<Output = ()>, source_info: SourceInfo { - span: $DIR/async_await.rs:16:8: 16:14 (#11), + span: $DIR/async_await.rs:16:8: 16:14 (#10), scope: scope[0], }, ignore_for_traits: false, diff --git a/tests/rustdoc-ui/doc_cfg_hide.stderr b/tests/rustdoc-ui/doc_cfg_hide.stderr index 03623368cd0..b7e8870fdf5 100644 --- a/tests/rustdoc-ui/doc_cfg_hide.stderr +++ b/tests/rustdoc-ui/doc_cfg_hide.stderr @@ -16,7 +16,7 @@ LL | #![deny(warnings)] help: to apply to the crate, use an inner attribute | LL | #![doc(cfg_hide(doc))] - | ~~~~~~~~~~~~~~~~~~~~~~ + | + error: `#[doc(cfg_hide(...)]` takes a list of attributes --> $DIR/doc_cfg_hide.rs:4:8 diff --git a/tests/rustdoc-ui/invalid-doc-attr.rs b/tests/rustdoc-ui/invalid-doc-attr.rs index de004b41e27..c231e43b35c 100644 --- a/tests/rustdoc-ui/invalid-doc-attr.rs +++ b/tests/rustdoc-ui/invalid-doc-attr.rs @@ -5,7 +5,7 @@ //~^ ERROR can only be applied at the crate level //~| WARN is being phased out //~| HELP to apply to the crate, use an inner attribute -//~| SUGGESTION #![doc(test(no_crate_inject))] +//~| SUGGESTION ! #[doc(inline)] //~^ ERROR can only be applied to a `use` item //~| WARN is being phased out diff --git a/tests/rustdoc-ui/invalid-doc-attr.stderr b/tests/rustdoc-ui/invalid-doc-attr.stderr index 3c66e587b47..b23b8ded867 100644 --- a/tests/rustdoc-ui/invalid-doc-attr.stderr +++ b/tests/rustdoc-ui/invalid-doc-attr.stderr @@ -16,7 +16,7 @@ LL | #![deny(warnings)] help: to apply to the crate, use an inner attribute | LL | #![doc(test(no_crate_inject))] - | + | + error: this attribute can only be applied to a `use` item --> $DIR/invalid-doc-attr.rs:9:7 diff --git a/tests/rustdoc/issue-106142.rs b/tests/rustdoc/issue-106142.rs new file mode 100644 index 00000000000..41505e72405 --- /dev/null +++ b/tests/rustdoc/issue-106142.rs @@ -0,0 +1,14 @@ +// @has 'issue_106142/a/index.html' +// @count 'issue_106142/a/index.html' '//ul[@class="item-table"]//li//a' 1 + +#![allow(rustdoc::broken_intra_doc_links)] + +pub mod a { + /// [`m`] + pub fn f() {} + + #[macro_export] + macro_rules! m { + () => {}; + } +} diff --git a/tests/ui/attributes/invalid-doc-attr.rs b/tests/ui/attributes/invalid-doc-attr.rs index de004b41e27..c231e43b35c 100644 --- a/tests/ui/attributes/invalid-doc-attr.rs +++ b/tests/ui/attributes/invalid-doc-attr.rs @@ -5,7 +5,7 @@ //~^ ERROR can only be applied at the crate level //~| WARN is being phased out //~| HELP to apply to the crate, use an inner attribute -//~| SUGGESTION #![doc(test(no_crate_inject))] +//~| SUGGESTION ! #[doc(inline)] //~^ ERROR can only be applied to a `use` item //~| WARN is being phased out diff --git a/tests/ui/attributes/invalid-doc-attr.stderr b/tests/ui/attributes/invalid-doc-attr.stderr index 3c66e587b47..b23b8ded867 100644 --- a/tests/ui/attributes/invalid-doc-attr.stderr +++ b/tests/ui/attributes/invalid-doc-attr.stderr @@ -16,7 +16,7 @@ LL | #![deny(warnings)] help: to apply to the crate, use an inner attribute | LL | #![doc(test(no_crate_inject))] - | + | + error: this attribute can only be applied to a `use` item --> $DIR/invalid-doc-attr.rs:9:7 diff --git a/tests/ui/coherence/coherence-overlap-negative-impls.rs b/tests/ui/coherence/coherence-overlap-negative-impls.rs new file mode 100644 index 00000000000..cd1df53a528 --- /dev/null +++ b/tests/ui/coherence/coherence-overlap-negative-impls.rs @@ -0,0 +1,41 @@ +// check-pass +// known-bug: #74629 + +// Should fail. The `0` and `1` impls overlap, violating coherence. Eg, with +// `T = Test, F = ()`, all bounds are true, making both impls applicable. +// `Test: Fold<Nil>`, `Test: Fold<()>` are true because of `2`. +// `Is<Test>: NotNil` is true because of `auto trait` and lack of negative impl. + +#![feature(negative_impls)] +#![feature(auto_traits)] + +struct Nil; +struct Cons<H>(H); +struct Test; + +trait Fold<F> {} + +impl<T, F> Fold<F> for Cons<T> // 0 +where + T: Fold<Nil>, +{} + +impl<T, F> Fold<F> for Cons<T> // 1 +where + T: Fold<F>, + private::Is<T>: private::NotNil, +{} + +impl<F> Fold<F> for Test {} // 2 + +mod private { + use crate::Nil; + + pub struct Is<T>(T); + pub auto trait NotNil {} + + #[allow(suspicious_auto_trait_impls)] + impl !NotNil for Is<Nil> {} +} + +fn main() {} diff --git a/tests/ui/generic-associated-types/self-outlives-lint.rs b/tests/ui/generic-associated-types/self-outlives-lint.rs index 673891fc3d1..0ea81b5aecb 100644 --- a/tests/ui/generic-associated-types/self-outlives-lint.rs +++ b/tests/ui/generic-associated-types/self-outlives-lint.rs @@ -189,7 +189,7 @@ trait MultipleMethods { } // We would normally require `Self: 'a`, but we can prove that `Self: 'static` -// because of the the bounds on the trait, so the bound is proven +// because of the bounds on the trait, so the bound is proven trait Trait: 'static { type Assoc<'a>; fn make_assoc(_: &u32) -> Self::Assoc<'_>; diff --git a/tests/ui/methods/method-not-found-generic-arg-elision.rs b/tests/ui/methods/method-not-found-generic-arg-elision.rs index 799ced5e9c4..538eeadae08 100644 --- a/tests/ui/methods/method-not-found-generic-arg-elision.rs +++ b/tests/ui/methods/method-not-found-generic-arg-elision.rs @@ -83,8 +83,8 @@ fn main() { //~^ ERROR no method named `distance` found for struct `Point<i32> let d = point_i32.other(); //~^ ERROR no method named `other` found for struct `Point - let v = vec![1_i32, 2, 3]; - v.iter().map(|x| x * x).extend(std::iter::once(100)); + let v = vec![1, 2, 3]; + v.iter().map(Box::new(|x| x * x) as Box<dyn Fn(&i32) -> i32>).extend(std::iter::once(100)); //~^ ERROR no method named `extend` found for struct `Map let wrapper = Wrapper(true); wrapper.method(); diff --git a/tests/ui/methods/method-not-found-generic-arg-elision.stderr b/tests/ui/methods/method-not-found-generic-arg-elision.stderr index f3db56d1d53..b97688d3868 100644 --- a/tests/ui/methods/method-not-found-generic-arg-elision.stderr +++ b/tests/ui/methods/method-not-found-generic-arg-elision.stderr @@ -20,10 +20,10 @@ LL | let d = point_i32.other(); | ^^^^^ method not found in `Point<i32>` error[E0599]: no method named `extend` found for struct `Map` in the current scope - --> $DIR/method-not-found-generic-arg-elision.rs:87:29 + --> $DIR/method-not-found-generic-arg-elision.rs:87:67 | -LL | v.iter().map(|x| x * x).extend(std::iter::once(100)); - | ^^^^^^ method not found in `Map<Iter<'_, i32>, [closure@method-not-found-generic-arg-elision.rs:87:18]>` +LL | v.iter().map(Box::new(|x| x * x) as Box<dyn Fn(&i32) -> i32>).extend(std::iter::once(100)); + | ^^^^^^ method not found in `Map<Iter<'_, i32>, Box<dyn Fn(&i32) -> i32>>` error[E0599]: no method named `method` found for struct `Wrapper<bool>` in the current scope --> $DIR/method-not-found-generic-arg-elision.rs:90:13 diff --git a/tests/ui/panics/fmt-only-once.rs b/tests/ui/panics/fmt-only-once.rs new file mode 100644 index 00000000000..6211bf961b3 --- /dev/null +++ b/tests/ui/panics/fmt-only-once.rs @@ -0,0 +1,21 @@ +// run-fail +// check-run-results +// exec-env:RUST_BACKTRACE=0 + +// Test that we format the panic message only once. +// Regression test for https://github.com/rust-lang/rust/issues/110717 + +use std::fmt; + +struct PrintOnFmt; + +impl fmt::Display for PrintOnFmt { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + eprintln!("fmt"); + f.write_str("PrintOnFmt") + } +} + +fn main() { + panic!("{}", PrintOnFmt) +} diff --git a/tests/ui/panics/fmt-only-once.run.stderr b/tests/ui/panics/fmt-only-once.run.stderr new file mode 100644 index 00000000000..39bd06881ad --- /dev/null +++ b/tests/ui/panics/fmt-only-once.run.stderr @@ -0,0 +1,3 @@ +fmt +thread 'main' panicked at 'PrintOnFmt', $DIR/fmt-only-once.rs:20:5 +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace diff --git a/tests/ui/specialization/issue-40582.rs b/tests/ui/specialization/issue-40582.rs new file mode 100644 index 00000000000..9805933553d --- /dev/null +++ b/tests/ui/specialization/issue-40582.rs @@ -0,0 +1,35 @@ +// check-pass +// known-bug: #40582 + +// Should fail. Should not be possible to implement `make_static`. + +#![feature(specialization)] +#![allow(incomplete_features)] + +trait FromRef<'a, T: ?Sized> { + fn from_ref(r: &'a T) -> Self; +} + +impl<'a, T: ?Sized> FromRef<'a, T> for &'a T { + fn from_ref(r: &'a T) -> Self { + r + } +} + +impl<'a, T: ?Sized, R> FromRef<'a, T> for R { + default fn from_ref(_: &'a T) -> Self { + unimplemented!() + } +} + +fn make_static<T: ?Sized>(data: &T) -> &'static T { + fn helper<T: ?Sized, R>(data: &T) -> R { + R::from_ref(data) + } + helper(data) +} + +fn main() { + let s = "specialization".to_owned(); + println!("{:?}", make_static(s.as_str())); +} diff --git a/tests/ui/specialization/specialization-default-items-drop-coherence.rs b/tests/ui/specialization/specialization-default-items-drop-coherence.rs new file mode 100644 index 00000000000..16ad942d5ab --- /dev/null +++ b/tests/ui/specialization/specialization-default-items-drop-coherence.rs @@ -0,0 +1,30 @@ +// check-pass +// known-bug: #105782 + +// Should fail. Default items completely drop candidates instead of ambiguity, +// which is unsound during coherence, since coherence requires completeness. + +#![feature(specialization)] +#![allow(incomplete_features)] + +trait Default { + type Id; +} + +impl<T> Default for T { + default type Id = T; +} + +trait Overlap { + type Assoc; +} + +impl Overlap for u32 { + type Assoc = usize; +} + +impl Overlap for <u32 as Default>::Id { + type Assoc = Box<usize>; +} + +fn main() {} diff --git a/tests/ui/thread-local/thread-local-static-ref-use-after-free.rs b/tests/ui/thread-local/thread-local-static-ref-use-after-free.rs new file mode 100644 index 00000000000..c282e2185bc --- /dev/null +++ b/tests/ui/thread-local/thread-local-static-ref-use-after-free.rs @@ -0,0 +1,46 @@ +// check-pass +// known-bug: #49682 +// edition:2021 + +// Should fail. Keeping references to thread local statics can result in a +// use-after-free. + +#![feature(thread_local)] + +use std::sync::atomic::{AtomicUsize, Ordering}; +use std::thread; + +#[allow(dead_code)] +#[thread_local] +static FOO: AtomicUsize = AtomicUsize::new(0); + +#[allow(dead_code)] +async fn bar() {} + +#[allow(dead_code)] +async fn foo() { + let r = &FOO; + bar().await; + r.load(Ordering::SeqCst); +} + +fn main() { + // &FOO = 0x7fd1e9cbf6d0 + _ = thread::spawn(|| { + let g = foo(); + println!("&FOO = {:p}", &FOO); + g + }) + .join() + .unwrap(); + + // &FOO = 0x7fd1e9cc0f50 + println!("&FOO = {:p}", &FOO); + + // &FOO = 0x7fd1e9cbf6d0 + thread::spawn(move || { + println!("&FOO = {:p}", &FOO); + }) + .join() + .unwrap(); +} |
