diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index d82d4cc39fb1c..516a080777889 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -250,7 +250,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { } let definition_ty = instantiated_ty - .remap_generic_params_to_declaration_params(opaque_type_key, self.tcx, false, origin) + .remap_generic_params_to_declaration_params(opaque_type_key, self.tcx, false) .ty; if !check_opaque_type_parameter_valid( diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index 0a7e25300cba8..639f81f20bfb9 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -4,6 +4,7 @@ use hir::{ GenericParamKind, HirId, Node, }; use rustc_hir as hir; +use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; use rustc_middle::ty::{self, TyCtxt}; use rustc_session::lint; @@ -142,7 +143,20 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics { Some(tcx.typeck_root_def_id(def_id)) } Node::Item(item) => match item.kind { - ItemKind::OpaqueTy(hir::OpaqueTy { .. }) => { + ItemKind::OpaqueTy(hir::OpaqueTy { + origin: + hir::OpaqueTyOrigin::FnReturn(fn_def_id) | hir::OpaqueTyOrigin::AsyncFn(fn_def_id), + in_trait, + .. + }) => { + if in_trait { + assert!(matches!(tcx.def_kind(fn_def_id), DefKind::AssocFn)) + } else { + assert!(matches!(tcx.def_kind(fn_def_id), DefKind::AssocFn | DefKind::Fn)) + } + Some(fn_def_id.to_def_id()) + } + ItemKind::OpaqueTy(hir::OpaqueTy { origin: hir::OpaqueTyOrigin::TyAlias, .. }) => { let parent_id = tcx.hir().get_parent_item(hir_id); assert_ne!(parent_id, hir::CRATE_OWNER_ID); debug!("generics_of: parent of opaque ty {:?} is {:?}", def_id, parent_id); diff --git a/compiler/rustc_hir_analysis/src/collect/lifetimes.rs b/compiler/rustc_hir_analysis/src/collect/lifetimes.rs index 9a7b261fffd4d..e4fe3e90ebe1c 100644 --- a/compiler/rustc_hir_analysis/src/collect/lifetimes.rs +++ b/compiler/rustc_hir_analysis/src/collect/lifetimes.rs @@ -1195,8 +1195,10 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { // Fresh lifetimes in APIT used to be allowed in async fns and forbidden in // regular fns. if let Some(hir::PredicateOrigin::ImplTrait) = where_bound_origin - && let hir::LifetimeName::Param(_) = lifetime_ref.res - && lifetime_ref.is_anonymous() + && let hir::LifetimeName::Param(param_id) = lifetime_ref.res + && let Some(generics) = self.tcx.hir().get_generics(self.tcx.local_parent(param_id)) + && let Some(param) = generics.params.iter().find(|p| p.def_id == param_id) + && param.is_elided_lifetime() && let hir::IsAsync::NotAsync = self.tcx.asyncness(lifetime_ref.hir_id.owner.def_id) && !self.tcx.features().anonymous_lifetime_in_impl_trait { diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index 58ced6a1d3b4f..52ffd286e88f6 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -565,7 +565,6 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { opaque_type_key, self.fcx.infcx.tcx, true, - decl.origin, ); self.typeck_results.concrete_opaque_types.insert(opaque_type_key.def_id, hidden_type); diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index c062e508ee3df..3f99efd250161 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -28,7 +28,6 @@ use crate::ty::util::Discr; pub use adt::*; pub use assoc::*; pub use generics::*; -use hir::OpaqueTyOrigin; use rustc_ast as ast; use rustc_ast::node_id::NodeMap; use rustc_attr as attr; @@ -1287,7 +1286,6 @@ impl<'tcx> OpaqueHiddenType<'tcx> { tcx: TyCtxt<'tcx>, // typeck errors have subpar spans for opaque types, so delay error reporting until borrowck. ignore_errors: bool, - origin: OpaqueTyOrigin, ) -> Self { let OpaqueTypeKey { def_id, substs } = opaque_type_key; @@ -1303,30 +1301,7 @@ impl<'tcx> OpaqueHiddenType<'tcx> { // This zip may have several times the same lifetime in `substs` paired with a different // lifetime from `id_substs`. Simply `collect`ing the iterator is the correct behaviour: // it will pick the last one, which is the one we introduced in the impl-trait desugaring. - let map = substs.iter().zip(id_substs); - - let map: FxHashMap, GenericArg<'tcx>> = match origin { - // HACK: The HIR lowering for async fn does not generate - // any `+ Captures<'x>` bounds for the `impl Future<...>`, so all async fns with lifetimes - // would now fail to compile. We should probably just make hir lowering fill this in properly. - OpaqueTyOrigin::AsyncFn(_) => map.collect(), - OpaqueTyOrigin::FnReturn(_) | OpaqueTyOrigin::TyAlias => { - // Opaque types may only use regions that are bound. So for - // ```rust - // type Foo<'a, 'b, 'c> = impl Trait<'a> + 'b; - // ``` - // we may not use `'c` in the hidden type. - let variances = tcx.variances_of(def_id); - debug!(?variances); - - map.filter(|(_, v)| { - let ty::GenericArgKind::Lifetime(lt) = v.unpack() else { return true }; - let ty::ReEarlyBound(ebr) = lt.kind() else { bug!() }; - variances[ebr.index as usize] == ty::Variance::Invariant - }) - .collect() - } - }; + let map = substs.iter().zip(id_substs).collect(); debug!("map = {:#?}", map); // Convert the type from the function into a type valid outside diff --git a/library/std/src/sync/mpmc/array.rs b/library/std/src/sync/mpmc/array.rs index f71edc6c525a2..c1e3e48b04468 100644 --- a/library/std/src/sync/mpmc/array.rs +++ b/library/std/src/sync/mpmc/array.rs @@ -168,7 +168,7 @@ impl Channel { return true; } Err(_) => { - backoff.spin(); + backoff.spin_light(); tail = self.tail.load(Ordering::Relaxed); } } @@ -182,11 +182,11 @@ impl Channel { return false; } - backoff.spin(); + backoff.spin_light(); tail = self.tail.load(Ordering::Relaxed); } else { // Snooze because we need to wait for the stamp to get updated. - backoff.snooze(); + backoff.spin_heavy(); tail = self.tail.load(Ordering::Relaxed); } } @@ -251,7 +251,7 @@ impl Channel { return true; } Err(_) => { - backoff.spin(); + backoff.spin_light(); head = self.head.load(Ordering::Relaxed); } } @@ -273,11 +273,11 @@ impl Channel { } } - backoff.spin(); + backoff.spin_light(); head = self.head.load(Ordering::Relaxed); } else { // Snooze because we need to wait for the stamp to get updated. - backoff.snooze(); + backoff.spin_heavy(); head = self.head.load(Ordering::Relaxed); } } @@ -330,7 +330,7 @@ impl Channel { if backoff.is_completed() { break; } else { - backoff.spin(); + backoff.spin_light(); } } diff --git a/library/std/src/sync/mpmc/list.rs b/library/std/src/sync/mpmc/list.rs index 2d5b2fb3b231d..ec6c0726ac790 100644 --- a/library/std/src/sync/mpmc/list.rs +++ b/library/std/src/sync/mpmc/list.rs @@ -46,7 +46,7 @@ impl Slot { fn wait_write(&self) { let backoff = Backoff::new(); while self.state.load(Ordering::Acquire) & WRITE == 0 { - backoff.snooze(); + backoff.spin_heavy(); } } } @@ -82,7 +82,7 @@ impl Block { if !next.is_null() { return next; } - backoff.snooze(); + backoff.spin_heavy(); } } @@ -191,7 +191,7 @@ impl Channel { // If we reached the end of the block, wait until the next one is installed. if offset == BLOCK_CAP { - backoff.snooze(); + backoff.spin_heavy(); tail = self.tail.index.load(Ordering::Acquire); block = self.tail.block.load(Ordering::Acquire); continue; @@ -247,7 +247,7 @@ impl Channel { return true; }, Err(_) => { - backoff.spin(); + backoff.spin_light(); tail = self.tail.index.load(Ordering::Acquire); block = self.tail.block.load(Ordering::Acquire); } @@ -286,7 +286,7 @@ impl Channel { // If we reached the end of the block, wait until the next one is installed. if offset == BLOCK_CAP { - backoff.snooze(); + backoff.spin_heavy(); head = self.head.index.load(Ordering::Acquire); block = self.head.block.load(Ordering::Acquire); continue; @@ -320,7 +320,7 @@ impl Channel { // The block can be null here only if the first message is being sent into the channel. // In that case, just wait until it gets initialized. if block.is_null() { - backoff.snooze(); + backoff.spin_heavy(); head = self.head.index.load(Ordering::Acquire); block = self.head.block.load(Ordering::Acquire); continue; @@ -351,7 +351,7 @@ impl Channel { return true; }, Err(_) => { - backoff.spin(); + backoff.spin_light(); head = self.head.index.load(Ordering::Acquire); block = self.head.block.load(Ordering::Acquire); } @@ -542,7 +542,7 @@ impl Channel { // New updates to tail will be rejected by MARK_BIT and aborted unless it's // at boundary. We need to wait for the updates take affect otherwise there // can be memory leaks. - backoff.snooze(); + backoff.spin_heavy(); tail = self.tail.index.load(Ordering::Acquire); } diff --git a/library/std/src/sync/mpmc/mod.rs b/library/std/src/sync/mpmc/mod.rs index cef99c5884300..7a602cecd3b89 100644 --- a/library/std/src/sync/mpmc/mod.rs +++ b/library/std/src/sync/mpmc/mod.rs @@ -43,7 +43,7 @@ mod zero; use crate::fmt; use crate::panic::{RefUnwindSafe, UnwindSafe}; use crate::time::{Duration, Instant}; -use error::*; +pub use error::*; /// Creates a channel of unbounded capacity. /// diff --git a/library/std/src/sync/mpmc/utils.rs b/library/std/src/sync/mpmc/utils.rs index d0904b4b94cbc..cfe42750d5239 100644 --- a/library/std/src/sync/mpmc/utils.rs +++ b/library/std/src/sync/mpmc/utils.rs @@ -91,9 +91,8 @@ impl DerefMut for CachePadded { } const SPIN_LIMIT: u32 = 6; -const YIELD_LIMIT: u32 = 10; -/// Performs exponential backoff in spin loops. +/// Performs quadratic backoff in spin loops. pub struct Backoff { step: Cell, } @@ -104,25 +103,27 @@ impl Backoff { Backoff { step: Cell::new(0) } } - /// Backs off in a lock-free loop. + /// Backs off using lightweight spinning. /// - /// This method should be used when we need to retry an operation because another thread made - /// progress. + /// This method should be used for: + /// - Retrying an operation because another thread made progress. i.e. on CAS failure. + /// - Waiting for an operation to complete by spinning optimistically for a few iterations + /// before falling back to parking the thread (see `Backoff::is_completed`). #[inline] - pub fn spin(&self) { + pub fn spin_light(&self) { let step = self.step.get().min(SPIN_LIMIT); for _ in 0..step.pow(2) { crate::hint::spin_loop(); } - if self.step.get() <= SPIN_LIMIT { - self.step.set(self.step.get() + 1); - } + self.step.set(self.step.get() + 1); } - /// Backs off in a blocking loop. + /// Backs off using heavyweight spinning. + /// + /// This method should be used in blocking loops where parking the thread is not an option. #[inline] - pub fn snooze(&self) { + pub fn spin_heavy(&self) { if self.step.get() <= SPIN_LIMIT { for _ in 0..self.step.get().pow(2) { crate::hint::spin_loop() @@ -131,14 +132,12 @@ impl Backoff { crate::thread::yield_now(); } - if self.step.get() <= YIELD_LIMIT { - self.step.set(self.step.get() + 1); - } + self.step.set(self.step.get() + 1); } - /// Returns `true` if exponential backoff has completed and blocking the thread is advised. + /// Returns `true` if quadratic backoff has completed and parking the thread is advised. #[inline] pub fn is_completed(&self) -> bool { - self.step.get() > YIELD_LIMIT + self.step.get() > SPIN_LIMIT } } diff --git a/library/std/src/sync/mpmc/zero.rs b/library/std/src/sync/mpmc/zero.rs index fccd6c29a7e46..33f768dcbe902 100644 --- a/library/std/src/sync/mpmc/zero.rs +++ b/library/std/src/sync/mpmc/zero.rs @@ -57,7 +57,7 @@ impl Packet { fn wait_ready(&self) { let backoff = Backoff::new(); while !self.ready.load(Ordering::Acquire) { - backoff.snooze(); + backoff.spin_heavy(); } } } diff --git a/library/std/src/sync/mpsc/mod.rs b/library/std/src/sync/mpsc/mod.rs index adb488d4378f0..6e3c28f10bb1b 100644 --- a/library/std/src/sync/mpsc/mod.rs +++ b/library/std/src/sync/mpsc/mod.rs @@ -738,6 +738,15 @@ impl SyncSender { pub fn try_send(&self, t: T) -> Result<(), TrySendError> { self.inner.try_send(t) } + + // Attempts to send for a value on this receiver, returning an error if the + // corresponding channel has hung up, or if it waits more than `timeout`. + // + // This method is currently private and only used for tests. + #[allow(unused)] + fn send_timeout(&self, t: T, timeout: Duration) -> Result<(), mpmc::SendTimeoutError> { + self.inner.send_timeout(t, timeout) + } } #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/std/src/sync/mpsc/sync_tests.rs b/library/std/src/sync/mpsc/sync_tests.rs index 63c79436974d5..9d2f92ffc9b14 100644 --- a/library/std/src/sync/mpsc/sync_tests.rs +++ b/library/std/src/sync/mpsc/sync_tests.rs @@ -1,5 +1,6 @@ use super::*; use crate::env; +use crate::sync::mpmc::SendTimeoutError; use crate::thread; use crate::time::Duration; @@ -41,6 +42,13 @@ fn recv_timeout() { assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Ok(1)); } +#[test] +fn send_timeout() { + let (tx, _rx) = sync_channel::(1); + assert_eq!(tx.send_timeout(1, Duration::from_millis(1)), Ok(())); + assert_eq!(tx.send_timeout(1, Duration::from_millis(1)), Err(SendTimeoutError::Timeout(1))); +} + #[test] fn smoke_threads() { let (tx, rx) = sync_channel::(0); diff --git a/src/bootstrap/install.rs b/src/bootstrap/install.rs index 7672b7c913594..38426f3a447e0 100644 --- a/src/bootstrap/install.rs +++ b/src/bootstrap/install.rs @@ -200,10 +200,14 @@ install!((self, builder, _config), install_sh(builder, "clippy", self.compiler.stage, Some(self.target), &tarball); }; Miri, alias = "miri", Self::should_build(_config), only_hosts: true, { - let tarball = builder - .ensure(dist::Miri { compiler: self.compiler, target: self.target }) - .expect("missing miri"); - install_sh(builder, "miri", self.compiler.stage, Some(self.target), &tarball); + if let Some(tarball) = builder.ensure(dist::Miri { compiler: self.compiler, target: self.target }) { + install_sh(builder, "miri", self.compiler.stage, Some(self.target), &tarball); + } else { + // Miri is only available on nightly + builder.info( + &format!("skipping Install miri stage{} ({})", self.compiler.stage, self.target), + ); + } }; Rustfmt, alias = "rustfmt", Self::should_build(_config), only_hosts: true, { if let Some(tarball) = builder.ensure(dist::Rustfmt { diff --git a/src/doc/rustdoc/src/lints.md b/src/doc/rustdoc/src/lints.md index bff01d7cb7c14..45db3bb9b007b 100644 --- a/src/doc/rustdoc/src/lints.md +++ b/src/doc/rustdoc/src/lints.md @@ -261,7 +261,7 @@ typo mistakes for some common attributes. ## `invalid_html_tags` -This lint is **allowed by default** and is **nightly-only**. It detects unclosed +This lint **warns by default**. It detects unclosed or invalid HTML tags. For example: ```rust diff --git a/src/test/ui/async-await/in-trait/nested-rpit.rs b/src/test/ui/async-await/in-trait/nested-rpit.rs index ae8e0aed0cc53..41d72ebb4d4c5 100644 --- a/src/test/ui/async-await/in-trait/nested-rpit.rs +++ b/src/test/ui/async-await/in-trait/nested-rpit.rs @@ -1,5 +1,7 @@ -// check-pass // edition: 2021 +// known-bug: #105197 +// failure-status:101 +// dont-check-compiler-stderr #![feature(async_fn_in_trait)] #![feature(return_position_impl_trait_in_trait)] diff --git a/src/test/ui/impl-trait/issues/issue-105826.rs b/src/test/ui/impl-trait/issues/issue-105826.rs new file mode 100644 index 0000000000000..06dc2d4c8d34b --- /dev/null +++ b/src/test/ui/impl-trait/issues/issue-105826.rs @@ -0,0 +1,39 @@ +// check-pass + +use std::io::Write; + +struct A(Vec); + +struct B<'a> { + one: &'a mut A, + two: &'a mut Vec, + three: Vec, +} + +impl<'a> B<'a> { + fn one(&mut self) -> &mut impl Write { + &mut self.one.0 + } + fn two(&mut self) -> &mut impl Write { + &mut *self.two + } + fn three(&mut self) -> &mut impl Write { + &mut self.three + } +} + +struct C<'a>(B<'a>); + +impl<'a> C<'a> { + fn one(&mut self) -> &mut impl Write { + self.0.one() + } + fn two(&mut self) -> &mut impl Write { + self.0.two() + } + fn three(&mut self) -> &mut impl Write { + self.0.three() + } +} + +fn main() {} diff --git a/src/test/ui/suggestions/impl-trait-missing-lifetime-gated.rs b/src/test/ui/suggestions/impl-trait-missing-lifetime-gated.rs index 9839e973bdfe4..a1a51c4814e8f 100644 --- a/src/test/ui/suggestions/impl-trait-missing-lifetime-gated.rs +++ b/src/test/ui/suggestions/impl-trait-missing-lifetime-gated.rs @@ -60,4 +60,9 @@ mod in_path { //~| ERROR missing lifetime specifier } +// This must not err, as the `&` actually resolves to `'a`. +fn resolved_anonymous<'a, T>(f: impl Fn(&'a str) -> &T) { + f("f") +} + fn main() {} diff --git a/src/tools/rust-installer b/src/tools/rust-installer index 300b5ec61ef38..5b2eee7eed72b 160000 --- a/src/tools/rust-installer +++ b/src/tools/rust-installer @@ -1 +1 @@ -Subproject commit 300b5ec61ef38855a07e6bb4955a37aa1c414c00 +Subproject commit 5b2eee7eed72b4894909c5eecbf014ea0b5ad995