mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-15 05:26:47 +00:00
Auto merge of #99315 - JohnTitor:rollup-77wzoc1, r=JohnTitor
Rollup of 7 pull requests Successful merges: - #98387 (Add new unstable API `downcast` to `std::io::Error`) - #98662 (Add std::fs::write documentation precision) - #99253 (Remove FIXME from MIR `always_storage_live_locals`) - #99264 (Fix typo in mod.rs) - #99270 (Add `#[must_use]` to `Box::from_raw`) - #99277 (Stabilize `core::ffi::CStr`, `alloc::ffi::CString`, and friends) - #99307 (Add regression test for #64401) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
7210e46dc6
compiler/rustc_mir_dataflow/src
library
alloc
core/src/ffi
std/src
src/test/ui
@ -4,9 +4,6 @@ use rustc_middle::mir::{self, Local};
|
||||
/// The set of locals in a MIR body that do not have `StorageLive`/`StorageDead` annotations.
|
||||
///
|
||||
/// These locals have fixed storage for the duration of the body.
|
||||
//
|
||||
// FIXME: Currently, we need to traverse the entire MIR to compute this. We should instead store it
|
||||
// as a field in the `LocalDecl` for each `Local`.
|
||||
pub fn always_storage_live_locals(body: &mir::Body<'_>) -> BitSet<Local> {
|
||||
let mut always_live_locals = BitSet::new_filled(body.local_decls.len());
|
||||
|
||||
|
@ -949,6 +949,7 @@ impl<T: ?Sized> Box<T> {
|
||||
/// [`Layout`]: crate::Layout
|
||||
#[stable(feature = "box_raw", since = "1.4.0")]
|
||||
#[inline]
|
||||
#[must_use = "call `drop(from_raw(ptr))` if you intend to drop the `Box`"]
|
||||
pub unsafe fn from_raw(raw: *mut T) -> Self {
|
||||
unsafe { Self::from_raw_in(raw, Global) }
|
||||
}
|
||||
|
@ -108,7 +108,7 @@ use crate::sync::Arc;
|
||||
/// and other memory errors.
|
||||
#[derive(PartialEq, PartialOrd, Eq, Ord, Hash, Clone)]
|
||||
#[cfg_attr(not(test), rustc_diagnostic_item = "cstring_type")]
|
||||
#[unstable(feature = "alloc_c_string", issue = "94079")]
|
||||
#[stable(feature = "alloc_c_string", since = "1.64.0")]
|
||||
pub struct CString {
|
||||
// Invariant 1: the slice ends with a zero byte and has a length of at least one.
|
||||
// Invariant 2: the slice contains only one zero byte.
|
||||
@ -132,7 +132,7 @@ pub struct CString {
|
||||
/// let _: NulError = CString::new(b"f\0oo".to_vec()).unwrap_err();
|
||||
/// ```
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
#[unstable(feature = "alloc_c_string", issue = "94079")]
|
||||
#[stable(feature = "alloc_c_string", since = "1.64.0")]
|
||||
pub struct NulError(usize, Vec<u8>);
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
@ -157,7 +157,7 @@ enum FromBytesWithNulErrorKind {
|
||||
/// let _: FromVecWithNulError = CString::from_vec_with_nul(b"f\0oo".to_vec()).unwrap_err();
|
||||
/// ```
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
#[unstable(feature = "alloc_c_string", issue = "94079")]
|
||||
#[stable(feature = "alloc_c_string", since = "1.64.0")]
|
||||
pub struct FromVecWithNulError {
|
||||
error_kind: FromBytesWithNulErrorKind,
|
||||
bytes: Vec<u8>,
|
||||
@ -223,7 +223,7 @@ impl FromVecWithNulError {
|
||||
/// This `struct` is created by [`CString::into_string()`]. See
|
||||
/// its documentation for more.
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
#[unstable(feature = "alloc_c_string", issue = "94079")]
|
||||
#[stable(feature = "alloc_c_string", since = "1.64.0")]
|
||||
pub struct IntoStringError {
|
||||
inner: CString,
|
||||
error: Utf8Error,
|
||||
|
@ -78,11 +78,11 @@
|
||||
//! [`String`]: crate::string::String
|
||||
//! [`CStr`]: core::ffi::CStr
|
||||
|
||||
#![unstable(feature = "alloc_ffi", issue = "94079")]
|
||||
#![stable(feature = "alloc_ffi", since = "1.64.0")]
|
||||
|
||||
#[unstable(feature = "alloc_c_string", issue = "94079")]
|
||||
#[stable(feature = "alloc_c_string", since = "1.64.0")]
|
||||
pub use self::c_str::FromVecWithNulError;
|
||||
#[unstable(feature = "alloc_c_string", issue = "94079")]
|
||||
#[stable(feature = "alloc_c_string", since = "1.64.0")]
|
||||
pub use self::c_str::{CString, IntoStringError, NulError};
|
||||
|
||||
mod c_str;
|
||||
|
@ -86,7 +86,6 @@
|
||||
#![allow(explicit_outlives_requirements)]
|
||||
//
|
||||
// Library features:
|
||||
#![cfg_attr(not(no_global_oom_handling), feature(alloc_c_string))]
|
||||
#![feature(alloc_layout_extra)]
|
||||
#![feature(allocator_api)]
|
||||
#![feature(array_chunks)]
|
||||
@ -106,7 +105,6 @@
|
||||
#![feature(const_maybe_uninit_write)]
|
||||
#![feature(const_maybe_uninit_as_mut_ptr)]
|
||||
#![feature(const_refs_to_cell)]
|
||||
#![feature(core_c_str)]
|
||||
#![feature(core_intrinsics)]
|
||||
#![feature(const_eval_select)]
|
||||
#![feature(const_pin)]
|
||||
|
@ -11,7 +11,6 @@
|
||||
#![feature(const_nonnull_slice_from_raw_parts)]
|
||||
#![feature(const_ptr_write)]
|
||||
#![feature(const_try)]
|
||||
#![feature(core_c_str)]
|
||||
#![feature(core_intrinsics)]
|
||||
#![feature(drain_filter)]
|
||||
#![feature(exact_size_is_empty)]
|
||||
|
@ -76,7 +76,7 @@ use crate::str;
|
||||
/// [str]: prim@str "str"
|
||||
#[derive(Hash)]
|
||||
#[cfg_attr(not(test), rustc_diagnostic_item = "CStr")]
|
||||
#[unstable(feature = "core_c_str", issue = "94079")]
|
||||
#[stable(feature = "core_c_str", since = "1.64.0")]
|
||||
#[rustc_has_incoherent_inherent_impls]
|
||||
// FIXME:
|
||||
// `fn from` in `impl From<&CStr> for Box<CStr>` current implementation relies
|
||||
@ -108,7 +108,7 @@ pub struct CStr {
|
||||
/// let _: FromBytesWithNulError = CStr::from_bytes_with_nul(b"f\0oo").unwrap_err();
|
||||
/// ```
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
#[unstable(feature = "core_c_str", issue = "94079")]
|
||||
#[stable(feature = "core_c_str", since = "1.64.0")]
|
||||
pub struct FromBytesWithNulError {
|
||||
kind: FromBytesWithNulErrorKind,
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ use crate::marker::PhantomData;
|
||||
use crate::num::*;
|
||||
use crate::ops::{Deref, DerefMut};
|
||||
|
||||
#[unstable(feature = "core_c_str", issue = "94079")]
|
||||
#[stable(feature = "core_c_str", since = "1.64.0")]
|
||||
pub use self::c_str::{CStr, FromBytesUntilNulError, FromBytesWithNulError};
|
||||
|
||||
mod c_str;
|
||||
|
@ -146,24 +146,10 @@
|
||||
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
|
||||
/// See [alloc::ffi::FromVecWithNulError].
|
||||
#[stable(feature = "cstring_from_vec_with_nul", since = "1.58.0")]
|
||||
pub type FromVecWithNulError = alloc::ffi::FromVecWithNulError;
|
||||
/// See [alloc::ffi::CString].
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub type CString = alloc::ffi::CString;
|
||||
/// See [alloc::ffi::IntoStringError].
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub type IntoStringError = alloc::ffi::IntoStringError;
|
||||
/// See [alloc::ffi::NulError].
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub type NulError = alloc::ffi::NulError;
|
||||
/// See [core::ffi::CStr].
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub type CStr = core::ffi::CStr;
|
||||
/// See [core::ffi::FromBytesWithNulError].
|
||||
#[stable(feature = "cstr_from_bytes", since = "1.10.0")]
|
||||
pub type FromBytesWithNulError = core::ffi::FromBytesWithNulError;
|
||||
#[stable(feature = "alloc_c_string", since = "1.64.0")]
|
||||
pub use alloc::ffi::{CString, FromVecWithNulError, IntoStringError, NulError};
|
||||
#[stable(feature = "core_c_str", since = "1.64.0")]
|
||||
pub use core::ffi::{CStr, FromBytesWithNulError};
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub use self::os_str::{OsStr, OsString};
|
||||
|
@ -295,6 +295,9 @@ pub fn read_to_string<P: AsRef<Path>>(path: P) -> io::Result<String> {
|
||||
/// This function will create a file if it does not exist,
|
||||
/// and will entirely replace its contents if it does.
|
||||
///
|
||||
/// Depending on the platform, this function may fail if the
|
||||
/// full directory path does not exist.
|
||||
///
|
||||
/// This is a convenience function for using [`File::create`] and [`write_all`]
|
||||
/// with fewer imports.
|
||||
///
|
||||
@ -349,6 +352,9 @@ impl File {
|
||||
/// This function will create a file if it does not exist,
|
||||
/// and will truncate it if it does.
|
||||
///
|
||||
/// Depending on the platform, this function may fail if the
|
||||
/// full directory path does not exist.
|
||||
///
|
||||
/// See the [`OpenOptions::open`] function for more details.
|
||||
///
|
||||
/// # Examples
|
||||
|
@ -795,6 +795,68 @@ impl Error {
|
||||
}
|
||||
}
|
||||
|
||||
/// Attempt to downgrade the inner error to `E` if any.
|
||||
///
|
||||
/// If this [`Error`] was constructed via [`new`] then this function will
|
||||
/// attempt to perform downgrade on it, otherwise it will return [`Err`].
|
||||
///
|
||||
/// If downgrade succeeds, it will return [`Ok`], otherwise it will also
|
||||
/// return [`Err`].
|
||||
///
|
||||
/// [`new`]: Error::new
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(io_error_downcast)]
|
||||
///
|
||||
/// use std::fmt;
|
||||
/// use std::io;
|
||||
/// use std::error::Error;
|
||||
///
|
||||
/// #[derive(Debug)]
|
||||
/// enum E {
|
||||
/// Io(io::Error),
|
||||
/// SomeOtherVariant,
|
||||
/// }
|
||||
///
|
||||
/// impl fmt::Display for E {
|
||||
/// // ...
|
||||
/// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
/// # todo!()
|
||||
/// # }
|
||||
/// }
|
||||
/// impl Error for E {}
|
||||
///
|
||||
/// impl From<io::Error> for E {
|
||||
/// fn from(err: io::Error) -> E {
|
||||
/// err.downcast::<E>()
|
||||
/// .map(|b| *b)
|
||||
/// .unwrap_or_else(E::Io)
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
#[unstable(feature = "io_error_downcast", issue = "99262")]
|
||||
pub fn downcast<E>(self) -> result::Result<Box<E>, Self>
|
||||
where
|
||||
E: error::Error + Send + Sync + 'static,
|
||||
{
|
||||
match self.repr.into_data() {
|
||||
ErrorData::Custom(b) if b.error.is::<E>() => {
|
||||
let res = (*b).error.downcast::<E>();
|
||||
|
||||
// downcast is a really trivial and is marked as inline, so
|
||||
// it's likely be inlined here.
|
||||
//
|
||||
// And the compiler should be able to eliminate the branch
|
||||
// that produces `Err` here since b.error.is::<E>()
|
||||
// returns true.
|
||||
Ok(res.unwrap())
|
||||
}
|
||||
repr_data => Err(Self { repr: Repr::new(repr_data) }),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the corresponding [`ErrorKind`] for this error.
|
||||
///
|
||||
/// # Examples
|
||||
|
@ -132,6 +132,15 @@ unsafe impl Send for Repr {}
|
||||
unsafe impl Sync for Repr {}
|
||||
|
||||
impl Repr {
|
||||
pub(super) fn new(dat: ErrorData<Box<Custom>>) -> Self {
|
||||
match dat {
|
||||
ErrorData::Os(code) => Self::new_os(code),
|
||||
ErrorData::Simple(kind) => Self::new_simple(kind),
|
||||
ErrorData::SimpleMessage(simple_message) => Self::new_simple_message(simple_message),
|
||||
ErrorData::Custom(b) => Self::new_custom(b),
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn new_custom(b: Box<Custom>) -> Self {
|
||||
let p = Box::into_raw(b).cast::<u8>();
|
||||
// Should only be possible if an allocator handed out a pointer with
|
||||
|
@ -10,6 +10,10 @@ type Inner = ErrorData<Box<Custom>>;
|
||||
pub(super) struct Repr(Inner);
|
||||
|
||||
impl Repr {
|
||||
#[inline]
|
||||
pub(super) fn new(dat: ErrorData<Box<Custom>>) -> Self {
|
||||
Self(dat)
|
||||
}
|
||||
pub(super) fn new_custom(b: Box<Custom>) -> Self {
|
||||
Self(Inner::Custom(b))
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
use super::{const_io_error, Custom, Error, ErrorData, ErrorKind, Repr};
|
||||
use super::{const_io_error, Custom, Error, ErrorData, ErrorKind, Repr, SimpleMessage};
|
||||
use crate::assert_matches::assert_matches;
|
||||
use crate::error;
|
||||
use crate::fmt;
|
||||
@ -141,3 +141,54 @@ fn test_custom_error_packing() {
|
||||
}) if error.downcast_ref::<Bojji>().as_deref() == Some(&Bojji(true)),
|
||||
);
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct E;
|
||||
|
||||
impl fmt::Display for E {
|
||||
fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl error::Error for E {}
|
||||
|
||||
#[test]
|
||||
fn test_std_io_error_downcast() {
|
||||
// Case 1: custom error, downcast succeeds
|
||||
let io_error = Error::new(ErrorKind::Other, Bojji(true));
|
||||
let e: Box<Bojji> = io_error.downcast().unwrap();
|
||||
assert!(e.0);
|
||||
|
||||
// Case 2: custom error, downcast fails
|
||||
let io_error = Error::new(ErrorKind::Other, Bojji(true));
|
||||
let io_error = io_error.downcast::<E>().unwrap_err();
|
||||
|
||||
// ensures that the custom error is intact
|
||||
assert_eq!(ErrorKind::Other, io_error.kind());
|
||||
let e: Box<Bojji> = io_error.downcast().unwrap();
|
||||
assert!(e.0);
|
||||
|
||||
// Case 3: os error
|
||||
let errno = 20;
|
||||
let io_error = Error::from_raw_os_error(errno);
|
||||
let io_error = io_error.downcast::<E>().unwrap_err();
|
||||
|
||||
assert_eq!(errno, io_error.raw_os_error().unwrap());
|
||||
|
||||
// Case 4: simple
|
||||
let kind = ErrorKind::OutOfMemory;
|
||||
let io_error: Error = kind.into();
|
||||
let io_error = io_error.downcast::<E>().unwrap_err();
|
||||
|
||||
assert_eq!(kind, io_error.kind());
|
||||
|
||||
// Case 5: simple message
|
||||
const SIMPLE_MESSAGE: SimpleMessage =
|
||||
SimpleMessage { kind: ErrorKind::Other, message: "simple message error test" };
|
||||
let io_error = Error::from_static_message(&SIMPLE_MESSAGE);
|
||||
let io_error = io_error.downcast::<E>().unwrap_err();
|
||||
|
||||
assert_eq!(SIMPLE_MESSAGE.kind, io_error.kind());
|
||||
assert_eq!(SIMPLE_MESSAGE.message, &*format!("{io_error}"));
|
||||
}
|
||||
|
@ -264,7 +264,6 @@
|
||||
#![feature(atomic_mut_ptr)]
|
||||
#![feature(char_error_internals)]
|
||||
#![feature(char_internals)]
|
||||
#![feature(core_c_str)]
|
||||
#![feature(core_intrinsics)]
|
||||
#![feature(cstr_from_bytes_until_nul)]
|
||||
#![feature(cstr_internals)]
|
||||
@ -297,8 +296,6 @@
|
||||
//
|
||||
// Library features (alloc):
|
||||
#![feature(alloc_layout_extra)]
|
||||
#![feature(alloc_c_string)]
|
||||
#![feature(alloc_ffi)]
|
||||
#![feature(allocator_api)]
|
||||
#![feature(get_mut_unchecked)]
|
||||
#![feature(map_try_insert)]
|
||||
|
@ -1114,7 +1114,7 @@ impl Thread {
|
||||
// Used only internally to construct a thread object without spawning
|
||||
// Panics if the name contains nuls.
|
||||
pub(crate) fn new(name: Option<CString>) -> Thread {
|
||||
// We have to use `unsafe` here to constuct the `Parker` in-place,
|
||||
// We have to use `unsafe` here to construct the `Parker` in-place,
|
||||
// which is required for the UNIX implementation.
|
||||
//
|
||||
// SAFETY: We pin the Arc immediately after creation, so its address never
|
||||
|
51
src/test/ui/codegen/issue-64401.rs
Normal file
51
src/test/ui/codegen/issue-64401.rs
Normal file
@ -0,0 +1,51 @@
|
||||
// build-pass
|
||||
// The ICE didn't happen with `cargo check` but `cargo build`.
|
||||
|
||||
use std::marker::PhantomData;
|
||||
|
||||
trait Owned<'a> {
|
||||
type Reader;
|
||||
}
|
||||
|
||||
impl<'a> Owned<'a> for () {
|
||||
type Reader = ();
|
||||
}
|
||||
|
||||
trait Handler {
|
||||
fn handle(&self);
|
||||
}
|
||||
|
||||
struct CtxHandlerWithoutState<M, F> {
|
||||
message_type: PhantomData<M>,
|
||||
_function: F,
|
||||
}
|
||||
|
||||
impl<M, F> CtxHandlerWithoutState<M, F> {
|
||||
pub fn new(_function: F) -> Self {
|
||||
Self {
|
||||
message_type: PhantomData,
|
||||
_function,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, M, F> Handler for CtxHandlerWithoutState<M, F>
|
||||
where
|
||||
F: Fn(<M as Owned<'a>>::Reader),
|
||||
M: Owned<'a>,
|
||||
{
|
||||
fn handle(&self) {}
|
||||
}
|
||||
|
||||
fn e_to_i<M: for<'a> Owned<'a>>(_: <M as Owned<'_>>::Reader) {}
|
||||
|
||||
fn send_external_to_internal<M>()
|
||||
where
|
||||
M: for<'a> Owned<'a>,
|
||||
{
|
||||
let _: Box<dyn Handler> = Box::new(CtxHandlerWithoutState::<M, _>::new(e_to_i::<M>));
|
||||
}
|
||||
|
||||
fn main() {
|
||||
send_external_to_internal::<()>()
|
||||
}
|
11
src/test/ui/lint/unused/must-use-box-from-raw.rs
Normal file
11
src/test/ui/lint/unused/must-use-box-from-raw.rs
Normal file
@ -0,0 +1,11 @@
|
||||
// #99269
|
||||
|
||||
// check-pass
|
||||
|
||||
#![warn(unused_must_use)]
|
||||
|
||||
unsafe fn free<T>(ptr: *mut T) {
|
||||
Box::from_raw(ptr); //~ WARNING unused return value
|
||||
}
|
||||
|
||||
fn main() {}
|
15
src/test/ui/lint/unused/must-use-box-from-raw.stderr
Normal file
15
src/test/ui/lint/unused/must-use-box-from-raw.stderr
Normal file
@ -0,0 +1,15 @@
|
||||
warning: unused return value of `Box::<T>::from_raw` that must be used
|
||||
--> $DIR/must-use-box-from-raw.rs:8:5
|
||||
|
|
||||
LL | Box::from_raw(ptr);
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/must-use-box-from-raw.rs:5:9
|
||||
|
|
||||
LL | #![warn(unused_must_use)]
|
||||
| ^^^^^^^^^^^^^^^
|
||||
= note: call `drop(from_raw(ptr))` if you intend to drop the `Box`
|
||||
|
||||
warning: 1 warning emitted
|
||||
|
Loading…
Reference in New Issue
Block a user