Skip to content

Rollup of 10 pull requests #98367

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

Closed
wants to merge 31 commits into from
Closed
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
f020fc0
clarify how Rust atomics correspond to C++ atomics
RalfJung May 29, 2022
8b7299d
Remove `likely!` and `unlikely!` macro from compiler
nbdd0121 May 31, 2022
44364dc
Add release notes for 1.62
Mark-Simulacrum May 27, 2022
7cefa8f
Make RwLockReadGuard covariant
r-raymond May 7, 2022
0b6e6e3
Formatting
r-raymond Jun 19, 2022
391f800
More formatting
r-raymond May 7, 2022
cf1238e
Address comments
r-raymond May 13, 2022
08650fb
*const to NonNull plus documentation
r-raymond May 14, 2022
0157593
Documentation typo
r-raymond May 14, 2022
fa1656e
Add safety comments
r-raymond May 26, 2022
09d937e
Add comment explaining why we use NonNull
r-raymond Jun 16, 2022
cb20e25
Add test to verify noalias is not being added
r-raymond Jun 19, 2022
43c6f9c
Make sure we don't match noalias in later lines
r-raymond Jun 19, 2022
048a801
UnsafeCell -> RwLock
r-raymond Jun 20, 2022
ac38258
Use futex based thread parker on Fuchsia.
m-ou-se May 6, 2022
8eb7ddf
update cpu-usage-over-time-plot script
seanpray Mar 29, 2022
c9340ec
Fix typo
lucasthormann Jun 21, 2022
1ca8b69
remove use of &Alloc in btree tests
RalfJung Jun 21, 2022
4768bfc
hedge our bets
RalfJung Jun 21, 2022
52409c4
Point at return expression for RPIT-related error
compiler-errors Jun 7, 2022
e53b2ba
Add some tests for impossible bounds
compiler-errors Jun 11, 2022
ecda292
Rollup merge of #95446 - notseanray:master, r=Mark-Simulacrum
JohnTitor Jun 22, 2022
4415af5
Rollup merge of #96768 - m-ou-se:futex-fuchsia, r=tmandry
JohnTitor Jun 22, 2022
c7aa270
Rollup merge of #96820 - r-raymond:master, r=cuviper
JohnTitor Jun 22, 2022
ffd6b0f
Rollup merge of #97454 - Mark-Simulacrum:relnotes, r=Mark-Simulacrum
JohnTitor Jun 22, 2022
39520e4
Rollup merge of #97516 - RalfJung:atomics, r=joshtriplett
JohnTitor Jun 22, 2022
3543cd7
Rollup merge of #97818 - compiler-errors:rpit-error-spanned, r=oli-obk
JohnTitor Jun 22, 2022
a07def6
Rollup merge of #97895 - nbdd0121:unlikely, r=estebank
JohnTitor Jun 22, 2022
5b0093a
Rollup merge of #98005 - compiler-errors:impossible-bounds, r=Mark-Si…
JohnTitor Jun 22, 2022
824443d
Rollup merge of #98356 - lucasthormann:patch-1, r=Mark-Simulacrum
JohnTitor Jun 22, 2022
ae8c200
Rollup merge of #98363 - RalfJung:btree-test-ref-alloc, r=thomcc
JohnTitor Jun 22, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -83,7 +83,7 @@ by running it with the `--help` flag or reading the [rustc dev guide][rustcguide
If you plan to use `x.py install` to create an installation, it is recommended
that you set the `prefix` value in the `[install]` section to a directory.

Create install directory if you are not installing in default directory
Create install directory if you are not installing in default directory.

4. Build and install:

125 changes: 125 additions & 0 deletions RELEASES.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,128 @@
Version 1.62.0 (2022-06-30)
==========================

Language
--------

- [Stabilize `#[derive(Default)]` on enums with a `#[default]` variant][94457]
- [Stop validating some checks in dead code after functions with uninhabited return types][93313]
- [Fix constants not getting dropped if part of a diverging expression][94775]
- [Support unit struct/enum variant in destructuring assignment][95380]
- [Remove mutable_borrow_reservation_conflict lint and allow the code pattern][96268]

Compiler
--------

- [linker: Stop using whole-archive on dependencies of dylibs][96436]
- [Make `unaligned_references` lint deny-by-default][95372]
This lint is also a future compatibility lint, and is expected to eventually
become a hard error.
- [Only add codegen backend to dep info if -Zbinary-dep-depinfo is used][93969]
- [Reject `#[thread_local]` attribute on non-static items][95006]
- [Add tier 3 `aarch64-pc-windows-gnullvm` and `x86_64-pc-windows-gnullvm` targets\*][94872]
- [Implement a lint to warn about unused macro rules][96150]
- [Promote `x86_64-unknown-none` target to Tier 2\*][95705]

\* Refer to Rust's [platform support page][platform-support-doc] for more
information on Rust's tiered platform support.

Libraries
---------

- [Move `CStr` to libcore, and `CString` to liballoc][94079]
- [Windows: Use a pipe relay for chaining pipes][95841]
- [Replace Linux Mutex and Condvar with futex based ones.][95035]
- [Replace RwLock by a futex based one on Linux][95801]
- [std: directly use pthread in UNIX parker implementation][96393]

Stabilized APIs
---------------

- [`bool::then_some`]
- [`f32::total_cmp`]
- [`f64::total_cmp`]
- [`Stdin::lines`]
- [`windows::CommandExt::raw_arg`]
- [`impl<T: Default> Default for AssertUnwindSafe<T>`]
- [`From<Rc<str>> for Rc<[u8]>`][rc-u8-from-str]
- [`From<Arc<str>> for Arc<[u8]>`][arc-u8-from-str]
- [`FusedIterator for EncodeWide`]
- [RDM intrinsics on aarch64][stdarch/1285]

Clippy
------

- [Create clippy lint against unexpectedly late drop for temporaries in match scrutinee expressions][94206]

Cargo
-----

- Added the `cargo add` command for adding dependencies to `Cargo.toml` from
the command-line.
[docs](https://doc.rust-lang.org/nightly/cargo/commands/cargo-add.html)
- Package ID specs now support `name@version` syntax in addition to the
previous `name:version` to align with the behavior in `cargo add` and other
tools. `cargo install` and `cargo yank` also now support this syntax so the
version does not need to passed as a separate flag.
- The `git` and `registry` directories in Cargo's home directory (usually
`~/.cargo`) are now marked as cache directories so that they are not
included in backups or content indexing (on Windows).
- Added automatic `@` argfile support, which will use "response files" if the
command-line to `rustc` exceeds the operating system's limit.

Compatibility Notes
-------------------

- `cargo test` now passes `--target` to `rustdoc` if the specified target is
the same as the host target.
[#10594](https://github.com/rust-lang/cargo/pull/10594)
- [rustdoc: Remove .woff font files][96279]
- [Enforce Copy bounds for repeat elements while considering lifetimes][95819]

Internal Changes
----------------

- [Unify ReentrantMutex implementations across all platforms][96042]

These changes provide no direct user facing benefits, but represent significant
improvements to the internals and overall performance of rustc
and related tools.

[93313]: https://github.com/rust-lang/rust/pull/93313/
[93969]: https://github.com/rust-lang/rust/pull/93969/
[94079]: https://github.com/rust-lang/rust/pull/94079/
[94206]: https://github.com/rust-lang/rust/pull/94206/
[94457]: https://github.com/rust-lang/rust/pull/94457/
[94775]: https://github.com/rust-lang/rust/pull/94775/
[94872]: https://github.com/rust-lang/rust/pull/94872/
[95006]: https://github.com/rust-lang/rust/pull/95006/
[95035]: https://github.com/rust-lang/rust/pull/95035/
[95372]: https://github.com/rust-lang/rust/pull/95372/
[95380]: https://github.com/rust-lang/rust/pull/95380/
[95431]: https://github.com/rust-lang/rust/pull/95431/
[95705]: https://github.com/rust-lang/rust/pull/95705/
[95801]: https://github.com/rust-lang/rust/pull/95801/
[95819]: https://github.com/rust-lang/rust/pull/95819/
[95841]: https://github.com/rust-lang/rust/pull/95841/
[96042]: https://github.com/rust-lang/rust/pull/96042/
[96150]: https://github.com/rust-lang/rust/pull/96150/
[96268]: https://github.com/rust-lang/rust/pull/96268/
[96279]: https://github.com/rust-lang/rust/pull/96279/
[96393]: https://github.com/rust-lang/rust/pull/96393/
[96436]: https://github.com/rust-lang/rust/pull/96436/
[96557]: https://github.com/rust-lang/rust/pull/96557/

[`bool::then_some`]: https://doc.rust-lang.org/stable/std/primitive.bool.html#method.then_some
[`f32::total_cmp`]: https://doc.rust-lang.org/stable/std/primitive.f32.html#method.total_cmp
[`f64::total_cmp`]: https://doc.rust-lang.org/stable/std/primitive.f64.html#method.total_cmp
[`Stdin::lines`]: https://doc.rust-lang.org/stable/std/io/struct.Stdin.html#method.lines
[`impl<T: Default> Default for AssertUnwindSafe<T>`]: https://doc.rust-lang.org/stable/std/panic/struct.AssertUnwindSafe.html#impl-Default
[rc-u8-from-str]: https://doc.rust-lang.org/stable/std/rc/struct.Rc.html#impl-From%3CRc%3Cstr%3E%3E
[arc-u8-from-str]: https://doc.rust-lang.org/stable/std/sync/struct.Arc.html#impl-From%3CArc%3Cstr%3E%3E
[stdarch/1285]: https://github.com/rust-lang/stdarch/pull/1285
[`windows::CommandExt::raw_arg`]: https://doc.rust-lang.org/stable/std/os/windows/process/trait.CommandExt.html#tymethod.raw_arg
[`FusedIterator for EncodeWide`]: https://doc.rust-lang.org/stable/std/os/windows/ffi/struct.EncodeWide.html#impl-FusedIterator

Version 1.61.0 (2022-05-19)
==========================

21 changes: 0 additions & 21 deletions compiler/rustc_data_structures/src/lib.rs
Original file line number Diff line number Diff line change
@@ -11,7 +11,6 @@
#![feature(associated_type_bounds)]
#![feature(auto_traits)]
#![feature(control_flow_enum)]
#![feature(core_intrinsics)]
#![feature(extend_one)]
#![feature(let_else)]
#![feature(hash_raw_entry)]
@@ -44,26 +43,6 @@ pub fn cold_path<F: FnOnce() -> R, R>(f: F) -> R {
f()
}

#[macro_export]
macro_rules! likely {
($e:expr) => {
match $e {
#[allow(unused_unsafe)]
e => unsafe { std::intrinsics::likely(e) },
}
};
}

#[macro_export]
macro_rules! unlikely {
($e:expr) => {
match $e {
#[allow(unused_unsafe)]
e => unsafe { std::intrinsics::unlikely(e) },
}
};
}

pub mod base_n;
pub mod binary_search_util;
pub mod captures;
3 changes: 2 additions & 1 deletion compiler/rustc_data_structures/src/profiling.rs
Original file line number Diff line number Diff line change
@@ -195,6 +195,7 @@ impl SelfProfilerRef {
F: for<'a> FnOnce(&'a SelfProfiler) -> TimingGuard<'a>,
{
#[inline(never)]
#[cold]
fn cold_call<F>(profiler_ref: &SelfProfilerRef, f: F) -> TimingGuard<'_>
where
F: for<'a> FnOnce(&'a SelfProfiler) -> TimingGuard<'a>,
@@ -203,7 +204,7 @@ impl SelfProfilerRef {
f(&**profiler)
}

if unlikely!(self.event_filter_mask.contains(event_filter)) {
if self.event_filter_mask.contains(event_filter) {
cold_call(self, f)
} else {
TimingGuard::none()
10 changes: 7 additions & 3 deletions compiler/rustc_infer/src/infer/opaque_types.rs
Original file line number Diff line number Diff line change
@@ -5,7 +5,7 @@ use hir::{HirId, OpaqueTyOrigin};
use rustc_data_structures::sync::Lrc;
use rustc_data_structures::vec_map::VecMap;
use rustc_hir as hir;
use rustc_middle::traits::ObligationCause;
use rustc_middle::traits::{ObligationCause, ObligationCauseCode};
use rustc_middle::ty::fold::BottomUpFolder;
use rustc_middle::ty::subst::{GenericArgKind, Subst};
use rustc_middle::ty::{
@@ -46,6 +46,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
value: T,
body_id: HirId,
span: Span,
code: ObligationCauseCode<'tcx>,
param_env: ty::ParamEnv<'tcx>,
) -> InferOk<'tcx, T> {
if !value.has_opaque_types() {
@@ -68,10 +69,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
) =>
{
let span = if span.is_dummy() { self.tcx.def_span(def_id) } else { span };
let cause = ObligationCause::misc(span, body_id);
let cause = ObligationCause::new(span, body_id, code.clone());
// FIXME(compiler-errors): We probably should add a new TypeVariableOriginKind
// for opaque types, and then use that kind to fix the spans for type errors
// that we see later on.
let ty_var = self.next_ty_var(TypeVariableOrigin {
kind: TypeVariableOriginKind::TypeInference,
span: cause.span,
span,
});
obligations.extend(
self.handle_opaque_type(ty, ty_var, true, &cause, param_env)
3 changes: 3 additions & 0 deletions compiler/rustc_middle/src/traits/mod.rs
Original file line number Diff line number Diff line change
@@ -387,6 +387,9 @@ pub enum ObligationCauseCode<'tcx> {
/// Return type of this function
ReturnType,

/// Opaque return type of this function
OpaqueReturnType(Option<(Ty<'tcx>, Span)>),

/// Block implicit return
BlockTailExpression(hir::HirId),

2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/ty/mod.rs
Original file line number Diff line number Diff line change
@@ -804,7 +804,7 @@ pub type PolyTraitPredicate<'tcx> = ty::Binder<'tcx, TraitPredicate<'tcx>>;

impl<'tcx> TraitPredicate<'tcx> {
pub fn remap_constness(&mut self, tcx: TyCtxt<'tcx>, param_env: &mut ParamEnv<'tcx>) {
if unlikely!(Some(self.trait_ref.def_id) == tcx.lang_items().drop_trait()) {
if std::intrinsics::unlikely(Some(self.trait_ref.def_id) == tcx.lang_items().drop_trait()) {
// remap without changing constness of this predicate.
// this is because `T: ~const Drop` has a different meaning to `T: Drop`
// FIXME(fee1-dead): remove this logic after beta bump
2 changes: 1 addition & 1 deletion compiler/rustc_query_system/src/dep_graph/graph.rs
Original file line number Diff line number Diff line change
@@ -750,7 +750,7 @@ impl<K: DepKind> DepGraph<K> {
dep_node
);

if unlikely!(!side_effects.is_empty()) {
if !side_effects.is_empty() {
self.emit_side_effects(tcx, data, dep_node_index, side_effects);
}

16 changes: 9 additions & 7 deletions compiler/rustc_query_system/src/query/plumbing.rs
Original file line number Diff line number Diff line change
@@ -316,7 +316,7 @@ where
OnHit: FnOnce(&C::Stored) -> R,
{
cache.lookup(&key, |value, index| {
if unlikely!(tcx.profiler().enabled()) {
if std::intrinsics::unlikely(tcx.profiler().enabled()) {
tcx.profiler().query_cache_hit(index.into());
}
tcx.dep_graph().read_index(index);
@@ -354,7 +354,7 @@ where
.lookup(&key, |value, index| (value.clone(), index))
.unwrap_or_else(|_| panic!("value must be in cache after waiting"));

if unlikely!(tcx.dep_context().profiler().enabled()) {
if std::intrinsics::unlikely(tcx.dep_context().profiler().enabled()) {
tcx.dep_context().profiler().query_cache_hit(index.into());
}
query_blocked_prof_timer.finish_with_query_invocation_id(index.into());
@@ -422,7 +422,7 @@ where
let diagnostics = diagnostics.into_inner();
let side_effects = QuerySideEffects { diagnostics };

if unlikely!(!side_effects.is_empty()) {
if std::intrinsics::unlikely(!side_effects.is_empty()) {
if query.anon {
tcx.store_side_effects_for_anon_node(dep_node_index, side_effects);
} else {
@@ -466,7 +466,9 @@ where
prof_timer.finish_with_query_invocation_id(dep_node_index.into());

if let Some(result) = result {
if unlikely!(tcx.dep_context().sess().opts.debugging_opts.query_dep_graph) {
if std::intrinsics::unlikely(
tcx.dep_context().sess().opts.debugging_opts.query_dep_graph,
) {
dep_graph.mark_debug_loaded_from_disk(*dep_node)
}

@@ -483,8 +485,8 @@ where
// currently afford to verify every hash. This subset should still
// give us some coverage of potential bugs though.
let try_verify = prev_fingerprint.as_value().1 % 32 == 0;
if unlikely!(
try_verify || tcx.dep_context().sess().opts.debugging_opts.incremental_verify_ich
if std::intrinsics::unlikely(
try_verify || tcx.dep_context().sess().opts.debugging_opts.incremental_verify_ich,
) {
incremental_verify_ich(*tcx.dep_context(), &result, dep_node, query);
}
@@ -723,7 +725,7 @@ where
// Ensure that only one of them runs the query.
let cache = Q::query_cache(tcx);
let cached = cache.lookup(&key, |_, index| {
if unlikely!(tcx.dep_context().profiler().enabled()) {
if std::intrinsics::unlikely(tcx.dep_context().profiler().enabled()) {
tcx.dep_context().profiler().query_cache_hit(index.into());
}
});
Original file line number Diff line number Diff line change
@@ -2661,6 +2661,15 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
err.help("add `#![feature(trivial_bounds)]` to the crate attributes to enable");
}
}
ObligationCauseCode::OpaqueReturnType(expr_info) => {
if let Some((expr_ty, expr_span)) = expr_info {
let expr_ty = self.resolve_vars_if_possible(expr_ty);
err.span_label(
expr_span,
format!("return type was inferred to be `{expr_ty}` here"),
);
}
}
}
}

2 changes: 2 additions & 0 deletions compiler/rustc_trait_selection/src/traits/project.rs
Original file line number Diff line number Diff line change
@@ -28,6 +28,7 @@ use rustc_hir::def::DefKind;
use rustc_hir::def_id::DefId;
use rustc_hir::lang_items::LangItem;
use rustc_infer::infer::resolve::OpportunisticRegionResolver;
use rustc_infer::traits::ObligationCauseCode;
use rustc_middle::traits::select::OverflowError;
use rustc_middle::ty::fold::{MaxUniverse, TypeFoldable, TypeFolder, TypeSuperFoldable};
use rustc_middle::ty::subst::Subst;
@@ -261,6 +262,7 @@ fn project_and_unify_type<'cx, 'tcx>(
actual,
obligation.cause.body_id,
obligation.cause.span,
ObligationCauseCode::MiscObligation,
obligation.param_env,
);
obligations.extend(new);
5 changes: 5 additions & 0 deletions compiler/rustc_typeck/src/check/check.rs
Original file line number Diff line number Diff line change
@@ -101,8 +101,13 @@ pub(super) fn check_fn<'a, 'tcx>(
declared_ret_ty,
body.value.hir_id,
DUMMY_SP,
traits::ObligationCauseCode::OpaqueReturnType(None),
param_env,
));
// If we replaced declared_ret_ty with infer vars, then we must be infering
// an opaque type, so set a flag so we can improve diagnostics.
fcx.return_type_has_opaque = ret_ty != declared_ret_ty;

fcx.ret_coercion = Some(RefCell::new(CoerceMany::new(ret_ty)));
fcx.ret_type_span = Some(decl.output.span());

10 changes: 8 additions & 2 deletions compiler/rustc_typeck/src/check/closure.rs
Original file line number Diff line number Diff line change
@@ -10,6 +10,7 @@ use rustc_hir::lang_items::LangItem;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::infer::LateBoundRegionConversionTime;
use rustc_infer::infer::{InferOk, InferResult};
use rustc_infer::traits::ObligationCauseCode;
use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::subst::InternalSubsts;
use rustc_middle::ty::{self, Ty};
@@ -645,8 +646,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}

fn hide_parent_opaque_types(&self, ty: Ty<'tcx>, span: Span, body_id: hir::HirId) -> Ty<'tcx> {
let InferOk { value, obligations } =
self.replace_opaque_types_with_inference_vars(ty, body_id, span, self.param_env);
let InferOk { value, obligations } = self.replace_opaque_types_with_inference_vars(
ty,
body_id,
span,
ObligationCauseCode::MiscObligation,
self.param_env,
);
self.register_predicates(obligations);
value
}
32 changes: 32 additions & 0 deletions compiler/rustc_typeck/src/check/expr.rs
Original file line number Diff line number Diff line change
@@ -39,6 +39,7 @@ use rustc_hir::{ExprKind, HirId, QPath};
use rustc_infer::infer;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::infer::InferOk;
use rustc_infer::traits::ObligationCause;
use rustc_middle::middle::stability;
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase};
use rustc_middle::ty::error::TypeError::FieldMisMatch;
@@ -839,6 +840,37 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return_expr,
return_expr_ty,
);

if self.return_type_has_opaque {
// Point any obligations that were registered due to opaque type
// inference at the return expression.
self.select_obligations_where_possible(false, |errors| {
self.point_at_return_for_opaque_ty_error(errors, span, return_expr_ty);
});
}
}

fn point_at_return_for_opaque_ty_error(
&self,
errors: &mut Vec<traits::FulfillmentError<'tcx>>,
span: Span,
return_expr_ty: Ty<'tcx>,
) {
// Don't point at the whole block if it's empty
if span == self.tcx.hir().span(self.body_id) {
return;
}
for err in errors {
let cause = &mut err.obligation.cause;
if let ObligationCauseCode::OpaqueReturnType(None) = cause.code() {
let new_cause = ObligationCause::new(
cause.span,
cause.body_id,
ObligationCauseCode::OpaqueReturnType(Some((return_expr_ty, span))),
);
*cause = new_cause;
}
}
}

pub(crate) fn check_lhs_assignable(
4 changes: 4 additions & 0 deletions compiler/rustc_typeck/src/check/fn_ctxt/mod.rs
Original file line number Diff line number Diff line change
@@ -115,6 +115,9 @@ pub struct FnCtxt<'a, 'tcx> {
/// either given explicitly or inferred from, say, an `Fn*` trait
/// bound. Used for diagnostic purposes only.
pub(super) return_type_pre_known: bool,

/// True if the return type has an Opaque type
pub(super) return_type_has_opaque: bool,
}

impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
@@ -141,6 +144,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}),
inh,
return_type_pre_known: true,
return_type_has_opaque: false,
}
}

12 changes: 6 additions & 6 deletions library/alloc/src/collections/btree/node/tests.rs
Original file line number Diff line number Diff line change
@@ -68,10 +68,10 @@ fn test_splitpoint() {

#[test]
fn test_partial_eq() {
let mut root1 = NodeRef::new_leaf(&Global);
let mut root1 = NodeRef::new_leaf(Global);
root1.borrow_mut().push(1, ());
let mut root1 = NodeRef::new_internal(root1.forget_type(), &Global).forget_type();
let root2 = Root::new(&Global);
let mut root1 = NodeRef::new_internal(root1.forget_type(), Global).forget_type();
let root2 = Root::new(Global);
root1.reborrow().assert_back_pointers();
root2.reborrow().assert_back_pointers();

@@ -87,9 +87,9 @@ fn test_partial_eq() {
assert!(top_edge_1 == top_edge_1);
assert!(top_edge_1 != top_edge_2);

root1.pop_internal_level(&Global);
unsafe { root1.into_dying().deallocate_and_ascend(&Global) };
unsafe { root2.into_dying().deallocate_and_ascend(&Global) };
root1.pop_internal_level(Global);
unsafe { root1.into_dying().deallocate_and_ascend(Global) };
unsafe { root2.into_dying().deallocate_and_ascend(Global) };
}

#[test]
7 changes: 7 additions & 0 deletions library/core/src/sync/atomic.rs
Original file line number Diff line number Diff line change
@@ -4,6 +4,12 @@
//! threads, and are the building blocks of other concurrent
//! types.
//!
//! Rust atomics currently follow the same rules as [C++20 atomics][cpp], specifically `atomic_ref`.
//! Basically, creating a *shared reference* to one of the Rust atomic types corresponds to creating
//! an `atomic_ref` in C++; the `atomic_ref` is destroyed when the lifetime of the shared reference
//! ends. (A Rust atomic type that is exclusively owned or behind a mutable reference does *not*
//! correspond to an "atomic object" in C++, since it can be accessed via non-atomic operations.)
//!
//! This module defines atomic versions of a select number of primitive
//! types, including [`AtomicBool`], [`AtomicIsize`], [`AtomicUsize`],
//! [`AtomicI8`], [`AtomicU16`], etc.
@@ -14,6 +20,7 @@
//! the memory barrier for that operation. These orderings are the
//! same as the [C++20 atomic orderings][1]. For more information see the [nomicon][2].
//!
//! [cpp]: https://en.cppreference.com/w/cpp/atomic
//! [1]: https://en.cppreference.com/w/cpp/atomic/memory_order
//! [2]: ../../../nomicon/atomics.html
//!
28 changes: 24 additions & 4 deletions library/std/src/sync/rwlock.rs
Original file line number Diff line number Diff line change
@@ -4,6 +4,7 @@ mod tests;
use crate::cell::UnsafeCell;
use crate::fmt;
use crate::ops::{Deref, DerefMut};
use crate::ptr::NonNull;
use crate::sync::{poison, LockResult, TryLockError, TryLockResult};
use crate::sys_common::rwlock as sys;

@@ -101,7 +102,12 @@ unsafe impl<T: ?Sized + Send + Sync> Sync for RwLock<T> {}
#[stable(feature = "rust1", since = "1.0.0")]
#[clippy::has_significant_drop]
pub struct RwLockReadGuard<'a, T: ?Sized + 'a> {
lock: &'a RwLock<T>,
// NB: we use a pointer instead of `&'a T` to avoid `noalias` violations, because a
// `Ref` argument doesn't hold immutability for its whole scope, only until it drops.
// `NonNull` is also covariant over `T`, just like we would have with `&T`. `NonNull`
// is preferable over `const* T` to allow for niche optimization.
data: NonNull<T>,
inner_lock: &'a sys::MovableRwLock,
}

#[stable(feature = "rust1", since = "1.0.0")]
@@ -511,12 +517,21 @@ impl<T> From<T> for RwLock<T> {
}

impl<'rwlock, T: ?Sized> RwLockReadGuard<'rwlock, T> {
/// Create a new instance of `RwLockReadGuard<T>` from a `RwLock<T>`.
// SAFETY: if and only if `lock.inner.read()` (or `lock.inner.try_read()`) has been
// successfully called from the same thread before instantiating this object.
unsafe fn new(lock: &'rwlock RwLock<T>) -> LockResult<RwLockReadGuard<'rwlock, T>> {
poison::map_result(lock.poison.borrow(), |()| RwLockReadGuard { lock })
poison::map_result(lock.poison.borrow(), |()| RwLockReadGuard {
data: NonNull::new_unchecked(lock.data.get()),
inner_lock: &lock.inner,
})
}
}

impl<'rwlock, T: ?Sized> RwLockWriteGuard<'rwlock, T> {
/// Create a new instance of `RwLockWriteGuard<T>` from a `RwLock<T>`.
// SAFETY: if and only if `lock.inner.write()` (or `lock.inner.try_write()`) has been
// successfully called from the same thread before instantiating this object.
unsafe fn new(lock: &'rwlock RwLock<T>) -> LockResult<RwLockWriteGuard<'rwlock, T>> {
poison::map_result(lock.poison.guard(), |guard| RwLockWriteGuard { lock, poison: guard })
}
@@ -555,7 +570,8 @@ impl<T: ?Sized> Deref for RwLockReadGuard<'_, T> {
type Target = T;

fn deref(&self) -> &T {
unsafe { &*self.lock.data.get() }
// SAFETY: the conditions of `RwLockGuard::new` were satisfied when created.
unsafe { self.data.as_ref() }
}
}

@@ -564,22 +580,25 @@ impl<T: ?Sized> Deref for RwLockWriteGuard<'_, T> {
type Target = T;

fn deref(&self) -> &T {
// SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when created.
unsafe { &*self.lock.data.get() }
}
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> DerefMut for RwLockWriteGuard<'_, T> {
fn deref_mut(&mut self) -> &mut T {
// SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when created.
unsafe { &mut *self.lock.data.get() }
}
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> Drop for RwLockReadGuard<'_, T> {
fn drop(&mut self) {
// SAFETY: the conditions of `RwLockReadGuard::new` were satisfied when created.
unsafe {
self.lock.inner.read_unlock();
self.inner_lock.read_unlock();
}
}
}
@@ -588,6 +607,7 @@ impl<T: ?Sized> Drop for RwLockReadGuard<'_, T> {
impl<T: ?Sized> Drop for RwLockWriteGuard<'_, T> {
fn drop(&mut self) {
self.lock.poison.done(&self.poison);
// SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when created.
unsafe {
self.lock.inner.write_unlock();
}
14 changes: 13 additions & 1 deletion library/std/src/sync/rwlock/tests.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::sync::atomic::{AtomicUsize, Ordering};
use crate::sync::mpsc::channel;
use crate::sync::{Arc, RwLock, TryLockError};
use crate::sync::{Arc, RwLock, RwLockReadGuard, TryLockError};
use crate::thread;
use rand::{self, Rng};

@@ -245,3 +245,15 @@ fn test_get_mut_poison() {
Ok(x) => panic!("get_mut of poisoned RwLock is Ok: {x:?}"),
}
}

#[test]
fn test_read_guard_covariance() {
fn do_stuff<'a>(_: RwLockReadGuard<'_, &'a i32>, _: &'a i32) {}
let j: i32 = 5;
let lock = RwLock::new(&j);
{
let i = 6;
do_stuff(lock.read().unwrap(), &i);
}
drop(lock);
}
50 changes: 50 additions & 0 deletions library/std/src/sys/unix/futex.rs
Original file line number Diff line number Diff line change
@@ -5,6 +5,7 @@
target_os = "freebsd",
target_os = "openbsd",
target_os = "dragonfly",
target_os = "fuchsia",
))]

use crate::sync::atomic::AtomicU32;
@@ -237,3 +238,52 @@ pub fn futex_wake(futex: &AtomicU32) -> bool {
pub fn futex_wake_all(futex: &AtomicU32) {
unsafe { emscripten_futex_wake(futex, i32::MAX) };
}

#[cfg(target_os = "fuchsia")]
mod zircon {
type zx_time_t = i64;
type zx_futex_t = crate::sync::atomic::AtomicU32;
type zx_handle_t = u32;
type zx_status_t = i32;

pub const ZX_HANDLE_INVALID: zx_handle_t = 0;
pub const ZX_ERR_TIMED_OUT: zx_status_t = -21;
pub const ZX_TIME_INFINITE: zx_time_t = zx_time_t::MAX;

extern "C" {
pub fn zx_futex_wait(
value_ptr: *const zx_futex_t,
current_value: zx_futex_t,
new_futex_owner: zx_handle_t,
deadline: zx_time_t,
) -> zx_status_t;
pub fn zx_futex_wake(value_ptr: *const zx_futex_t, wake_count: u32) -> zx_status_t;
pub fn zx_clock_get_monotonic() -> zx_time_t;
}
}

#[cfg(target_os = "fuchsia")]
pub fn futex_wait(futex: &AtomicU32, expected: u32, timeout: Option<Duration>) -> bool {
use crate::convert::TryFrom;

// Sleep forever if the timeout is longer than fits in a i64.
let deadline = timeout
.and_then(|d| {
i64::try_from(d.as_nanos())
.ok()?
.checked_add(unsafe { zircon::zx_clock_get_monotonic() })
})
.unwrap_or(zircon::ZX_TIME_INFINITE);

unsafe {
zircon::zx_futex_wait(futex, AtomicU32::new(expected), zircon::ZX_HANDLE_INVALID, deadline)
!= zircon::ZX_ERR_TIMED_OUT
}
}

// Fuchsia doesn't tell us how many threads are woken up, so this always returns false.
#[cfg(target_os = "fuchsia")]
pub fn futex_wake(futex: &AtomicU32) -> bool {
unsafe { zircon::zx_futex_wake(futex, 1) };
false
}
1 change: 1 addition & 0 deletions library/std/src/sys/unix/thread_parker.rs
Original file line number Diff line number Diff line change
@@ -7,6 +7,7 @@
target_os = "freebsd",
target_os = "openbsd",
target_os = "dragonfly",
target_os = "fuchsia",
)))]

use crate::cell::UnsafeCell;
1 change: 1 addition & 0 deletions library/std/src/sys_common/thread_parker/mod.rs
Original file line number Diff line number Diff line change
@@ -6,6 +6,7 @@ cfg_if::cfg_if! {
target_os = "freebsd",
target_os = "openbsd",
target_os = "dragonfly",
target_os = "fuchsia",
))] {
mod futex;
pub use futex::Parker;
20 changes: 15 additions & 5 deletions src/etc/cpu-usage-over-time-plot.sh
Original file line number Diff line number Diff line change
@@ -7,13 +7,21 @@
# commit SHA of the build you're interested in, and the second is the name of
# the builder. For example:
#
# ./src/etc/cpu-usage-over-time-plot.sh e699ea096fcc2fc9ce8e8bcf884e11496a31cc9f i686-mingw-1
# ./src/etc/cpu-usage-over-time-plot.sh 7737e0b5c4103216d6fd8cf941b7ab9bdbaace7c x86_64-gnu
#
# That will generate `$builder.png` in the current directory which you can open
# up to see a hopefully pretty graph.
#
# Improvements to this script are greatly appreciated!

if [[ $# != 2 ]]; then
echo "expected 2 arguments, recieved $#"
echo "example usage: './src/etc/cpu-usage-over-time-plot.sh \
7737e0b5c4103216d6fd8cf941b7ab9bdbaace7c \
x86_64-gnu'"
exit 1
fi

set -ex

bucket=rust-lang-ci2
@@ -30,7 +38,7 @@ set ylabel "CPU Usage %"
set xlabel "Time"
set datafile sep ','
set term png size 3000,1000
set output "$builder.png"
set output "$builder-$commit-cpu-usage-plot.png"
set grid
f(x) = mean_y
@@ -43,7 +51,9 @@ set ytics 10
set boxwidth 0.5
plot \\
mean_y with lines linetype 1 linecolor rgb "#ff0000" title "average", \\
"cpu-$builder.csv" using 1:(100-\$2) with points pointtype 7 pointsize 0.4 title "$builder", \\
"" using 1:(100-\$2) smooth bezier linewidth 3 title "bezier"
mean_y with lines linetype 1 linecolor rgb "#ff0000" title "average", "cpu-$builder.csv" \\
using 1:(100-\$2) with points pointtype 7 pointsize 0.4 title "$builder", "" \\
using 1:(100-\$2) smooth bezier linewidth 3 title "bezier"
EOF

rm "cpu-$builder.csv"
14 changes: 14 additions & 0 deletions src/test/codegen/noalias-rwlockreadguard.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// compile-flags: -O -C no-prepopulate-passes -Z mutable-noalias=yes

#![crate_type = "lib"]

use std::sync::{RwLock, RwLockReadGuard};

// Make sure that `RwLockReadGuard` does not get a `noalias` attribute, because
// the `RwLock` might alias writes after it is dropped.

// CHECK-LABEL: @maybe_aliased(
// CHECK-NOT: noalias
// CHECK-SAME: %_data
#[no_mangle]
pub unsafe fn maybe_aliased(_: RwLockReadGuard<'_, i32>, _data: &RwLock<i32>) {}
Original file line number Diff line number Diff line change
@@ -6,6 +6,9 @@ LL | fn bar() -> impl Bar {
...
LL | fn baz() -> impl Bar<Item = i32> {
| ^^^^^^^^^^^^^^^^^^^^ expected associated type, found `i32`
LL |
LL | bar()
| ----- return type was inferred to be `impl Bar` here
|
= note: expected associated type `<impl Bar as Foo>::Item`
found type `i32`
9 changes: 9 additions & 0 deletions src/test/ui/const-generics/defaults/rp_impl_trait_fail.stderr
Original file line number Diff line number Diff line change
@@ -3,6 +3,9 @@ error[E0277]: the trait bound `Uwu<10_u32, 12_u32>: Trait` is not satisfied
|
LL | fn rawr() -> impl Trait {
| ^^^^^^^^^^ the trait `Trait` is not implemented for `Uwu<10_u32, 12_u32>`
LL |
LL | Uwu::<10, 12>
| ------------- return type was inferred to be `Uwu<10_u32, 12_u32>` here
|
= help: the trait `Trait` is implemented for `Uwu<N>`

@@ -11,6 +14,9 @@ error[E0277]: the trait bound `u32: Traitor<N>` is not satisfied
|
LL | fn uwu<const N: u8>() -> impl Traitor<N> {
| ^^^^^^^^^^^^^^^ the trait `Traitor<N>` is not implemented for `u32`
LL |
LL | 1_u32
| ----- return type was inferred to be `u32` here
|
= help: the following other types implement trait `Traitor<N, M>`:
<u32 as Traitor<N, 2_u8>>
@@ -21,6 +27,9 @@ error[E0277]: the trait bound `u64: Traitor` is not satisfied
|
LL | fn owo() -> impl Traitor {
| ^^^^^^^^^^^^ the trait `Traitor` is not implemented for `u64`
LL |
LL | 1_u64
| ----- return type was inferred to be `u64` here
|
= help: the following other types implement trait `Traitor<N, M>`:
<u32 as Traitor<N, 2_u8>>
6 changes: 6 additions & 0 deletions src/test/ui/impl-trait/bound-normalization-fail.stderr
Original file line number Diff line number Diff line change
@@ -3,6 +3,9 @@ error[E0271]: type mismatch resolving `<Foo<()> as FooLike>::Output == <T as imp
|
LL | fn foo_fail<T: Trait>() -> impl FooLike<Output = T::Assoc> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type mismatch resolving `<Foo<()> as FooLike>::Output == <T as impl_trait::Trait>::Assoc`
LL |
LL | Foo(())
| ------- return type was inferred to be `Foo<()>` here
|
note: expected this to be `()`
--> $DIR/bound-normalization-fail.rs:14:19
@@ -27,6 +30,9 @@ error[E0271]: type mismatch resolving `<Foo<()> as FooLike>::Output == <T as lif
|
LL | fn foo2_fail<'a, T: Trait<'a>>() -> impl FooLike<Output = T::Assoc> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type mismatch resolving `<Foo<()> as FooLike>::Output == <T as lifetimes::Trait<'static>>::Assoc`
...
LL | Foo(())
| ------- return type was inferred to be `Foo<()>` here
|
note: expected this to be `()`
--> $DIR/bound-normalization-fail.rs:14:19
3 changes: 3 additions & 0 deletions src/test/ui/issues-71798.stderr
Original file line number Diff line number Diff line change
@@ -9,6 +9,9 @@ error[E0277]: `u32` is not a future
|
LL | fn test_ref(x: &u32) -> impl std::future::Future<Output = u32> + '_ {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `u32` is not a future
LL |
LL | *x
| -- return type was inferred to be `u32` here
|
= help: the trait `Future` is not implemented for `u32`
= note: u32 must be a future or must implement `IntoFuture` to be awaited
17 changes: 11 additions & 6 deletions src/test/ui/trait-bounds/issue-93008.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
// compile-flags: -Zmir-opt-level=4
// build-pass
// compile-flags: -Zmir-opt-level=3 --crate-type=lib

pub fn bar<T>(s: &'static mut ())
#![feature(trivial_bounds)]
#![allow(trivial_bounds)]

trait Foo {
fn test(self);
}
fn baz<T>()
where
&'static mut (): Clone, //~ ERROR the trait bound
&'static str: Foo,
{
<&'static mut () as Clone>::clone(&s);
"Foo".test()
}

fn main() {}
12 changes: 0 additions & 12 deletions src/test/ui/trait-bounds/issue-93008.stderr

This file was deleted.

14 changes: 14 additions & 0 deletions src/test/ui/trait-bounds/issue-94680.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// check-pass

fn main() {
println!("{:?}", {
type T = ();

pub fn cloneit(it: &'_ mut T) -> (&'_ mut T, &'_ mut T)
where
for<'any> &'any mut T: Clone,
{
(it.clone(), it)
}
});
}
34 changes: 34 additions & 0 deletions src/test/ui/trait-bounds/issue-94999.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// check-pass

trait Identity<Q> {
type T;
}

impl<Q, T> Identity<Q> for T {
type T = T;
}

trait Holds {
type Q;
}

struct S;
struct X(S);

struct XHelper;

impl Holds for X {
type Q = XHelper;
}

impl<Q> Clone for X
where
<S as Identity<Q>>::T: Clone,
X: Holds<Q = Q>,
{
fn clone(&self) -> Self {
Self(self.0.clone())
}
}

fn main() {}
31 changes: 31 additions & 0 deletions src/test/ui/trait-bounds/issue-95640.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// build-pass
// compile-flags:-Zmir-opt-level=3

struct D;

trait Tr {
type It;
fn foo(self) -> Option<Self::It>;
}

impl<'a> Tr for &'a D {
type It = ();
fn foo(self) -> Option<()> {
None
}
}

fn run<F>(f: F)
where
for<'a> &'a D: Tr,
F: Fn(<&D as Tr>::It),
{
let d = &D;
while let Some(i) = d.foo() {
f(i);
}
}

fn main() {
run(|_| {});
}
43 changes: 43 additions & 0 deletions src/test/ui/trait-bounds/select-param-env-instead-of-blanket.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// known-bug
// build-fail
// failure-status: 101
// compile-flags:--crate-type=lib -Zmir-opt-level=3
// rustc-env:RUST_BACKTRACE=0

// normalize-stderr-test "thread 'rustc' panicked.*" -> "thread 'rustc' panicked"
// normalize-stderr-test "note:.*RUST_BACKTRACE=1.*\n" -> ""
// normalize-stderr-test "error: internal compiler error.*" -> "error: internal compiler error"
// normalize-stderr-test "encountered.*with incompatible types:" "encountered ... with incompatible types:"
// normalize-stderr-test "note:.*unexpectedly panicked.*\n\n" -> ""
// normalize-stderr-test "note: we would appreciate a bug report.*\n\n" -> ""
// normalize-stderr-test "note: compiler flags.*\n\n" -> ""
// normalize-stderr-test "note: rustc.*running on.*\n\n" -> ""
// normalize-stderr-test "query stack during panic:\n" -> ""
// normalize-stderr-test "we're just showing a limited slice of the query stack\n" -> ""
// normalize-stderr-test "end of query stack\n" -> ""
// normalize-stderr-test "#.*\n" -> ""

// This is a known bug that @compiler-errors tried to fix in #94238,
// but the solution was probably not correct.

pub trait Factory<T> {
type Item;
}

pub struct IntFactory;

impl<T> Factory<T> for IntFactory {
type Item = usize;
}

pub fn foo<T>()
where
IntFactory: Factory<T>,
{
let mut x: <IntFactory as Factory<T>>::Item = bar::<T>();
}

#[inline]
pub fn bar<T>() -> <IntFactory as Factory<T>>::Item {
0usize
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
error: internal compiler error

error: internal compiler error
encountered ... with incompatible types:
left-hand side has type: <IntFactory as Factory<T>>::Item
right-hand side has type: usize
--> $DIR/select-param-env-instead-of-blanket.rs:42:5
|
LL | let mut x: <IntFactory as Factory<T>>::Item = bar::<T>();
| ---------- in this inlined function call
...
LL | 0usize
| ^^^^^^
|
= note: delayed at compiler/rustc_const_eval/src/transform/validate.rs:128:36

thread 'rustc' panicked

Original file line number Diff line number Diff line change
@@ -3,6 +3,9 @@ error[E0277]: the trait bound `(): Foo<FooX>` is not satisfied
|
LL | fn foo() -> impl Foo<FooX> {
| ^^^^^^^^^^^^^^ the trait `Foo<FooX>` is not implemented for `()`
...
LL | ()
| -- return type was inferred to be `()` here
|
= help: the trait `Foo<()>` is implemented for `()`

Original file line number Diff line number Diff line change
@@ -3,6 +3,9 @@ error[E0277]: the trait bound `(): Foo<FooX>` is not satisfied
|
LL | fn foo() -> impl Foo<FooX> {
| ^^^^^^^^^^^^^^ the trait `Foo<FooX>` is not implemented for `()`
LL |
LL | ()
| -- return type was inferred to be `()` here
|
= help: the following other types implement trait `Foo<A>`:
<() as Foo<()>>