Auto merge of #95653 - Dylan-DPC:rollup-2p9hzi3, r=Dylan-DPC
Rollup of 7 pull requests Successful merges: - #92942 (stabilize windows_process_extensions_raw_arg) - #94817 (Release notes for 1.60.0) - #95343 (Reduce unnecessary escaping in proc_macro::Literal::character/string) - #95431 (Stabilize total_cmp) - #95438 (Add SyncUnsafeCell.) - #95467 (Windows: Synchronize asynchronous pipe reads and writes) - #95609 (Suggest borrowing when trying to coerce unsized type into `dyn Trait`) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
60e50fc1cf
19 changed files with 501 additions and 25 deletions
155
RELEASES.md
155
RELEASES.md
|
@ -1,3 +1,158 @@
|
|||
Version 1.60.0 (2022-04-07)
|
||||
==========================
|
||||
|
||||
Language
|
||||
--------
|
||||
- [Stabilize `#[cfg(panic = "...")]` for either `"unwind"` or `"abort"`.][93658]
|
||||
- [Stabilize `#[cfg(target_has_atomic = "...")]` for each integer size and `"ptr"`.][93824]
|
||||
|
||||
Compiler
|
||||
--------
|
||||
- [Enable combining `+crt-static` and `relocation-model=pic` on `x86_64-unknown-linux-gnu`][86374]
|
||||
- [Fixes wrong `unreachable_pub` lints on nested and glob public reexport][87487]
|
||||
- [Stabilize `-Z instrument-coverage` as `-C instrument-coverage`][90132]
|
||||
- [Stabilize `-Z print-link-args` as `--print link-args`][91606]
|
||||
- [Add new Tier 3 target `mips64-openwrt-linux-musl`\*][92300]
|
||||
- [Add new Tier 3 target `armv7-unknown-linux-uclibceabi` (softfloat)\*][92383]
|
||||
- [Fix invalid removal of newlines from doc comments][92357]
|
||||
- [Add kernel target for RustyHermit][92670]
|
||||
- [Deny mixing bin crate type with lib crate types][92933]
|
||||
- [Make rustc use `RUST_BACKTRACE=full` by default][93566]
|
||||
- [Upgrade to LLVM 14][93577]
|
||||
|
||||
\* Refer to Rust's [platform support page][platform-support-doc] for more
|
||||
information on Rust's tiered platform support.
|
||||
|
||||
Libraries
|
||||
---------
|
||||
- [Guarantee call order for `sort_by_cached_key`][89621]
|
||||
- [Improve `Duration::try_from_secs_f32`/`f64` accuracy by directly processing exponent and mantissa][90247]
|
||||
- [Make `Instant::{duration_since, elapsed, sub}` saturating][89926]
|
||||
- [Remove non-monotonic clocks workarounds in `Instant::now`][89926]
|
||||
- [Make `BuildHasherDefault`, `iter::Empty` and `future::Pending` covariant][92630]
|
||||
|
||||
Stabilized APIs
|
||||
---------------
|
||||
- [`Arc::new_cyclic`][arc_new_cyclic]
|
||||
- [`Rc::new_cyclic`][rc_new_cyclic]
|
||||
- [`slice::EscapeAscii`][slice_escape_ascii]
|
||||
- [`<[u8]>::escape_ascii`][slice_u8_escape_ascii]
|
||||
- [`u8::escape_ascii`][u8_escape_ascii]
|
||||
- [`Vec::spare_capacity_mut`][vec_spare_capacity_mut]
|
||||
- [`MaybeUninit::assume_init_drop`][assume_init_drop]
|
||||
- [`MaybeUninit::assume_init_read`][assume_init_read]
|
||||
- [`i8::abs_diff`][i8_abs_diff]
|
||||
- [`i16::abs_diff`][i16_abs_diff]
|
||||
- [`i32::abs_diff`][i32_abs_diff]
|
||||
- [`i64::abs_diff`][i64_abs_diff]
|
||||
- [`i128::abs_diff`][i128_abs_diff]
|
||||
- [`isize::abs_diff`][isize_abs_diff]
|
||||
- [`u8::abs_diff`][u8_abs_diff]
|
||||
- [`u16::abs_diff`][u16_abs_diff]
|
||||
- [`u32::abs_diff`][u32_abs_diff]
|
||||
- [`u64::abs_diff`][u64_abs_diff]
|
||||
- [`u128::abs_diff`][u128_abs_diff]
|
||||
- [`usize::abs_diff`][usize_abs_diff]
|
||||
- [`Display for io::ErrorKind`][display_error_kind]
|
||||
- [`From<u8> for ExitCode`][from_u8_exit_code]
|
||||
- [`Not for !` (the "never" type)][not_never]
|
||||
- [_Op_`Assign<$t> for Wrapping<$t>`][wrapping_assign_ops]
|
||||
- [`arch::is_aarch64_feature_detected!`][is_aarch64_feature_detected]
|
||||
|
||||
Cargo
|
||||
-----
|
||||
- [Port cargo from `toml-rs` to `toml_edit`][cargo/10086]
|
||||
- [Stabilize `-Ztimings` as `--timings`][cargo/10245]
|
||||
- [Stabilize namespaced and weak dependency features.][cargo/10269]
|
||||
- [Accept more `cargo:rustc-link-arg-*` types from build script output.][cargo/10274]
|
||||
- [cargo-new should not add ignore rule on Cargo.lock inside subdirs][cargo/10379]
|
||||
|
||||
Misc
|
||||
----
|
||||
- [Ship docs on Tier 2 platforms by reusing the closest Tier 1 platform docs][92800]
|
||||
- [Drop rustc-docs from complete profile][93742]
|
||||
- [bootstrap: tidy up flag handling for llvm build][93918]
|
||||
|
||||
Compatibility Notes
|
||||
-------------------
|
||||
- [Remove compiler-rt linking hack on Android][83822]
|
||||
- [Mitigations for platforms with non-monotonic clocks have been removed from
|
||||
`Instant::now`][89926]. On platforms that don't provide monotonic clocks, an
|
||||
instant is not guaranteed to be greater than an earlier instant anymore.
|
||||
- [`Instant::{duration_since, elapsed, sub}` do not panic anymore on underflow,
|
||||
saturating to `0` instead][89926]. In the real world the panic happened mostly
|
||||
on platforms with buggy monotonic clock implementations rather than catching
|
||||
programming errors like reversing the start and end times. Such programming
|
||||
errors will now results in `0` rather than a panic.
|
||||
- In a future release we're planning to increase the baseline requirements for
|
||||
the Linux kernel to version 3.2, and for glibc to version 2.17. We'd love
|
||||
your feedback in [PR #95026][95026].
|
||||
|
||||
Internal Changes
|
||||
----------------
|
||||
|
||||
These changes provide no direct user facing benefits, but represent significant
|
||||
improvements to the internals and overall performance of rustc
|
||||
and related tools.
|
||||
|
||||
- [Switch all libraries to the 2021 edition][92068]
|
||||
|
||||
[83822]: https://github.com/rust-lang/rust/pull/83822
|
||||
[86374]: https://github.com/rust-lang/rust/pull/86374
|
||||
[87487]: https://github.com/rust-lang/rust/pull/87487
|
||||
[89621]: https://github.com/rust-lang/rust/pull/89621
|
||||
[89926]: https://github.com/rust-lang/rust/pull/89926
|
||||
[90132]: https://github.com/rust-lang/rust/pull/90132
|
||||
[90247]: https://github.com/rust-lang/rust/pull/90247
|
||||
[91606]: https://github.com/rust-lang/rust/pull/91606
|
||||
[92068]: https://github.com/rust-lang/rust/pull/92068
|
||||
[92300]: https://github.com/rust-lang/rust/pull/92300
|
||||
[92357]: https://github.com/rust-lang/rust/pull/92357
|
||||
[92383]: https://github.com/rust-lang/rust/pull/92383
|
||||
[92630]: https://github.com/rust-lang/rust/pull/92630
|
||||
[92670]: https://github.com/rust-lang/rust/pull/92670
|
||||
[92800]: https://github.com/rust-lang/rust/pull/92800
|
||||
[92933]: https://github.com/rust-lang/rust/pull/92933
|
||||
[93566]: https://github.com/rust-lang/rust/pull/93566
|
||||
[93577]: https://github.com/rust-lang/rust/pull/93577
|
||||
[93658]: https://github.com/rust-lang/rust/pull/93658
|
||||
[93742]: https://github.com/rust-lang/rust/pull/93742
|
||||
[93824]: https://github.com/rust-lang/rust/pull/93824
|
||||
[93918]: https://github.com/rust-lang/rust/pull/93918
|
||||
[95026]: https://github.com/rust-lang/rust/pull/95026
|
||||
|
||||
[cargo/10086]: https://github.com/rust-lang/cargo/pull/10086
|
||||
[cargo/10245]: https://github.com/rust-lang/cargo/pull/10245
|
||||
[cargo/10269]: https://github.com/rust-lang/cargo/pull/10269
|
||||
[cargo/10274]: https://github.com/rust-lang/cargo/pull/10274
|
||||
[cargo/10379]: https://github.com/rust-lang/cargo/pull/10379
|
||||
|
||||
[arc_new_cyclic]: https://doc.rust-lang.org/stable/std/sync/struct.Arc.html#method.new_cyclic
|
||||
[rc_new_cyclic]: https://doc.rust-lang.org/stable/std/rc/struct.Rc.html#method.new_cyclic
|
||||
[slice_escape_ascii]: https://doc.rust-lang.org/stable/std/slice/struct.EscapeAscii.html
|
||||
[slice_u8_escape_ascii]: https://doc.rust-lang.org/stable/std/primitive.slice.html#method.escape_ascii
|
||||
[u8_escape_ascii]: https://doc.rust-lang.org/stable/std/primitive.u8.html#method.escape_ascii
|
||||
[vec_spare_capacity_mut]: https://doc.rust-lang.org/stable/std/vec/struct.Vec.html#method.spare_capacity_mut
|
||||
[assume_init_drop]: https://doc.rust-lang.org/stable/std/mem/union.MaybeUninit.html#method.assume_init_drop
|
||||
[assume_init_read]: https://doc.rust-lang.org/stable/std/mem/union.MaybeUninit.html#method.assume_init_read
|
||||
[i8_abs_diff]: https://doc.rust-lang.org/stable/std/primitive.i8.html#method.abs_diff
|
||||
[i16_abs_diff]: https://doc.rust-lang.org/stable/std/primitive.i16.html#method.abs_diff
|
||||
[i32_abs_diff]: https://doc.rust-lang.org/stable/std/primitive.i32.html#method.abs_diff
|
||||
[i64_abs_diff]: https://doc.rust-lang.org/stable/std/primitive.i64.html#method.abs_diff
|
||||
[i128_abs_diff]: https://doc.rust-lang.org/stable/std/primitive.i128.html#method.abs_diff
|
||||
[isize_abs_diff]: https://doc.rust-lang.org/stable/std/primitive.isize.html#method.abs_diff
|
||||
[u8_abs_diff]: https://doc.rust-lang.org/stable/std/primitive.u8.html#method.abs_diff
|
||||
[u16_abs_diff]: https://doc.rust-lang.org/stable/std/primitive.u16.html#method.abs_diff
|
||||
[u32_abs_diff]: https://doc.rust-lang.org/stable/std/primitive.u32.html#method.abs_diff
|
||||
[u64_abs_diff]: https://doc.rust-lang.org/stable/std/primitive.u64.html#method.abs_diff
|
||||
[u128_abs_diff]: https://doc.rust-lang.org/stable/std/primitive.u128.html#method.abs_diff
|
||||
[usize_abs_diff]: https://doc.rust-lang.org/stable/std/primitive.usize.html#method.abs_diff
|
||||
[display_error_kind]: https://doc.rust-lang.org/stable/std/io/enum.ErrorKind.html#impl-Display
|
||||
[from_u8_exit_code]: https://doc.rust-lang.org/stable/std/process/struct.ExitCode.html#impl-From%3Cu8%3E
|
||||
[not_never]: https://doc.rust-lang.org/stable/std/primitive.never.html#impl-Not
|
||||
[wrapping_assign_ops]: https://doc.rust-lang.org/stable/std/num/struct.Wrapping.html#trait-implementations
|
||||
[is_aarch64_feature_detected]: https://doc.rust-lang.org/stable/std/arch/macro.is_aarch64_feature_detected.html
|
||||
|
||||
Version 1.59.0 (2022-02-24)
|
||||
==========================
|
||||
|
||||
|
|
|
@ -658,16 +658,16 @@ impl server::Literal for Rustc<'_, '_> {
|
|||
self.lit(token::Float, Symbol::intern(n), Some(sym::f64))
|
||||
}
|
||||
fn string(&mut self, string: &str) -> Self::Literal {
|
||||
let mut escaped = String::new();
|
||||
for ch in string.chars() {
|
||||
escaped.extend(ch.escape_debug());
|
||||
}
|
||||
self.lit(token::Str, Symbol::intern(&escaped), None)
|
||||
let quoted = format!("{:?}", string);
|
||||
assert!(quoted.starts_with('"') && quoted.ends_with('"'));
|
||||
let symbol = "ed[1..quoted.len() - 1];
|
||||
self.lit(token::Str, Symbol::intern(symbol), None)
|
||||
}
|
||||
fn character(&mut self, ch: char) -> Self::Literal {
|
||||
let mut escaped = String::new();
|
||||
escaped.extend(ch.escape_unicode());
|
||||
self.lit(token::Char, Symbol::intern(&escaped), None)
|
||||
let quoted = format!("{:?}", ch);
|
||||
assert!(quoted.starts_with('\'') && quoted.ends_with('\''));
|
||||
let symbol = "ed[1..quoted.len() - 1];
|
||||
self.lit(token::Char, Symbol::intern(symbol), None)
|
||||
}
|
||||
fn byte_string(&mut self, bytes: &[u8]) -> Self::Literal {
|
||||
let string = bytes
|
||||
|
|
|
@ -474,6 +474,12 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
|||
err.span_label(span, explanation);
|
||||
}
|
||||
|
||||
if let ObligationCauseCode::ObjectCastObligation(obj_ty) = obligation.cause.code().peel_derives() &&
|
||||
let Some(self_ty) = trait_predicate.self_ty().no_bound_vars() &&
|
||||
Some(trait_ref.def_id()) == self.tcx.lang_items().sized_trait() {
|
||||
self.suggest_borrowing_for_object_cast(&mut err, &obligation, self_ty, *obj_ty);
|
||||
}
|
||||
|
||||
if trait_predicate.is_const_if_const() && obligation.param_env.is_const() {
|
||||
let non_const_predicate = trait_ref.without_const();
|
||||
let non_const_obligation = Obligation {
|
||||
|
|
|
@ -77,6 +77,14 @@ pub trait InferCtxtExt<'tcx> {
|
|||
has_custom_message: bool,
|
||||
) -> bool;
|
||||
|
||||
fn suggest_borrowing_for_object_cast(
|
||||
&self,
|
||||
err: &mut Diagnostic,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
self_ty: Ty<'tcx>,
|
||||
object_ty: Ty<'tcx>,
|
||||
);
|
||||
|
||||
fn suggest_remove_reference(
|
||||
&self,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
|
@ -801,6 +809,35 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
// Suggest borrowing the type
|
||||
fn suggest_borrowing_for_object_cast(
|
||||
&self,
|
||||
err: &mut Diagnostic,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
self_ty: Ty<'tcx>,
|
||||
object_ty: Ty<'tcx>,
|
||||
) {
|
||||
let ty::Dynamic(predicates, _) = object_ty.kind() else { return; };
|
||||
let self_ref_ty = self.tcx.mk_imm_ref(self.tcx.lifetimes.re_erased, self_ty);
|
||||
|
||||
for predicate in predicates.iter() {
|
||||
if !self.predicate_must_hold_modulo_regions(
|
||||
&obligation.with(predicate.with_self_ty(self.tcx, self_ref_ty)),
|
||||
) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
err.span_suggestion(
|
||||
obligation.cause.span.shrink_to_lo(),
|
||||
&format!(
|
||||
"consider borrowing the value, since `&{self_ty}` can be coerced into `{object_ty}`"
|
||||
),
|
||||
"&".to_string(),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
|
||||
/// Whenever references are used by mistake, like `for (i, e) in &vec.iter().enumerate()`,
|
||||
/// suggest removing these references until we reach a type that implements the trait.
|
||||
fn suggest_remove_reference(
|
||||
|
|
|
@ -1990,9 +1990,106 @@ impl<T> const From<T> for UnsafeCell<T> {
|
|||
#[unstable(feature = "coerce_unsized", issue = "27732")]
|
||||
impl<T: CoerceUnsized<U>, U> CoerceUnsized<UnsafeCell<U>> for UnsafeCell<T> {}
|
||||
|
||||
#[allow(unused)]
|
||||
fn assert_coerce_unsized(a: UnsafeCell<&i32>, b: Cell<&i32>, c: RefCell<&i32>) {
|
||||
let _: UnsafeCell<&dyn Send> = a;
|
||||
let _: Cell<&dyn Send> = b;
|
||||
let _: RefCell<&dyn Send> = c;
|
||||
/// [`UnsafeCell`], but [`Sync`].
|
||||
///
|
||||
/// This is just an `UnsafeCell`, except it implements `Sync`
|
||||
/// if `T` implements `Sync`.
|
||||
///
|
||||
/// `UnsafeCell` doesn't implement `Sync`, to prevent accidental mis-use.
|
||||
/// You can use `SyncUnsafeCell` instead of `UnsafeCell` to allow it to be
|
||||
/// shared between threads, if that's intentional.
|
||||
/// Providing proper synchronization is still the task of the user,
|
||||
/// making this type just as unsafe to use.
|
||||
///
|
||||
/// See [`UnsafeCell`] for details.
|
||||
#[unstable(feature = "sync_unsafe_cell", issue = "95439")]
|
||||
#[repr(transparent)]
|
||||
pub struct SyncUnsafeCell<T: ?Sized> {
|
||||
value: UnsafeCell<T>,
|
||||
}
|
||||
|
||||
#[unstable(feature = "sync_unsafe_cell", issue = "95439")]
|
||||
unsafe impl<T: ?Sized + Sync> Sync for SyncUnsafeCell<T> {}
|
||||
|
||||
#[unstable(feature = "sync_unsafe_cell", issue = "95439")]
|
||||
impl<T> SyncUnsafeCell<T> {
|
||||
/// Constructs a new instance of `SyncUnsafeCell` which will wrap the specified value.
|
||||
#[inline]
|
||||
pub const fn new(value: T) -> Self {
|
||||
Self { value: UnsafeCell { value } }
|
||||
}
|
||||
|
||||
/// Unwraps the value.
|
||||
#[inline]
|
||||
pub const fn into_inner(self) -> T {
|
||||
self.value.into_inner()
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "sync_unsafe_cell", issue = "95439")]
|
||||
impl<T: ?Sized> SyncUnsafeCell<T> {
|
||||
/// Gets a mutable pointer to the wrapped value.
|
||||
///
|
||||
/// This can be cast to a pointer of any kind.
|
||||
/// Ensure that the access is unique (no active references, mutable or not)
|
||||
/// when casting to `&mut T`, and ensure that there are no mutations
|
||||
/// or mutable aliases going on when casting to `&T`
|
||||
#[inline]
|
||||
pub const fn get(&self) -> *mut T {
|
||||
self.value.get()
|
||||
}
|
||||
|
||||
/// Returns a mutable reference to the underlying data.
|
||||
///
|
||||
/// This call borrows the `SyncUnsafeCell` mutably (at compile-time) which
|
||||
/// guarantees that we possess the only reference.
|
||||
#[inline]
|
||||
pub const fn get_mut(&mut self) -> &mut T {
|
||||
self.value.get_mut()
|
||||
}
|
||||
|
||||
/// Gets a mutable pointer to the wrapped value.
|
||||
///
|
||||
/// See [`UnsafeCell::get`] for details.
|
||||
#[inline]
|
||||
pub const fn raw_get(this: *const Self) -> *mut T {
|
||||
// We can just cast the pointer from `SyncUnsafeCell<T>` to `T` because
|
||||
// of #[repr(transparent)] on both SyncUnsafeCell and UnsafeCell.
|
||||
// See UnsafeCell::raw_get.
|
||||
this as *const T as *mut T
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "sync_unsafe_cell", issue = "95439")]
|
||||
impl<T: Default> Default for SyncUnsafeCell<T> {
|
||||
/// Creates an `SyncUnsafeCell`, with the `Default` value for T.
|
||||
fn default() -> SyncUnsafeCell<T> {
|
||||
SyncUnsafeCell::new(Default::default())
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "sync_unsafe_cell", issue = "95439")]
|
||||
#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
|
||||
impl<T> const From<T> for SyncUnsafeCell<T> {
|
||||
/// Creates a new `SyncUnsafeCell<T>` containing the given value.
|
||||
fn from(t: T) -> SyncUnsafeCell<T> {
|
||||
SyncUnsafeCell::new(t)
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "coerce_unsized", issue = "27732")]
|
||||
//#[unstable(feature = "sync_unsafe_cell", issue = "95439")]
|
||||
impl<T: CoerceUnsized<U>, U> CoerceUnsized<SyncUnsafeCell<U>> for SyncUnsafeCell<T> {}
|
||||
|
||||
#[allow(unused)]
|
||||
fn assert_coerce_unsized(
|
||||
a: UnsafeCell<&i32>,
|
||||
b: SyncUnsafeCell<&i32>,
|
||||
c: Cell<&i32>,
|
||||
d: RefCell<&i32>,
|
||||
) {
|
||||
let _: UnsafeCell<&dyn Send> = a;
|
||||
let _: SyncUnsafeCell<&dyn Send> = b;
|
||||
let _: Cell<&dyn Send> = c;
|
||||
let _: RefCell<&dyn Send> = d;
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
|
||||
use crate::cell::{Cell, Ref, RefCell, RefMut, UnsafeCell};
|
||||
use crate::cell::{Cell, Ref, RefCell, RefMut, SyncUnsafeCell, UnsafeCell};
|
||||
use crate::char::EscapeDebugExtArgs;
|
||||
use crate::marker::PhantomData;
|
||||
use crate::mem;
|
||||
|
@ -2400,6 +2400,13 @@ impl<T: ?Sized> Debug for UnsafeCell<T> {
|
|||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "sync_unsafe_cell", issue = "95439")]
|
||||
impl<T: ?Sized> Debug for SyncUnsafeCell<T> {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
|
||||
f.debug_struct("SyncUnsafeCell").finish_non_exhaustive()
|
||||
}
|
||||
}
|
||||
|
||||
// If you expected tests to be here, look instead at the core/tests/fmt.rs file,
|
||||
// it's a lot easier than creating all of the rt::Piece structures here.
|
||||
// There are also tests in the alloc crate, for those that need allocations.
|
||||
|
|
|
@ -139,6 +139,7 @@
|
|||
#![feature(const_type_id)]
|
||||
#![feature(const_type_name)]
|
||||
#![feature(const_default_impls)]
|
||||
#![feature(const_unsafecell_get_mut)]
|
||||
#![feature(core_panic)]
|
||||
#![feature(duration_consts_float)]
|
||||
#![feature(maybe_uninit_uninit_array)]
|
||||
|
|
|
@ -1040,7 +1040,6 @@ impl f32 {
|
|||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(total_cmp)]
|
||||
/// struct GoodBoy {
|
||||
/// name: String,
|
||||
/// weight: f32,
|
||||
|
@ -1060,7 +1059,7 @@ impl f32 {
|
|||
/// # .zip([-5.0, 0.1, 10.0, 99.0, f32::INFINITY, f32::NAN].iter())
|
||||
/// # .all(|(a, b)| a.to_bits() == b.to_bits()))
|
||||
/// ```
|
||||
#[unstable(feature = "total_cmp", issue = "72599")]
|
||||
#[stable(feature = "total_cmp", since = "1.62.0")]
|
||||
#[must_use]
|
||||
#[inline]
|
||||
pub fn total_cmp(&self, other: &Self) -> crate::cmp::Ordering {
|
||||
|
|
|
@ -1056,7 +1056,6 @@ impl f64 {
|
|||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(total_cmp)]
|
||||
/// struct GoodBoy {
|
||||
/// name: String,
|
||||
/// weight: f64,
|
||||
|
@ -1076,7 +1075,7 @@ impl f64 {
|
|||
/// # .zip([-5.0, 0.1, 10.0, 99.0, f64::INFINITY, f64::NAN].iter())
|
||||
/// # .all(|(a, b)| a.to_bits() == b.to_bits()))
|
||||
/// ```
|
||||
#[unstable(feature = "total_cmp", issue = "72599")]
|
||||
#[stable(feature = "total_cmp", since = "1.62.0")]
|
||||
#[must_use]
|
||||
#[inline]
|
||||
pub fn total_cmp(&self, other: &Self) -> crate::cmp::Ordering {
|
||||
|
|
|
@ -285,7 +285,6 @@
|
|||
#![feature(std_internals)]
|
||||
#![feature(str_internals)]
|
||||
#![feature(strict_provenance)]
|
||||
#![feature(total_cmp)]
|
||||
//
|
||||
// Library features (alloc):
|
||||
#![feature(alloc_layout_extra)]
|
||||
|
|
|
@ -159,7 +159,7 @@ pub trait CommandExt: Sealed {
|
|||
///
|
||||
/// This is useful for passing arguments to `cmd.exe /c`, which doesn't follow
|
||||
/// `CommandLineToArgvW` escaping rules.
|
||||
#[unstable(feature = "windows_process_extensions_raw_arg", issue = "29494")]
|
||||
#[stable(feature = "windows_process_extensions_raw_arg", since = "1.62.0")]
|
||||
fn raw_arg<S: AsRef<OsStr>>(&mut self, text_to_append_as_is: S) -> &mut process::Command;
|
||||
}
|
||||
|
||||
|
|
|
@ -326,6 +326,12 @@ impl Default for IO_STATUS_BLOCK {
|
|||
}
|
||||
}
|
||||
|
||||
pub type LPOVERLAPPED_COMPLETION_ROUTINE = unsafe extern "system" fn(
|
||||
dwErrorCode: DWORD,
|
||||
dwNumberOfBytesTransfered: DWORD,
|
||||
lpOverlapped: *mut OVERLAPPED,
|
||||
);
|
||||
|
||||
#[repr(C)]
|
||||
#[cfg(not(target_pointer_width = "64"))]
|
||||
pub struct WSADATA {
|
||||
|
@ -891,6 +897,7 @@ extern "system" {
|
|||
pub fn WaitForSingleObject(hHandle: HANDLE, dwMilliseconds: DWORD) -> DWORD;
|
||||
pub fn SwitchToThread() -> BOOL;
|
||||
pub fn Sleep(dwMilliseconds: DWORD);
|
||||
pub fn SleepEx(dwMilliseconds: DWORD, bAlertable: BOOL) -> DWORD;
|
||||
pub fn GetProcessId(handle: HANDLE) -> DWORD;
|
||||
pub fn CopyFileExW(
|
||||
lpExistingFileName: LPCWSTR,
|
||||
|
@ -957,6 +964,13 @@ extern "system" {
|
|||
lpNumberOfBytesRead: LPDWORD,
|
||||
lpOverlapped: LPOVERLAPPED,
|
||||
) -> BOOL;
|
||||
pub fn ReadFileEx(
|
||||
hFile: BorrowedHandle<'_>,
|
||||
lpBuffer: LPVOID,
|
||||
nNumberOfBytesToRead: DWORD,
|
||||
lpOverlapped: LPOVERLAPPED,
|
||||
lpCompletionRoutine: LPOVERLAPPED_COMPLETION_ROUTINE,
|
||||
) -> BOOL;
|
||||
pub fn WriteFile(
|
||||
hFile: BorrowedHandle<'_>,
|
||||
lpBuffer: LPVOID,
|
||||
|
@ -964,6 +978,13 @@ extern "system" {
|
|||
lpNumberOfBytesWritten: LPDWORD,
|
||||
lpOverlapped: LPOVERLAPPED,
|
||||
) -> BOOL;
|
||||
pub fn WriteFileEx(
|
||||
hFile: BorrowedHandle<'_>,
|
||||
lpBuffer: LPVOID,
|
||||
nNumberOfBytesToWrite: DWORD,
|
||||
lpOverlapped: LPOVERLAPPED,
|
||||
lpCompletionRoutine: LPOVERLAPPED_COMPLETION_ROUTINE,
|
||||
) -> BOOL;
|
||||
pub fn CloseHandle(hObject: HANDLE) -> BOOL;
|
||||
pub fn MoveFileExW(lpExistingFileName: LPCWSTR, lpNewFileName: LPCWSTR, dwFlags: DWORD)
|
||||
-> BOOL;
|
||||
|
|
|
@ -173,6 +173,15 @@ fn random_number() -> usize {
|
|||
}
|
||||
}
|
||||
|
||||
// Abstracts over `ReadFileEx` and `WriteFileEx`
|
||||
type AlertableIoFn = unsafe extern "system" fn(
|
||||
BorrowedHandle<'_>,
|
||||
c::LPVOID,
|
||||
c::DWORD,
|
||||
c::LPOVERLAPPED,
|
||||
c::LPOVERLAPPED_COMPLETION_ROUTINE,
|
||||
) -> c::BOOL;
|
||||
|
||||
impl AnonPipe {
|
||||
pub fn handle(&self) -> &Handle {
|
||||
&self.inner
|
||||
|
@ -182,7 +191,19 @@ impl AnonPipe {
|
|||
}
|
||||
|
||||
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
self.inner.read(buf)
|
||||
let result = unsafe {
|
||||
let len = crate::cmp::min(buf.len(), c::DWORD::MAX as usize) as c::DWORD;
|
||||
self.alertable_io_internal(c::ReadFileEx, buf.as_mut_ptr() as _, len)
|
||||
};
|
||||
|
||||
match result {
|
||||
// The special treatment of BrokenPipe is to deal with Windows
|
||||
// pipe semantics, which yields this error when *reading* from
|
||||
// a pipe after the other end has closed; we interpret that as
|
||||
// EOF on the pipe.
|
||||
Err(ref e) if e.kind() == io::ErrorKind::BrokenPipe => Ok(0),
|
||||
_ => result,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
|
||||
|
@ -195,7 +216,10 @@ impl AnonPipe {
|
|||
}
|
||||
|
||||
pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
|
||||
self.inner.write(buf)
|
||||
unsafe {
|
||||
let len = crate::cmp::min(buf.len(), c::DWORD::MAX as usize) as c::DWORD;
|
||||
self.alertable_io_internal(c::WriteFileEx, buf.as_ptr() as _, len)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
|
||||
|
@ -206,6 +230,99 @@ impl AnonPipe {
|
|||
pub fn is_write_vectored(&self) -> bool {
|
||||
self.inner.is_write_vectored()
|
||||
}
|
||||
|
||||
/// Synchronizes asynchronous reads or writes using our anonymous pipe.
|
||||
///
|
||||
/// This is a wrapper around [`ReadFileEx`] or [`WriteFileEx`] that uses
|
||||
/// [Asynchronous Procedure Call] (APC) to synchronize reads or writes.
|
||||
///
|
||||
/// Note: This should not be used for handles we don't create.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// `buf` must be a pointer to a buffer that's valid for reads or writes
|
||||
/// up to `len` bytes. The `AlertableIoFn` must be either `ReadFileEx` or `WriteFileEx`
|
||||
///
|
||||
/// [`ReadFileEx`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-readfileex
|
||||
/// [`WriteFileEx`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-writefileex
|
||||
/// [Asynchronous Procedure Call]: https://docs.microsoft.com/en-us/windows/win32/sync/asynchronous-procedure-calls
|
||||
unsafe fn alertable_io_internal(
|
||||
&self,
|
||||
io: AlertableIoFn,
|
||||
buf: c::LPVOID,
|
||||
len: c::DWORD,
|
||||
) -> io::Result<usize> {
|
||||
// Use "alertable I/O" to synchronize the pipe I/O.
|
||||
// This has four steps.
|
||||
//
|
||||
// STEP 1: Start the asynchronous I/O operation.
|
||||
// This simply calls either `ReadFileEx` or `WriteFileEx`,
|
||||
// giving it a pointer to the buffer and callback function.
|
||||
//
|
||||
// STEP 2: Enter an alertable state.
|
||||
// The callback set in step 1 will not be called until the thread
|
||||
// enters an "alertable" state. This can be done using `SleepEx`.
|
||||
//
|
||||
// STEP 3: The callback
|
||||
// Once the I/O is complete and the thread is in an alertable state,
|
||||
// the callback will be run on the same thread as the call to
|
||||
// `ReadFileEx` or `WriteFileEx` done in step 1.
|
||||
// In the callback we simply set the result of the async operation.
|
||||
//
|
||||
// STEP 4: Return the result.
|
||||
// At this point we'll have a result from the callback function
|
||||
// and can simply return it. Note that we must not return earlier,
|
||||
// while the I/O is still in progress.
|
||||
|
||||
// The result that will be set from the asynchronous callback.
|
||||
let mut async_result: Option<AsyncResult> = None;
|
||||
struct AsyncResult {
|
||||
error: u32,
|
||||
transfered: u32,
|
||||
}
|
||||
|
||||
// STEP 3: The callback.
|
||||
unsafe extern "system" fn callback(
|
||||
dwErrorCode: u32,
|
||||
dwNumberOfBytesTransfered: u32,
|
||||
lpOverlapped: *mut c::OVERLAPPED,
|
||||
) {
|
||||
// Set `async_result` using a pointer smuggled through `hEvent`.
|
||||
let result = AsyncResult { error: dwErrorCode, transfered: dwNumberOfBytesTransfered };
|
||||
*(*lpOverlapped).hEvent.cast::<Option<AsyncResult>>() = Some(result);
|
||||
}
|
||||
|
||||
// STEP 1: Start the I/O operation.
|
||||
let mut overlapped: c::OVERLAPPED = crate::mem::zeroed();
|
||||
// `hEvent` is unused by `ReadFileEx` and `WriteFileEx`.
|
||||
// Therefore the documentation suggests using it to smuggle a pointer to the callback.
|
||||
overlapped.hEvent = &mut async_result as *mut _ as *mut _;
|
||||
|
||||
// Asynchronous read of the pipe.
|
||||
// If successful, `callback` will be called once it completes.
|
||||
let result = io(self.inner.as_handle(), buf, len, &mut overlapped, callback);
|
||||
if result == c::FALSE {
|
||||
// We can return here because the call failed.
|
||||
// After this we must not return until the I/O completes.
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
|
||||
// Wait indefinitely for the result.
|
||||
let result = loop {
|
||||
// STEP 2: Enter an alertable state.
|
||||
// The second parameter of `SleepEx` is used to make this sleep alertable.
|
||||
c::SleepEx(c::INFINITE, c::TRUE);
|
||||
if let Some(result) = async_result {
|
||||
break result;
|
||||
}
|
||||
};
|
||||
// STEP 4: Return the result.
|
||||
// `async_result` is always `Some` at this point
|
||||
match result.error {
|
||||
c::ERROR_SUCCESS => Ok(result.transfered as usize),
|
||||
error => Err(io::Error::from_raw_os_error(error as _)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read2(p1: AnonPipe, v1: &mut Vec<u8>, p2: AnonPipe, v2: &mut Vec<u8>) -> io::Result<()> {
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
#![feature(staged_api)]
|
||||
#![feature(process_exitcode_internals)]
|
||||
#![feature(test)]
|
||||
#![feature(total_cmp)]
|
||||
|
||||
// Public reexports
|
||||
pub use self::bench::{black_box, Bencher};
|
||||
|
|
|
@ -6,6 +6,10 @@ LL | let _x = "test" as &dyn (::std::any::Any);
|
|||
|
|
||||
= help: the trait `Sized` is not implemented for `str`
|
||||
= note: required for the cast to the object type `dyn Any`
|
||||
help: consider borrowing the value, since `&str` can be coerced into `dyn Any`
|
||||
|
|
||||
LL | let _x = &"test" as &dyn (::std::any::Any);
|
||||
| +
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
@ -224,6 +224,10 @@ LL | let _ = fat_v as *const dyn Foo;
|
|||
|
|
||||
= help: the trait `Sized` is not implemented for `[u8]`
|
||||
= note: required for the cast to the object type `dyn Foo`
|
||||
help: consider borrowing the value, since `&[u8]` can be coerced into `dyn Foo`
|
||||
|
|
||||
LL | let _ = &fat_v as *const dyn Foo;
|
||||
| +
|
||||
|
||||
error[E0277]: the size for values of type `str` cannot be known at compilation time
|
||||
--> $DIR/cast-rfc0401.rs:62:13
|
||||
|
@ -233,6 +237,10 @@ LL | let _ = a as *const dyn Foo;
|
|||
|
|
||||
= help: the trait `Sized` is not implemented for `str`
|
||||
= note: required for the cast to the object type `dyn Foo`
|
||||
help: consider borrowing the value, since `&str` can be coerced into `dyn Foo`
|
||||
|
|
||||
LL | let _ = &a as *const dyn Foo;
|
||||
| +
|
||||
|
||||
error[E0606]: casting `&{float}` as `f32` is invalid
|
||||
--> $DIR/cast-rfc0401.rs:71:30
|
||||
|
|
|
@ -18,6 +18,17 @@ fn test_display_literal() {
|
|||
Literal::f64_unsuffixed(1e100).to_string(),
|
||||
"10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0",
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
Literal::string("a \t ❤ ' \" \u{1}").to_string(),
|
||||
"\"a \\t ❤ ' \\\" \\u{1}\"",
|
||||
);
|
||||
assert_eq!(Literal::character('a').to_string(), "'a'");
|
||||
assert_eq!(Literal::character('\t').to_string(), "'\\t'");
|
||||
assert_eq!(Literal::character('❤').to_string(), "'❤'");
|
||||
assert_eq!(Literal::character('\'').to_string(), "'\\''");
|
||||
assert_eq!(Literal::character('"').to_string(), "'\"'");
|
||||
assert_eq!(Literal::character('\u{1}').to_string(), "'\\u{1}'");
|
||||
}
|
||||
|
||||
fn test_parse_literal() {
|
||||
|
|
|
@ -22,7 +22,7 @@ fn main() {
|
|||
crate::Span::recover_proc_macro_span(0)))),
|
||||
crate::TokenStream::from(crate::TokenTree::Ident(crate::Ident::new("hello",
|
||||
crate::Span::recover_proc_macro_span(1)))),
|
||||
crate::TokenStream::from(crate::TokenTree::Punct(crate::Punct::new('\u{3d}',
|
||||
crate::TokenStream::from(crate::TokenTree::Punct(crate::Punct::new('=',
|
||||
crate::Spacing::Alone))),
|
||||
crate::TokenStream::from(crate::TokenTree::Literal({
|
||||
let mut iter =
|
||||
|
@ -35,7 +35,7 @@ fn main() {
|
|||
::core::panicking::panic("internal error: entered unreachable code")
|
||||
}
|
||||
})),
|
||||
crate::TokenStream::from(crate::TokenTree::Punct(crate::Punct::new('\u{3b}',
|
||||
crate::TokenStream::from(crate::TokenTree::Punct(crate::Punct::new(';',
|
||||
crate::Spacing::Alone)))].iter().cloned().collect::<crate::TokenStream>()
|
||||
}
|
||||
const _: () =
|
||||
|
|
|
@ -6,6 +6,10 @@ LL | foo11("bar", &"baz");
|
|||
|
|
||||
= help: the trait `Sized` is not implemented for `str`
|
||||
= note: required for the cast to the object type `dyn AsRef<Path>`
|
||||
help: consider borrowing the value, since `&str` can be coerced into `dyn AsRef<Path>`
|
||||
|
|
||||
LL | foo11(&"bar", &"baz");
|
||||
| +
|
||||
|
||||
error[E0277]: the size for values of type `str` cannot be known at compilation time
|
||||
--> $DIR/unsized-fn-param.rs:13:19
|
||||
|
@ -15,6 +19,10 @@ LL | foo12(&"bar", "baz");
|
|||
|
|
||||
= help: the trait `Sized` is not implemented for `str`
|
||||
= note: required for the cast to the object type `dyn AsRef<Path>`
|
||||
help: consider borrowing the value, since `&str` can be coerced into `dyn AsRef<Path>`
|
||||
|
|
||||
LL | foo12(&"bar", &"baz");
|
||||
| +
|
||||
|
||||
error[E0277]: the size for values of type `str` cannot be known at compilation time
|
||||
--> $DIR/unsized-fn-param.rs:16:11
|
||||
|
@ -24,6 +32,10 @@ LL | foo21("bar", &"baz");
|
|||
|
|
||||
= help: the trait `Sized` is not implemented for `str`
|
||||
= note: required for the cast to the object type `dyn AsRef<str>`
|
||||
help: consider borrowing the value, since `&str` can be coerced into `dyn AsRef<str>`
|
||||
|
|
||||
LL | foo21(&"bar", &"baz");
|
||||
| +
|
||||
|
||||
error[E0277]: the size for values of type `str` cannot be known at compilation time
|
||||
--> $DIR/unsized-fn-param.rs:18:19
|
||||
|
@ -33,6 +45,10 @@ LL | foo22(&"bar", "baz");
|
|||
|
|
||||
= help: the trait `Sized` is not implemented for `str`
|
||||
= note: required for the cast to the object type `dyn AsRef<str>`
|
||||
help: consider borrowing the value, since `&str` can be coerced into `dyn AsRef<str>`
|
||||
|
|
||||
LL | foo22(&"bar", &"baz");
|
||||
| +
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue