Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[beta] backport rollup #107071

Merged
merged 9 commits into from
Jan 20, 2023
2 changes: 1 addition & 1 deletion compiler/rustc_borrowck/src/region_infer/opaque_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
16 changes: 15 additions & 1 deletion compiler/rustc_hir_analysis/src/collect/generics_of.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down
6 changes: 4 additions & 2 deletions compiler/rustc_hir_analysis/src/collect/lifetimes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down
1 change: 0 additions & 1 deletion compiler/rustc_hir_typeck/src/writeback.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
27 changes: 1 addition & 26 deletions compiler/rustc_middle/src/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;

Expand All @@ -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>, 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
Expand Down
14 changes: 7 additions & 7 deletions library/std/src/sync/mpmc/array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ impl<T> Channel<T> {
return true;
}
Err(_) => {
backoff.spin();
backoff.spin_light();
tail = self.tail.load(Ordering::Relaxed);
}
}
Expand All @@ -182,11 +182,11 @@ impl<T> Channel<T> {
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);
}
}
Expand Down Expand Up @@ -251,7 +251,7 @@ impl<T> Channel<T> {
return true;
}
Err(_) => {
backoff.spin();
backoff.spin_light();
head = self.head.load(Ordering::Relaxed);
}
}
Expand All @@ -273,11 +273,11 @@ impl<T> Channel<T> {
}
}

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);
}
}
Expand Down Expand Up @@ -330,7 +330,7 @@ impl<T> Channel<T> {
if backoff.is_completed() {
break;
} else {
backoff.spin();
backoff.spin_light();
}
}

Expand Down
16 changes: 8 additions & 8 deletions library/std/src/sync/mpmc/list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ impl<T> Slot<T> {
fn wait_write(&self) {
let backoff = Backoff::new();
while self.state.load(Ordering::Acquire) & WRITE == 0 {
backoff.snooze();
backoff.spin_heavy();
}
}
}
Expand Down Expand Up @@ -82,7 +82,7 @@ impl<T> Block<T> {
if !next.is_null() {
return next;
}
backoff.snooze();
backoff.spin_heavy();
}
}

Expand Down Expand Up @@ -191,7 +191,7 @@ impl<T> Channel<T> {

// 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;
Expand Down Expand Up @@ -247,7 +247,7 @@ impl<T> Channel<T> {
return true;
},
Err(_) => {
backoff.spin();
backoff.spin_light();
tail = self.tail.index.load(Ordering::Acquire);
block = self.tail.block.load(Ordering::Acquire);
}
Expand Down Expand Up @@ -286,7 +286,7 @@ impl<T> Channel<T> {

// 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;
Expand Down Expand Up @@ -320,7 +320,7 @@ impl<T> Channel<T> {
// 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;
Expand Down Expand Up @@ -351,7 +351,7 @@ impl<T> Channel<T> {
return true;
},
Err(_) => {
backoff.spin();
backoff.spin_light();
head = self.head.index.load(Ordering::Acquire);
block = self.head.block.load(Ordering::Acquire);
}
Expand Down Expand Up @@ -542,7 +542,7 @@ impl<T> Channel<T> {
// 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);
}

Expand Down
2 changes: 1 addition & 1 deletion library/std/src/sync/mpmc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
///
Expand Down
31 changes: 15 additions & 16 deletions library/std/src/sync/mpmc/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,8 @@ impl<T> DerefMut for CachePadded<T> {
}

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<u32>,
}
Expand All @@ -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()
Expand All @@ -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
}
}
2 changes: 1 addition & 1 deletion library/std/src/sync/mpmc/zero.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ impl<T> Packet<T> {
fn wait_ready(&self) {
let backoff = Backoff::new();
while !self.ready.load(Ordering::Acquire) {
backoff.snooze();
backoff.spin_heavy();
}
}
}
Expand Down
9 changes: 9 additions & 0 deletions library/std/src/sync/mpsc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -738,6 +738,15 @@ impl<T> SyncSender<T> {
pub fn try_send(&self, t: T) -> Result<(), TrySendError<T>> {
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<T>> {
self.inner.send_timeout(t, timeout)
}
}

#[stable(feature = "rust1", since = "1.0.0")]
Expand Down
8 changes: 8 additions & 0 deletions library/std/src/sync/mpsc/sync_tests.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use super::*;
use crate::env;
use crate::sync::mpmc::SendTimeoutError;
use crate::thread;
use crate::time::Duration;

Expand Down Expand Up @@ -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::<i32>(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::<i32>(0);
Expand Down
12 changes: 8 additions & 4 deletions src/bootstrap/install.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
2 changes: 1 addition & 1 deletion src/doc/rustdoc/src/lints.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 3 additions & 1 deletion src/test/ui/async-await/in-trait/nested-rpit.rs
Original file line number Diff line number Diff line change
@@ -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)]
Expand Down
Loading