diff --git a/RELEASES.md b/RELEASES.md index 08040f4815836..0965e37574d07 100644 --- a/RELEASES.md +++ b/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 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) ========================== diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs index bfdf99762f57a..20351070f71b9 100644 --- a/compiler/rustc_expand/src/proc_macro_server.rs +++ b/compiler/rustc_expand/src/proc_macro_server.rs @@ -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 diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 216aa89dd1f28..0a22c02520939 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -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 { diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index b49a5f6578f75..105e338048680 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -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( diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index 9dbb5eecd469b..2a49017de3cc8 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -1990,9 +1990,106 @@ impl const From for UnsafeCell { #[unstable(feature = "coerce_unsized", issue = "27732")] impl, U> CoerceUnsized> for UnsafeCell {} +/// [`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 { + value: UnsafeCell, +} + +#[unstable(feature = "sync_unsafe_cell", issue = "95439")] +unsafe impl Sync for SyncUnsafeCell {} + +#[unstable(feature = "sync_unsafe_cell", issue = "95439")] +impl SyncUnsafeCell { + /// 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 SyncUnsafeCell { + /// 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` 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 Default for SyncUnsafeCell { + /// Creates an `SyncUnsafeCell`, with the `Default` value for T. + fn default() -> SyncUnsafeCell { + SyncUnsafeCell::new(Default::default()) + } +} + +#[unstable(feature = "sync_unsafe_cell", issue = "95439")] +#[rustc_const_unstable(feature = "const_convert", issue = "88674")] +impl const From for SyncUnsafeCell { + /// Creates a new `SyncUnsafeCell` containing the given value. + fn from(t: T) -> SyncUnsafeCell { + SyncUnsafeCell::new(t) + } +} + +#[unstable(feature = "coerce_unsized", issue = "27732")] +//#[unstable(feature = "sync_unsafe_cell", issue = "95439")] +impl, U> CoerceUnsized> for SyncUnsafeCell {} + #[allow(unused)] -fn assert_coerce_unsized(a: UnsafeCell<&i32>, b: Cell<&i32>, c: RefCell<&i32>) { +fn assert_coerce_unsized( + a: UnsafeCell<&i32>, + b: SyncUnsafeCell<&i32>, + c: Cell<&i32>, + d: RefCell<&i32>, +) { let _: UnsafeCell<&dyn Send> = a; - let _: Cell<&dyn Send> = b; - let _: RefCell<&dyn Send> = c; + let _: SyncUnsafeCell<&dyn Send> = b; + let _: Cell<&dyn Send> = c; + let _: RefCell<&dyn Send> = d; } diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index 6c1d20f36e2f6..fac959ac7347d 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -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 Debug for UnsafeCell { } } +#[unstable(feature = "sync_unsafe_cell", issue = "95439")] +impl Debug for SyncUnsafeCell { + 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. diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 7dfcc36ce9391..e13f50b0d7a53 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -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)] diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index 17ca854768546..e56e602a662c1 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs @@ -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 { diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs index 350d8529de57a..8304caf649cc2 100644 --- a/library/core/src/num/f64.rs +++ b/library/core/src/num/f64.rs @@ -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 { diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index e1c1800438354..1016fbc99d826 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -285,7 +285,6 @@ #![feature(std_internals)] #![feature(str_internals)] #![feature(strict_provenance)] -#![feature(total_cmp)] // // Library features (alloc): #![feature(alloc_layout_extra)] diff --git a/library/std/src/os/windows/process.rs b/library/std/src/os/windows/process.rs index 9510d104806db..e189630991436 100644 --- a/library/std/src/os/windows/process.rs +++ b/library/std/src/os/windows/process.rs @@ -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>(&mut self, text_to_append_as_is: S) -> &mut process::Command; } diff --git a/library/std/src/sys/windows/c.rs b/library/std/src/sys/windows/c.rs index 0edf43e5d9dd5..0ecc2a5cfdad5 100644 --- a/library/std/src/sys/windows/c.rs +++ b/library/std/src/sys/windows/c.rs @@ -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; diff --git a/library/std/src/sys/windows/pipe.rs b/library/std/src/sys/windows/pipe.rs index 63d3d6c5ed42f..df4f1b24eec26 100644 --- a/library/std/src/sys/windows/pipe.rs +++ b/library/std/src/sys/windows/pipe.rs @@ -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 { - 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 { @@ -195,7 +216,10 @@ impl AnonPipe { } pub fn write(&self, buf: &[u8]) -> io::Result { - 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 { @@ -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 { + // 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 = 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::>() = 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, p2: AnonPipe, v2: &mut Vec) -> io::Result<()> { diff --git a/library/test/src/lib.rs b/library/test/src/lib.rs index 889f7cb9db941..0c748da1a59cc 100644 --- a/library/test/src/lib.rs +++ b/library/test/src/lib.rs @@ -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}; diff --git a/src/test/ui/issues/issue-14366.stderr b/src/test/ui/issues/issue-14366.stderr index d5dab561ddefb..b96b07c91a1fe 100644 --- a/src/test/ui/issues/issue-14366.stderr +++ b/src/test/ui/issues/issue-14366.stderr @@ -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 diff --git a/src/test/ui/mismatched_types/cast-rfc0401.stderr b/src/test/ui/mismatched_types/cast-rfc0401.stderr index 5f11e4ded8004..84220ea172a11 100644 --- a/src/test/ui/mismatched_types/cast-rfc0401.stderr +++ b/src/test/ui/mismatched_types/cast-rfc0401.stderr @@ -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 diff --git a/src/test/ui/proc-macro/auxiliary/api/parse.rs b/src/test/ui/proc-macro/auxiliary/api/parse.rs index 6186b941ef69f..27391f8311176 100644 --- a/src/test/ui/proc-macro/auxiliary/api/parse.rs +++ b/src/test/ui/proc-macro/auxiliary/api/parse.rs @@ -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() { diff --git a/src/test/ui/proc-macro/quote-debug.stdout b/src/test/ui/proc-macro/quote-debug.stdout index ec54851fcf9d7..d2cc5c6e2a3f7 100644 --- a/src/test/ui/proc-macro/quote-debug.stdout +++ b/src/test/ui/proc-macro/quote-debug.stdout @@ -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::() } const _: () = diff --git a/src/test/ui/unsized/unsized-fn-param.stderr b/src/test/ui/unsized/unsized-fn-param.stderr index b498259efe700..3eecca0fa09d9 100644 --- a/src/test/ui/unsized/unsized-fn-param.stderr +++ b/src/test/ui/unsized/unsized-fn-param.stderr @@ -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` +help: consider borrowing the value, since `&str` can be coerced into `dyn AsRef` + | +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` +help: consider borrowing the value, since `&str` can be coerced into `dyn AsRef` + | +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` +help: consider borrowing the value, since `&str` can be coerced into `dyn AsRef` + | +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` +help: consider borrowing the value, since `&str` can be coerced into `dyn AsRef` + | +LL | foo22(&"bar", &"baz"); + | + error: aborting due to 4 previous errors