Auto merge of #102632 - matthiaskrgr:rollup-h8s3zmo, r=matthiaskrgr
Rollup of 7 pull requests Successful merges: - #98218 (Document the conditional existence of `alloc::sync` and `alloc::task`.) - #99216 (docs: be less harsh in wording for Vec::from_raw_parts) - #99460 (docs: Improve AsRef / AsMut docs on blanket impls) - #100470 (Tweak `FpCategory` example order.) - #101040 (Fix `#[derive(Default)]` on a generic `#[default]` enum adding unnecessary `Default` bounds) - #101308 (introduce `{char, u8}::is_ascii_octdigit`) - #102486 (Add diagnostic struct for const eval error in `rustc_middle`) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
f83e0266cf
@ -16,6 +16,7 @@ pub fn expand_deriving_copy(
|
||||
let trait_def = TraitDef {
|
||||
span,
|
||||
path: path_std!(marker::Copy),
|
||||
skip_path_as_bound: false,
|
||||
additional_bounds: Vec::new(),
|
||||
generics: Bounds::empty(),
|
||||
supports_unions: true,
|
||||
|
@ -72,6 +72,7 @@ pub fn expand_deriving_clone(
|
||||
let trait_def = TraitDef {
|
||||
span,
|
||||
path: path_std!(clone::Clone),
|
||||
skip_path_as_bound: false,
|
||||
additional_bounds: bounds,
|
||||
generics: Bounds::empty(),
|
||||
supports_unions: true,
|
||||
|
@ -25,6 +25,7 @@ pub fn expand_deriving_eq(
|
||||
let trait_def = TraitDef {
|
||||
span,
|
||||
path: path_std!(cmp::Eq),
|
||||
skip_path_as_bound: false,
|
||||
additional_bounds: Vec::new(),
|
||||
generics: Bounds::empty(),
|
||||
supports_unions: true,
|
||||
|
@ -19,6 +19,7 @@ pub fn expand_deriving_ord(
|
||||
let trait_def = TraitDef {
|
||||
span,
|
||||
path: path_std!(cmp::Ord),
|
||||
skip_path_as_bound: false,
|
||||
additional_bounds: Vec::new(),
|
||||
generics: Bounds::empty(),
|
||||
supports_unions: false,
|
||||
|
@ -83,6 +83,7 @@ pub fn expand_deriving_partial_eq(
|
||||
let trait_def = TraitDef {
|
||||
span,
|
||||
path: path_std!(cmp::PartialEq),
|
||||
skip_path_as_bound: false,
|
||||
additional_bounds: Vec::new(),
|
||||
generics: Bounds::empty(),
|
||||
supports_unions: false,
|
||||
|
@ -37,6 +37,7 @@ pub fn expand_deriving_partial_ord(
|
||||
let trait_def = TraitDef {
|
||||
span,
|
||||
path: path_std!(cmp::PartialOrd),
|
||||
skip_path_as_bound: false,
|
||||
additional_bounds: vec![],
|
||||
generics: Bounds::empty(),
|
||||
supports_unions: false,
|
||||
|
@ -20,6 +20,7 @@ pub fn expand_deriving_debug(
|
||||
let trait_def = TraitDef {
|
||||
span,
|
||||
path: path_std!(fmt::Debug),
|
||||
skip_path_as_bound: false,
|
||||
additional_bounds: Vec::new(),
|
||||
generics: Bounds::empty(),
|
||||
supports_unions: false,
|
||||
|
@ -23,6 +23,7 @@ pub fn expand_deriving_rustc_decodable(
|
||||
let trait_def = TraitDef {
|
||||
span,
|
||||
path: Path::new_(vec![krate, sym::Decodable], vec![], PathKind::Global),
|
||||
skip_path_as_bound: false,
|
||||
additional_bounds: Vec::new(),
|
||||
generics: Bounds::empty(),
|
||||
supports_unions: false,
|
||||
|
@ -24,6 +24,7 @@ pub fn expand_deriving_default(
|
||||
let trait_def = TraitDef {
|
||||
span,
|
||||
path: Path::new(vec![kw::Default, sym::Default]),
|
||||
skip_path_as_bound: has_a_default_variant(item),
|
||||
additional_bounds: Vec::new(),
|
||||
generics: Bounds::empty(),
|
||||
supports_unions: false,
|
||||
@ -262,3 +263,22 @@ impl<'a, 'b> rustc_ast::visit::Visitor<'a> for DetectNonVariantDefaultAttr<'a, '
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn has_a_default_variant(item: &Annotatable) -> bool {
|
||||
struct HasDefaultAttrOnVariant {
|
||||
found: bool,
|
||||
}
|
||||
|
||||
impl<'ast> rustc_ast::visit::Visitor<'ast> for HasDefaultAttrOnVariant {
|
||||
fn visit_variant(&mut self, v: &'ast rustc_ast::Variant) {
|
||||
if v.attrs.iter().any(|attr| attr.has_name(kw::Default)) {
|
||||
self.found = true;
|
||||
}
|
||||
// no need to subrecurse.
|
||||
}
|
||||
}
|
||||
|
||||
let mut visitor = HasDefaultAttrOnVariant { found: false };
|
||||
item.visit_with(&mut visitor);
|
||||
visitor.found
|
||||
}
|
||||
|
@ -107,6 +107,7 @@ pub fn expand_deriving_rustc_encodable(
|
||||
let trait_def = TraitDef {
|
||||
span,
|
||||
path: Path::new_(vec![krate, sym::Encodable], vec![], PathKind::Global),
|
||||
skip_path_as_bound: false,
|
||||
additional_bounds: Vec::new(),
|
||||
generics: Bounds::empty(),
|
||||
supports_unions: false,
|
||||
|
@ -174,6 +174,7 @@ use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
||||
use rustc_span::Span;
|
||||
use std::cell::RefCell;
|
||||
use std::iter;
|
||||
use std::ops::Not;
|
||||
use std::vec;
|
||||
use thin_vec::thin_vec;
|
||||
use ty::{Bounds, Path, Ref, Self_, Ty};
|
||||
@ -187,6 +188,9 @@ pub struct TraitDef<'a> {
|
||||
/// Path of the trait, including any type parameters
|
||||
pub path: Path,
|
||||
|
||||
/// Whether to skip adding the current trait as a bound to the type parameters of the type.
|
||||
pub skip_path_as_bound: bool,
|
||||
|
||||
/// Additional bounds required of any type parameters of the type,
|
||||
/// other than the current trait
|
||||
pub additional_bounds: Vec<Ty>,
|
||||
@ -596,7 +600,7 @@ impl<'a> TraitDef<'a> {
|
||||
cx.trait_bound(p.to_path(cx, self.span, type_ident, generics))
|
||||
}).chain(
|
||||
// require the current trait
|
||||
iter::once(cx.trait_bound(trait_path.clone()))
|
||||
self.skip_path_as_bound.not().then(|| cx.trait_bound(trait_path.clone()))
|
||||
).chain(
|
||||
// also add in any bounds from the declaration
|
||||
param.bounds.iter().cloned()
|
||||
|
@ -22,6 +22,7 @@ pub fn expand_deriving_hash(
|
||||
let hash_trait_def = TraitDef {
|
||||
span,
|
||||
path,
|
||||
skip_path_as_bound: false,
|
||||
additional_bounds: Vec::new(),
|
||||
generics: Bounds::empty(),
|
||||
supports_unions: false,
|
||||
|
@ -15,3 +15,6 @@ middle_previous_use_here =
|
||||
middle_limit_invalid =
|
||||
`limit` must be a non-negative integer
|
||||
.label = {$error_str}
|
||||
|
||||
middle_const_eval_non_int =
|
||||
constant evaluation of enum discriminant resulted in non-integer
|
||||
|
@ -48,3 +48,10 @@ pub struct LimitInvalid<'a> {
|
||||
pub value_span: Span,
|
||||
pub error_str: &'a str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(middle::const_eval_non_int)]
|
||||
pub struct ConstEvalNonIntError {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
@ -458,11 +458,9 @@ impl<'tcx> AdtDef<'tcx> {
|
||||
Some(Discr { val: b, ty })
|
||||
} else {
|
||||
info!("invalid enum discriminant: {:#?}", val);
|
||||
crate::mir::interpret::struct_error(
|
||||
tcx.at(tcx.def_span(expr_did)),
|
||||
"constant evaluation of enum discriminant resulted in non-integer",
|
||||
)
|
||||
.emit();
|
||||
tcx.sess.emit_err(crate::error::ConstEvalNonIntError {
|
||||
span: tcx.def_span(expr_did),
|
||||
});
|
||||
None
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,10 @@
|
||||
//! Thread-safe reference-counting pointers.
|
||||
//!
|
||||
//! See the [`Arc<T>`][Arc] documentation for more details.
|
||||
//!
|
||||
//! **Note**: This module is only available on platforms that support atomic
|
||||
//! loads and stores of pointers. This may be detected at compile time using
|
||||
//! `#[cfg(target_has_atomic = "ptr")]`.
|
||||
|
||||
use core::any::Any;
|
||||
use core::borrow;
|
||||
@ -82,6 +86,11 @@ macro_rules! acquire {
|
||||
/// [`Mutex`][mutex], [`RwLock`][rwlock], or one of the [`Atomic`][atomic]
|
||||
/// types.
|
||||
///
|
||||
/// **Note**: This type is only available on platforms that support atomic
|
||||
/// loads and stores of pointers, which includes all platforms that support
|
||||
/// the `std` crate but not all those which only support [`alloc`](crate).
|
||||
/// This may be detected at compile time using `#[cfg(target_has_atomic = "ptr")]`.
|
||||
///
|
||||
/// ## Thread Safety
|
||||
///
|
||||
/// Unlike [`Rc<T>`], `Arc<T>` uses atomic operations for its reference
|
||||
|
@ -1,5 +1,11 @@
|
||||
#![stable(feature = "wake_trait", since = "1.51.0")]
|
||||
|
||||
//! Types and Traits for working with asynchronous tasks.
|
||||
//!
|
||||
//! **Note**: This module is only available on platforms that support atomic
|
||||
//! loads and stores of pointers. This may be detected at compile time using
|
||||
//! `#[cfg(target_has_atomic = "ptr")]`.
|
||||
|
||||
use core::mem::ManuallyDrop;
|
||||
use core::task::{RawWaker, RawWakerVTable, Waker};
|
||||
|
||||
|
@ -483,15 +483,13 @@ impl<T> Vec<T> {
|
||||
Self::with_capacity_in(capacity, Global)
|
||||
}
|
||||
|
||||
/// Creates a `Vec<T>` directly from the raw components of another vector.
|
||||
/// Creates a `Vec<T>` directly from a pointer, a capacity, and a length.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This is highly unsafe, due to the number of invariants that aren't
|
||||
/// checked:
|
||||
///
|
||||
/// * `ptr` needs to have been previously allocated via [`String`]/`Vec<T>`
|
||||
/// (at least, it's highly likely to be incorrect if it wasn't).
|
||||
/// * `T` needs to have the same alignment as what `ptr` was allocated with.
|
||||
/// (`T` having a less strict alignment is not sufficient, the alignment really
|
||||
/// needs to be equal to satisfy the [`dealloc`] requirement that memory must be
|
||||
@ -500,6 +498,14 @@ impl<T> Vec<T> {
|
||||
/// to be the same size as the pointer was allocated with. (Because similar to
|
||||
/// alignment, [`dealloc`] must be called with the same layout `size`.)
|
||||
/// * `length` needs to be less than or equal to `capacity`.
|
||||
/// * The first `length` values must be properly initialized values of type `T`.
|
||||
/// * `capacity` needs to be the capacity that the pointer was allocated with.
|
||||
/// * The allocated size in bytes must be no larger than `isize::MAX`.
|
||||
/// See the safety documentation of [`pointer::offset`].
|
||||
///
|
||||
/// These requirements are always upheld by any `ptr` that has been allocated
|
||||
/// via `Vec<T>`. Other allocation sources are allowed if the invariants are
|
||||
/// upheld.
|
||||
///
|
||||
/// Violating these may cause problems like corrupting the allocator's
|
||||
/// internal data structures. For example it is normally **not** safe
|
||||
@ -551,6 +557,32 @@ impl<T> Vec<T> {
|
||||
/// assert_eq!(rebuilt, [4, 5, 6]);
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// Using memory that was allocated elsewhere:
|
||||
///
|
||||
/// ```rust
|
||||
/// #![feature(allocator_api)]
|
||||
///
|
||||
/// use std::alloc::{AllocError, Allocator, Global, Layout};
|
||||
///
|
||||
/// fn main() {
|
||||
/// let layout = Layout::array::<u32>(16).expect("overflow cannot happen");
|
||||
///
|
||||
/// let vec = unsafe {
|
||||
/// let mem = match Global.allocate(layout) {
|
||||
/// Ok(mem) => mem.cast::<u32>().as_ptr(),
|
||||
/// Err(AllocError) => return,
|
||||
/// };
|
||||
///
|
||||
/// mem.write(1_000_000);
|
||||
///
|
||||
/// Vec::from_raw_parts_in(mem, 1, 16, Global)
|
||||
/// };
|
||||
///
|
||||
/// assert_eq!(vec, &[1_000_000]);
|
||||
/// assert_eq!(vec.capacity(), 16);
|
||||
/// }
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub unsafe fn from_raw_parts(ptr: *mut T, length: usize, capacity: usize) -> Self {
|
||||
@ -641,21 +673,30 @@ impl<T, A: Allocator> Vec<T, A> {
|
||||
Vec { buf: RawVec::with_capacity_in(capacity, alloc), len: 0 }
|
||||
}
|
||||
|
||||
/// Creates a `Vec<T, A>` directly from the raw components of another vector.
|
||||
/// Creates a `Vec<T, A>` directly from a pointer, a capacity, a length,
|
||||
/// and an allocator.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This is highly unsafe, due to the number of invariants that aren't
|
||||
/// checked:
|
||||
///
|
||||
/// * `ptr` needs to have been previously allocated via [`String`]/`Vec<T>`
|
||||
/// (at least, it's highly likely to be incorrect if it wasn't).
|
||||
/// * `T` needs to have the same size and alignment as what `ptr` was allocated with.
|
||||
/// * `T` needs to have the same alignment as what `ptr` was allocated with.
|
||||
/// (`T` having a less strict alignment is not sufficient, the alignment really
|
||||
/// needs to be equal to satisfy the [`dealloc`] requirement that memory must be
|
||||
/// allocated and deallocated with the same layout.)
|
||||
/// * The size of `T` times the `capacity` (ie. the allocated size in bytes) needs
|
||||
/// to be the same size as the pointer was allocated with. (Because similar to
|
||||
/// alignment, [`dealloc`] must be called with the same layout `size`.)
|
||||
/// * `length` needs to be less than or equal to `capacity`.
|
||||
/// * `capacity` needs to be the capacity that the pointer was allocated with.
|
||||
/// * The first `length` values must be properly initialized values of type `T`.
|
||||
/// * `capacity` needs to [*fit*] the layout size that the pointer was allocated with.
|
||||
/// * The allocated size in bytes must be no larger than `isize::MAX`.
|
||||
/// See the safety documentation of [`pointer::offset`].
|
||||
///
|
||||
/// These requirements are always upheld by any `ptr` that has been allocated
|
||||
/// via `Vec<T, A>`. Other allocation sources are allowed if the invariants are
|
||||
/// upheld.
|
||||
///
|
||||
/// Violating these may cause problems like corrupting the allocator's
|
||||
/// internal data structures. For example it is **not** safe
|
||||
@ -673,6 +714,7 @@ impl<T, A: Allocator> Vec<T, A> {
|
||||
///
|
||||
/// [`String`]: crate::string::String
|
||||
/// [`dealloc`]: crate::alloc::GlobalAlloc::dealloc
|
||||
/// [*fit*]: crate::alloc::Allocator#memory-fitting
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@ -711,6 +753,29 @@ impl<T, A: Allocator> Vec<T, A> {
|
||||
/// assert_eq!(rebuilt, [4, 5, 6]);
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// Using memory that was allocated elsewhere:
|
||||
///
|
||||
/// ```rust
|
||||
/// use std::alloc::{alloc, Layout};
|
||||
///
|
||||
/// fn main() {
|
||||
/// let layout = Layout::array::<u32>(16).expect("overflow cannot happen");
|
||||
/// let vec = unsafe {
|
||||
/// let mem = alloc(layout).cast::<u32>();
|
||||
/// if mem.is_null() {
|
||||
/// return;
|
||||
/// }
|
||||
///
|
||||
/// mem.write(1_000_000);
|
||||
///
|
||||
/// Vec::from_raw_parts(mem, 1, 16)
|
||||
/// };
|
||||
///
|
||||
/// assert_eq!(vec, &[1_000_000]);
|
||||
/// assert_eq!(vec.capacity(), 16);
|
||||
/// }
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "allocator_api", issue = "32838")]
|
||||
pub unsafe fn from_raw_parts_in(ptr: *mut T, length: usize, capacity: usize, alloc: A) -> Self {
|
||||
|
@ -1444,6 +1444,38 @@ impl char {
|
||||
matches!(*self, '0'..='9')
|
||||
}
|
||||
|
||||
/// Checks if the value is an ASCII octal digit:
|
||||
/// U+0030 '0' ..= U+0037 '7'.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(is_ascii_octdigit)]
|
||||
///
|
||||
/// let uppercase_a = 'A';
|
||||
/// let a = 'a';
|
||||
/// let zero = '0';
|
||||
/// let seven = '7';
|
||||
/// let nine = '9';
|
||||
/// let percent = '%';
|
||||
/// let lf = '\n';
|
||||
///
|
||||
/// assert!(!uppercase_a.is_ascii_octdigit());
|
||||
/// assert!(!a.is_ascii_octdigit());
|
||||
/// assert!(zero.is_ascii_octdigit());
|
||||
/// assert!(seven.is_ascii_octdigit());
|
||||
/// assert!(!nine.is_ascii_octdigit());
|
||||
/// assert!(!percent.is_ascii_octdigit());
|
||||
/// assert!(!lf.is_ascii_octdigit());
|
||||
/// ```
|
||||
#[must_use]
|
||||
#[unstable(feature = "is_ascii_octdigit", issue = "101288")]
|
||||
#[rustc_const_unstable(feature = "is_ascii_octdigit", issue = "101288")]
|
||||
#[inline]
|
||||
pub const fn is_ascii_octdigit(&self) -> bool {
|
||||
matches!(*self, '0'..='7')
|
||||
}
|
||||
|
||||
/// Checks if the value is an ASCII hexadecimal digit:
|
||||
///
|
||||
/// - U+0030 '0' ..= U+0039 '9', or
|
||||
|
@ -25,6 +25,7 @@
|
||||
//! # Generic Implementations
|
||||
//!
|
||||
//! - [`AsRef`] and [`AsMut`] auto-dereference if the inner type is a reference
|
||||
//! (but not generally for all [dereferenceable types][core::ops::Deref])
|
||||
//! - [`From`]`<U> for T` implies [`Into`]`<T> for U`
|
||||
//! - [`TryFrom`]`<U> for T` implies [`TryInto`]`<T> for U`
|
||||
//! - [`From`] and [`Into`] are reflexive, which means that all types can
|
||||
@ -109,10 +110,12 @@ pub const fn identity<T>(x: T) -> T {
|
||||
/// If you need to do a costly conversion it is better to implement [`From`] with type
|
||||
/// `&T` or write a custom function.
|
||||
///
|
||||
/// # Relation to `Borrow`
|
||||
///
|
||||
/// `AsRef` has the same signature as [`Borrow`], but [`Borrow`] is different in a few aspects:
|
||||
///
|
||||
/// - Unlike `AsRef`, [`Borrow`] has a blanket impl for any `T`, and can be used to accept either
|
||||
/// a reference or a value.
|
||||
/// a reference or a value. (See also note on `AsRef`'s reflexibility below.)
|
||||
/// - [`Borrow`] also requires that [`Hash`], [`Eq`] and [`Ord`] for a borrowed value are
|
||||
/// equivalent to those of the owned value. For this reason, if you want to
|
||||
/// borrow only a single field of a struct you can implement `AsRef`, but not [`Borrow`].
|
||||
@ -122,9 +125,66 @@ pub const fn identity<T>(x: T) -> T {
|
||||
///
|
||||
/// # Generic Implementations
|
||||
///
|
||||
/// - `AsRef` auto-dereferences if the inner type is a reference or a mutable
|
||||
/// reference (e.g.: `foo.as_ref()` will work the same if `foo` has type
|
||||
/// `&mut Foo` or `&&mut Foo`)
|
||||
/// `AsRef` auto-dereferences if the inner type is a reference or a mutable reference
|
||||
/// (e.g.: `foo.as_ref()` will work the same if `foo` has type `&mut Foo` or `&&mut Foo`).
|
||||
///
|
||||
/// Note that due to historic reasons, the above currently does not hold generally for all
|
||||
/// [dereferenceable types], e.g. `foo.as_ref()` will *not* work the same as
|
||||
/// `Box::new(foo).as_ref()`. Instead, many smart pointers provide an `as_ref` implementation which
|
||||
/// simply returns a reference to the [pointed-to value] (but do not perform a cheap
|
||||
/// reference-to-reference conversion for that value). However, [`AsRef::as_ref`] should not be
|
||||
/// used for the sole purpose of dereferencing; instead ['`Deref` coercion'] can be used:
|
||||
///
|
||||
/// [dereferenceable types]: core::ops::Deref
|
||||
/// [pointed-to value]: core::ops::Deref::Target
|
||||
/// ['`Deref` coercion']: core::ops::Deref#more-on-deref-coercion
|
||||
///
|
||||
/// ```
|
||||
/// let x = Box::new(5i32);
|
||||
/// // Avoid this:
|
||||
/// // let y: &i32 = x.as_ref();
|
||||
/// // Better just write:
|
||||
/// let y: &i32 = &x;
|
||||
/// ```
|
||||
///
|
||||
/// Types which implement [`Deref`] should consider implementing `AsRef<T>` as follows:
|
||||
///
|
||||
/// [`Deref`]: core::ops::Deref
|
||||
///
|
||||
/// ```
|
||||
/// # use core::ops::Deref;
|
||||
/// # struct SomeType;
|
||||
/// # impl Deref for SomeType {
|
||||
/// # type Target = [u8];
|
||||
/// # fn deref(&self) -> &[u8] {
|
||||
/// # &[]
|
||||
/// # }
|
||||
/// # }
|
||||
/// impl<T> AsRef<T> for SomeType
|
||||
/// where
|
||||
/// T: ?Sized,
|
||||
/// <SomeType as Deref>::Target: AsRef<T>,
|
||||
/// {
|
||||
/// fn as_ref(&self) -> &T {
|
||||
/// self.deref().as_ref()
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// # Reflexivity
|
||||
///
|
||||
/// Ideally, `AsRef` would be reflexive, i.e. there would be an `impl<T: ?Sized> AsRef<T> for T`
|
||||
/// with [`as_ref`] simply returning its argument unchanged.
|
||||
/// Such a blanket implementation is currently *not* provided due to technical restrictions of
|
||||
/// Rust's type system (it would be overlapping with another existing blanket implementation for
|
||||
/// `&T where T: AsRef<U>` which allows `AsRef` to auto-dereference, see "Generic Implementations"
|
||||
/// above).
|
||||
///
|
||||
/// [`as_ref`]: AsRef::as_ref
|
||||
///
|
||||
/// A trivial implementation of `AsRef<T> for T` must be added explicitly for a particular type `T`
|
||||
/// where needed or desired. Note, however, that not all types from `std` contain such an
|
||||
/// implementation, and those cannot be added by external code due to orphan rules.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@ -172,29 +232,138 @@ pub trait AsRef<T: ?Sized> {
|
||||
///
|
||||
/// # Generic Implementations
|
||||
///
|
||||
/// - `AsMut` auto-dereferences if the inner type is a mutable reference
|
||||
/// (e.g.: `foo.as_mut()` will work the same if `foo` has type `&mut Foo`
|
||||
/// or `&mut &mut Foo`)
|
||||
/// `AsMut` auto-dereferences if the inner type is a mutable reference
|
||||
/// (e.g.: `foo.as_mut()` will work the same if `foo` has type `&mut Foo` or `&mut &mut Foo`).
|
||||
///
|
||||
/// Note that due to historic reasons, the above currently does not hold generally for all
|
||||
/// [mutably dereferenceable types], e.g. `foo.as_mut()` will *not* work the same as
|
||||
/// `Box::new(foo).as_mut()`. Instead, many smart pointers provide an `as_mut` implementation which
|
||||
/// simply returns a reference to the [pointed-to value] (but do not perform a cheap
|
||||
/// reference-to-reference conversion for that value). However, [`AsMut::as_mut`] should not be
|
||||
/// used for the sole purpose of mutable dereferencing; instead ['`Deref` coercion'] can be used:
|
||||
///
|
||||
/// [mutably dereferenceable types]: core::ops::DerefMut
|
||||
/// [pointed-to value]: core::ops::Deref::Target
|
||||
/// ['`Deref` coercion']: core::ops::DerefMut#more-on-deref-coercion
|
||||
///
|
||||
/// ```
|
||||
/// let mut x = Box::new(5i32);
|
||||
/// // Avoid this:
|
||||
/// // let y: &mut i32 = x.as_mut();
|
||||
/// // Better just write:
|
||||
/// let y: &mut i32 = &mut x;
|
||||
/// ```
|
||||
///
|
||||
/// Types which implement [`DerefMut`] should consider to add an implementation of `AsMut<T>` as
|
||||
/// follows:
|
||||
///
|
||||
/// [`DerefMut`]: core::ops::DerefMut
|
||||
///
|
||||
/// ```
|
||||
/// # use core::ops::{Deref, DerefMut};
|
||||
/// # struct SomeType;
|
||||
/// # impl Deref for SomeType {
|
||||
/// # type Target = [u8];
|
||||
/// # fn deref(&self) -> &[u8] {
|
||||
/// # &[]
|
||||
/// # }
|
||||
/// # }
|
||||
/// # impl DerefMut for SomeType {
|
||||
/// # fn deref_mut(&mut self) -> &mut [u8] {
|
||||
/// # &mut []
|
||||
/// # }
|
||||
/// # }
|
||||
/// impl<T> AsMut<T> for SomeType
|
||||
/// where
|
||||
/// <SomeType as Deref>::Target: AsMut<T>,
|
||||
/// {
|
||||
/// fn as_mut(&mut self) -> &mut T {
|
||||
/// self.deref_mut().as_mut()
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// # Reflexivity
|
||||
///
|
||||
/// Ideally, `AsMut` would be reflexive, i.e. there would be an `impl<T: ?Sized> AsMut<T> for T`
|
||||
/// with [`as_mut`] simply returning its argument unchanged.
|
||||
/// Such a blanket implementation is currently *not* provided due to technical restrictions of
|
||||
/// Rust's type system (it would be overlapping with another existing blanket implementation for
|
||||
/// `&mut T where T: AsMut<U>` which allows `AsMut` to auto-dereference, see "Generic
|
||||
/// Implementations" above).
|
||||
///
|
||||
/// [`as_mut`]: AsMut::as_mut
|
||||
///
|
||||
/// A trivial implementation of `AsMut<T> for T` must be added explicitly for a particular type `T`
|
||||
/// where needed or desired. Note, however, that not all types from `std` contain such an
|
||||
/// implementation, and those cannot be added by external code due to orphan rules.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Using `AsMut` as trait bound for a generic function we can accept all mutable references
|
||||
/// that can be converted to type `&mut T`. Because [`Box<T>`] implements `AsMut<T>` we can
|
||||
/// write a function `add_one` that takes all arguments that can be converted to `&mut u64`.
|
||||
/// Because [`Box<T>`] implements `AsMut<T>`, `add_one` accepts arguments of type
|
||||
/// `&mut Box<u64>` as well:
|
||||
/// Using `AsMut` as trait bound for a generic function, we can accept all mutable references that
|
||||
/// can be converted to type `&mut T`. Unlike [dereference], which has a single [target type],
|
||||
/// there can be multiple implementations of `AsMut` for a type. In particular, `Vec<T>` implements
|
||||
/// both `AsMut<Vec<T>>` and `AsMut<[T]>`.
|
||||
///
|
||||
/// In the following, the example functions `caesar` and `null_terminate` provide a generic
|
||||
/// interface which work with any type that can be converted by cheap mutable-to-mutable conversion
|
||||
/// into a byte slice (`[u8]`) or byte vector (`Vec<u8>`), respectively.
|
||||
///
|
||||
/// [dereference]: core::ops::DerefMut
|
||||
/// [target type]: core::ops::Deref::Target
|
||||
///
|
||||
/// ```
|
||||
/// fn add_one<T: AsMut<u64>>(num: &mut T) {
|
||||
/// *num.as_mut() += 1;
|
||||
/// struct Document {
|
||||
/// info: String,
|
||||
/// content: Vec<u8>,
|
||||
/// }
|
||||
///
|
||||
/// let mut boxed_num = Box::new(0);
|
||||
/// add_one(&mut boxed_num);
|
||||
/// assert_eq!(*boxed_num, 1);
|
||||
/// impl<T: ?Sized> AsMut<T> for Document
|
||||
/// where
|
||||
/// Vec<u8>: AsMut<T>,
|
||||
/// {
|
||||
/// fn as_mut(&mut self) -> &mut T {
|
||||
/// self.content.as_mut()
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// fn caesar<T: AsMut<[u8]>>(data: &mut T, key: u8) {
|
||||
/// for byte in data.as_mut() {
|
||||
/// *byte = byte.wrapping_add(key);
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// fn null_terminate<T: AsMut<Vec<u8>>>(data: &mut T) {
|
||||
/// // Using a non-generic inner function, which contains most of the
|
||||
/// // functionality, helps to minimize monomorphization overhead.
|
||||
/// fn doit(data: &mut Vec<u8>) {
|
||||
/// let len = data.len();
|
||||
/// if len == 0 || data[len-1] != 0 {
|
||||
/// data.push(0);
|
||||
/// }
|
||||
/// }
|
||||
/// doit(data.as_mut());
|
||||
/// }
|
||||
///
|
||||
/// fn main() {
|
||||
/// let mut v: Vec<u8> = vec![1, 2, 3];
|
||||
/// caesar(&mut v, 5);
|
||||
/// assert_eq!(v, [6, 7, 8]);
|
||||
/// null_terminate(&mut v);
|
||||
/// assert_eq!(v, [6, 7, 8, 0]);
|
||||
/// let mut doc = Document {
|
||||
/// info: String::from("Example"),
|
||||
/// content: vec![17, 19, 8],
|
||||
/// };
|
||||
/// caesar(&mut doc, 1);
|
||||
/// assert_eq!(doc.content, [18, 20, 9]);
|
||||
/// null_terminate(&mut doc);
|
||||
/// assert_eq!(doc.content, [18, 20, 9, 0]);
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// [`Box<T>`]: ../../std/boxed/struct.Box.html
|
||||
/// Note, however, that APIs don't need to be generic. In many cases taking a `&mut [u8]` or
|
||||
/// `&mut Vec<u8>`, for example, is the better choice (callers need to pass the correct type then).
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[cfg_attr(not(test), rustc_diagnostic_item = "AsMut")]
|
||||
#[const_trait]
|
||||
|
@ -164,6 +164,7 @@
|
||||
#![feature(const_slice_index)]
|
||||
#![feature(const_is_char_boundary)]
|
||||
#![feature(const_cstr_methods)]
|
||||
#![feature(is_ascii_octdigit)]
|
||||
//
|
||||
// Language features:
|
||||
#![feature(abi_unadjusted)]
|
||||
|
@ -622,6 +622,38 @@ impl u8 {
|
||||
matches!(*self, b'0'..=b'9')
|
||||
}
|
||||
|
||||
/// Checks if the value is an ASCII octal digit:
|
||||
/// U+0030 '0' ..= U+0037 '7'.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(is_ascii_octdigit)]
|
||||
///
|
||||
/// let uppercase_a = b'A';
|
||||
/// let a = b'a';
|
||||
/// let zero = b'0';
|
||||
/// let seven = b'7';
|
||||
/// let nine = b'9';
|
||||
/// let percent = b'%';
|
||||
/// let lf = b'\n';
|
||||
///
|
||||
/// assert!(!uppercase_a.is_ascii_octdigit());
|
||||
/// assert!(!a.is_ascii_octdigit());
|
||||
/// assert!(zero.is_ascii_octdigit());
|
||||
/// assert!(seven.is_ascii_octdigit());
|
||||
/// assert!(!nine.is_ascii_octdigit());
|
||||
/// assert!(!percent.is_ascii_octdigit());
|
||||
/// assert!(!lf.is_ascii_octdigit());
|
||||
/// ```
|
||||
#[must_use]
|
||||
#[unstable(feature = "is_ascii_octdigit", issue = "101288")]
|
||||
#[rustc_const_unstable(feature = "is_ascii_octdigit", issue = "101288")]
|
||||
#[inline]
|
||||
pub const fn is_ascii_octdigit(&self) -> bool {
|
||||
matches!(*self, b'0'..=b'7')
|
||||
}
|
||||
|
||||
/// Checks if the value is an ASCII hexadecimal digit:
|
||||
///
|
||||
/// - U+0030 '0' ..= U+0039 '9', or
|
||||
@ -976,8 +1008,8 @@ impl usize {
|
||||
/// assert_eq!(num.classify(), FpCategory::Normal);
|
||||
/// assert_eq!(inf.classify(), FpCategory::Infinite);
|
||||
/// assert_eq!(zero.classify(), FpCategory::Zero);
|
||||
/// assert_eq!(nan.classify(), FpCategory::Nan);
|
||||
/// assert_eq!(sub.classify(), FpCategory::Subnormal);
|
||||
/// assert_eq!(nan.classify(), FpCategory::Nan);
|
||||
/// ```
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
@ -251,6 +251,23 @@ fn test_is_ascii_digit() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_is_ascii_octdigit() {
|
||||
assert_all!(is_ascii_octdigit, "", "01234567");
|
||||
assert_none!(
|
||||
is_ascii_octdigit,
|
||||
"abcdefghijklmnopqrstuvwxyz",
|
||||
"ABCDEFGHIJKLMNOQPRSTUVWXYZ",
|
||||
"!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~",
|
||||
" \t\n\x0c\r",
|
||||
"\x00\x01\x02\x03\x04\x05\x06\x07",
|
||||
"\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
|
||||
"\x10\x11\x12\x13\x14\x15\x16\x17",
|
||||
"\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
|
||||
"\x7f",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_is_ascii_hexdigit() {
|
||||
assert_all!(is_ascii_hexdigit, "", "0123456789", "abcdefABCDEF",);
|
||||
@ -454,6 +471,7 @@ fn ascii_ctype_const() {
|
||||
is_ascii_lowercase => [true, false, false, false, false];
|
||||
is_ascii_alphanumeric => [true, true, true, false, false];
|
||||
is_ascii_digit => [false, false, true, false, false];
|
||||
is_ascii_octdigit => [false, false, false, false, false];
|
||||
is_ascii_hexdigit => [true, true, true, false, false];
|
||||
is_ascii_punctuation => [false, false, false, true, false];
|
||||
is_ascii_graphic => [true, true, true, true, false];
|
||||
|
@ -100,6 +100,7 @@
|
||||
#![feature(slice_flatten)]
|
||||
#![feature(provide_any)]
|
||||
#![feature(utf8_chunks)]
|
||||
#![feature(is_ascii_octdigit)]
|
||||
#![deny(unsafe_op_in_unsafe_fn)]
|
||||
|
||||
extern crate test;
|
||||
|
@ -12,6 +12,16 @@ enum Foo {
|
||||
Beta(NotDefault),
|
||||
}
|
||||
|
||||
// #[default] on a generic enum does not add `Default` bounds to the type params.
|
||||
#[derive(Default)]
|
||||
enum MyOption<T> {
|
||||
#[default]
|
||||
None,
|
||||
#[allow(dead_code)]
|
||||
Some(T),
|
||||
}
|
||||
|
||||
fn main() {
|
||||
assert_eq!(Foo::default(), Foo::Alpha);
|
||||
assert!(matches!(MyOption::<NotDefault>::default(), MyOption::None));
|
||||
}
|
||||
|
@ -116,3 +116,24 @@ fn main() {
|
||||
|
||||
trace_macros!(invalid); //~ ERROR
|
||||
}
|
||||
|
||||
/// Check that `#[derive(Default)]` does use a `T : Default` bound when the
|
||||
/// `#[default]` variant is `#[non_exhaustive]` (should this end up allowed).
|
||||
const _: () = {
|
||||
#[derive(Default)]
|
||||
enum NonExhaustiveDefaultGeneric<T> {
|
||||
#[default]
|
||||
#[non_exhaustive]
|
||||
Foo, //~ ERROR default variant must be exhaustive
|
||||
Bar(T),
|
||||
}
|
||||
|
||||
fn assert_impls_default<T: Default>() {}
|
||||
|
||||
enum NotDefault {}
|
||||
|
||||
// Note: the `derive(Default)` currently bails early enough for trait-checking
|
||||
// not to happen. Should it bail late enough, or even pass, make sure to
|
||||
// assert that the following line fails.
|
||||
let _ = assert_impls_default::<NonExhaustiveDefaultGeneric<NotDefault>>;
|
||||
};
|
||||
|
@ -215,11 +215,21 @@ error: trace_macros! accepts only `true` or `false`
|
||||
LL | trace_macros!(invalid);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: default variant must be exhaustive
|
||||
--> $DIR/macros-nonfatal-errors.rs:127:9
|
||||
|
|
||||
LL | #[non_exhaustive]
|
||||
| ----------------- declared `#[non_exhaustive]` here
|
||||
LL | Foo,
|
||||
| ^^^
|
||||
|
|
||||
= help: consider a manual implementation of `Default`
|
||||
|
||||
error: cannot find macro `llvm_asm` in this scope
|
||||
--> $DIR/macros-nonfatal-errors.rs:99:5
|
||||
|
|
||||
LL | llvm_asm!(invalid);
|
||||
| ^^^^^^^^
|
||||
|
||||
error: aborting due to 27 previous errors
|
||||
error: aborting due to 28 previous errors
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user