- name: dist-x86_64-apple
env:
SCRIPT: "./x.py dist"
- RUST_CONFIGURE_ARGS: "--host=x86_64-apple-darwin --target=aarch64-apple-ios,x86_64-apple-ios --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false"
- RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
- MACOSX_DEPLOYMENT_TARGET: 10.7
- NO_LLVM_ASSERTIONS: 1
- NO_DEBUG_ASSERTIONS: 1
- DIST_REQUIRE_ALL_TOOLS: 1
- os: macos-latest
- - name: dist-x86_64-apple-alt
- env:
- SCRIPT: "./x.py dist"
- RUST_CONFIGURE_ARGS: "--enable-extended --enable-profiler --set rust.jemalloc --set llvm.ninja=false"
- RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
- MACOSX_DEPLOYMENT_TARGET: 10.7
- NO_LLVM_ASSERTIONS: 1
- NO_DEBUG_ASSERTIONS: 1
- os: macos-latest
- - name: x86_64-apple
- env:
- SCRIPT: "./x.py --stage 2 test"
- RUST_CONFIGURE_ARGS: "--build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false"
- RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
- MACOSX_DEPLOYMENT_TARGET: 10.8
- MACOSX_STD_DEPLOYMENT_TARGET: 10.7
- NO_LLVM_ASSERTIONS: 1
- NO_DEBUG_ASSERTIONS: 1
- os: macos-latest
- - name: dist-x86_64-apple
- env:
- SCRIPT: "./x.py dist"
- RUST_CONFIGURE_ARGS: "--host=x86_64-apple-darwin --target=aarch64-apple-ios,x86_64-apple-ios --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false"
+ RUST_CONFIGURE_ARGS: "--host=x86_64-apple-darwin --target=x86_64-apple-darwin,aarch64-apple-ios,x86_64-apple-ios --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false"
RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
MACOSX_DEPLOYMENT_TARGET: 10.7
NO_LLVM_ASSERTIONS: 1
os: windows-latest-xl
- name: dist-i686-msvc
env:
- RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-msvc --host=i686-pc-windows-msvc --target=i586-pc-windows-msvc --enable-full-tools --enable-profiler"
+ RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-msvc --host=i686-pc-windows-msvc --target=i686-pc-windows-msvc,i586-pc-windows-msvc --enable-full-tools --enable-profiler"
SCRIPT: python x.py dist
DIST_REQUIRE_ALL_TOOLS: 1
os: windows-latest-xl
[[package]]
name = "cc"
-version = "1.0.58"
+version = "1.0.60"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f9a06fb2e53271d7c279ec1efea6ab691c35a2ae67ec0d91d7acec0caf13b518"
+checksum = "ef611cc68ff783f18535d77ddd080185275713d852c4f5cbb6122c462a7a825c"
dependencies = [
"jobserver",
]
[[package]]
name = "libz-sys"
-version = "1.0.27"
+version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6ca8894883d250240341478bf987467332fbdd5da5c42426c69a8f93dbc302f2"
+checksum = "602113192b08db8f38796c4e85c39e960c145965140e918018bcde1952429655"
dependencies = [
"cc",
"libc",
name = "rustc_infer"
version = "0.0.0"
dependencies = [
+ "arrayvec",
"rustc_ast",
"rustc_data_structures",
"rustc_errors",
name = "rustc_middle"
version = "0.0.0"
dependencies = [
+ "arrayvec",
"bitflags",
"chalk-ir",
"measureme",
2. Clone the [source] with `git`:
```sh
- $ git clone https://github.com/rust-lang/rust.git
- $ cd rust
+ git clone https://github.com/rust-lang/rust.git
+ cd rust
```
[source]: https://github.com/rust-lang/rust
Copy the default `config.toml.example` to `config.toml` to get started.
```sh
- $ cp config.toml.example config.toml
+ cp config.toml.example config.toml
```
If you plan to use `x.py install` to create an installation, it is recommended
4. Build and install:
```sh
- $ ./x.py build && ./x.py install
+ ./x.py build && ./x.py install
```
When complete, `./x.py install` will place several programs into
```sh
# Update package mirrors (may be needed if you have a fresh install of MSYS2)
- $ pacman -Sy pacman-mirrors
+ pacman -Sy pacman-mirrors
# Install build tools needed for Rust. If you're building a 32-bit compiler,
# then replace "x86_64" below with "i686". If you've already got git, python,
# that it is important that you do **not** use the 'python2', 'cmake' and 'ninja'
# packages from the 'msys2' subsystem. The build has historically been known
# to fail with these packages.
- $ pacman -S git \
+ pacman -S git \
make \
diffutils \
tar \
4. Navigate to Rust's source code (or clone it), then build it:
```sh
- $ ./x.py build && ./x.py install
+ ./x.py build && ./x.py install
```
#### MSVC
shell with:
```sh
-> python x.py build
+python x.py build
```
Currently, building Rust only works with some known versions of Visual Studio. If
by manually calling the appropriate vcvars file before running the bootstrap.
```batch
-> CALL "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat"
-> python x.py build
+CALL "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat"
+python x.py build
```
#### Specifying an ABI
configure script and makefile (the latter of which just invokes `x.py`).
```sh
-$ ./configure
-$ make && sudo make install
+./configure
+make && sudo make install
```
When using the configure script, the generated `config.mk` file may override the
If you’d like to build the documentation, it’s almost the same:
```sh
-$ ./x.py doc
+./x.py doc
```
The generated documentation will appear under `doc` in the `build` directory for
html_root_url = "https://doc.rust-lang.org/nightly/",
test(no_crate_inject, attr(deny(warnings)))
)]
-#![feature(core_intrinsics)]
#![feature(dropck_eyepatch)]
-#![feature(raw_vec_internals)]
+#![feature(new_uninit)]
+#![feature(maybe_uninit_slice)]
#![cfg_attr(test, feature(test))]
#![allow(deprecated)]
-extern crate alloc;
-
use rustc_data_structures::cold_path;
use smallvec::SmallVec;
use std::alloc::Layout;
use std::cell::{Cell, RefCell};
use std::cmp;
-use std::intrinsics;
use std::marker::{PhantomData, Send};
-use std::mem;
+use std::mem::{self, MaybeUninit};
use std::ptr;
use std::slice;
-use alloc::raw_vec::RawVec;
-
/// An arena that can hold objects of only one type.
pub struct TypedArena<T> {
/// A pointer to the next object to be allocated.
struct TypedArenaChunk<T> {
/// The raw storage for the arena chunk.
- storage: RawVec<T>,
+ storage: Box<[MaybeUninit<T>]>,
/// The number of valid entries in the chunk.
entries: usize,
}
impl<T> TypedArenaChunk<T> {
#[inline]
unsafe fn new(capacity: usize) -> TypedArenaChunk<T> {
- TypedArenaChunk { storage: RawVec::with_capacity(capacity), entries: 0 }
+ TypedArenaChunk { storage: Box::new_uninit_slice(capacity), entries: 0 }
}
/// Destroys this arena chunk.
// The branch on needs_drop() is an -O1 performance optimization.
// Without the branch, dropping TypedArena<u8> takes linear time.
if mem::needs_drop::<T>() {
- let mut start = self.start();
- // Destroy all allocated objects.
- for _ in 0..len {
- ptr::drop_in_place(start);
- start = start.offset(1);
- }
+ ptr::drop_in_place(MaybeUninit::slice_assume_init_mut(&mut self.storage[..len]));
}
}
// Returns a pointer to the first allocated object.
#[inline]
- fn start(&self) -> *mut T {
- self.storage.ptr()
+ fn start(&mut self) -> *mut T {
+ MaybeUninit::slice_as_mut_ptr(&mut self.storage)
}
// Returns a pointer to the end of the allocated space.
#[inline]
- fn end(&self) -> *mut T {
+ fn end(&mut self) -> *mut T {
unsafe {
if mem::size_of::<T>() == 0 {
// A pointer as large as possible for zero-sized elements.
!0 as *mut T
} else {
- self.start().add(self.storage.capacity())
+ self.start().add(self.storage.len())
}
}
}
unsafe {
if mem::size_of::<T>() == 0 {
- self.ptr.set(intrinsics::arith_offset(self.ptr.get() as *mut u8, 1) as *mut T);
+ self.ptr.set((self.ptr.get() as *mut u8).wrapping_offset(1) as *mut T);
let ptr = mem::align_of::<T>() as *mut T;
// Don't drop the object. This `write` is equivalent to `forget`.
ptr::write(ptr, object);
let used_bytes = self.ptr.get() as usize - last_chunk.start() as usize;
last_chunk.entries = used_bytes / mem::size_of::<T>();
- // If the previous chunk's capacity is less than HUGE_PAGE
+ // If the previous chunk's len is less than HUGE_PAGE
// bytes, then this chunk will be least double the previous
// chunk's size.
- new_cap = last_chunk.storage.capacity();
+ new_cap = last_chunk.storage.len();
if new_cap < HUGE_PAGE / elem_size {
new_cap = new_cap.checked_mul(2).unwrap();
}
// Also ensure that this chunk can fit `additional`.
new_cap = cmp::max(additional, new_cap);
- let chunk = TypedArenaChunk::<T>::new(new_cap);
+ let mut chunk = TypedArenaChunk::<T>::new(new_cap);
self.ptr.set(chunk.start());
self.end.set(chunk.end());
chunks.push(chunk);
chunk.destroy(chunk.entries);
}
}
- // RawVec handles deallocation of `last_chunk` and `self.chunks`.
+ // Box handles deallocation of `last_chunk` and `self.chunks`.
}
}
}
// There is no need to update `last_chunk.entries` because that
// field isn't used by `DroplessArena`.
- // If the previous chunk's capacity is less than HUGE_PAGE
+ // If the previous chunk's len is less than HUGE_PAGE
// bytes, then this chunk will be least double the previous
// chunk's size.
- new_cap = last_chunk.storage.capacity();
+ new_cap = last_chunk.storage.len();
if new_cap < HUGE_PAGE {
new_cap = new_cap.checked_mul(2).unwrap();
}
// Also ensure that this chunk can fit `additional`.
new_cap = cmp::max(additional, new_cap);
- let chunk = TypedArenaChunk::<u8>::new(new_cap);
+ let mut chunk = TypedArenaChunk::<u8>::new(new_cap);
self.ptr.set(chunk.start());
self.end.set(chunk.end());
chunks.push(chunk);
})
}
+#[bench]
+pub fn bench_typed_arena_clear_100(b: &mut Bencher) {
+ let mut arena = TypedArena::default();
+ b.iter(|| {
+ for _ in 0..100 {
+ arena.alloc(Point { x: 1, y: 2, z: 3 });
+ }
+ arena.clear();
+ })
+}
+
// Drop tests
struct DropCounter<'a> {
impl TyKind {
pub fn is_implicit_self(&self) -> bool {
- if let TyKind::ImplicitSelf = *self { true } else { false }
+ matches!(self, TyKind::ImplicitSelf)
}
pub fn is_unit(&self) -> bool {
impl Async {
pub fn is_async(self) -> bool {
- if let Async::Yes { .. } = self { true } else { false }
+ matches!(self, Async::Yes { .. })
}
/// In this case this is an `async` return, the `NodeId` for the generated `impl Trait` item.
impl VisibilityKind {
pub fn is_pub(&self) -> bool {
- if let VisibilityKind::Public = *self { true } else { false }
+ matches!(self, VisibilityKind::Public)
}
}
//! This API is completely unstable and subject to change.
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/", test(attr(deny(warnings))))]
-#![feature(bool_to_option)]
#![feature(box_syntax)]
#![feature(const_fn)] // For the `transmute` in `P::new`
#![feature(const_panic)]
-#![feature(const_fn_transmute)]
#![feature(crate_visibility_modifier)]
#![feature(label_break_value)]
#![feature(nll)]
#![feature(or_patterns)]
-#![feature(try_trait)]
-#![feature(unicode_internals)]
#![recursion_limit = "256"]
#[macro_use]
impl ItemLowerer<'_, '_, '_> {
fn with_trait_impl_ref(&mut self, impl_ref: &Option<TraitRef>, f: impl FnOnce(&mut Self)) {
let old = self.lctx.is_in_trait_impl;
- self.lctx.is_in_trait_impl = if let &None = impl_ref { false } else { true };
+ self.lctx.is_in_trait_impl = impl_ref.is_some();
f(self);
self.lctx.is_in_trait_impl = old;
}
.emit();
}
- if !bounds
- .iter()
- .any(|b| if let GenericBound::Trait(..) = *b { true } else { false })
- {
+ if !bounds.iter().any(|b| matches!(b, GenericBound::Trait(..))) {
self.err_handler().span_err(ty.span, "at least one trait must be specified");
}
impl StabilityLevel {
pub fn is_unstable(&self) -> bool {
- if let StabilityLevel::Unstable { .. } = *self { true } else { false }
+ matches!(self, StabilityLevel::Unstable { .. })
}
pub fn is_stable(&self) -> bool {
- if let StabilityLevel::Stable { .. } = *self { true } else { false }
+ matches!(self, StabilityLevel::Stable { .. })
}
}
}
}
- let is_tuple = if let ast::VariantData::Tuple(..) = struct_def { true } else { false };
+ let is_tuple = matches!(struct_def, ast::VariantData::Tuple(..));
match (just_spans.is_empty(), named_idents.is_empty()) {
(false, false) => cx.span_bug(
self.span,
use rustc_hir::Node;
use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
use rustc_middle::mir::interpret::{
- read_target_uint, Allocation, ConstValue, ErrorHandled, GlobalAlloc, Pointer,
+ read_target_uint, Allocation, ErrorHandled, GlobalAlloc, Pointer,
};
use rustc_middle::mir::mono::MonoItem;
use rustc_middle::ty::{self, Instance, Ty};
cx: &CodegenCx<'ll, 'tcx>,
def_id: DefId,
) -> Result<(&'ll Value, &'tcx Allocation), ErrorHandled> {
- let alloc = match cx.tcx.const_eval_poly(def_id)? {
- ConstValue::ByRef { alloc, offset } if offset.bytes() == 0 => alloc,
- val => bug!("static const eval returned {:#?}", val),
- };
+ let alloc = cx.tcx.eval_static_initializer(def_id)?;
Ok((const_alloc_to_llvm(cx, alloc), alloc))
}
use crate::va_arg::emit_va_arg;
use crate::value::Value;
-use rustc_ast as ast;
use rustc_codegen_ssa::base::{compare_simd_types, wants_msvc_seh};
use rustc_codegen_ssa::common::span_invalid_monomorphization_error;
use rustc_codegen_ssa::common::{IntPredicate, TypeKind};
-use rustc_codegen_ssa::glue;
-use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue};
+use rustc_codegen_ssa::mir::operand::OperandRef;
use rustc_codegen_ssa::mir::place::PlaceRef;
use rustc_codegen_ssa::traits::*;
-use rustc_codegen_ssa::MemFlags;
use rustc_hir as hir;
use rustc_middle::ty::layout::{FnAbiExt, HasTyCtxt};
use rustc_middle::ty::{self, Ty};
sym::nearbyintf64 => "llvm.nearbyint.f64",
sym::roundf32 => "llvm.round.f32",
sym::roundf64 => "llvm.round.f64",
- sym::assume => "llvm.assume",
- sym::abort => "llvm.trap",
_ => return None,
};
Some(cx.get_intrinsic(&llvm_name))
&args.iter().map(|arg| arg.immediate()).collect::<Vec<_>>(),
None,
),
- sym::unreachable => {
- return;
- }
sym::likely => {
let expect = self.get_intrinsic(&("llvm.expect.i1"));
self.call(expect, &[args[0].immediate(), self.const_bool(true)], None)
let llfn = self.get_intrinsic(&("llvm.debugtrap"));
self.call(llfn, &[], None)
}
- sym::va_start => self.va_start(args[0].immediate()),
- sym::va_end => self.va_end(args[0].immediate()),
sym::va_copy => {
let intrinsic = self.cx().get_intrinsic(&("llvm.va_copy"));
self.call(intrinsic, &[args[0].immediate(), args[1].immediate()], None)
_ => bug!("the va_arg intrinsic does not work with non-scalar types"),
}
}
- sym::size_of_val => {
- let tp_ty = substs.type_at(0);
- if let OperandValue::Pair(_, meta) = args[0].val {
- let (llsize, _) = glue::size_and_align_of_dst(self, tp_ty, Some(meta));
- llsize
- } else {
- self.const_usize(self.size_of(tp_ty).bytes())
- }
- }
- sym::min_align_of_val => {
- let tp_ty = substs.type_at(0);
- if let OperandValue::Pair(_, meta) = args[0].val {
- let (_, llalign) = glue::size_and_align_of_dst(self, tp_ty, Some(meta));
- llalign
- } else {
- self.const_usize(self.align_of(tp_ty).bytes())
- }
- }
- sym::size_of
- | sym::pref_align_of
- | sym::min_align_of
- | sym::needs_drop
- | sym::type_id
- | sym::type_name
- | sym::variant_count => {
- let value = self
- .tcx
- .const_eval_instance(ty::ParamEnv::reveal_all(), instance, None)
- .unwrap();
- OperandRef::from_const(self, value, ret_ty).immediate_or_packed_pair(self)
- }
- // Effectively no-op
- sym::forget => {
- return;
- }
- sym::offset => {
- let ptr = args[0].immediate();
- let offset = args[1].immediate();
- self.inbounds_gep(ptr, &[offset])
- }
- sym::arith_offset => {
- let ptr = args[0].immediate();
- let offset = args[1].immediate();
- self.gep(ptr, &[offset])
- }
-
- sym::copy_nonoverlapping => {
- copy_intrinsic(
- self,
- false,
- false,
- substs.type_at(0),
- args[1].immediate(),
- args[0].immediate(),
- args[2].immediate(),
- );
- return;
- }
- sym::copy => {
- copy_intrinsic(
- self,
- true,
- false,
- substs.type_at(0),
- args[1].immediate(),
- args[0].immediate(),
- args[2].immediate(),
- );
- return;
- }
- sym::write_bytes => {
- memset_intrinsic(
- self,
- false,
- substs.type_at(0),
- args[0].immediate(),
- args[1].immediate(),
- args[2].immediate(),
- );
- return;
- }
- sym::volatile_copy_nonoverlapping_memory => {
- copy_intrinsic(
- self,
- false,
- true,
- substs.type_at(0),
- args[0].immediate(),
- args[1].immediate(),
- args[2].immediate(),
- );
- return;
- }
- sym::volatile_copy_memory => {
- copy_intrinsic(
- self,
- true,
- true,
- substs.type_at(0),
- args[0].immediate(),
- args[1].immediate(),
- args[2].immediate(),
- );
- return;
- }
- sym::volatile_set_memory => {
- memset_intrinsic(
- self,
- true,
- substs.type_at(0),
- args[0].immediate(),
- args[1].immediate(),
- args[2].immediate(),
- );
- return;
- }
sym::volatile_load | sym::unaligned_volatile_load => {
let tp_ty = substs.type_at(0);
let mut ptr = args[0].immediate();
| sym::ctpop
| sym::bswap
| sym::bitreverse
- | sym::add_with_overflow
- | sym::sub_with_overflow
- | sym::mul_with_overflow
- | sym::wrapping_add
- | sym::wrapping_sub
- | sym::wrapping_mul
- | sym::unchecked_div
- | sym::unchecked_rem
- | sym::unchecked_shl
- | sym::unchecked_shr
- | sym::unchecked_add
- | sym::unchecked_sub
- | sym::unchecked_mul
- | sym::exact_div
| sym::rotate_left
| sym::rotate_right
| sym::saturating_add
&[args[0].immediate()],
None,
),
- sym::add_with_overflow
- | sym::sub_with_overflow
- | sym::mul_with_overflow => {
- let intrinsic = format!(
- "llvm.{}{}.with.overflow.i{}",
- if signed { 's' } else { 'u' },
- &name_str[..3],
- width
- );
- let llfn = self.get_intrinsic(&intrinsic);
-
- // Convert `i1` to a `bool`, and write it to the out parameter
- let pair =
- self.call(llfn, &[args[0].immediate(), args[1].immediate()], None);
- let val = self.extract_value(pair, 0);
- let overflow = self.extract_value(pair, 1);
- let overflow = self.zext(overflow, self.type_bool());
-
- let dest = result.project_field(self, 0);
- self.store(val, dest.llval, dest.align);
- let dest = result.project_field(self, 1);
- self.store(overflow, dest.llval, dest.align);
-
- return;
- }
- sym::wrapping_add => self.add(args[0].immediate(), args[1].immediate()),
- sym::wrapping_sub => self.sub(args[0].immediate(), args[1].immediate()),
- sym::wrapping_mul => self.mul(args[0].immediate(), args[1].immediate()),
- sym::exact_div => {
- if signed {
- self.exactsdiv(args[0].immediate(), args[1].immediate())
- } else {
- self.exactudiv(args[0].immediate(), args[1].immediate())
- }
- }
- sym::unchecked_div => {
- if signed {
- self.sdiv(args[0].immediate(), args[1].immediate())
- } else {
- self.udiv(args[0].immediate(), args[1].immediate())
- }
- }
- sym::unchecked_rem => {
- if signed {
- self.srem(args[0].immediate(), args[1].immediate())
- } else {
- self.urem(args[0].immediate(), args[1].immediate())
- }
- }
- sym::unchecked_shl => self.shl(args[0].immediate(), args[1].immediate()),
- sym::unchecked_shr => {
- if signed {
- self.ashr(args[0].immediate(), args[1].immediate())
- } else {
- self.lshr(args[0].immediate(), args[1].immediate())
- }
- }
- sym::unchecked_add => {
- if signed {
- self.unchecked_sadd(args[0].immediate(), args[1].immediate())
- } else {
- self.unchecked_uadd(args[0].immediate(), args[1].immediate())
- }
- }
- sym::unchecked_sub => {
- if signed {
- self.unchecked_ssub(args[0].immediate(), args[1].immediate())
- } else {
- self.unchecked_usub(args[0].immediate(), args[1].immediate())
- }
- }
- sym::unchecked_mul => {
- if signed {
- self.unchecked_smul(args[0].immediate(), args[1].immediate())
- } else {
- self.unchecked_umul(args[0].immediate(), args[1].immediate())
- }
- }
sym::rotate_left | sym::rotate_right => {
let is_left = name == sym::rotate_left;
let val = args[0].immediate();
}
}
}
- sym::fadd_fast | sym::fsub_fast | sym::fmul_fast | sym::fdiv_fast | sym::frem_fast => {
- match float_type_width(arg_tys[0]) {
- Some(_width) => match name {
- sym::fadd_fast => self.fadd_fast(args[0].immediate(), args[1].immediate()),
- sym::fsub_fast => self.fsub_fast(args[0].immediate(), args[1].immediate()),
- sym::fmul_fast => self.fmul_fast(args[0].immediate(), args[1].immediate()),
- sym::fdiv_fast => self.fdiv_fast(args[0].immediate(), args[1].immediate()),
- sym::frem_fast => self.frem_fast(args[0].immediate(), args[1].immediate()),
- _ => bug!(),
- },
- None => {
- span_invalid_monomorphization_error(
- tcx.sess,
- span,
- &format!(
- "invalid monomorphization of `{}` intrinsic: \
- expected basic float type, found `{}`",
- name, arg_tys[0]
- ),
- );
- return;
- }
- }
- }
-
- sym::float_to_int_unchecked => {
- if float_type_width(arg_tys[0]).is_none() {
- span_invalid_monomorphization_error(
- tcx.sess,
- span,
- &format!(
- "invalid monomorphization of `float_to_int_unchecked` \
- intrinsic: expected basic float type, \
- found `{}`",
- arg_tys[0]
- ),
- );
- return;
- }
- let (width, signed) = match int_type_width_signed(ret_ty, self.cx) {
- Some(pair) => pair,
- None => {
- span_invalid_monomorphization_error(
- tcx.sess,
- span,
- &format!(
- "invalid monomorphization of `float_to_int_unchecked` \
- intrinsic: expected basic integer type, \
- found `{}`",
- ret_ty
- ),
- );
- return;
- }
- };
- if signed {
- self.fptosi(args[0].immediate(), self.cx.type_ix(width))
- } else {
- self.fptoui(args[0].immediate(), self.cx.type_ix(width))
- }
- }
-
- sym::discriminant_value => {
- if ret_ty.is_integral() {
- args[0].deref(self.cx()).codegen_get_discr(self, ret_ty)
- } else {
- span_bug!(span, "Invalid discriminant type for `{:?}`", arg_tys[0])
- }
- }
_ if name_str.starts_with("simd_") => {
match generic_simd_intrinsic(self, name, callee_ty, args, ret_ty, llret_ty, span) {
Err(()) => return,
}
}
- // This requires that atomic intrinsics follow a specific naming pattern:
- // "atomic_<operation>[_<ordering>]", and no ordering means SeqCst
- name if name_str.starts_with("atomic_") => {
- use rustc_codegen_ssa::common::AtomicOrdering::*;
- use rustc_codegen_ssa::common::{AtomicRmwBinOp, SynchronizationScope};
-
- let split: Vec<&str> = name_str.split('_').collect();
-
- let is_cxchg = split[1] == "cxchg" || split[1] == "cxchgweak";
- let (order, failorder) = match split.len() {
- 2 => (SequentiallyConsistent, SequentiallyConsistent),
- 3 => match split[2] {
- "unordered" => (Unordered, Unordered),
- "relaxed" => (Monotonic, Monotonic),
- "acq" => (Acquire, Acquire),
- "rel" => (Release, Monotonic),
- "acqrel" => (AcquireRelease, Acquire),
- "failrelaxed" if is_cxchg => (SequentiallyConsistent, Monotonic),
- "failacq" if is_cxchg => (SequentiallyConsistent, Acquire),
- _ => self.sess().fatal("unknown ordering in atomic intrinsic"),
- },
- 4 => match (split[2], split[3]) {
- ("acq", "failrelaxed") if is_cxchg => (Acquire, Monotonic),
- ("acqrel", "failrelaxed") if is_cxchg => (AcquireRelease, Monotonic),
- _ => self.sess().fatal("unknown ordering in atomic intrinsic"),
- },
- _ => self.sess().fatal("Atomic intrinsic not in correct format"),
- };
-
- let invalid_monomorphization = |ty| {
- span_invalid_monomorphization_error(
- tcx.sess,
- span,
- &format!(
- "invalid monomorphization of `{}` intrinsic: \
- expected basic integer type, found `{}`",
- name, ty
- ),
- );
- };
-
- match split[1] {
- "cxchg" | "cxchgweak" => {
- let ty = substs.type_at(0);
- if int_type_width_signed(ty, self).is_some() {
- let weak = split[1] == "cxchgweak";
- let pair = self.atomic_cmpxchg(
- args[0].immediate(),
- args[1].immediate(),
- args[2].immediate(),
- order,
- failorder,
- weak,
- );
- let val = self.extract_value(pair, 0);
- let success = self.extract_value(pair, 1);
- let success = self.zext(success, self.type_bool());
-
- let dest = result.project_field(self, 0);
- self.store(val, dest.llval, dest.align);
- let dest = result.project_field(self, 1);
- self.store(success, dest.llval, dest.align);
- return;
- } else {
- return invalid_monomorphization(ty);
- }
- }
-
- "load" => {
- let ty = substs.type_at(0);
- if int_type_width_signed(ty, self).is_some() {
- let size = self.size_of(ty);
- self.atomic_load(args[0].immediate(), order, size)
- } else {
- return invalid_monomorphization(ty);
- }
- }
-
- "store" => {
- let ty = substs.type_at(0);
- if int_type_width_signed(ty, self).is_some() {
- let size = self.size_of(ty);
- self.atomic_store(
- args[1].immediate(),
- args[0].immediate(),
- order,
- size,
- );
- return;
- } else {
- return invalid_monomorphization(ty);
- }
- }
-
- "fence" => {
- self.atomic_fence(order, SynchronizationScope::CrossThread);
- return;
- }
-
- "singlethreadfence" => {
- self.atomic_fence(order, SynchronizationScope::SingleThread);
- return;
- }
-
- // These are all AtomicRMW ops
- op => {
- let atom_op = match op {
- "xchg" => AtomicRmwBinOp::AtomicXchg,
- "xadd" => AtomicRmwBinOp::AtomicAdd,
- "xsub" => AtomicRmwBinOp::AtomicSub,
- "and" => AtomicRmwBinOp::AtomicAnd,
- "nand" => AtomicRmwBinOp::AtomicNand,
- "or" => AtomicRmwBinOp::AtomicOr,
- "xor" => AtomicRmwBinOp::AtomicXor,
- "max" => AtomicRmwBinOp::AtomicMax,
- "min" => AtomicRmwBinOp::AtomicMin,
- "umax" => AtomicRmwBinOp::AtomicUMax,
- "umin" => AtomicRmwBinOp::AtomicUMin,
- _ => self.sess().fatal("unknown atomic operation"),
- };
-
- let ty = substs.type_at(0);
- if int_type_width_signed(ty, self).is_some() {
- self.atomic_rmw(
- atom_op,
- args[0].immediate(),
- args[1].immediate(),
- order,
- )
- } else {
- return invalid_monomorphization(ty);
- }
- }
- }
- }
-
- sym::nontemporal_store => {
- let dst = args[0].deref(self.cx());
- args[1].val.nontemporal_store(self, dst);
- return;
- }
-
- sym::ptr_guaranteed_eq | sym::ptr_guaranteed_ne => {
- let a = args[0].immediate();
- let b = args[1].immediate();
- if name == sym::ptr_guaranteed_eq {
- self.icmp(IntPredicate::IntEQ, a, b)
- } else {
- self.icmp(IntPredicate::IntNE, a, b)
- }
- }
-
- sym::ptr_offset_from => {
- let ty = substs.type_at(0);
- let pointee_size = self.size_of(ty);
-
- // This is the same sequence that Clang emits for pointer subtraction.
- // It can be neither `nsw` nor `nuw` because the input is treated as
- // unsigned but then the output is treated as signed, so neither works.
- let a = args[0].immediate();
- let b = args[1].immediate();
- let a = self.ptrtoint(a, self.type_isize());
- let b = self.ptrtoint(b, self.type_isize());
- let d = self.sub(a, b);
- let pointee_size = self.const_usize(pointee_size.bytes());
- // this is where the signed magic happens (notice the `s` in `exactsdiv`)
- self.exactsdiv(d, pointee_size)
- }
_ => bug!("unknown intrinsic '{}'", name),
};
}
}
-fn copy_intrinsic(
- bx: &mut Builder<'a, 'll, 'tcx>,
- allow_overlap: bool,
- volatile: bool,
- ty: Ty<'tcx>,
- dst: &'ll Value,
- src: &'ll Value,
- count: &'ll Value,
-) {
- let (size, align) = bx.size_and_align_of(ty);
- let size = bx.mul(bx.const_usize(size.bytes()), count);
- let flags = if volatile { MemFlags::VOLATILE } else { MemFlags::empty() };
- if allow_overlap {
- bx.memmove(dst, align, src, align, size, flags);
- } else {
- bx.memcpy(dst, align, src, align, size, flags);
- }
-}
-
-fn memset_intrinsic(
- bx: &mut Builder<'a, 'll, 'tcx>,
- volatile: bool,
- ty: Ty<'tcx>,
- dst: &'ll Value,
- val: &'ll Value,
- count: &'ll Value,
-) {
- let (size, align) = bx.size_and_align_of(ty);
- let size = bx.mul(bx.const_usize(size.bytes()), count);
- let flags = if volatile { MemFlags::VOLATILE } else { MemFlags::empty() };
- bx.memset(dst, val, size, align, flags);
-}
-
fn try_intrinsic(
bx: &mut Builder<'a, 'll, 'tcx>,
try_func: &'ll Value,
// stuffs.
fn int_type_width_signed(ty: Ty<'_>, cx: &CodegenCx<'_, '_>) -> Option<(u64, bool)> {
match ty.kind() {
- ty::Int(t) => Some((
- match t {
- ast::IntTy::Isize => u64::from(cx.tcx.sess.target.ptr_width),
- ast::IntTy::I8 => 8,
- ast::IntTy::I16 => 16,
- ast::IntTy::I32 => 32,
- ast::IntTy::I64 => 64,
- ast::IntTy::I128 => 128,
- },
- true,
- )),
- ty::Uint(t) => Some((
- match t {
- ast::UintTy::Usize => u64::from(cx.tcx.sess.target.ptr_width),
- ast::UintTy::U8 => 8,
- ast::UintTy::U16 => 16,
- ast::UintTy::U32 => 32,
- ast::UintTy::U64 => 64,
- ast::UintTy::U128 => 128,
- },
- false,
- )),
- _ => None,
- }
-}
-
-// Returns the width of a float Ty
-// Returns None if the type is not a float
-fn float_type_width(ty: Ty<'_>) -> Option<u64> {
- match ty.kind() {
- ty::Float(t) => Some(t.bit_width()),
+ ty::Int(t) => {
+ Some((t.bit_width().unwrap_or(u64::from(cx.tcx.sess.target.ptr_width)), true))
+ }
+ ty::Uint(t) => {
+ Some((t.bit_width().unwrap_or(u64::from(cx.tcx.sess.target.ptr_width)), false))
+ }
_ => None,
}
}
#![feature(or_patterns)]
#![feature(trusted_len)]
#![feature(associated_type_bounds)]
-#![feature(const_fn)] // for rustc_index::newtype_index
-#![feature(const_panic)] // for rustc_index::newtype_index
#![recursion_limit = "256"]
//! This crate contains codegen code that is used by all codegen backends (LLVM and others).
use rustc_hir::lang_items::LangItem;
use rustc_index::vec::Idx;
use rustc_middle::mir;
-use rustc_middle::mir::interpret::{AllocId, ConstValue, Pointer, Scalar};
+use rustc_middle::mir::interpret::ConstValue;
use rustc_middle::mir::AssertKind;
use rustc_middle::ty::layout::{FnAbiExt, HasTyCtxt};
use rustc_middle::ty::print::with_no_trimmed_paths;
})
.collect();
- bx.codegen_intrinsic_call(
+ Self::codegen_intrinsic_call(
+ &mut bx,
*instance.as_ref().unwrap(),
&fn_abi,
&args,
let ty = constant.literal.ty;
let size = bx.layout_of(ty).size;
let scalar = match const_value {
- // Promoted constants are evaluated into a ByRef instead of a Scalar,
- // but we want the scalar value here.
- ConstValue::ByRef { alloc, offset } => {
- let ptr = Pointer::new(AllocId(0), offset);
- alloc
- .read_scalar(&bx, ptr, size)
- .and_then(|s| s.check_init())
- .unwrap_or_else(|e| {
- bx.tcx().sess.span_err(
- span,
- &format!("Could not evaluate asm const: {}", e),
- );
-
- // We are erroring out, just emit a dummy constant.
- Scalar::from_u64(0)
- })
- }
- _ => span_bug!(span, "expected ByRef for promoted asm const"),
+ ConstValue::Scalar(s) => s,
+ _ => span_bug!(
+ span,
+ "expected Scalar for promoted asm const, but got {:#?}",
+ const_value
+ ),
};
let value = scalar.assert_bits(size);
let string = match ty.kind() {
--- /dev/null
+use super::operand::{OperandRef, OperandValue};
+use super::place::PlaceRef;
+use super::FunctionCx;
+use crate::common::{span_invalid_monomorphization_error, IntPredicate};
+use crate::glue;
+use crate::traits::*;
+use crate::MemFlags;
+
+use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_span::{sym, Span};
+use rustc_target::abi::call::{FnAbi, PassMode};
+
+fn copy_intrinsic<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
+ bx: &mut Bx,
+ allow_overlap: bool,
+ volatile: bool,
+ ty: Ty<'tcx>,
+ dst: Bx::Value,
+ src: Bx::Value,
+ count: Bx::Value,
+) {
+ let layout = bx.layout_of(ty);
+ let size = layout.size;
+ let align = layout.align.abi;
+ let size = bx.mul(bx.const_usize(size.bytes()), count);
+ let flags = if volatile { MemFlags::VOLATILE } else { MemFlags::empty() };
+ if allow_overlap {
+ bx.memmove(dst, align, src, align, size, flags);
+ } else {
+ bx.memcpy(dst, align, src, align, size, flags);
+ }
+}
+
+fn memset_intrinsic<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
+ bx: &mut Bx,
+ volatile: bool,
+ ty: Ty<'tcx>,
+ dst: Bx::Value,
+ val: Bx::Value,
+ count: Bx::Value,
+) {
+ let layout = bx.layout_of(ty);
+ let size = layout.size;
+ let align = layout.align.abi;
+ let size = bx.mul(bx.const_usize(size.bytes()), count);
+ let flags = if volatile { MemFlags::VOLATILE } else { MemFlags::empty() };
+ bx.memset(dst, val, size, align, flags);
+}
+
+impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
+ pub fn codegen_intrinsic_call(
+ bx: &mut Bx,
+ instance: ty::Instance<'tcx>,
+ fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
+ args: &[OperandRef<'tcx, Bx::Value>],
+ llresult: Bx::Value,
+ span: Span,
+ ) {
+ let callee_ty = instance.ty(bx.tcx(), ty::ParamEnv::reveal_all());
+
+ let (def_id, substs) = match *callee_ty.kind() {
+ ty::FnDef(def_id, substs) => (def_id, substs),
+ _ => bug!("expected fn item type, found {}", callee_ty),
+ };
+
+ let sig = callee_ty.fn_sig(bx.tcx());
+ let sig = bx.tcx().normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig);
+ let arg_tys = sig.inputs();
+ let ret_ty = sig.output();
+ let name = bx.tcx().item_name(def_id);
+ let name_str = &*name.as_str();
+
+ let llret_ty = bx.backend_type(bx.layout_of(ret_ty));
+ let result = PlaceRef::new_sized(llresult, fn_abi.ret.layout);
+
+ let llval = match name {
+ sym::assume => {
+ bx.assume(args[0].immediate());
+ return;
+ }
+ sym::abort => {
+ bx.abort();
+ return;
+ }
+
+ sym::unreachable => {
+ return;
+ }
+ sym::va_start => bx.va_start(args[0].immediate()),
+ sym::va_end => bx.va_end(args[0].immediate()),
+ sym::size_of_val => {
+ let tp_ty = substs.type_at(0);
+ if let OperandValue::Pair(_, meta) = args[0].val {
+ let (llsize, _) = glue::size_and_align_of_dst(bx, tp_ty, Some(meta));
+ llsize
+ } else {
+ bx.const_usize(bx.layout_of(tp_ty).size.bytes())
+ }
+ }
+ sym::min_align_of_val => {
+ let tp_ty = substs.type_at(0);
+ if let OperandValue::Pair(_, meta) = args[0].val {
+ let (_, llalign) = glue::size_and_align_of_dst(bx, tp_ty, Some(meta));
+ llalign
+ } else {
+ bx.const_usize(bx.layout_of(tp_ty).align.abi.bytes())
+ }
+ }
+ sym::size_of
+ | sym::pref_align_of
+ | sym::min_align_of
+ | sym::needs_drop
+ | sym::type_id
+ | sym::type_name
+ | sym::variant_count => {
+ let value = bx
+ .tcx()
+ .const_eval_instance(ty::ParamEnv::reveal_all(), instance, None)
+ .unwrap();
+ OperandRef::from_const(bx, value, ret_ty).immediate_or_packed_pair(bx)
+ }
+ // Effectively no-op
+ sym::forget => {
+ return;
+ }
+ sym::offset => {
+ let ptr = args[0].immediate();
+ let offset = args[1].immediate();
+ bx.inbounds_gep(ptr, &[offset])
+ }
+ sym::arith_offset => {
+ let ptr = args[0].immediate();
+ let offset = args[1].immediate();
+ bx.gep(ptr, &[offset])
+ }
+
+ sym::copy_nonoverlapping => {
+ copy_intrinsic(
+ bx,
+ false,
+ false,
+ substs.type_at(0),
+ args[1].immediate(),
+ args[0].immediate(),
+ args[2].immediate(),
+ );
+ return;
+ }
+ sym::copy => {
+ copy_intrinsic(
+ bx,
+ true,
+ false,
+ substs.type_at(0),
+ args[1].immediate(),
+ args[0].immediate(),
+ args[2].immediate(),
+ );
+ return;
+ }
+ sym::write_bytes => {
+ memset_intrinsic(
+ bx,
+ false,
+ substs.type_at(0),
+ args[0].immediate(),
+ args[1].immediate(),
+ args[2].immediate(),
+ );
+ return;
+ }
+
+ sym::volatile_copy_nonoverlapping_memory => {
+ copy_intrinsic(
+ bx,
+ false,
+ true,
+ substs.type_at(0),
+ args[0].immediate(),
+ args[1].immediate(),
+ args[2].immediate(),
+ );
+ return;
+ }
+ sym::volatile_copy_memory => {
+ copy_intrinsic(
+ bx,
+ true,
+ true,
+ substs.type_at(0),
+ args[0].immediate(),
+ args[1].immediate(),
+ args[2].immediate(),
+ );
+ return;
+ }
+ sym::volatile_set_memory => {
+ memset_intrinsic(
+ bx,
+ true,
+ substs.type_at(0),
+ args[0].immediate(),
+ args[1].immediate(),
+ args[2].immediate(),
+ );
+ return;
+ }
+ sym::volatile_store => {
+ let dst = args[0].deref(bx.cx());
+ args[1].val.volatile_store(bx, dst);
+ return;
+ }
+ sym::unaligned_volatile_store => {
+ let dst = args[0].deref(bx.cx());
+ args[1].val.unaligned_volatile_store(bx, dst);
+ return;
+ }
+ sym::add_with_overflow
+ | sym::sub_with_overflow
+ | sym::mul_with_overflow
+ | sym::wrapping_add
+ | sym::wrapping_sub
+ | sym::wrapping_mul
+ | sym::unchecked_div
+ | sym::unchecked_rem
+ | sym::unchecked_shl
+ | sym::unchecked_shr
+ | sym::unchecked_add
+ | sym::unchecked_sub
+ | sym::unchecked_mul
+ | sym::exact_div => {
+ let ty = arg_tys[0];
+ match int_type_width_signed(ty, bx.tcx()) {
+ Some((_width, signed)) => match name {
+ sym::add_with_overflow
+ | sym::sub_with_overflow
+ | sym::mul_with_overflow => {
+ let op = match name {
+ sym::add_with_overflow => OverflowOp::Add,
+ sym::sub_with_overflow => OverflowOp::Sub,
+ sym::mul_with_overflow => OverflowOp::Mul,
+ _ => bug!(),
+ };
+ let (val, overflow) =
+ bx.checked_binop(op, ty, args[0].immediate(), args[1].immediate());
+ // Convert `i1` to a `bool`, and write it to the out parameter
+ let val = bx.from_immediate(val);
+ let overflow = bx.from_immediate(overflow);
+
+ let dest = result.project_field(bx, 0);
+ bx.store(val, dest.llval, dest.align);
+ let dest = result.project_field(bx, 1);
+ bx.store(overflow, dest.llval, dest.align);
+
+ return;
+ }
+ sym::wrapping_add => bx.add(args[0].immediate(), args[1].immediate()),
+ sym::wrapping_sub => bx.sub(args[0].immediate(), args[1].immediate()),
+ sym::wrapping_mul => bx.mul(args[0].immediate(), args[1].immediate()),
+ sym::exact_div => {
+ if signed {
+ bx.exactsdiv(args[0].immediate(), args[1].immediate())
+ } else {
+ bx.exactudiv(args[0].immediate(), args[1].immediate())
+ }
+ }
+ sym::unchecked_div => {
+ if signed {
+ bx.sdiv(args[0].immediate(), args[1].immediate())
+ } else {
+ bx.udiv(args[0].immediate(), args[1].immediate())
+ }
+ }
+ sym::unchecked_rem => {
+ if signed {
+ bx.srem(args[0].immediate(), args[1].immediate())
+ } else {
+ bx.urem(args[0].immediate(), args[1].immediate())
+ }
+ }
+ sym::unchecked_shl => bx.shl(args[0].immediate(), args[1].immediate()),
+ sym::unchecked_shr => {
+ if signed {
+ bx.ashr(args[0].immediate(), args[1].immediate())
+ } else {
+ bx.lshr(args[0].immediate(), args[1].immediate())
+ }
+ }
+ sym::unchecked_add => {
+ if signed {
+ bx.unchecked_sadd(args[0].immediate(), args[1].immediate())
+ } else {
+ bx.unchecked_uadd(args[0].immediate(), args[1].immediate())
+ }
+ }
+ sym::unchecked_sub => {
+ if signed {
+ bx.unchecked_ssub(args[0].immediate(), args[1].immediate())
+ } else {
+ bx.unchecked_usub(args[0].immediate(), args[1].immediate())
+ }
+ }
+ sym::unchecked_mul => {
+ if signed {
+ bx.unchecked_smul(args[0].immediate(), args[1].immediate())
+ } else {
+ bx.unchecked_umul(args[0].immediate(), args[1].immediate())
+ }
+ }
+ _ => bug!(),
+ },
+ None => {
+ span_invalid_monomorphization_error(
+ bx.tcx().sess,
+ span,
+ &format!(
+ "invalid monomorphization of `{}` intrinsic: \
+ expected basic integer type, found `{}`",
+ name, ty
+ ),
+ );
+ return;
+ }
+ }
+ }
+ sym::fadd_fast | sym::fsub_fast | sym::fmul_fast | sym::fdiv_fast | sym::frem_fast => {
+ match float_type_width(arg_tys[0]) {
+ Some(_width) => match name {
+ sym::fadd_fast => bx.fadd_fast(args[0].immediate(), args[1].immediate()),
+ sym::fsub_fast => bx.fsub_fast(args[0].immediate(), args[1].immediate()),
+ sym::fmul_fast => bx.fmul_fast(args[0].immediate(), args[1].immediate()),
+ sym::fdiv_fast => bx.fdiv_fast(args[0].immediate(), args[1].immediate()),
+ sym::frem_fast => bx.frem_fast(args[0].immediate(), args[1].immediate()),
+ _ => bug!(),
+ },
+ None => {
+ span_invalid_monomorphization_error(
+ bx.tcx().sess,
+ span,
+ &format!(
+ "invalid monomorphization of `{}` intrinsic: \
+ expected basic float type, found `{}`",
+ name, arg_tys[0]
+ ),
+ );
+ return;
+ }
+ }
+ }
+
+ sym::float_to_int_unchecked => {
+ if float_type_width(arg_tys[0]).is_none() {
+ span_invalid_monomorphization_error(
+ bx.tcx().sess,
+ span,
+ &format!(
+ "invalid monomorphization of `float_to_int_unchecked` \
+ intrinsic: expected basic float type, \
+ found `{}`",
+ arg_tys[0]
+ ),
+ );
+ return;
+ }
+ let (_width, signed) = match int_type_width_signed(ret_ty, bx.tcx()) {
+ Some(pair) => pair,
+ None => {
+ span_invalid_monomorphization_error(
+ bx.tcx().sess,
+ span,
+ &format!(
+ "invalid monomorphization of `float_to_int_unchecked` \
+ intrinsic: expected basic integer type, \
+ found `{}`",
+ ret_ty
+ ),
+ );
+ return;
+ }
+ };
+ if signed {
+ bx.fptosi(args[0].immediate(), llret_ty)
+ } else {
+ bx.fptoui(args[0].immediate(), llret_ty)
+ }
+ }
+
+ sym::discriminant_value => {
+ if ret_ty.is_integral() {
+ args[0].deref(bx.cx()).codegen_get_discr(bx, ret_ty)
+ } else {
+ span_bug!(span, "Invalid discriminant type for `{:?}`", arg_tys[0])
+ }
+ }
+
+ // This requires that atomic intrinsics follow a specific naming pattern:
+ // "atomic_<operation>[_<ordering>]", and no ordering means SeqCst
+ name if name_str.starts_with("atomic_") => {
+ use crate::common::AtomicOrdering::*;
+ use crate::common::{AtomicRmwBinOp, SynchronizationScope};
+
+ let split: Vec<&str> = name_str.split('_').collect();
+
+ let is_cxchg = split[1] == "cxchg" || split[1] == "cxchgweak";
+ let (order, failorder) = match split.len() {
+ 2 => (SequentiallyConsistent, SequentiallyConsistent),
+ 3 => match split[2] {
+ "unordered" => (Unordered, Unordered),
+ "relaxed" => (Monotonic, Monotonic),
+ "acq" => (Acquire, Acquire),
+ "rel" => (Release, Monotonic),
+ "acqrel" => (AcquireRelease, Acquire),
+ "failrelaxed" if is_cxchg => (SequentiallyConsistent, Monotonic),
+ "failacq" if is_cxchg => (SequentiallyConsistent, Acquire),
+ _ => bx.sess().fatal("unknown ordering in atomic intrinsic"),
+ },
+ 4 => match (split[2], split[3]) {
+ ("acq", "failrelaxed") if is_cxchg => (Acquire, Monotonic),
+ ("acqrel", "failrelaxed") if is_cxchg => (AcquireRelease, Monotonic),
+ _ => bx.sess().fatal("unknown ordering in atomic intrinsic"),
+ },
+ _ => bx.sess().fatal("Atomic intrinsic not in correct format"),
+ };
+
+ let invalid_monomorphization = |ty| {
+ span_invalid_monomorphization_error(
+ bx.tcx().sess,
+ span,
+ &format!(
+ "invalid monomorphization of `{}` intrinsic: \
+ expected basic integer type, found `{}`",
+ name, ty
+ ),
+ );
+ };
+
+ match split[1] {
+ "cxchg" | "cxchgweak" => {
+ let ty = substs.type_at(0);
+ if int_type_width_signed(ty, bx.tcx()).is_some() {
+ let weak = split[1] == "cxchgweak";
+ let pair = bx.atomic_cmpxchg(
+ args[0].immediate(),
+ args[1].immediate(),
+ args[2].immediate(),
+ order,
+ failorder,
+ weak,
+ );
+ let val = bx.extract_value(pair, 0);
+ let success = bx.extract_value(pair, 1);
+ let val = bx.from_immediate(val);
+ let success = bx.from_immediate(success);
+
+ let dest = result.project_field(bx, 0);
+ bx.store(val, dest.llval, dest.align);
+ let dest = result.project_field(bx, 1);
+ bx.store(success, dest.llval, dest.align);
+ return;
+ } else {
+ return invalid_monomorphization(ty);
+ }
+ }
+
+ "load" => {
+ let ty = substs.type_at(0);
+ if int_type_width_signed(ty, bx.tcx()).is_some() {
+ let size = bx.layout_of(ty).size;
+ bx.atomic_load(args[0].immediate(), order, size)
+ } else {
+ return invalid_monomorphization(ty);
+ }
+ }
+
+ "store" => {
+ let ty = substs.type_at(0);
+ if int_type_width_signed(ty, bx.tcx()).is_some() {
+ let size = bx.layout_of(ty).size;
+ bx.atomic_store(args[1].immediate(), args[0].immediate(), order, size);
+ return;
+ } else {
+ return invalid_monomorphization(ty);
+ }
+ }
+
+ "fence" => {
+ bx.atomic_fence(order, SynchronizationScope::CrossThread);
+ return;
+ }
+
+ "singlethreadfence" => {
+ bx.atomic_fence(order, SynchronizationScope::SingleThread);
+ return;
+ }
+
+ // These are all AtomicRMW ops
+ op => {
+ let atom_op = match op {
+ "xchg" => AtomicRmwBinOp::AtomicXchg,
+ "xadd" => AtomicRmwBinOp::AtomicAdd,
+ "xsub" => AtomicRmwBinOp::AtomicSub,
+ "and" => AtomicRmwBinOp::AtomicAnd,
+ "nand" => AtomicRmwBinOp::AtomicNand,
+ "or" => AtomicRmwBinOp::AtomicOr,
+ "xor" => AtomicRmwBinOp::AtomicXor,
+ "max" => AtomicRmwBinOp::AtomicMax,
+ "min" => AtomicRmwBinOp::AtomicMin,
+ "umax" => AtomicRmwBinOp::AtomicUMax,
+ "umin" => AtomicRmwBinOp::AtomicUMin,
+ _ => bx.sess().fatal("unknown atomic operation"),
+ };
+
+ let ty = substs.type_at(0);
+ if int_type_width_signed(ty, bx.tcx()).is_some() {
+ bx.atomic_rmw(atom_op, args[0].immediate(), args[1].immediate(), order)
+ } else {
+ return invalid_monomorphization(ty);
+ }
+ }
+ }
+ }
+
+ sym::nontemporal_store => {
+ let dst = args[0].deref(bx.cx());
+ args[1].val.nontemporal_store(bx, dst);
+ return;
+ }
+
+ sym::ptr_guaranteed_eq | sym::ptr_guaranteed_ne => {
+ let a = args[0].immediate();
+ let b = args[1].immediate();
+ if name == sym::ptr_guaranteed_eq {
+ bx.icmp(IntPredicate::IntEQ, a, b)
+ } else {
+ bx.icmp(IntPredicate::IntNE, a, b)
+ }
+ }
+
+ sym::ptr_offset_from => {
+ let ty = substs.type_at(0);
+ let pointee_size = bx.layout_of(ty).size;
+
+ // This is the same sequence that Clang emits for pointer subtraction.
+ // It can be neither `nsw` nor `nuw` because the input is treated as
+ // unsigned but then the output is treated as signed, so neither works.
+ let a = args[0].immediate();
+ let b = args[1].immediate();
+ let a = bx.ptrtoint(a, bx.type_isize());
+ let b = bx.ptrtoint(b, bx.type_isize());
+ let d = bx.sub(a, b);
+ let pointee_size = bx.const_usize(pointee_size.bytes());
+ // this is where the signed magic happens (notice the `s` in `exactsdiv`)
+ bx.exactsdiv(d, pointee_size)
+ }
+
+ _ => {
+ // Need to use backend-specific things in the implementation.
+ bx.codegen_intrinsic_call(instance, fn_abi, args, llresult, span);
+ return;
+ }
+ };
+
+ if !fn_abi.ret.is_ignore() {
+ if let PassMode::Cast(ty) = fn_abi.ret.mode {
+ let ptr_llty = bx.type_ptr_to(bx.cast_backend_type(&ty));
+ let ptr = bx.pointercast(result.llval, ptr_llty);
+ bx.store(llval, ptr, result.align);
+ } else {
+ OperandRef::from_immediate_or_packed_pair(bx, llval, result.layout)
+ .val
+ .store(bx, result);
+ }
+ }
+ }
+}
+
+// Returns the width of an int Ty, and if it's signed or not
+// Returns None if the type is not an integer
+// FIXME: there’s multiple of this functions, investigate using some of the already existing
+// stuffs.
+fn int_type_width_signed(ty: Ty<'_>, tcx: TyCtxt<'_>) -> Option<(u64, bool)> {
+ match ty.kind() {
+ ty::Int(t) => Some((t.bit_width().unwrap_or(u64::from(tcx.sess.target.ptr_width)), true)),
+ ty::Uint(t) => Some((t.bit_width().unwrap_or(u64::from(tcx.sess.target.ptr_width)), false)),
+ _ => None,
+ }
+}
+
+// Returns the width of a float Ty
+// Returns None if the type is not a float
+fn float_type_width(ty: Ty<'_>) -> Option<u64> {
+ match ty.kind() {
+ ty::Float(t) => Some(t.bit_width()),
+ _ => None,
+ }
+}
pub mod constant;
pub mod coverageinfo;
pub mod debuginfo;
+mod intrinsic;
pub mod operand;
pub mod place;
mod rvalue;
};
use rustc_span::symbol::Symbol;
use rustc_target::abi::LayoutOf;
+use rustc_target::spec::Target;
pub use rustc_data_structures::sync::MetadataRef;
fn print_passes(&self) {}
fn print_version(&self) {}
+ /// If this plugin provides additional builtin targets, provide the one enabled by the options here.
+ /// Be careful: this is called *before* init() is called.
+ fn target_override(&self, _opts: &config::Options) -> Option<Target> {
+ None
+ }
+
fn metadata_loader(&self) -> Box<MetadataLoaderDyn>;
fn provide(&self, _providers: &mut Providers);
fn provide_extern(&self, _providers: &mut Providers);
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
#![allow(incomplete_features)]
+#![feature(array_windows)]
#![feature(control_flow_enum)]
#![feature(in_band_lifetimes)]
#![feature(unboxed_closures)]
-#![feature(generators)]
#![feature(generator_trait)]
#![feature(fn_traits)]
+#![feature(int_bits_const)]
#![feature(min_specialization)]
#![feature(optin_builtin_traits)]
#![feature(nll)]
#![feature(thread_id_value)]
#![feature(extend_one)]
#![feature(const_panic)]
-#![feature(const_generics)]
+#![feature(min_const_generics)]
#![feature(once_cell)]
#![allow(rustc::default_hash_types)]
/// and that there are no duplicates.
#[inline]
pub fn from_presorted_elements(elements: Vec<(K, V)>) -> SortedMap<K, V> {
- debug_assert!(elements.windows(2).all(|w| w[0].0 < w[1].0));
+ debug_assert!(elements.array_windows().all(|[fst, snd]| fst.0 < snd.0));
SortedMap { data: elements }
}
return;
}
- debug_assert!(elements.windows(2).all(|w| w[0].0 < w[1].0));
+ debug_assert!(elements.array_windows().all(|[fst, snd]| fst.0 < snd.0));
let start_index = self.lookup_index_for(&elements[0].0);
P: Pointer,
T: Tag,
{
- const TAG_BIT_SHIFT: usize = (8 * std::mem::size_of::<usize>()) - T::BITS;
+ const TAG_BIT_SHIFT: usize = usize::BITS as usize - T::BITS;
const ASSERTION: () = {
assert!(T::BITS <= P::BITS);
// Used for the transmute_copy's below
use std::io;
pub fn arg_expand(arg: String) -> Result<Vec<String>, Error> {
- if arg.starts_with('@') {
- let path = &arg[1..];
+ if let Some(path) = arg.strip_prefix('@') {
let file = match fs::read_to_string(path) {
Ok(file) => file,
Err(ref err) if err.kind() == io::ErrorKind::InvalidData => {
impl Annotation {
/// Whether this annotation is a vertical line placeholder.
pub fn is_line(&self) -> bool {
- if let AnnotationType::MultilineLine(_) = self.annotation_type { true } else { false }
+ matches!(self.annotation_type, AnnotationType::MultilineLine(_))
}
pub fn is_multiline(&self) -> bool {
- match self.annotation_type {
+ matches!(self.annotation_type,
AnnotationType::Multiline(_)
| AnnotationType::MultilineStart(_)
| AnnotationType::MultilineLine(_)
- | AnnotationType::MultilineEnd(_) => true,
- _ => false,
- }
+ | AnnotationType::MultilineEnd(_))
}
pub fn len(&self) -> usize {
#![feature(bool_to_option)]
-#![feature(cow_is_borrowed)]
#![feature(crate_visibility_modifier)]
#![feature(decl_macro)]
#![feature(or_patterns)]
rustc_span = { path = "../rustc_span" }
rustc_target = { path = "../rustc_target" }
smallvec = { version = "1.0", features = ["union", "may_dangle"] }
+arrayvec = { version = "0.5.1", default-features = false }
rustc_ast = { path = "../rustc_ast" }
use super::unify_key::{ConstVarValue, ConstVariableValue};
use super::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
use super::{InferCtxt, MiscVariable, TypeTrace};
+use arrayvec::ArrayVec;
+use rustc_data_structures::fx::FxHashMap;
+use std::hash::Hash;
use crate::traits::{Obligation, PredicateObligations};
use rustc_middle::ty::{IntType, UintType};
use rustc_span::DUMMY_SP;
+/// Small-storage-optimized implementation of a map
+/// made specifically for caching results.
+///
+/// Stores elements in a small array up to a certain length
+/// and switches to `HashMap` when that length is exceeded.
+enum MiniMap<K, V> {
+ Array(ArrayVec<[(K, V); 8]>),
+ Map(FxHashMap<K, V>),
+}
+
+impl<K: Eq + Hash, V> MiniMap<K, V> {
+ /// Creates an empty `MiniMap`.
+ pub fn new() -> Self {
+ MiniMap::Array(ArrayVec::new())
+ }
+
+ /// Inserts or updates value in the map.
+ pub fn insert(&mut self, key: K, value: V) {
+ match self {
+ MiniMap::Array(array) => {
+ for pair in array.iter_mut() {
+ if pair.0 == key {
+ pair.1 = value;
+ return;
+ }
+ }
+ if let Err(error) = array.try_push((key, value)) {
+ let mut map: FxHashMap<K, V> = array.drain(..).collect();
+ let (key, value) = error.element();
+ map.insert(key, value);
+ *self = MiniMap::Map(map);
+ }
+ }
+ MiniMap::Map(map) => {
+ map.insert(key, value);
+ }
+ }
+ }
+
+ /// Return value by key if any.
+ pub fn get(&self, key: &K) -> Option<&V> {
+ match self {
+ MiniMap::Array(array) => {
+ for pair in array {
+ if pair.0 == *key {
+ return Some(&pair.1);
+ }
+ }
+ return None;
+ }
+ MiniMap::Map(map) => {
+ return map.get(key);
+ }
+ }
+ }
+}
+
#[derive(Clone)]
pub struct CombineFields<'infcx, 'tcx> {
pub infcx: &'infcx InferCtxt<'infcx, 'tcx>,
needs_wf: false,
root_ty: ty,
param_env: self.param_env,
+ cache: MiniMap::new(),
};
let ty = match generalize.relate(ty, ty) {
root_ty: Ty<'tcx>,
param_env: ty::ParamEnv<'tcx>,
+
+ cache: MiniMap<Ty<'tcx>, RelateResult<'tcx, Ty<'tcx>>>,
}
/// Result from a generalization operation. This includes
fn tys(&mut self, t: Ty<'tcx>, t2: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
assert_eq!(t, t2); // we are abusing TypeRelation here; both LHS and RHS ought to be ==
+ if let Some(result) = self.cache.get(&t) {
+ return result.clone();
+ }
debug!("generalize: t={:?}", t);
// Check to see whether the type we are generalizing references
// any other type variable related to `vid` via
// subtyping. This is basically our "occurs check", preventing
// us from creating infinitely sized types.
- match *t.kind() {
+ let result = match *t.kind() {
ty::Infer(ty::TyVar(vid)) => {
let vid = self.infcx.inner.borrow_mut().type_variables().root_var(vid);
let sub_vid = self.infcx.inner.borrow_mut().type_variables().sub_root_var(vid);
Ok(t)
}
_ => relate::super_relate_tys(self, t, t),
- }
+ };
+
+ self.cache.insert(t, result.clone());
+ return result;
}
fn regions(
use rustc_middle::infer::unify_key::{ConstVarValue, ConstVariableValue};
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind, ToType};
use rustc_middle::mir;
-use rustc_middle::mir::interpret::ConstEvalResult;
+use rustc_middle::mir::interpret::EvalToConstValueResult;
use rustc_middle::traits::select;
use rustc_middle::ty::error::{ExpectedFound, TypeError, UnconstrainedNumeric};
use rustc_middle::ty::fold::{TypeFoldable, TypeFolder};
substs: SubstsRef<'tcx>,
promoted: Option<mir::Promoted>,
span: Option<Span>,
- ) -> ConstEvalResult<'tcx> {
+ ) -> EvalToConstValueResult<'tcx> {
let mut original_values = OriginalQueryValues::default();
let canonical = self.canonicalize_query(&(param_env, substs), &mut original_values);
use rustc_data_structures::captures::Captures;
use rustc_hir::def_id::DefId;
use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst};
+use rustc_middle::ty::walk::MiniSet;
use rustc_middle::ty::{self, Ty, TyCtxt};
/// The `TypeOutlives` struct has the job of "lowering" a `T: 'a`
/// Returns a "verify bound" that encodes what we know about
/// `generic` and the regions it outlives.
pub fn generic_bound(&self, generic: GenericKind<'tcx>) -> VerifyBound<'tcx> {
+ let mut visited = MiniSet::new();
match generic {
GenericKind::Param(param_ty) => self.param_bound(param_ty),
- GenericKind::Projection(projection_ty) => self.projection_bound(projection_ty),
+ GenericKind::Projection(projection_ty) => {
+ self.projection_bound(projection_ty, &mut visited)
+ }
}
}
- fn type_bound(&self, ty: Ty<'tcx>) -> VerifyBound<'tcx> {
+ fn type_bound(
+ &self,
+ ty: Ty<'tcx>,
+ visited: &mut MiniSet<GenericArg<'tcx>>,
+ ) -> VerifyBound<'tcx> {
match *ty.kind() {
ty::Param(p) => self.param_bound(p),
- ty::Projection(data) => self.projection_bound(data),
+ ty::Projection(data) => self.projection_bound(data, visited),
ty::FnDef(_, substs) => {
// HACK(eddyb) ignore lifetimes found shallowly in `substs`.
// This is inconsistent with `ty::Adt` (including all substs),
let mut bounds = substs
.iter()
.filter_map(|child| match child.unpack() {
- GenericArgKind::Type(ty) => Some(self.type_bound(ty)),
+ GenericArgKind::Type(ty) => Some(self.type_bound(ty, visited)),
GenericArgKind::Lifetime(_) => None,
- GenericArgKind::Const(_) => Some(self.recursive_bound(child)),
+ GenericArgKind::Const(_) => Some(self.recursive_bound(child, visited)),
})
.filter(|bound| {
// Remove bounds that must hold, since they are not interesting.
),
}
}
- _ => self.recursive_bound(ty.into()),
+ _ => self.recursive_bound(ty.into(), visited),
}
}
self.declared_projection_bounds_from_trait(projection_ty)
}
- pub fn projection_bound(&self, projection_ty: ty::ProjectionTy<'tcx>) -> VerifyBound<'tcx> {
+ pub fn projection_bound(
+ &self,
+ projection_ty: ty::ProjectionTy<'tcx>,
+ visited: &mut MiniSet<GenericArg<'tcx>>,
+ ) -> VerifyBound<'tcx> {
debug!("projection_bound(projection_ty={:?})", projection_ty);
let projection_ty_as_ty =
// see the extensive comment in projection_must_outlive
let ty = self.tcx.mk_projection(projection_ty.item_def_id, projection_ty.substs);
- let recursive_bound = self.recursive_bound(ty.into());
+ let recursive_bound = self.recursive_bound(ty.into(), visited);
VerifyBound::AnyBound(env_bounds.chain(trait_bounds).collect()).or(recursive_bound)
}
- fn recursive_bound(&self, parent: GenericArg<'tcx>) -> VerifyBound<'tcx> {
+ fn recursive_bound(
+ &self,
+ parent: GenericArg<'tcx>,
+ visited: &mut MiniSet<GenericArg<'tcx>>,
+ ) -> VerifyBound<'tcx> {
let mut bounds = parent
- .walk_shallow()
+ .walk_shallow(visited)
.filter_map(|child| match child.unpack() {
- GenericArgKind::Type(ty) => Some(self.type_bound(ty)),
+ GenericArgKind::Type(ty) => Some(self.type_bound(ty, visited)),
GenericArgKind::Lifetime(lt) => {
// Ignore late-bound regions.
if !lt.is_late_bound() { Some(VerifyBound::OutlivedBy(lt)) } else { None }
}
- GenericArgKind::Const(_) => Some(self.recursive_bound(child)),
+ GenericArgKind::Const(_) => Some(self.recursive_bound(child, visited)),
})
.filter(|bound| {
// Remove bounds that must hold, since they are not interesting.
//! This API is completely unstable and subject to change.
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
-#![feature(bindings_after_at)]
#![feature(bool_to_option)]
#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(never_type)]
#![feature(or_patterns)]
#![feature(in_band_lifetimes)]
-#![feature(crate_visibility_modifier)]
#![recursion_limit = "512"] // For rustdoc
#[macro_use]
DiagnosticOutput::Default,
Default::default(),
None,
+ None,
);
(sess, cfg)
}
lint_caps: FxHashMap<lint::LintId, lint::Level>,
descriptions: Registry,
) -> (Lrc<Session>, Lrc<Box<dyn CodegenBackend>>) {
+ let codegen_backend = get_codegen_backend(&sopts);
+ // target_override is documented to be called before init(), so this is okay
+ let target_override = codegen_backend.target_override(&sopts);
+
let mut sess = session::build_session(
sopts,
input_path,
diagnostic_output,
lint_caps,
file_loader,
+ target_override,
);
- let codegen_backend = get_codegen_backend(&sess);
+ codegen_backend.init(&sess);
let mut cfg = config::build_configuration(&sess, config::to_crate_config(cfg));
add_configuration(&mut cfg, &mut sess, &*codegen_backend);
}
}
-pub fn get_codegen_backend(sess: &Session) -> Box<dyn CodegenBackend> {
+pub fn get_codegen_backend(sopts: &config::Options) -> Box<dyn CodegenBackend> {
static INIT: Once = Once::new();
static mut LOAD: fn() -> Box<dyn CodegenBackend> = || unreachable!();
INIT.call_once(|| {
- let codegen_name = sess.opts.debugging_opts.codegen_backend.as_deref().unwrap_or("llvm");
+ let codegen_name = sopts.debugging_opts.codegen_backend.as_deref().unwrap_or("llvm");
let backend = match codegen_name {
filename if filename.contains('.') => load_backend_from_dylib(filename.as_ref()),
codegen_name => get_builtin_codegen_backend(codegen_name),
LOAD = backend;
}
});
- let backend = unsafe { LOAD() };
- backend.init(sess);
- backend
+ unsafe { LOAD() }
}
// This is used for rustdoc, but it uses similar machinery to codegen backend
//! `late_lint_methods!` invocation in `lib.rs`.
use crate::{
- types::CItemKind, EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext,
+ types::{transparent_newtype_field, CItemKind},
+ EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext,
};
use rustc_ast::attr::{self, HasAttrs};
use rustc_ast::tokenstream::{TokenStream, TokenTree};
UnusedBrokenConst => []
);
-fn check_const(cx: &LateContext<'_>, body_id: hir::BodyId) {
- let def_id = cx.tcx.hir().body_owner_def_id(body_id).to_def_id();
- // trigger the query once for all constants since that will already report the errors
- // FIXME: Use ensure here
- let _ = cx.tcx.const_eval_poly(def_id);
-}
-
impl<'tcx> LateLintPass<'tcx> for UnusedBrokenConst {
fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) {
match it.kind {
hir::ItemKind::Const(_, body_id) => {
- check_const(cx, body_id);
+ let def_id = cx.tcx.hir().body_owner_def_id(body_id).to_def_id();
+ // trigger the query once for all constants since that will already report the errors
+ // FIXME: Use ensure here
+ let _ = cx.tcx.const_eval_poly(def_id);
}
hir::ItemKind::Static(_, _, body_id) => {
- check_const(cx, body_id);
+ let def_id = cx.tcx.hir().body_owner_def_id(body_id).to_def_id();
+ // FIXME: Use ensure here
+ let _ = cx.tcx.eval_static_initializer(def_id);
}
_ => {}
}
.filter_map(|(i, bound)| {
if let hir::GenericBound::Outlives(lifetime) = bound {
let is_inferred = match tcx.named_region(lifetime.hir_id) {
- Some(Region::Static) if infer_static => inferred_outlives
- .iter()
- .any(|r| if let ty::ReStatic = r { true } else { false }),
+ Some(Region::Static) if infer_static => {
+ inferred_outlives.iter().any(|r| matches!(r, ty::ReStatic))
+ }
Some(Region::EarlyBound(index, ..)) => inferred_outlives.iter().any(|r| {
if let ty::ReEarlyBound(ebr) = r { ebr.index == index } else { false }
}),
let mut lint_spans = Vec::new();
for param in hir_generics.params {
- let has_lifetime_bounds = param.bounds.iter().any(|bound| {
- if let hir::GenericBound::Outlives(_) = bound { true } else { false }
- });
+ let has_lifetime_bounds = param
+ .bounds
+ .iter()
+ .any(|bound| matches!(bound, hir::GenericBound::Outlives(_)));
if !has_lifetime_bounds {
continue;
}
if is_transparent && !is_non_null {
debug_assert!(def.variants.len() == 1);
let v = &def.variants[VariantIdx::new(0)];
- ty = v
- .transparent_newtype_field(tcx)
+ ty = transparent_newtype_field(tcx, v)
.expect(
"single-variant transparent structure with zero-sized field",
)
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
#![cfg_attr(test, feature(test))]
+#![feature(array_windows)]
#![feature(bool_to_option)]
#![feature(box_syntax)]
#![feature(crate_visibility_modifier)]
// ones (some scripts don't have a concept of upper/lowercase)
!name.chars().next().unwrap().is_lowercase()
&& !name.contains("__")
- && !name.chars().collect::<Vec<_>>().windows(2).any(|pair| {
+ && !name.chars().collect::<Vec<_>>().array_windows().any(|&[fst, snd]| {
// contains a capitalisable character followed by, or preceded by, an underscore
- char_has_case(pair[0]) && pair[1] == '_' || char_has_case(pair[1]) && pair[0] == '_'
+ char_has_case(fst) && snd == '_' || char_has_case(snd) && fst == '_'
})
}
.any(|a| tcx.sess.check_name(a, sym::rustc_nonnull_optimization_guaranteed))
}
+/// `repr(transparent)` structs can have a single non-ZST field, this function returns that
+/// field.
+pub fn transparent_newtype_field<'a, 'tcx>(
+ tcx: TyCtxt<'tcx>,
+ variant: &'a ty::VariantDef,
+) -> Option<&'a ty::FieldDef> {
+ let param_env = tcx.param_env(variant.def_id);
+ for field in &variant.fields {
+ let field_ty = tcx.type_of(field.did);
+ let is_zst =
+ tcx.layout_of(param_env.and(field_ty)).map(|layout| layout.is_zst()).unwrap_or(false);
+
+ if !is_zst {
+ return Some(field);
+ }
+ }
+
+ None
+}
+
/// Is type known to be non-null?
crate fn ty_is_known_nonnull<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, mode: CItemKind) -> bool {
let tcx = cx.tcx;
}
for variant in &def.variants {
- if let Some(field) = variant.transparent_newtype_field(tcx) {
+ if let Some(field) = transparent_newtype_field(cx.tcx, variant) {
if ty_is_known_nonnull(cx, field.ty(tcx, substs), mode) {
return true;
}
ty::Adt(field_def, field_substs) => {
let inner_field_ty = {
let first_non_zst_ty =
- field_def.variants.iter().filter_map(|v| v.transparent_newtype_field(tcx));
+ field_def.variants.iter().filter_map(|v| transparent_newtype_field(cx.tcx, v));
debug_assert_eq!(
first_non_zst_ty.clone().count(),
1,
if def.repr.transparent() {
// Can assume that only one field is not a ZST, so only check
// that field's type for FFI-safety.
- if let Some(field) = variant.transparent_newtype_field(self.cx.tcx) {
+ if let Some(field) = transparent_newtype_field(self.cx.tcx, variant) {
self.check_field_type_for_ffi(cache, field, substs)
} else {
bug!("malformed transparent type");
[build-dependencies]
build_helper = { path = "../../src/build_helper" }
-cc = "1.0.58"
+cc = "1.0.60"
}
}
+impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for &'tcx [mir::abstract_const::Node<'tcx>] {
+ fn decode(d: &mut DecodeContext<'a, 'tcx>) -> Result<Self, String> {
+ ty::codec::RefDecodable::decode(d)
+ }
+}
+
impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for &'tcx [(ty::Predicate<'tcx>, Span)] {
fn decode(d: &mut DecodeContext<'a, 'tcx>) -> Result<Self, String> {
ty::codec::RefDecodable::decode(d)
.decode((self, tcx))
}
+ fn get_mir_abstract_const(
+ &self,
+ tcx: TyCtxt<'tcx>,
+ id: DefIndex,
+ ) -> Option<&'tcx [mir::abstract_const::Node<'tcx>]> {
+ self.root
+ .tables
+ .mir_abstract_consts
+ .get(self, id)
+ .filter(|_| !self.is_proc_macro(id))
+ .map_or(None, |v| Some(v.decode((self, tcx))))
+ }
+
fn get_unused_generic_params(&self, id: DefIndex) -> FiniteBitSet<u32> {
self.root
.tables
}
optimized_mir => { tcx.arena.alloc(cdata.get_optimized_mir(tcx, def_id.index)) }
promoted_mir => { tcx.arena.alloc(cdata.get_promoted_mir(tcx, def_id.index)) }
+ mir_abstract_const => { cdata.get_mir_abstract_const(tcx, def_id.index) }
unused_generic_params => { cdata.get_unused_generic_params(def_id.index) }
mir_const_qualif => { cdata.mir_const_qualif(def_id.index) }
fn_sig => { cdata.fn_sig(def_id.index, tcx) }
}
}
+impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for &'tcx [mir::abstract_const::Node<'tcx>] {
+ fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) -> opaque::EncodeResult {
+ (**self).encode(s)
+ }
+}
+
impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for &'tcx [(ty::Predicate<'tcx>, Span)] {
fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) -> opaque::EncodeResult {
(**self).encode(s)
if !unused.is_empty() {
record!(self.tables.unused_generic_params[def_id.to_def_id()] <- unused);
}
+
+ let abstract_const = self.tcx.mir_abstract_const(def_id);
+ if let Some(abstract_const) = abstract_const {
+ record!(self.tables.mir_abstract_consts[def_id.to_def_id()] <- abstract_const);
+ }
}
}
super_predicates: Table<DefIndex, Lazy!(ty::GenericPredicates<'tcx>)>,
mir: Table<DefIndex, Lazy!(mir::Body<'tcx>)>,
promoted_mir: Table<DefIndex, Lazy!(IndexVec<mir::Promoted, mir::Body<'tcx>>)>,
+ mir_abstract_consts: Table<DefIndex, Lazy!(&'tcx [mir::abstract_const::Node<'tcx>])>,
unused_generic_params: Table<DefIndex, Lazy<FiniteBitSet<u32>>>,
// `def_keys` and `def_path_hashes` represent a lazy version of a
// `DefPathTable`. This allows us to avoid deserializing an entire
rustc_span = { path = "../rustc_span" }
chalk-ir = "0.21.0"
smallvec = { version = "1.0", features = ["union", "may_dangle"] }
+arrayvec = { version = "0.5.1", default-features = false }
measureme = "0.7.1"
rustc_session = { path = "../rustc_session" }
//! This API is completely unstable and subject to change.
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
+#![feature(array_windows)]
#![feature(backtrace)]
#![feature(bool_to_option)]
#![feature(box_patterns)]
#![feature(cmp_min_max_by)]
#![feature(const_fn)]
#![feature(const_panic)]
-#![feature(const_fn_transmute)]
#![feature(core_intrinsics)]
#![feature(discriminant_kind)]
-#![feature(drain_filter)]
#![feature(never_type)]
-#![feature(exhaustive_patterns)]
#![feature(extern_types)]
#![feature(nll)]
#![feature(once_cell)]
#![feature(or_patterns)]
#![feature(min_specialization)]
#![feature(trusted_len)]
-#![feature(stmt_expr_attributes)]
#![feature(test)]
#![feature(in_band_lifetimes)]
#![feature(crate_visibility_modifier)]
#![feature(associated_type_bounds)]
#![feature(rustc_attrs)]
-#![feature(hash_raw_entry)]
#![feature(int_error_matching)]
#![recursion_limit = "512"]
impl LibSource {
pub fn is_some(&self) -> bool {
- if let LibSource::Some(_) = *self { true } else { false }
+ matches!(self, LibSource::Some(_))
}
pub fn option(&self) -> Option<PathBuf> {
--- /dev/null
+//! A subset of a mir body used for const evaluatability checking.
+use crate::mir;
+use crate::ty;
+
+rustc_index::newtype_index! {
+ /// An index into an `AbstractConst`.
+ pub struct NodeId {
+ derive [HashStable]
+ DEBUG_FORMAT = "n{}",
+ }
+}
+
+/// A node of an `AbstractConst`.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
+pub enum Node<'tcx> {
+ Leaf(&'tcx ty::Const<'tcx>),
+ Binop(mir::BinOp, NodeId, NodeId),
+ UnaryOp(mir::UnOp, NodeId),
+ FunctionCall(NodeId, &'tcx [NodeId]),
+}
-use super::{AllocId, Pointer, RawConst, Scalar};
+use super::{AllocId, ConstAlloc, Pointer, Scalar};
use crate::mir::interpret::ConstValue;
use crate::ty::{layout, query::TyCtxtAt, tls, FnSig, Ty};
ErrorHandled,
}
-pub type ConstEvalRawResult<'tcx> = Result<RawConst<'tcx>, ErrorHandled>;
-pub type ConstEvalResult<'tcx> = Result<ConstValue<'tcx>, ErrorHandled>;
+pub type EvalToAllocationRawResult<'tcx> = Result<ConstAlloc<'tcx>, ErrorHandled>;
+pub type EvalToConstValueResult<'tcx> = Result<ConstValue<'tcx>, ErrorHandled>;
pub fn struct_error<'tcx>(tcx: TyCtxtAt<'tcx>, msg: &str) -> DiagnosticBuilder<'tcx> {
struct_span_err!(tcx.sess, tcx.span, E0080, "{}", msg)
use crate::ty::{self, Instance, Ty, TyCtxt};
pub use self::error::{
- struct_error, CheckInAllocMsg, ConstEvalRawResult, ConstEvalResult, ErrorHandled, InterpError,
- InterpErrorInfo, InterpResult, InvalidProgramInfo, MachineStopType, ResourceExhaustionInfo,
- UndefinedBehaviorInfo, UninitBytesAccess, UnsupportedOpInfo,
+ struct_error, CheckInAllocMsg, ErrorHandled, EvalToAllocationRawResult, EvalToConstValueResult,
+ InterpError, InterpErrorInfo, InterpResult, InvalidProgramInfo, MachineStopType,
+ ResourceExhaustionInfo, UndefinedBehaviorInfo, UninitBytesAccess, UnsupportedOpInfo,
};
-pub use self::value::{get_slice_bytes, ConstValue, RawConst, Scalar, ScalarMaybeUninit};
+pub use self::value::{get_slice_bytes, ConstAlloc, ConstValue, Scalar, ScalarMaybeUninit};
pub use self::allocation::{Allocation, AllocationExtra, InitMask, Relocations};
-use super::{ConstEvalResult, ErrorHandled, GlobalId};
+use super::{ErrorHandled, EvalToConstValueResult, GlobalId};
use crate::mir;
use crate::ty::subst::{InternalSubsts, SubstsRef};
/// Evaluates a constant without providing any substitutions. This is useful to evaluate consts
/// that can't take any generic arguments like statics, const items or enum discriminants. If a
/// generic parameter is used within the constant `ErrorHandled::ToGeneric` will be returned.
- pub fn const_eval_poly(self, def_id: DefId) -> ConstEvalResult<'tcx> {
+ pub fn const_eval_poly(self, def_id: DefId) -> EvalToConstValueResult<'tcx> {
// In some situations def_id will have substitutions within scope, but they aren't allowed
// to be used. So we can't use `Instance::mono`, instead we feed unresolved substitutions
// into `const_eval` which will return `ErrorHandled::ToGeneric` if any of them are
substs: SubstsRef<'tcx>,
promoted: Option<mir::Promoted>,
span: Option<Span>,
- ) -> ConstEvalResult<'tcx> {
+ ) -> EvalToConstValueResult<'tcx> {
match ty::Instance::resolve_opt_const_arg(self, param_env, def, substs) {
Ok(Some(instance)) => {
let cid = GlobalId { instance, promoted };
param_env: ty::ParamEnv<'tcx>,
instance: ty::Instance<'tcx>,
span: Option<Span>,
- ) -> ConstEvalResult<'tcx> {
+ ) -> EvalToConstValueResult<'tcx> {
self.const_eval_global_id(param_env, GlobalId { instance, promoted: None }, span)
}
param_env: ty::ParamEnv<'tcx>,
cid: GlobalId<'tcx>,
span: Option<Span>,
- ) -> ConstEvalResult<'tcx> {
+ ) -> EvalToConstValueResult<'tcx> {
// Const-eval shouldn't depend on lifetimes at all, so we can erase them, which should
// improve caching of queries.
let inputs = self.erase_regions(¶m_env.and(cid));
if let Some(span) = span {
- self.at(span).const_eval_validated(inputs)
+ self.at(span).eval_to_const_value_raw(inputs)
} else {
- self.const_eval_validated(inputs)
+ self.eval_to_const_value_raw(inputs)
}
}
param_env: ty::ParamEnv<'tcx>,
) -> Result<&'tcx mir::Allocation, ErrorHandled> {
trace!("eval_to_allocation: Need to compute {:?}", gid);
- let raw_const = self.const_eval_raw(param_env.and(gid))?;
+ let raw_const = self.eval_to_allocation_raw(param_env.and(gid))?;
Ok(self.global_alloc(raw_const.alloc_id).unwrap_memory())
}
}
use super::{sign_extend, truncate, AllocId, Allocation, InterpResult, Pointer, PointerArithmetic};
-/// Represents the result of a raw const operation, pre-validation.
+/// Represents the result of const evaluation via the `eval_to_allocation` query.
#[derive(Clone, HashStable)]
-pub struct RawConst<'tcx> {
+pub struct ConstAlloc<'tcx> {
// the value lives here, at offset 0, and that allocation definitely is a `AllocKind::Memory`
// (so you can use `AllocMap::unwrap_memory`).
pub alloc_id: AllocId,
Uninit,
}
+#[cfg(target_arch = "x86_64")]
+static_assert_size!(ScalarMaybeUninit, 24);
+
impl<Tag> From<Scalar<Tag>> for ScalarMaybeUninit<Tag> {
#[inline(always)]
fn from(s: Scalar<Tag>) -> Self {
use self::predecessors::{PredecessorCache, Predecessors};
pub use self::query::*;
+pub mod abstract_const;
pub mod coverage;
pub mod interpret;
pub mod mono;
// BasicBlock
rustc_index::newtype_index! {
+ /// A node in the MIR [control-flow graph][CFG].
+ ///
+ /// There are no branches (e.g., `if`s, function calls, etc.) within a basic block, which makes
+ /// it easier to do [data-flow analyses] and optimizations. Instead, branches are represented
+ /// as an edge in a graph between basic blocks.
+ ///
+ /// Basic blocks consist of a series of [statements][Statement], ending with a
+ /// [terminator][Terminator]. Basic blocks can have multiple predecessors and successors,
+ /// however there is a MIR pass ([`CriticalCallEdges`]) that removes *critical edges*, which
+ /// are edges that go from a multi-successor node to a multi-predecessor node. This pass is
+ /// needed because some analyses require that there are no critical edges in the CFG.
+ ///
+ /// Read more about basic blocks in the [rustc-dev-guide][guide-mir].
+ ///
+ /// [CFG]: https://rustc-dev-guide.rust-lang.org/appendix/background.html#cfg
+ /// [data-flow analyses]:
+ /// https://rustc-dev-guide.rust-lang.org/appendix/background.html#what-is-a-dataflow-analysis
+ /// [`CriticalCallEdges`]: ../../rustc_mir/transform/add_call_guards/enum.AddCallGuards.html#variant.CriticalCallEdges
+ /// [guide-mir]: https://rustc-dev-guide.rust-lang.org/mir/
pub struct BasicBlock {
derive [HashStable]
DEBUG_FORMAT = "bb{}",
///////////////////////////////////////////////////////////////////////////
// BasicBlockData and Terminator
+/// See [`BasicBlock`] for documentation on what basic blocks are at a high level.
#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable)]
pub struct BasicBlockData<'tcx> {
/// List of statements in this block.
/// Constants
///
/// Two constants are equal if they are the same constant. Note that
-/// this does not necessarily mean that they are `==` in Rust -- in
+/// this does not necessarily mean that they are `==` in Rust. In
/// particular, one must be wary of `NaN`!
#[derive(Clone, Copy, PartialEq, TyEncodable, TyDecodable, HashStable)]
no_hash
}
+ /// Try to build an abstract representation of the given constant.
+ query mir_abstract_const(
+ key: DefId
+ ) -> Option<&'tcx [mir::abstract_const::Node<'tcx>]> {
+ desc {
+ |tcx| "building an abstract representation for {}", tcx.def_path_str(key),
+ }
+ }
+ /// Try to build an abstract representation of the given constant.
+ query mir_abstract_const_of_const_arg(
+ key: (LocalDefId, DefId)
+ ) -> Option<&'tcx [mir::abstract_const::Node<'tcx>]> {
+ desc {
+ |tcx|
+ "building an abstract representation for the const argument {}",
+ tcx.def_path_str(key.0.to_def_id()),
+ }
+ }
+
+ query try_unify_abstract_consts(key: (
+ (ty::WithOptConstParam<DefId>, SubstsRef<'tcx>),
+ (ty::WithOptConstParam<DefId>, SubstsRef<'tcx>)
+ )) -> bool {
+ desc {
+ |tcx| "trying to unify the generic constants {} and {}",
+ tcx.def_path_str(key.0.0.did), tcx.def_path_str(key.1.0.did)
+ }
+ }
+
query mir_drops_elaborated_and_const_checked(
key: ty::WithOptConstParam<LocalDefId>
) -> &'tcx Steal<mir::Body<'tcx>> {
}
Other {
- /// Evaluates a constant without running sanity checks.
+ /// Evaluates a constant and returns the computed allocation.
///
- /// **Do not use this** outside const eval. Const eval uses this to break query cycles
- /// during validation. Please add a comment to every use site explaining why using
- /// `const_eval_validated` isn't sufficient. The returned constant also isn't in a suitable
- /// form to be used outside of const eval.
- query const_eval_raw(key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>)
- -> ConstEvalRawResult<'tcx> {
+ /// **Do not use this** directly, use the `tcx.eval_static_initializer` wrapper.
+ query eval_to_allocation_raw(key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>)
+ -> EvalToAllocationRawResult<'tcx> {
desc { |tcx|
- "const-evaluating `{}`",
+ "const-evaluating + checking `{}`",
key.value.display(tcx)
}
}
- /// Results of evaluating const items or constants embedded in
- /// other items (such as enum variant explicit discriminants).
- ///
- /// In contrast to `const_eval_raw` this performs some validation on the constant, and
- /// returns a proper constant that is usable by the rest of the compiler.
+ /// Evaluates const items or anonymous constants
+ /// (such as enum variant explicit discriminants or array lengths)
+ /// into a representation suitable for the type system and const generics.
///
/// **Do not use this** directly, use one of the following wrappers: `tcx.const_eval_poly`,
/// `tcx.const_eval_resolve`, `tcx.const_eval_instance`, or `tcx.const_eval_global_id`.
- query const_eval_validated(key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>)
- -> ConstEvalResult<'tcx> {
+ query eval_to_const_value_raw(key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>)
+ -> EvalToConstValueResult<'tcx> {
desc { |tcx|
- "const-evaluating + checking `{}`",
+ "simplifying constant for the type system `{}`",
key.value.display(tcx)
}
cache_on_disk_if(_, opt_result) {
}
}
+impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [mir::abstract_const::Node<'tcx>] {
+ fn decode(decoder: &mut D) -> Result<&'tcx Self, D::Error> {
+ Ok(decoder.tcx().arena.alloc_from_iter(
+ (0..decoder.read_usize()?)
+ .map(|_| Decodable::decode(decoder))
+ .collect::<Result<Vec<_>, _>>()?,
+ ))
+ }
+}
+
+impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [mir::abstract_const::NodeId] {
+ fn decode(decoder: &mut D) -> Result<&'tcx Self, D::Error> {
+ Ok(decoder.tcx().arena.alloc_from_iter(
+ (0..decoder.read_usize()?)
+ .map(|_| Decodable::decode(decoder))
+ .collect::<Result<Vec<_>, _>>()?,
+ ))
+ }
+}
+
impl_decodable_via_ref! {
&'tcx ty::TypeckResults<'tcx>,
&'tcx ty::List<Ty<'tcx>>,
eps: &[ExistentialPredicate<'tcx>],
) -> &'tcx List<ExistentialPredicate<'tcx>> {
assert!(!eps.is_empty());
- assert!(eps.windows(2).all(|w| w[0].stable_cmp(self, &w[1]) != Ordering::Greater));
+ assert!(eps.array_windows().all(|[a, b]| a.stable_cmp(self, b) != Ordering::Greater));
self._intern_existential_predicates(eps)
}
/// `<fn() as FnTrait>::call_*` (generated `FnTrait` implementation for `fn()` pointers).
///
/// `DefId` is `FnTrait::call_*`.
- ///
- /// NB: the (`fn` pointer) type must currently be monomorphic to avoid double substitution
- /// problems with the MIR shim bodies. `Instance::resolve` enforces this.
- // FIXME(#69925) support polymorphic MIR shim bodies properly instead.
FnPtrShim(DefId, Ty<'tcx>),
/// Dynamic dispatch to `<dyn Trait as Trait>::fn`.
/// The `DefId` is for `core::ptr::drop_in_place`.
/// The `Option<Ty<'tcx>>` is either `Some(T)`, or `None` for empty drop
/// glue.
- ///
- /// NB: the type must currently be monomorphic to avoid double substitution
- /// problems with the MIR shim bodies. `Instance::resolve` enforces this.
- // FIXME(#69925) support polymorphic MIR shim bodies properly instead.
DropGlue(DefId, Option<Ty<'tcx>>),
/// Compiler-generated `<T as Clone>::clone` implementation.
/// Additionally, arrays, tuples, and closures get a `Clone` shim even if they aren't `Copy`.
///
/// The `DefId` is for `Clone::clone`, the `Ty` is the type `T` with the builtin `Clone` impl.
- ///
- /// NB: the type must currently be monomorphic to avoid double substitution
- /// problems with the MIR shim bodies. `Instance::resolve` enforces this.
- // FIXME(#69925) support polymorphic MIR shim bodies properly instead.
CloneShim(DefId, Ty<'tcx>),
}
_ => false,
}
}
+
+ /// Returns `true` when the MIR body associated with this instance should be monomorphized
+ /// by its users (e.g. codegen or miri) by substituting the `substs` from `Instance` (see
+ /// `Instance::substs_for_mir_body`).
+ ///
+ /// Otherwise, returns `false` only for some kinds of shims where the construction of the MIR
+ /// body should perform necessary substitutions.
+ pub fn has_polymorphic_mir_body(&self) -> bool {
+ match *self {
+ InstanceDef::CloneShim(..)
+ | InstanceDef::FnPtrShim(..)
+ | InstanceDef::DropGlue(_, Some(_)) => false,
+ InstanceDef::ClosureOnceShim { .. }
+ | InstanceDef::DropGlue(..)
+ | InstanceDef::Item(_)
+ | InstanceDef::Intrinsic(..)
+ | InstanceDef::ReifyShim(..)
+ | InstanceDef::Virtual(..)
+ | InstanceDef::VtableShim(..) => true,
+ }
+ }
}
impl<'tcx> fmt::Display for Instance<'tcx> {
Instance { def, substs }
}
- /// FIXME(#69925) Depending on the kind of `InstanceDef`, the MIR body associated with an
+ /// Depending on the kind of `InstanceDef`, the MIR body associated with an
/// instance is expressed in terms of the generic parameters of `self.def_id()`, and in other
/// cases the MIR body is expressed in terms of the types found in the substitution array.
/// In the former case, we want to substitute those generic types and replace them with the
/// values from the substs when monomorphizing the function body. But in the latter case, we
/// don't want to do that substitution, since it has already been done effectively.
///
- /// This function returns `Some(substs)` in the former case and None otherwise -- i.e., if
+ /// This function returns `Some(substs)` in the former case and `None` otherwise -- i.e., if
/// this function returns `None`, then the MIR body does not require substitution during
- /// monomorphization.
+ /// codegen.
pub fn substs_for_mir_body(&self) -> Option<SubstsRef<'tcx>> {
- match self.def {
- InstanceDef::CloneShim(..)
- | InstanceDef::DropGlue(_, Some(_)) => None,
- InstanceDef::ClosureOnceShim { .. }
- | InstanceDef::DropGlue(..)
- // FIXME(#69925): `FnPtrShim` should be in the other branch.
- | InstanceDef::FnPtrShim(..)
- | InstanceDef::Item(_)
- | InstanceDef::Intrinsic(..)
- | InstanceDef::ReifyShim(..)
- | InstanceDef::Virtual(..)
- | InstanceDef::VtableShim(..) => Some(self.substs),
- }
+ if self.def.has_polymorphic_mir_body() { Some(self.substs) } else { None }
}
/// Returns a new `Instance` where generic parameters in `instance.substs` are replaced by
flags: VariantFlags,
}
-impl<'tcx> VariantDef {
+impl VariantDef {
/// Creates a new `VariantDef`.
///
/// `variant_did` is the `DefId` that identifies the enum variant (if this `VariantDef`
pub fn is_recovered(&self) -> bool {
self.flags.intersects(VariantFlags::IS_RECOVERED)
}
-
- /// `repr(transparent)` structs can have a single non-ZST field, this function returns that
- /// field.
- pub fn transparent_newtype_field(&self, tcx: TyCtxt<'tcx>) -> Option<&FieldDef> {
- for field in &self.fields {
- let field_ty = field.ty(tcx, InternalSubsts::identity_for_item(tcx, self.def_id));
- if !field_ty.is_zst(tcx, self.def_id) {
- return Some(field);
- }
- }
-
- None
- }
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)]
// RFC for reference.
use crate::ty::subst::{GenericArg, GenericArgKind};
+use crate::ty::walk::MiniSet;
use crate::ty::{self, Ty, TyCtxt, TypeFoldable};
use smallvec::SmallVec;
/// Push onto `out` all the things that must outlive `'a` for the condition
/// `ty0: 'a` to hold. Note that `ty0` must be a **fully resolved type**.
pub fn push_outlives_components(self, ty0: Ty<'tcx>, out: &mut SmallVec<[Component<'tcx>; 4]>) {
- compute_components(self, ty0, out);
+ let mut visited = MiniSet::new();
+ compute_components(self, ty0, out, &mut visited);
debug!("components({:?}) = {:?}", ty0, out);
}
}
-fn compute_components(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, out: &mut SmallVec<[Component<'tcx>; 4]>) {
+fn compute_components(
+ tcx: TyCtxt<'tcx>,
+ ty: Ty<'tcx>,
+ out: &mut SmallVec<[Component<'tcx>; 4]>,
+ visited: &mut MiniSet<GenericArg<'tcx>>,
+) {
// Descend through the types, looking for the various "base"
// components and collecting them into `out`. This is not written
// with `collect()` because of the need to sometimes skip subtrees
for child in substs {
match child.unpack() {
GenericArgKind::Type(ty) => {
- compute_components(tcx, ty, out);
+ compute_components(tcx, ty, out, visited);
}
GenericArgKind::Lifetime(_) => {}
GenericArgKind::Const(_) => {
- compute_components_recursive(tcx, child, out);
+ compute_components_recursive(tcx, child, out, visited);
}
}
}
ty::Array(element, _) => {
// Don't look into the len const as it doesn't affect regions
- compute_components(tcx, element, out);
+ compute_components(tcx, element, out, visited);
}
ty::Closure(_, ref substs) => {
for upvar_ty in substs.as_closure().upvar_tys() {
- compute_components(tcx, upvar_ty, out);
+ compute_components(tcx, upvar_ty, out, visited);
}
}
ty::Generator(_, ref substs, _) => {
// Same as the closure case
for upvar_ty in substs.as_generator().upvar_tys() {
- compute_components(tcx, upvar_ty, out);
+ compute_components(tcx, upvar_ty, out, visited);
}
// We ignore regions in the generator interior as we don't
// OutlivesProjectionComponents. Continue walking
// through and constrain Pi.
let mut subcomponents = smallvec![];
- compute_components_recursive(tcx, ty.into(), &mut subcomponents);
+ let mut subvisited = MiniSet::new();
+ compute_components_recursive(tcx, ty.into(), &mut subcomponents, &mut subvisited);
out.push(Component::EscapingProjection(subcomponents.into_iter().collect()));
}
}
// the "bound regions list". In our representation, no such
// list is maintained explicitly, because bound regions
// themselves can be readily identified.
- compute_components_recursive(tcx, ty.into(), out);
+ compute_components_recursive(tcx, ty.into(), out, visited);
}
}
}
tcx: TyCtxt<'tcx>,
parent: GenericArg<'tcx>,
out: &mut SmallVec<[Component<'tcx>; 4]>,
+ visited: &mut MiniSet<GenericArg<'tcx>>,
) {
- for child in parent.walk_shallow() {
+ for child in parent.walk_shallow(visited) {
match child.unpack() {
GenericArgKind::Type(ty) => {
- compute_components(tcx, ty, out);
+ compute_components(tcx, ty, out, visited);
}
GenericArgKind::Lifetime(lt) => {
// Ignore late-bound regions.
}
}
GenericArgKind::Const(_) => {
- compute_components_recursive(tcx, child, out);
+ compute_components_recursive(tcx, child, out, visited);
}
}
}
use rustc_data_structures::fx::FxHashSet;
use rustc_hir::def_id::{CrateNum, DefId};
use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData};
+use rustc_middle::ty::walk::MiniSet;
// `pretty` is a separate module only for organization.
mod pretty;
/// function tries to find a "characteristic `DefId`" for a
/// type. It's just a heuristic so it makes some questionable
/// decisions and we may want to adjust it later.
-pub fn characteristic_def_id_of_type(ty: Ty<'_>) -> Option<DefId> {
+///
+/// Visited set is needed to avoid full iteration over
+/// deeply nested tuples that have no DefId.
+fn characteristic_def_id_of_type_cached<'a>(
+ ty: Ty<'a>,
+ visited: &mut MiniSet<Ty<'a>>,
+) -> Option<DefId> {
match *ty.kind() {
ty::Adt(adt_def, _) => Some(adt_def.did),
ty::Dynamic(data, ..) => data.principal_def_id(),
- ty::Array(subty, _) | ty::Slice(subty) => characteristic_def_id_of_type(subty),
+ ty::Array(subty, _) | ty::Slice(subty) => {
+ characteristic_def_id_of_type_cached(subty, visited)
+ }
- ty::RawPtr(mt) => characteristic_def_id_of_type(mt.ty),
+ ty::RawPtr(mt) => characteristic_def_id_of_type_cached(mt.ty, visited),
- ty::Ref(_, ty, _) => characteristic_def_id_of_type(ty),
+ ty::Ref(_, ty, _) => characteristic_def_id_of_type_cached(ty, visited),
- ty::Tuple(ref tys) => {
- tys.iter().find_map(|ty| characteristic_def_id_of_type(ty.expect_ty()))
- }
+ ty::Tuple(ref tys) => tys.iter().find_map(|ty| {
+ let ty = ty.expect_ty();
+ if visited.insert(ty) {
+ return characteristic_def_id_of_type_cached(ty, visited);
+ }
+ return None;
+ }),
ty::FnDef(def_id, _)
| ty::Closure(def_id, _)
| ty::Float(_) => None,
}
}
+pub fn characteristic_def_id_of_type(ty: Ty<'_>) -> Option<DefId> {
+ characteristic_def_id_of_type_cached(ty, &mut MiniSet::new())
+}
impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> for ty::RegionKind {
type Output = P::Region;
used_region_names: FxHashSet<Symbol>,
region_index: usize,
binder_depth: usize,
+ printed_type_count: usize,
pub region_highlight_mode: RegionHighlightMode,
used_region_names: Default::default(),
region_index: 0,
binder_depth: 0,
+ printed_type_count: 0,
region_highlight_mode: RegionHighlightMode::default(),
name_resolver: None,
}))
self.pretty_print_region(region)
}
- fn print_type(self, ty: Ty<'tcx>) -> Result<Self::Type, Self::Error> {
- self.pretty_print_type(ty)
+ fn print_type(mut self, ty: Ty<'tcx>) -> Result<Self::Type, Self::Error> {
+ if self.tcx.sess.type_length_limit().value_within_limit(self.printed_type_count) {
+ self.printed_type_count += 1;
+ self.pretty_print_type(ty)
+ } else {
+ write!(self, "...")?;
+ Ok(self)
+ }
}
fn print_dyn_existential(
}
}
+impl<'tcx> Key
+ for (
+ (ty::WithOptConstParam<DefId>, SubstsRef<'tcx>),
+ (ty::WithOptConstParam<DefId>, SubstsRef<'tcx>),
+ )
+{
+ type CacheSelector = DefaultCacheSelector;
+
+ fn query_crate(&self) -> CrateNum {
+ (self.0).0.did.krate
+ }
+ fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
+ (self.0).0.did.default_span(tcx)
+ }
+}
+
impl<'tcx> Key for (LocalDefId, DefId, SubstsRef<'tcx>) {
type CacheSelector = DefaultCacheSelector;
use crate::middle::stability::{self, DeprecationEntry};
use crate::mir;
use crate::mir::interpret::GlobalId;
-use crate::mir::interpret::{ConstEvalRawResult, ConstEvalResult, ConstValue};
+use crate::mir::interpret::{ConstValue, EvalToAllocationRawResult, EvalToConstValueResult};
use crate::mir::interpret::{LitToConstError, LitToConstInput};
use crate::mir::mono::CodegenUnit;
use crate::traits::query::{
}
}
+impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx [mir::abstract_const::Node<'tcx>] {
+ fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> {
+ RefDecodable::decode(d)
+ }
+}
+
impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx [(ty::Predicate<'tcx>, Span)] {
fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> {
RefDecodable::decode(d)
new_val.map(ty::ConstKind::Value)
}
- // FIXME(const_generics): this is wrong, as it is a projection
+ (
+ ty::ConstKind::Unevaluated(a_def, a_substs, None),
+ ty::ConstKind::Unevaluated(b_def, b_substs, None),
+ ) if tcx.features().const_evaluatable_checked => {
+ if tcx.try_unify_abstract_consts(((a_def, a_substs), (b_def, b_substs))) {
+ Ok(a.val)
+ } else {
+ Err(TypeError::ConstMismatch(expected_found(relation, a, b)))
+ }
+ }
+
+ // While this is slightly incorrect, it shouldn't matter for `min_const_generics`
+ // and is the better alternative to waiting until `const_evaluatable_checked` can
+ // be stabilized.
(
ty::ConstKind::Unevaluated(a_def, a_substs, a_promoted),
ty::ConstKind::Unevaluated(b_def, b_substs, b_promoted),
}
}
}
-
- /// Is this a zero-sized type?
- pub fn is_zst(&'tcx self, tcx: TyCtxt<'tcx>, did: DefId) -> bool {
- tcx.layout_of(tcx.param_env(did).and(self)).map(|layout| layout.is_zst()).unwrap_or(false)
- }
}
use crate::ty;
use crate::ty::subst::{GenericArg, GenericArgKind};
+use arrayvec::ArrayVec;
+use rustc_data_structures::fx::FxHashSet;
use smallvec::{self, SmallVec};
+use std::hash::Hash;
+
+/// Small-storage-optimized implementation of a set
+/// made specifically for walking type tree.
+///
+/// Stores elements in a small array up to a certain length
+/// and switches to `HashSet` when that length is exceeded.
+pub enum MiniSet<T> {
+ Array(ArrayVec<[T; 8]>),
+ Set(FxHashSet<T>),
+}
+
+impl<T: Eq + Hash + Copy> MiniSet<T> {
+ /// Creates an empty `MiniSet`.
+ pub fn new() -> Self {
+ MiniSet::Array(ArrayVec::new())
+ }
+
+ /// Adds a value to the set.
+ ///
+ /// If the set did not have this value present, true is returned.
+ ///
+ /// If the set did have this value present, false is returned.
+ pub fn insert(&mut self, elem: T) -> bool {
+ match self {
+ MiniSet::Array(array) => {
+ if array.iter().any(|e| *e == elem) {
+ false
+ } else {
+ if array.try_push(elem).is_err() {
+ let mut set: FxHashSet<T> = array.iter().copied().collect();
+ set.insert(elem);
+ *self = MiniSet::Set(set);
+ }
+ true
+ }
+ }
+ MiniSet::Set(set) => set.insert(elem),
+ }
+ }
+}
// The TypeWalker's stack is hot enough that it's worth going to some effort to
// avoid heap allocations.
pub struct TypeWalker<'tcx> {
stack: TypeWalkerStack<'tcx>,
last_subtree: usize,
+ visited: MiniSet<GenericArg<'tcx>>,
}
+/// An iterator for walking the type tree.
+///
+/// It's very easy to produce a deeply
+/// nested type tree with a lot of
+/// identical subtrees. In order to work efficiently
+/// in this situation walker only visits each type once.
+/// It maintains a set of visited types and
+/// skips any types that are already there.
impl<'tcx> TypeWalker<'tcx> {
- pub fn new(root: GenericArg<'tcx>) -> TypeWalker<'tcx> {
- TypeWalker { stack: smallvec![root], last_subtree: 1 }
+ pub fn new(root: GenericArg<'tcx>) -> Self {
+ Self { stack: smallvec![root], last_subtree: 1, visited: MiniSet::new() }
}
/// Skips the subtree corresponding to the last type
fn next(&mut self) -> Option<GenericArg<'tcx>> {
debug!("next(): stack={:?}", self.stack);
- let next = self.stack.pop()?;
- self.last_subtree = self.stack.len();
- push_inner(&mut self.stack, next);
- debug!("next: stack={:?}", self.stack);
- Some(next)
+ loop {
+ let next = self.stack.pop()?;
+ self.last_subtree = self.stack.len();
+ if self.visited.insert(next) {
+ push_inner(&mut self.stack, next);
+ debug!("next: stack={:?}", self.stack);
+ return Some(next);
+ }
+ }
}
}
/// Iterator that walks the immediate children of `self`. Hence
/// `Foo<Bar<i32>, u32>` yields the sequence `[Bar<i32>, u32]`
/// (but not `i32`, like `walk`).
- pub fn walk_shallow(self) -> impl Iterator<Item = GenericArg<'tcx>> {
+ ///
+ /// Iterator only walks items once.
+ /// It accepts visited set, updates it with all visited types
+ /// and skips any types that are already there.
+ pub fn walk_shallow(
+ self,
+ visited: &mut MiniSet<GenericArg<'tcx>>,
+ ) -> impl Iterator<Item = GenericArg<'tcx>> {
let mut stack = SmallVec::new();
push_inner(&mut stack, self);
+ stack.retain(|a| visited.insert(*a));
stack.into_iter()
}
}
{
if let Ok(pat_snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(pat_span)
{
- if pat_snippet.starts_with('&') {
- let pat_snippet = pat_snippet[1..].trim_start();
+ if let Some(stripped) = pat_snippet.strip_prefix('&') {
+ let pat_snippet = stripped.trim_start();
let (suggestion, to_remove) = if pat_snippet.starts_with("mut")
&& pat_snippet["mut".len()..].starts_with(rustc_lexer::is_whitespace)
{
let lt_name = &src[1..ws_pos];
let ty = &src[ws_pos..];
return (assignment_rhs_span, format!("&{} mut {}", lt_name, ty));
- } else if src.starts_with('&') {
- let borrowed_expr = &src[1..];
- return (assignment_rhs_span, format!("&mut {}", borrowed_expr));
+ } else if let Some(stripped) = src.strip_prefix('&') {
+ return (assignment_rhs_span, format!("&mut {}", stripped));
}
}
}
// should just replace 'a with 'static.
// 3) Suggest unifying 'a with 'b if we have both 'a: 'b and 'b: 'a
- if outlived.iter().any(|(_, outlived_name)| {
- if let RegionNameSource::Static = outlived_name.source { true } else { false }
- }) {
+ if outlived
+ .iter()
+ .any(|(_, outlived_name)| matches!(outlived_name.source, RegionNameSource::Static))
+ {
suggested.push(SuggestedConstraint::Static(fr_name));
} else {
// We want to isolate out all lifetimes that should be unified and print out
use super::{CompileTimeEvalContext, CompileTimeInterpreter, ConstEvalErr, MemoryExtra};
use crate::interpret::eval_nullary_intrinsic;
use crate::interpret::{
- intern_const_alloc_recursive, Allocation, ConstValue, GlobalId, Immediate, InternKind,
- InterpCx, InterpResult, MPlaceTy, MemoryKind, OpTy, RawConst, RefTracking, Scalar,
+ intern_const_alloc_recursive, Allocation, ConstAlloc, ConstValue, GlobalId, Immediate,
+ InternKind, InterpCx, InterpResult, MPlaceTy, MemoryKind, OpTy, RefTracking, Scalar,
ScalarMaybeUninit, StackPopCleanup,
};
)
}
+/// This function converts an interpreter value into a constant that is meant for use in the
+/// type system.
pub(super) fn op_to_const<'tcx>(
ecx: &CompileTimeEvalContext<'_, 'tcx>,
op: OpTy<'tcx>,
}
}
-fn validate_and_turn_into_const<'tcx>(
+fn turn_into_const_value<'tcx>(
tcx: TyCtxt<'tcx>,
- constant: RawConst<'tcx>,
+ constant: ConstAlloc<'tcx>,
key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>,
-) -> ::rustc_middle::mir::interpret::ConstEvalResult<'tcx> {
+) -> ConstValue<'tcx> {
let cid = key.value;
let def_id = cid.instance.def.def_id();
let is_static = tcx.is_static(def_id);
let ecx = mk_eval_cx(tcx, tcx.def_span(key.value.instance.def_id()), key.param_env, is_static);
- let val = (|| {
- let mplace = ecx.raw_const_to_mplace(constant)?;
- // FIXME do not validate promoteds until a decision on
- // https://github.com/rust-lang/rust/issues/67465 is made
- if cid.promoted.is_none() {
- let mut ref_tracking = RefTracking::new(mplace);
- while let Some((mplace, path)) = ref_tracking.todo.pop() {
- ecx.const_validate_operand(
- mplace.into(),
- path,
- &mut ref_tracking,
- /*may_ref_to_static*/ ecx.memory.extra.can_access_statics,
- )?;
- }
- }
- // Now that we validated, turn this into a proper constant.
- // Statics/promoteds are always `ByRef`, for the rest `op_to_const` decides
- // whether they become immediates.
- if is_static || cid.promoted.is_some() {
- let ptr = mplace.ptr.assert_ptr();
- Ok(ConstValue::ByRef {
- alloc: ecx.tcx.global_alloc(ptr.alloc_id).unwrap_memory(),
- offset: ptr.offset,
- })
- } else {
- Ok(op_to_const(&ecx, mplace.into()))
- }
- })();
-
- val.map_err(|error| {
- let err = ConstEvalErr::new(&ecx, error, None);
- err.struct_error(ecx.tcx, "it is undefined behavior to use this value", |mut diag| {
- diag.note(note_on_undefined_behavior_error());
- diag.emit();
- })
- })
+ let mplace = ecx.raw_const_to_mplace(constant).expect(
+ "can only fail if layout computation failed, \
+ which should have given a good error before ever invoking this function",
+ );
+ assert!(
+ !is_static || cid.promoted.is_some(),
+ "the `eval_to_const_value_raw` query should not be used for statics, use `eval_to_allocation` instead"
+ );
+ // Turn this into a proper constant.
+ op_to_const(&ecx, mplace.into())
}
-pub fn const_eval_validated_provider<'tcx>(
+pub fn eval_to_const_value_raw_provider<'tcx>(
tcx: TyCtxt<'tcx>,
key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>,
-) -> ::rustc_middle::mir::interpret::ConstEvalResult<'tcx> {
+) -> ::rustc_middle::mir::interpret::EvalToConstValueResult<'tcx> {
// see comment in const_eval_raw_provider for what we're doing here
if key.param_env.reveal() == Reveal::All {
let mut key = key;
key.param_env = key.param_env.with_user_facing();
- match tcx.const_eval_validated(key) {
+ match tcx.eval_to_const_value_raw(key) {
// try again with reveal all as requested
Err(ErrorHandled::TooGeneric) => {}
// deduplicate calls
});
}
- tcx.const_eval_raw(key).and_then(|val| validate_and_turn_into_const(tcx, val, key))
+ tcx.eval_to_allocation_raw(key).map(|val| turn_into_const_value(tcx, val, key))
}
-pub fn const_eval_raw_provider<'tcx>(
+pub fn eval_to_allocation_raw_provider<'tcx>(
tcx: TyCtxt<'tcx>,
key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>,
-) -> ::rustc_middle::mir::interpret::ConstEvalRawResult<'tcx> {
+) -> ::rustc_middle::mir::interpret::EvalToAllocationRawResult<'tcx> {
// Because the constant is computed twice (once per value of `Reveal`), we are at risk of
// reporting the same error twice here. To resolve this, we check whether we can evaluate the
// constant in the more restrictive `Reveal::UserFacing`, which most likely already was
if key.param_env.reveal() == Reveal::All {
let mut key = key;
key.param_env = key.param_env.with_user_facing();
- match tcx.const_eval_raw(key) {
+ match tcx.eval_to_allocation_raw(key) {
// try again with reveal all as requested
Err(ErrorHandled::TooGeneric) => {}
// deduplicate calls
);
let res = ecx.load_mir(cid.instance.def, cid.promoted);
- res.and_then(|body| eval_body_using_ecx(&mut ecx, cid, &body))
- .map(|place| RawConst { alloc_id: place.ptr.assert_ptr().alloc_id, ty: place.layout.ty })
- .map_err(|error| {
+ match res.and_then(|body| eval_body_using_ecx(&mut ecx, cid, &body)) {
+ Err(error) => {
let err = ConstEvalErr::new(&ecx, error, None);
// errors in statics are always emitted as fatal errors
if is_static {
);
}
- v
+ Err(v)
} else if let Some(def) = def.as_local() {
// constant defined in this crate, we can figure out a lint level!
match tcx.def_kind(def.did.to_def_id()) {
// compatibility hazard
DefKind::Const | DefKind::AssocConst => {
let hir_id = tcx.hir().local_def_id_to_hir_id(def.did);
- err.report_as_lint(
+ Err(err.report_as_lint(
tcx.at(tcx.def_span(def.did)),
"any use of this value will cause an error",
hir_id,
Some(err.span),
- )
+ ))
}
// promoting runtime code is only allowed to error if it references broken
// constants any other kind of error will be reported to the user as a
if let Some(p) = cid.promoted {
let span = tcx.promoted_mir_of_opt_const_arg(def.to_global())[p].span;
if let err_inval!(ReferencedConstant) = err.error {
- err.report_as_error(
+ Err(err.report_as_error(
tcx.at(span),
"evaluation of constant expression failed",
- )
+ ))
} else {
- err.report_as_lint(
+ Err(err.report_as_lint(
tcx.at(span),
"reaching this expression at runtime will panic or abort",
tcx.hir().local_def_id_to_hir_id(def.did),
Some(err.span),
- )
+ ))
}
// anything else (array lengths, enum initializers, constant patterns) are
// reported as hard errors
} else {
- err.report_as_error(
+ Err(err.report_as_error(
ecx.tcx.at(ecx.cur_span()),
"evaluation of constant value failed",
- )
+ ))
}
}
}
} else {
// use of broken constant from other crate
- err.report_as_error(ecx.tcx.at(ecx.cur_span()), "could not evaluate constant")
+ Err(err.report_as_error(ecx.tcx.at(ecx.cur_span()), "could not evaluate constant"))
}
- })
+ }
+ Ok(mplace) => {
+ // Since evaluation had no errors, valiate the resulting constant:
+ let validation = try {
+ // FIXME do not validate promoteds until a decision on
+ // https://github.com/rust-lang/rust/issues/67465 is made
+ if cid.promoted.is_none() {
+ let mut ref_tracking = RefTracking::new(mplace);
+ while let Some((mplace, path)) = ref_tracking.todo.pop() {
+ ecx.const_validate_operand(
+ mplace.into(),
+ path,
+ &mut ref_tracking,
+ /*may_ref_to_static*/ ecx.memory.extra.can_access_statics,
+ )?;
+ }
+ }
+ };
+ if let Err(error) = validation {
+ // Validation failed, report an error
+ let err = ConstEvalErr::new(&ecx, error, None);
+ Err(err.struct_error(
+ ecx.tcx,
+ "it is undefined behavior to use this value",
+ |mut diag| {
+ diag.note(note_on_undefined_behavior_error());
+ diag.emit();
+ },
+ ))
+ } else {
+ // Convert to raw constant
+ Ok(ConstAlloc { alloc_id: mplace.ptr.assert_ptr().alloc_id, ty: mplace.layout.ty })
+ }
+ }
+ }
}
let gid = GlobalId { instance, promoted: None };
- let place = self.const_eval_raw(gid)?;
+ let place = self.eval_to_allocation(gid)?;
self.copy_op(place.into(), dest)?;
//! A helpful diagram for debugging dataflow problems.
use std::borrow::Cow;
+use std::lazy::SyncOnceCell;
use std::{io, ops, str};
use regex::Regex;
}
}
+macro_rules! regex {
+ ($re:literal $(,)?) => {{
+ static RE: SyncOnceCell<regex::Regex> = SyncOnceCell::new();
+ RE.get_or_init(|| Regex::new($re).unwrap())
+ }};
+}
+
fn diff_pretty<T, C>(new: T, old: T, ctxt: &C) -> String
where
T: DebugWithContext<C>,
return String::new();
}
- let re = Regex::new("\t?\u{001f}([+-])").unwrap();
+ let re = regex!("\t?\u{001f}([+-])");
let raw_diff = format!("{:#?}", DebugDiffWithAdapter { new, old, ctxt });
/// `EverInitializedPlaces` tracks all places that might have ever been
/// initialized upon reaching a particular point in the control flow
-/// for a function, without an intervening `Storage Dead`.
+/// for a function, without an intervening `StorageDead`.
///
/// This dataflow is used to determine if an immutable local variable may
/// be assigned to.
use rustc_middle::ty::{self, TyCtxt};
use smallvec::{smallvec, SmallVec};
-use std::convert::TryInto;
use std::mem;
use super::abs_domain::Lift;
};
let base_ty = base_place.ty(self.builder.body, self.builder.tcx).ty;
let len: u64 = match base_ty.kind() {
- ty::Array(_, size) => {
- let length = size.eval_usize(self.builder.tcx, self.builder.param_env);
- length
- .try_into()
- .expect("slice pattern of array with more than u32::MAX elements")
- }
+ ty::Array(_, size) => size.eval_usize(self.builder.tcx, self.builder.param_env),
_ => bug!("from_end: false slice pattern of non-array type"),
};
for offset in from..to {
use rustc_target::abi::{Align, HasDataLayout, LayoutOf, Size, TargetDataLayout};
use super::{
- Immediate, MPlaceTy, Machine, MemPlace, MemPlaceMeta, Memory, OpTy, Operand, Place, PlaceTy,
+ Immediate, MPlaceTy, Machine, MemPlace, MemPlaceMeta, Memory, Operand, Place, PlaceTy,
ScalarMaybeUninit, StackPopJump,
};
use crate::transform::validate::equal_up_to_regions;
Ok(())
}
- pub(super) fn const_eval(
- &self,
- gid: GlobalId<'tcx>,
- ty: Ty<'tcx>,
- ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
- // For statics we pick `ParamEnv::reveal_all`, because statics don't have generics
- // and thus don't care about the parameter environment. While we could just use
- // `self.param_env`, that would mean we invoke the query to evaluate the static
- // with different parameter environments, thus causing the static to be evaluated
- // multiple times.
- let param_env = if self.tcx.is_static(gid.instance.def_id()) {
- ty::ParamEnv::reveal_all()
- } else {
- self.param_env
- };
- let val = self.tcx.const_eval_global_id(param_env, gid, Some(self.tcx.span))?;
-
- // Even though `ecx.const_eval` is called from `const_to_op` we can never have a
- // recursion deeper than one level, because the `tcx.const_eval` above is guaranteed to not
- // return `ConstValue::Unevaluated`, which is the only way that `const_to_op` will call
- // `ecx.const_eval`.
- let const_ = ty::Const { val: ty::ConstKind::Value(val), ty };
- self.const_to_op(&const_, None)
- }
-
- pub fn const_eval_raw(
+ pub fn eval_to_allocation(
&self,
gid: GlobalId<'tcx>,
) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
} else {
self.param_env
};
- // We use `const_eval_raw` here, and get an unvalidated result. That is okay:
- // Our result will later be validated anyway, and there seems no good reason
- // to have to fail early here. This is also more consistent with
- // `Memory::get_static_alloc` which has to use `const_eval_raw` to avoid cycles.
- // FIXME: We can hit delay_span_bug if this is an invalid const, interning finds
- // that problem, but we never run validation to show an error. Can we ensure
- // this does not happen?
- let val = self.tcx.const_eval_raw(param_env.and(gid))?;
+ let val = self.tcx.eval_to_allocation_raw(param_env.and(gid))?;
self.raw_const_to_mplace(val)
}
sym::type_name => self.tcx.mk_static_str(),
_ => bug!("already checked for nullary intrinsics"),
};
- let val = self.const_eval(gid, ty)?;
+ let val =
+ self.tcx.const_eval_global_id(self.param_env, gid, Some(self.tcx.span))?;
+ let const_ = ty::Const { val: ty::ConstKind::Value(val), ty };
+ let val = self.const_to_op(&const_, None)?;
self.copy_op(val, dest)?;
}
// Notice that every static has two `AllocId` that will resolve to the same
// thing here: one maps to `GlobalAlloc::Static`, this is the "lazy" ID,
// and the other one is maps to `GlobalAlloc::Memory`, this is returned by
- // `const_eval_raw` and it is the "resolved" ID.
+ // `eval_static_initializer` and it is the "resolved" ID.
// The resolved ID is never used by the interpreted program, it is hidden.
// This is relied upon for soundness of const-patterns; a pointer to the resolved
// ID would "sidestep" the checks that make sure consts do not point to statics!
ty::ConstKind::Error(_) => throw_inval!(TypeckError(ErrorReported)),
ty::ConstKind::Unevaluated(def, substs, promoted) => {
let instance = self.resolve(def.did, substs)?;
- // We use `const_eval` here and `const_eval_raw` elsewhere in mir interpretation.
- // The reason we use `const_eval_raw` everywhere else is to prevent cycles during
- // validation, because validation automatically reads through any references, thus
- // potentially requiring the current static to be evaluated again. This is not a
- // problem here, because we are building an operand which means an actual read is
- // happening.
- return Ok(self.const_eval(GlobalId { instance, promoted }, val.ty)?);
+ return Ok(self.eval_to_allocation(GlobalId { instance, promoted })?.into());
}
ty::ConstKind::Infer(..)
| ty::ConstKind::Bound(..)
use rustc_target::abi::{HasDataLayout, LayoutOf, Size, VariantIdx, Variants};
use super::{
- mir_assign_valid_types, truncate, AllocId, AllocMap, Allocation, AllocationExtra, ImmTy,
- Immediate, InterpCx, InterpResult, LocalValue, Machine, MemoryKind, OpTy, Operand, Pointer,
- PointerArithmetic, RawConst, Scalar, ScalarMaybeUninit,
+ mir_assign_valid_types, truncate, AllocId, AllocMap, Allocation, AllocationExtra, ConstAlloc,
+ ImmTy, Immediate, InterpCx, InterpResult, LocalValue, Machine, MemoryKind, OpTy, Operand,
+ Pointer, PointerArithmetic, Scalar, ScalarMaybeUninit,
};
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable)]
let n = base.len(self)?;
if n < min_length {
// This can only be reached in ConstProp and non-rustc-MIR.
- throw_ub!(BoundsCheckFailed { len: min_length.into(), index: n });
+ throw_ub!(BoundsCheckFailed { len: min_length, index: n });
}
let index = if from_end {
self.mplace_index(base, index)?
}
- Subslice { from, to, from_end } => {
- self.mplace_subslice(base, u64::from(from), u64::from(to), from_end)?
- }
+ Subslice { from, to, from_end } => self.mplace_subslice(base, from, to, from_end)?,
})
}
pub fn raw_const_to_mplace(
&self,
- raw: RawConst<'tcx>,
+ raw: ConstAlloc<'tcx>,
) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
// This must be an allocation in `tcx`
let _ = self.tcx.global_alloc(raw.alloc_id);
let alloc_kind = self.ecx.tcx.get_global_alloc(ptr.alloc_id);
if let Some(GlobalAlloc::Static(did)) = alloc_kind {
assert!(!self.ecx.tcx.is_thread_local_static(did));
- // See const_eval::machine::MemoryExtra::can_access_statics for why
- // this check is so important.
- // This check is reachable when the const just referenced the static,
- // but never read it (so we never entered `before_access_global`).
- // We also need to do it here instead of going on to avoid running
- // into the `before_access_global` check during validation.
- if !self.may_ref_to_static && self.ecx.tcx.is_static(did) {
+ assert!(self.ecx.tcx.is_static(did));
+ if self.may_ref_to_static {
+ // We skip checking other statics. These statics must be sound by
+ // themselves, and the only way to get broken statics here is by using
+ // unsafe code.
+ // The reasons we don't check other statics is twofold. For one, in all
+ // sound cases, the static was already validated on its own, and second, we
+ // trigger cycle errors if we try to compute the value of the other static
+ // and that static refers back to us.
+ // We might miss const-invalid data,
+ // but things are still sound otherwise (in particular re: consts
+ // referring to statics).
+ return Ok(());
+ } else {
+ // See const_eval::machine::MemoryExtra::can_access_statics for why
+ // this check is so important.
+ // This check is reachable when the const just referenced the static,
+ // but never read it (so we never entered `before_access_global`).
throw_validation_failure!(self.path,
{ "a {} pointing to a static variable", kind }
);
}
- // `extern static` cannot be validated as they have no body.
- // FIXME: Statics from other crates are also skipped.
- // They might be checked at a different type, but for now we
- // want to avoid recursing too deeply. We might miss const-invalid data,
- // but things are still sound otherwise (in particular re: consts
- // referring to statics).
- if !did.is_local() || self.ecx.tcx.is_foreign_item(did) {
- return Ok(());
- }
}
}
// Proceed recursively even for ZST, no reason to skip them!
#![feature(nll)]
#![feature(in_band_lifetimes)]
+#![feature(array_windows)]
+#![feature(bindings_after_at)]
#![feature(bool_to_option)]
#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(const_panic)]
#![feature(crate_visibility_modifier)]
#![feature(decl_macro)]
-#![feature(drain_filter)]
#![feature(exact_size_is_empty)]
#![feature(exhaustive_patterns)]
-#![feature(iter_order_by)]
#![feature(never_type)]
#![feature(min_specialization)]
#![feature(trusted_len)]
#![feature(try_blocks)]
-#![feature(associated_type_bounds)]
#![feature(associated_type_defaults)]
#![feature(stmt_expr_attributes)]
#![feature(trait_alias)]
#![feature(option_expect_none)]
#![feature(or_patterns)]
+#![feature(once_cell)]
#![recursion_limit = "256"]
#[macro_use]
transform::provide(providers);
monomorphize::partitioning::provide(providers);
monomorphize::polymorphize::provide(providers);
- providers.const_eval_validated = const_eval::const_eval_validated_provider;
- providers.const_eval_raw = const_eval::const_eval_raw_provider;
+ providers.eval_to_const_value_raw = const_eval::eval_to_const_value_raw_provider;
+ providers.eval_to_allocation_raw = const_eval::eval_to_allocation_raw_provider;
providers.const_caller_location = const_eval::const_caller_location;
providers.destructure_const = |tcx, param_env_and_value| {
let (param_env, value) = param_env_and_value.into_parts();
recursion_depth_reset = None;
- if let Ok(val) = tcx.const_eval_poly(def_id) {
- collect_const_value(tcx, val, &mut neighbors);
+ if let Ok(alloc) = tcx.eval_static_initializer(def_id) {
+ for &((), id) in alloc.relocations().values() {
+ collect_miri(tcx, id, &mut neighbors);
+ }
}
}
MonoItem::Fn(instance) => {
inlining_map.lock_mut().record_accesses(caller, &accesses);
}
+// Shrinks string by keeping prefix and suffix of given sizes.
+fn shrink(s: String, before: usize, after: usize) -> String {
+ // An iterator of all byte positions including the end of the string.
+ let positions = || s.char_indices().map(|(i, _)| i).chain(iter::once(s.len()));
+
+ let shrunk = format!(
+ "{before}...{after}",
+ before = &s[..positions().nth(before).unwrap_or(s.len())],
+ after = &s[positions().rev().nth(after).unwrap_or(0)..],
+ );
+
+ // Only use the shrunk version if it's really shorter.
+ // This also avoids the case where before and after slices overlap.
+ if shrunk.len() < s.len() { shrunk } else { s }
+}
+
+// Format instance name that is already known to be too long for rustc.
+// Show only the first and last 32 characters to avoid blasting
+// the user's terminal with thousands of lines of type-name.
+fn shrunk_instance_name(instance: &Instance<'tcx>) -> String {
+ shrink(instance.to_string(), 32, 32)
+}
+
fn check_recursion_limit<'tcx>(
tcx: TyCtxt<'tcx>,
instance: Instance<'tcx>,
// more than the recursion limit is assumed to be causing an
// infinite expansion.
if !tcx.sess.recursion_limit().value_within_limit(adjusted_recursion_depth) {
- let error = format!("reached the recursion limit while instantiating `{}`", instance);
+ let error = format!(
+ "reached the recursion limit while instantiating `{}`",
+ shrunk_instance_name(&instance),
+ );
let mut err = tcx.sess.struct_span_fatal(span, &error);
err.span_note(
tcx.def_span(def_id),
//
// Bail out in these cases to avoid that bad user experience.
if !tcx.sess.type_length_limit().value_within_limit(type_length) {
- // The instance name is already known to be too long for rustc.
- // Show only the first and last 32 characters to avoid blasting
- // the user's terminal with thousands of lines of type-name.
- let shrink = |s: String, before: usize, after: usize| {
- // An iterator of all byte positions including the end of the string.
- let positions = || s.char_indices().map(|(i, _)| i).chain(iter::once(s.len()));
-
- let shrunk = format!(
- "{before}...{after}",
- before = &s[..positions().nth(before).unwrap_or(s.len())],
- after = &s[positions().rev().nth(after).unwrap_or(0)..],
- );
-
- // Only use the shrunk version if it's really shorter.
- // This also avoids the case where before and after slices overlap.
- if shrunk.len() < s.len() { shrunk } else { s }
- };
let msg = format!(
"reached the type-length limit while instantiating `{}`",
- shrink(instance.to_string(), 32, 32)
+ shrunk_instance_name(&instance),
);
let mut diag = tcx.sess.struct_span_fatal(tcx.def_span(instance.def_id()), &msg);
diag.note(&format!(
symbols.sort_by_key(|sym| sym.1);
- for pair in symbols.windows(2) {
- let sym1 = &pair[0].1;
- let sym2 = &pair[1].1;
-
+ for &[(mono_item1, ref sym1), (mono_item2, ref sym2)] in symbols.array_windows() {
if sym1 == sym2 {
- let mono_item1 = pair[0].0;
- let mono_item2 = pair[1].0;
-
let span1 = mono_item1.local_span(tcx);
let span2 = mono_item2.local_span(tcx);
let mut result = match instance {
ty::InstanceDef::Item(..) => bug!("item {:?} passed to make_shim", instance),
ty::InstanceDef::VtableShim(def_id) => {
- build_call_shim(tcx, instance, Some(Adjustment::Deref), CallKind::Direct(def_id), None)
+ build_call_shim(tcx, instance, Some(Adjustment::Deref), CallKind::Direct(def_id))
}
ty::InstanceDef::FnPtrShim(def_id, ty) => {
let trait_ = tcx.trait_of_item(def_id).unwrap();
Some(ty::ClosureKind::FnMut | ty::ClosureKind::Fn) => Adjustment::Deref,
None => bug!("fn pointer {:?} is not an fn", ty),
};
- // HACK: we need the "real" argument types for the MIR,
- // but because our substs are (Self, Args), where Args
- // is a tuple, we must include the *concrete* argument
- // types in the MIR. They will be substituted again with
- // the param-substs, but because they are concrete, this
- // will not do any harm.
- let sig = tcx.erase_late_bound_regions(&ty.fn_sig(tcx));
- let arg_tys = sig.inputs();
-
- build_call_shim(tcx, instance, Some(adjustment), CallKind::Indirect(ty), Some(arg_tys))
+
+ build_call_shim(tcx, instance, Some(adjustment), CallKind::Indirect(ty))
}
// We are generating a call back to our def-id, which the
// codegen backend knows to turn to an actual call, be it
// indirect calls must be codegen'd differently than direct ones
// (such as `#[track_caller]`).
ty::InstanceDef::ReifyShim(def_id) => {
- build_call_shim(tcx, instance, None, CallKind::Direct(def_id), None)
+ build_call_shim(tcx, instance, None, CallKind::Direct(def_id))
}
ty::InstanceDef::ClosureOnceShim { call_once: _ } => {
let fn_mut = tcx.require_lang_item(LangItem::FnMut, None);
.unwrap()
.def_id;
- build_call_shim(
- tcx,
- instance,
- Some(Adjustment::RefMut),
- CallKind::Direct(call_mut),
- None,
- )
+ build_call_shim(tcx, instance, Some(Adjustment::RefMut), CallKind::Direct(call_mut))
}
ty::InstanceDef::DropGlue(def_id, ty) => build_drop_shim(tcx, def_id, ty),
ty::InstanceDef::CloneShim(def_id, ty) => build_clone_shim(tcx, def_id, ty),
}
}
-/// Builds a "call" shim for `instance`. The shim calls the
-/// function specified by `call_kind`, first adjusting its first
-/// argument according to `rcvr_adjustment`.
-///
-/// If `untuple_args` is a vec of types, the second argument of the
-/// function will be untupled as these types.
+/// Builds a "call" shim for `instance`. The shim calls the function specified by `call_kind`,
+/// first adjusting its first argument according to `rcvr_adjustment`.
fn build_call_shim<'tcx>(
tcx: TyCtxt<'tcx>,
instance: ty::InstanceDef<'tcx>,
rcvr_adjustment: Option<Adjustment>,
call_kind: CallKind<'tcx>,
- untuple_args: Option<&[Ty<'tcx>]>,
) -> Body<'tcx> {
debug!(
- "build_call_shim(instance={:?}, rcvr_adjustment={:?}, \
- call_kind={:?}, untuple_args={:?})",
- instance, rcvr_adjustment, call_kind, untuple_args
+ "build_call_shim(instance={:?}, rcvr_adjustment={:?}, call_kind={:?})",
+ instance, rcvr_adjustment, call_kind
);
+ // `FnPtrShim` contains the fn pointer type that a call shim is being built for - this is used
+ // to substitute into the signature of the shim. It is not necessary for users of this
+ // MIR body to perform further substitutions (see `InstanceDef::has_polymorphic_mir_body`).
+ let (sig_substs, untuple_args) = if let ty::InstanceDef::FnPtrShim(_, ty) = instance {
+ let sig = tcx.erase_late_bound_regions(&ty.fn_sig(tcx));
+
+ let untuple_args = sig.inputs();
+
+ // Create substitutions for the `Self` and `Args` generic parameters of the shim body.
+ let arg_tup = tcx.mk_tup(untuple_args.iter());
+ let sig_substs = tcx.mk_substs_trait(ty, &[ty::subst::GenericArg::from(arg_tup)]);
+
+ (Some(sig_substs), Some(untuple_args))
+ } else {
+ (None, None)
+ };
+
let def_id = instance.def_id();
let sig = tcx.fn_sig(def_id);
let mut sig = tcx.erase_late_bound_regions(&sig);
+ assert_eq!(sig_substs.is_some(), !instance.has_polymorphic_mir_body());
+ if let Some(sig_substs) = sig_substs {
+ sig = sig.subst(tcx, sig_substs);
+ }
+
if let CallKind::Indirect(fnty) = call_kind {
// `sig` determines our local decls, and thus the callee type in the `Call` terminator. This
// can only be an `FnDef` or `FnPtr`, but currently will be `Self` since the types come from
--- /dev/null
+//! Propagates assignment destinations backwards in the CFG to eliminate redundant assignments.
+//!
+//! # Motivation
+//!
+//! MIR building can insert a lot of redundant copies, and Rust code in general often tends to move
+//! values around a lot. The result is a lot of assignments of the form `dest = {move} src;` in MIR.
+//! MIR building for constants in particular tends to create additional locals that are only used
+//! inside a single block to shuffle a value around unnecessarily.
+//!
+//! LLVM by itself is not good enough at eliminating these redundant copies (eg. see
+//! https://github.com/rust-lang/rust/issues/32966), so this leaves some performance on the table
+//! that we can regain by implementing an optimization for removing these assign statements in rustc
+//! itself. When this optimization runs fast enough, it can also speed up the constant evaluation
+//! and code generation phases of rustc due to the reduced number of statements and locals.
+//!
+//! # The Optimization
+//!
+//! Conceptually, this optimization is "destination propagation". It is similar to the Named Return
+//! Value Optimization, or NRVO, known from the C++ world, except that it isn't limited to return
+//! values or the return place `_0`. On a very high level, independent of the actual implementation
+//! details, it does the following:
+//!
+//! 1) Identify `dest = src;` statements that can be soundly eliminated.
+//! 2) Replace all mentions of `src` with `dest` ("unifying" them and propagating the destination
+//! backwards).
+//! 3) Delete the `dest = src;` statement (by making it a `nop`).
+//!
+//! Step 1) is by far the hardest, so it is explained in more detail below.
+//!
+//! ## Soundness
+//!
+//! Given an `Assign` statement `dest = src;`, where `dest` is a `Place` and `src` is an `Rvalue`,
+//! there are a few requirements that must hold for the optimization to be sound:
+//!
+//! * `dest` must not contain any *indirection* through a pointer. It must access part of the base
+//! local. Otherwise it might point to arbitrary memory that is hard to track.
+//!
+//! It must also not contain any indexing projections, since those take an arbitrary `Local` as
+//! the index, and that local might only be initialized shortly before `dest` is used.
+//!
+//! Subtle case: If `dest` is a, or projects through a union, then we have to make sure that there
+//! remains an assignment to it, since that sets the "active field" of the union. But if `src` is
+//! a ZST, it might not be initialized, so there might not be any use of it before the assignment,
+//! and performing the optimization would simply delete the assignment, leaving `dest`
+//! uninitialized.
+//!
+//! * `src` must be a bare `Local` without any indirections or field projections (FIXME: Is this a
+//! fundamental restriction or just current impl state?). It can be copied or moved by the
+//! assignment.
+//!
+//! * The `dest` and `src` locals must never be [*live*][liveness] at the same time. If they are, it
+//! means that they both hold a (potentially different) value that is needed by a future use of
+//! the locals. Unifying them would overwrite one of the values.
+//!
+//! Note that computing liveness of locals that have had their address taken is more difficult:
+//! Short of doing full escape analysis on the address/pointer/reference, the pass would need to
+//! assume that any operation that can potentially involve opaque user code (such as function
+//! calls, destructors, and inline assembly) may access any local that had its address taken
+//! before that point.
+//!
+//! Here, the first two conditions are simple structural requirements on the `Assign` statements
+//! that can be trivially checked. The liveness requirement however is more difficult and costly to
+//! check.
+//!
+//! ## Previous Work
+//!
+//! A [previous attempt] at implementing an optimization like this turned out to be a significant
+//! regression in compiler performance. Fixing the regressions introduced a lot of undesirable
+//! complexity to the implementation.
+//!
+//! A [subsequent approach] tried to avoid the costly computation by limiting itself to acyclic
+//! CFGs, but still turned out to be far too costly to run due to suboptimal performance within
+//! individual basic blocks, requiring a walk across the entire block for every assignment found
+//! within the block. For the `tuple-stress` benchmark, which has 458745 statements in a single
+//! block, this proved to be far too costly.
+//!
+//! Since the first attempt at this, the compiler has improved dramatically, and new analysis
+//! frameworks have been added that should make this approach viable without requiring a limited
+//! approach that only works for some classes of CFGs:
+//! - rustc now has a powerful dataflow analysis framework that can handle forwards and backwards
+//! analyses efficiently.
+//! - Layout optimizations for generators have been added to improve code generation for
+//! async/await, which are very similar in spirit to what this optimization does. Both walk the
+//! MIR and record conflicting uses of locals in a `BitMatrix`.
+//!
+//! Also, rustc now has a simple NRVO pass (see `nrvo.rs`), which handles a subset of the cases that
+//! this destination propagation pass handles, proving that similar optimizations can be performed
+//! on MIR.
+//!
+//! ## Pre/Post Optimization
+//!
+//! It is recommended to run `SimplifyCfg` and then `SimplifyLocals` some time after this pass, as
+//! it replaces the eliminated assign statements with `nop`s and leaves unused locals behind.
+//!
+//! [liveness]: https://en.wikipedia.org/wiki/Live_variable_analysis
+//! [previous attempt]: https://github.com/rust-lang/rust/pull/47954
+//! [subsequent approach]: https://github.com/rust-lang/rust/pull/71003
+
+use crate::dataflow::impls::{MaybeInitializedLocals, MaybeLiveLocals};
+use crate::dataflow::Analysis;
+use crate::{
+ transform::{MirPass, MirSource},
+ util::{dump_mir, PassWhere},
+};
+use itertools::Itertools;
+use rustc_data_structures::unify::{InPlaceUnificationTable, UnifyKey};
+use rustc_index::{
+ bit_set::{BitMatrix, BitSet},
+ vec::IndexVec,
+};
+use rustc_middle::mir::tcx::PlaceTy;
+use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor};
+use rustc_middle::mir::{
+ traversal, Body, InlineAsmOperand, Local, LocalKind, Location, Operand, Place, PlaceElem,
+ Rvalue, Statement, StatementKind, Terminator, TerminatorKind,
+};
+use rustc_middle::ty::{self, Ty, TyCtxt};
+
+// Empirical measurements have resulted in some observations:
+// - Running on a body with a single block and 500 locals takes barely any time
+// - Running on a body with ~400 blocks and ~300 relevant locals takes "too long"
+// ...so we just limit both to somewhat reasonable-ish looking values.
+const MAX_LOCALS: usize = 500;
+const MAX_BLOCKS: usize = 250;
+
+pub struct DestinationPropagation;
+
+impl<'tcx> MirPass<'tcx> for DestinationPropagation {
+ fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'tcx>) {
+ // Only run at mir-opt-level=2 or higher for now (we don't fix up debuginfo and remove
+ // storage statements at the moment).
+ if tcx.sess.opts.debugging_opts.mir_opt_level <= 1 {
+ return;
+ }
+
+ let candidates = find_candidates(tcx, body);
+ if candidates.is_empty() {
+ debug!("{:?}: no dest prop candidates, done", source.def_id());
+ return;
+ }
+
+ // Collect all locals we care about. We only compute conflicts for these to save time.
+ let mut relevant_locals = BitSet::new_empty(body.local_decls.len());
+ for CandidateAssignment { dest, src, loc: _ } in &candidates {
+ relevant_locals.insert(dest.local);
+ relevant_locals.insert(*src);
+ }
+
+ // This pass unfortunately has `O(l² * s)` performance, where `l` is the number of locals
+ // and `s` is the number of statements and terminators in the function.
+ // To prevent blowing up compile times too much, we bail out when there are too many locals.
+ let relevant = relevant_locals.count();
+ debug!(
+ "{:?}: {} locals ({} relevant), {} blocks",
+ source.def_id(),
+ body.local_decls.len(),
+ relevant,
+ body.basic_blocks().len()
+ );
+ if relevant > MAX_LOCALS {
+ warn!(
+ "too many candidate locals in {:?} ({}, max is {}), not optimizing",
+ source.def_id(),
+ relevant,
+ MAX_LOCALS
+ );
+ return;
+ }
+ if body.basic_blocks().len() > MAX_BLOCKS {
+ warn!(
+ "too many blocks in {:?} ({}, max is {}), not optimizing",
+ source.def_id(),
+ body.basic_blocks().len(),
+ MAX_BLOCKS
+ );
+ return;
+ }
+
+ let mut conflicts = Conflicts::build(tcx, body, source, &relevant_locals);
+
+ let mut replacements = Replacements::new(body.local_decls.len());
+ for candidate @ CandidateAssignment { dest, src, loc } in candidates {
+ // Merge locals that don't conflict.
+ if !conflicts.can_unify(dest.local, src) {
+ debug!("at assignment {:?}, conflict {:?} vs. {:?}", loc, dest.local, src);
+ continue;
+ }
+
+ if replacements.for_src(candidate.src).is_some() {
+ debug!("src {:?} already has replacement", candidate.src);
+ continue;
+ }
+
+ if !tcx.consider_optimizing(|| {
+ format!("DestinationPropagation {:?} {:?}", source.def_id(), candidate)
+ }) {
+ break;
+ }
+
+ replacements.push(candidate);
+ conflicts.unify(candidate.src, candidate.dest.local);
+ }
+
+ replacements.flatten(tcx);
+
+ debug!("replacements {:?}", replacements.map);
+
+ Replacer { tcx, replacements, place_elem_cache: Vec::new() }.visit_body(body);
+
+ // FIXME fix debug info
+ }
+}
+
+#[derive(Debug, Eq, PartialEq, Copy, Clone)]
+struct UnifyLocal(Local);
+
+impl From<Local> for UnifyLocal {
+ fn from(l: Local) -> Self {
+ Self(l)
+ }
+}
+
+impl UnifyKey for UnifyLocal {
+ type Value = ();
+ fn index(&self) -> u32 {
+ self.0.as_u32()
+ }
+ fn from_index(u: u32) -> Self {
+ Self(Local::from_u32(u))
+ }
+ fn tag() -> &'static str {
+ "UnifyLocal"
+ }
+}
+
+struct Replacements<'tcx> {
+ /// Maps locals to their replacement.
+ map: IndexVec<Local, Option<Place<'tcx>>>,
+
+ /// Whose locals' live ranges to kill.
+ kill: BitSet<Local>,
+}
+
+impl Replacements<'tcx> {
+ fn new(locals: usize) -> Self {
+ Self { map: IndexVec::from_elem_n(None, locals), kill: BitSet::new_empty(locals) }
+ }
+
+ fn push(&mut self, candidate: CandidateAssignment<'tcx>) {
+ trace!("Replacements::push({:?})", candidate);
+ let entry = &mut self.map[candidate.src];
+ assert!(entry.is_none());
+
+ *entry = Some(candidate.dest);
+ self.kill.insert(candidate.src);
+ self.kill.insert(candidate.dest.local);
+ }
+
+ /// Applies the stored replacements to all replacements, until no replacements would result in
+ /// locals that need further replacements when applied.
+ fn flatten(&mut self, tcx: TyCtxt<'tcx>) {
+ // Note: This assumes that there are no cycles in the replacements, which is enforced via
+ // `self.unified_locals`. Otherwise this can cause an infinite loop.
+
+ for local in self.map.indices() {
+ if let Some(replacement) = self.map[local] {
+ // Substitute the base local of `replacement` until fixpoint.
+ let mut base = replacement.local;
+ let mut reversed_projection_slices = Vec::with_capacity(1);
+ while let Some(replacement_for_replacement) = self.map[base] {
+ base = replacement_for_replacement.local;
+ reversed_projection_slices.push(replacement_for_replacement.projection);
+ }
+
+ let projection: Vec<_> = reversed_projection_slices
+ .iter()
+ .rev()
+ .flat_map(|projs| projs.iter())
+ .chain(replacement.projection.iter())
+ .collect();
+ let projection = tcx.intern_place_elems(&projection);
+
+ // Replace with the final `Place`.
+ self.map[local] = Some(Place { local: base, projection });
+ }
+ }
+ }
+
+ fn for_src(&self, src: Local) -> Option<Place<'tcx>> {
+ self.map[src]
+ }
+}
+
+struct Replacer<'tcx> {
+ tcx: TyCtxt<'tcx>,
+ replacements: Replacements<'tcx>,
+ place_elem_cache: Vec<PlaceElem<'tcx>>,
+}
+
+impl<'tcx> MutVisitor<'tcx> for Replacer<'tcx> {
+ fn tcx<'a>(&'a self) -> TyCtxt<'tcx> {
+ self.tcx
+ }
+
+ fn visit_local(&mut self, local: &mut Local, context: PlaceContext, location: Location) {
+ if context.is_use() && self.replacements.for_src(*local).is_some() {
+ bug!(
+ "use of local {:?} should have been replaced by visit_place; context={:?}, loc={:?}",
+ local,
+ context,
+ location,
+ );
+ }
+ }
+
+ fn process_projection_elem(
+ &mut self,
+ elem: PlaceElem<'tcx>,
+ _: Location,
+ ) -> Option<PlaceElem<'tcx>> {
+ match elem {
+ PlaceElem::Index(local) => {
+ if let Some(replacement) = self.replacements.for_src(local) {
+ bug!(
+ "cannot replace {:?} with {:?} in index projection {:?}",
+ local,
+ replacement,
+ elem,
+ );
+ } else {
+ None
+ }
+ }
+ _ => None,
+ }
+ }
+
+ fn visit_place(&mut self, place: &mut Place<'tcx>, context: PlaceContext, location: Location) {
+ if let Some(replacement) = self.replacements.for_src(place.local) {
+ // Rebase `place`s projections onto `replacement`'s.
+ self.place_elem_cache.clear();
+ self.place_elem_cache.extend(replacement.projection.iter().chain(place.projection));
+ let projection = self.tcx.intern_place_elems(&self.place_elem_cache);
+ let new_place = Place { local: replacement.local, projection };
+
+ debug!("Replacer: {:?} -> {:?}", place, new_place);
+ *place = new_place;
+ }
+
+ self.super_place(place, context, location);
+ }
+
+ fn visit_statement(&mut self, statement: &mut Statement<'tcx>, location: Location) {
+ self.super_statement(statement, location);
+
+ match &statement.kind {
+ // FIXME: Don't delete storage statements, merge the live ranges instead
+ StatementKind::StorageDead(local) | StatementKind::StorageLive(local)
+ if self.replacements.kill.contains(*local) =>
+ {
+ statement.make_nop()
+ }
+
+ StatementKind::Assign(box (dest, rvalue)) => {
+ match rvalue {
+ Rvalue::Use(Operand::Copy(place) | Operand::Move(place)) => {
+ // These might've been turned into self-assignments by the replacement
+ // (this includes the original statement we wanted to eliminate).
+ if dest == place {
+ debug!("{:?} turned into self-assignment, deleting", location);
+ statement.make_nop();
+ }
+ }
+ _ => {}
+ }
+ }
+
+ _ => {}
+ }
+ }
+}
+
+struct Conflicts<'a> {
+ relevant_locals: &'a BitSet<Local>,
+
+ /// The conflict matrix. It is always symmetric and the adjacency matrix of the corresponding
+ /// conflict graph.
+ matrix: BitMatrix<Local, Local>,
+
+ /// Preallocated `BitSet` used by `unify`.
+ unify_cache: BitSet<Local>,
+
+ /// Tracks locals that have been merged together to prevent cycles and propagate conflicts.
+ unified_locals: InPlaceUnificationTable<UnifyLocal>,
+}
+
+impl Conflicts<'a> {
+ fn build<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ body: &'_ Body<'tcx>,
+ source: MirSource<'tcx>,
+ relevant_locals: &'a BitSet<Local>,
+ ) -> Self {
+ // We don't have to look out for locals that have their address taken, since
+ // `find_candidates` already takes care of that.
+
+ let conflicts = BitMatrix::from_row_n(
+ &BitSet::new_empty(body.local_decls.len()),
+ body.local_decls.len(),
+ );
+
+ let def_id = source.def_id();
+ let mut init = MaybeInitializedLocals
+ .into_engine(tcx, body, def_id)
+ .iterate_to_fixpoint()
+ .into_results_cursor(body);
+ let mut live = MaybeLiveLocals
+ .into_engine(tcx, body, def_id)
+ .iterate_to_fixpoint()
+ .into_results_cursor(body);
+
+ let mut reachable = None;
+ dump_mir(
+ tcx,
+ None,
+ "DestinationPropagation-dataflow",
+ &"",
+ source,
+ body,
+ |pass_where, w| {
+ let reachable =
+ reachable.get_or_insert_with(|| traversal::reachable_as_bitset(body));
+
+ match pass_where {
+ PassWhere::BeforeLocation(loc) if reachable.contains(loc.block) => {
+ init.seek_before_primary_effect(loc);
+ live.seek_after_primary_effect(loc);
+
+ writeln!(w, " // init: {:?}", init.get())?;
+ writeln!(w, " // live: {:?}", live.get())?;
+ }
+ PassWhere::AfterTerminator(bb) if reachable.contains(bb) => {
+ let loc = body.terminator_loc(bb);
+ init.seek_after_primary_effect(loc);
+ live.seek_before_primary_effect(loc);
+
+ writeln!(w, " // init: {:?}", init.get())?;
+ writeln!(w, " // live: {:?}", live.get())?;
+ }
+
+ PassWhere::BeforeBlock(bb) if reachable.contains(bb) => {
+ init.seek_to_block_start(bb);
+ live.seek_to_block_start(bb);
+
+ writeln!(w, " // init: {:?}", init.get())?;
+ writeln!(w, " // live: {:?}", live.get())?;
+ }
+
+ PassWhere::BeforeCFG | PassWhere::AfterCFG | PassWhere::AfterLocation(_) => {}
+
+ PassWhere::BeforeLocation(_) | PassWhere::AfterTerminator(_) => {
+ writeln!(w, " // init: <unreachable>")?;
+ writeln!(w, " // live: <unreachable>")?;
+ }
+
+ PassWhere::BeforeBlock(_) => {
+ writeln!(w, " // init: <unreachable>")?;
+ writeln!(w, " // live: <unreachable>")?;
+ }
+ }
+
+ Ok(())
+ },
+ );
+
+ let mut this = Self {
+ relevant_locals,
+ matrix: conflicts,
+ unify_cache: BitSet::new_empty(body.local_decls.len()),
+ unified_locals: {
+ let mut table = InPlaceUnificationTable::new();
+ // Pre-fill table with all locals (this creates N nodes / "connected" components,
+ // "graph"-ically speaking).
+ for local in 0..body.local_decls.len() {
+ assert_eq!(table.new_key(()), UnifyLocal(Local::from_usize(local)));
+ }
+ table
+ },
+ };
+
+ let mut live_and_init_locals = Vec::new();
+
+ // Visit only reachable basic blocks. The exact order is not important.
+ for (block, data) in traversal::preorder(body) {
+ // We need to observe the dataflow state *before* all possible locations (statement or
+ // terminator) in each basic block, and then observe the state *after* the terminator
+ // effect is applied. As long as neither `init` nor `borrowed` has a "before" effect,
+ // we will observe all possible dataflow states.
+
+ // Since liveness is a backwards analysis, we need to walk the results backwards. To do
+ // that, we first collect in the `MaybeInitializedLocals` results in a forwards
+ // traversal.
+
+ live_and_init_locals.resize_with(data.statements.len() + 1, || {
+ BitSet::new_empty(body.local_decls.len())
+ });
+
+ // First, go forwards for `MaybeInitializedLocals` and apply intra-statement/terminator
+ // conflicts.
+ for (i, statement) in data.statements.iter().enumerate() {
+ this.record_statement_conflicts(statement);
+
+ let loc = Location { block, statement_index: i };
+ init.seek_before_primary_effect(loc);
+
+ live_and_init_locals[i].clone_from(init.get());
+ }
+
+ this.record_terminator_conflicts(data.terminator());
+ let term_loc = Location { block, statement_index: data.statements.len() };
+ init.seek_before_primary_effect(term_loc);
+ live_and_init_locals[term_loc.statement_index].clone_from(init.get());
+
+ // Now, go backwards and union with the liveness results.
+ for statement_index in (0..=data.statements.len()).rev() {
+ let loc = Location { block, statement_index };
+ live.seek_after_primary_effect(loc);
+
+ live_and_init_locals[statement_index].intersect(live.get());
+
+ trace!("record conflicts at {:?}", loc);
+
+ this.record_dataflow_conflicts(&mut live_and_init_locals[statement_index]);
+ }
+
+ init.seek_to_block_end(block);
+ live.seek_to_block_end(block);
+ let mut conflicts = init.get().clone();
+ conflicts.intersect(live.get());
+ trace!("record conflicts at end of {:?}", block);
+
+ this.record_dataflow_conflicts(&mut conflicts);
+ }
+
+ this
+ }
+
+ fn record_dataflow_conflicts(&mut self, new_conflicts: &mut BitSet<Local>) {
+ // Remove all locals that are not candidates.
+ new_conflicts.intersect(self.relevant_locals);
+
+ for local in new_conflicts.iter() {
+ self.matrix.union_row_with(&new_conflicts, local);
+ }
+ }
+
+ fn record_local_conflict(&mut self, a: Local, b: Local, why: &str) {
+ trace!("conflict {:?} <-> {:?} due to {}", a, b, why);
+ self.matrix.insert(a, b);
+ self.matrix.insert(b, a);
+ }
+
+ /// Records locals that must not overlap during the evaluation of `stmt`. These locals conflict
+ /// and must not be merged.
+ fn record_statement_conflicts(&mut self, stmt: &Statement<'_>) {
+ match &stmt.kind {
+ // While the left and right sides of an assignment must not overlap, we do not mark
+ // conflicts here as that would make this optimization useless. When we optimize, we
+ // eliminate the resulting self-assignments automatically.
+ StatementKind::Assign(_) => {}
+
+ StatementKind::LlvmInlineAsm(asm) => {
+ // Inputs and outputs must not overlap.
+ for (_, input) in &*asm.inputs {
+ if let Some(in_place) = input.place() {
+ if !in_place.is_indirect() {
+ for out_place in &*asm.outputs {
+ if !out_place.is_indirect() && !in_place.is_indirect() {
+ self.record_local_conflict(
+ in_place.local,
+ out_place.local,
+ "aliasing llvm_asm! operands",
+ );
+ }
+ }
+ }
+ }
+ }
+ }
+
+ StatementKind::SetDiscriminant { .. }
+ | StatementKind::StorageLive(..)
+ | StatementKind::StorageDead(..)
+ | StatementKind::Retag(..)
+ | StatementKind::FakeRead(..)
+ | StatementKind::AscribeUserType(..)
+ | StatementKind::Coverage(..)
+ | StatementKind::Nop => {}
+ }
+ }
+
+ fn record_terminator_conflicts(&mut self, term: &Terminator<'_>) {
+ match &term.kind {
+ TerminatorKind::DropAndReplace {
+ place: dropped_place,
+ value,
+ target: _,
+ unwind: _,
+ } => {
+ if let Some(place) = value.place() {
+ if !place.is_indirect() && !dropped_place.is_indirect() {
+ self.record_local_conflict(
+ place.local,
+ dropped_place.local,
+ "DropAndReplace operand overlap",
+ );
+ }
+ }
+ }
+ TerminatorKind::Yield { value, resume: _, resume_arg, drop: _ } => {
+ if let Some(place) = value.place() {
+ if !place.is_indirect() && !resume_arg.is_indirect() {
+ self.record_local_conflict(
+ place.local,
+ resume_arg.local,
+ "Yield operand overlap",
+ );
+ }
+ }
+ }
+ TerminatorKind::Call {
+ func,
+ args,
+ destination: Some((dest_place, _)),
+ cleanup: _,
+ from_hir_call: _,
+ fn_span: _,
+ } => {
+ // No arguments may overlap with the destination.
+ for arg in args.iter().chain(Some(func)) {
+ if let Some(place) = arg.place() {
+ if !place.is_indirect() && !dest_place.is_indirect() {
+ self.record_local_conflict(
+ dest_place.local,
+ place.local,
+ "call dest/arg overlap",
+ );
+ }
+ }
+ }
+ }
+ TerminatorKind::InlineAsm {
+ template: _,
+ operands,
+ options: _,
+ line_spans: _,
+ destination: _,
+ } => {
+ // The intended semantics here aren't documented, we just assume that nothing that
+ // could be written to by the assembly may overlap with any other operands.
+ for op in operands {
+ match op {
+ InlineAsmOperand::Out { reg: _, late: _, place: Some(dest_place) }
+ | InlineAsmOperand::InOut {
+ reg: _,
+ late: _,
+ in_value: _,
+ out_place: Some(dest_place),
+ } => {
+ // For output place `place`, add all places accessed by the inline asm.
+ for op in operands {
+ match op {
+ InlineAsmOperand::In { reg: _, value } => {
+ if let Some(p) = value.place() {
+ if !p.is_indirect() && !dest_place.is_indirect() {
+ self.record_local_conflict(
+ p.local,
+ dest_place.local,
+ "asm! operand overlap",
+ );
+ }
+ }
+ }
+ InlineAsmOperand::Out {
+ reg: _,
+ late: _,
+ place: Some(place),
+ } => {
+ if !place.is_indirect() && !dest_place.is_indirect() {
+ self.record_local_conflict(
+ place.local,
+ dest_place.local,
+ "asm! operand overlap",
+ );
+ }
+ }
+ InlineAsmOperand::InOut {
+ reg: _,
+ late: _,
+ in_value,
+ out_place,
+ } => {
+ if let Some(place) = in_value.place() {
+ if !place.is_indirect() && !dest_place.is_indirect() {
+ self.record_local_conflict(
+ place.local,
+ dest_place.local,
+ "asm! operand overlap",
+ );
+ }
+ }
+
+ if let Some(place) = out_place {
+ if !place.is_indirect() && !dest_place.is_indirect() {
+ self.record_local_conflict(
+ place.local,
+ dest_place.local,
+ "asm! operand overlap",
+ );
+ }
+ }
+ }
+ InlineAsmOperand::Out { reg: _, late: _, place: None }
+ | InlineAsmOperand::Const { value: _ }
+ | InlineAsmOperand::SymFn { value: _ }
+ | InlineAsmOperand::SymStatic { def_id: _ } => {}
+ }
+ }
+ }
+ InlineAsmOperand::Const { value } => {
+ assert!(value.place().is_none());
+ }
+ InlineAsmOperand::InOut {
+ reg: _,
+ late: _,
+ in_value: _,
+ out_place: None,
+ }
+ | InlineAsmOperand::In { reg: _, value: _ }
+ | InlineAsmOperand::Out { reg: _, late: _, place: None }
+ | InlineAsmOperand::SymFn { value: _ }
+ | InlineAsmOperand::SymStatic { def_id: _ } => {}
+ }
+ }
+ }
+
+ TerminatorKind::Goto { .. }
+ | TerminatorKind::Call { destination: None, .. }
+ | TerminatorKind::SwitchInt { .. }
+ | TerminatorKind::Resume
+ | TerminatorKind::Abort
+ | TerminatorKind::Return
+ | TerminatorKind::Unreachable
+ | TerminatorKind::Drop { .. }
+ | TerminatorKind::Assert { .. }
+ | TerminatorKind::GeneratorDrop
+ | TerminatorKind::FalseEdge { .. }
+ | TerminatorKind::FalseUnwind { .. } => {}
+ }
+ }
+
+ /// Checks whether `a` and `b` may be merged. Returns `false` if there's a conflict.
+ fn can_unify(&mut self, a: Local, b: Local) -> bool {
+ // After some locals have been unified, their conflicts are only tracked in the root key,
+ // so look that up.
+ let a = self.unified_locals.find(a).0;
+ let b = self.unified_locals.find(b).0;
+
+ if a == b {
+ // Already merged (part of the same connected component).
+ return false;
+ }
+
+ if self.matrix.contains(a, b) {
+ // Conflict (derived via dataflow, intra-statement conflicts, or inherited from another
+ // local during unification).
+ return false;
+ }
+
+ true
+ }
+
+ /// Merges the conflicts of `a` and `b`, so that each one inherits all conflicts of the other.
+ ///
+ /// `can_unify` must have returned `true` for the same locals, or this may panic or lead to
+ /// miscompiles.
+ ///
+ /// This is called when the pass makes the decision to unify `a` and `b` (or parts of `a` and
+ /// `b`) and is needed to ensure that future unification decisions take potentially newly
+ /// introduced conflicts into account.
+ ///
+ /// For an example, assume we have locals `_0`, `_1`, `_2`, and `_3`. There are these conflicts:
+ ///
+ /// * `_0` <-> `_1`
+ /// * `_1` <-> `_2`
+ /// * `_3` <-> `_0`
+ ///
+ /// We then decide to merge `_2` with `_3` since they don't conflict. Then we decide to merge
+ /// `_2` with `_0`, which also doesn't have a conflict in the above list. However `_2` is now
+ /// `_3`, which does conflict with `_0`.
+ fn unify(&mut self, a: Local, b: Local) {
+ trace!("unify({:?}, {:?})", a, b);
+
+ // Get the root local of the connected components. The root local stores the conflicts of
+ // all locals in the connected component (and *is stored* as the conflicting local of other
+ // locals).
+ let a = self.unified_locals.find(a).0;
+ let b = self.unified_locals.find(b).0;
+ assert_ne!(a, b);
+
+ trace!("roots: a={:?}, b={:?}", a, b);
+ trace!("{:?} conflicts: {:?}", a, self.matrix.iter(a).format(", "));
+ trace!("{:?} conflicts: {:?}", b, self.matrix.iter(b).format(", "));
+
+ self.unified_locals.union(a, b);
+
+ let root = self.unified_locals.find(a).0;
+ assert!(root == a || root == b);
+
+ // Make all locals that conflict with `a` also conflict with `b`, and vice versa.
+ self.unify_cache.clear();
+ for conflicts_with_a in self.matrix.iter(a) {
+ self.unify_cache.insert(conflicts_with_a);
+ }
+ for conflicts_with_b in self.matrix.iter(b) {
+ self.unify_cache.insert(conflicts_with_b);
+ }
+ for conflicts_with_a_or_b in self.unify_cache.iter() {
+ // Set both `a` and `b` for this local's row.
+ self.matrix.insert(conflicts_with_a_or_b, a);
+ self.matrix.insert(conflicts_with_a_or_b, b);
+ }
+
+ // Write the locals `a` conflicts with to `b`'s row.
+ self.matrix.union_rows(a, b);
+ // Write the locals `b` conflicts with to `a`'s row.
+ self.matrix.union_rows(b, a);
+ }
+}
+
+/// A `dest = {move} src;` statement at `loc`.
+///
+/// We want to consider merging `dest` and `src` due to this assignment.
+#[derive(Debug, Copy, Clone)]
+struct CandidateAssignment<'tcx> {
+ /// Does not contain indirection or indexing (so the only local it contains is the place base).
+ dest: Place<'tcx>,
+ src: Local,
+ loc: Location,
+}
+
+/// Scans the MIR for assignments between locals that we might want to consider merging.
+///
+/// This will filter out assignments that do not match the right form (as described in the top-level
+/// comment) and also throw out assignments that involve a local that has its address taken or is
+/// otherwise ineligible (eg. locals used as array indices are ignored because we cannot propagate
+/// arbitrary places into array indices).
+fn find_candidates<'a, 'tcx>(
+ tcx: TyCtxt<'tcx>,
+ body: &'a Body<'tcx>,
+) -> Vec<CandidateAssignment<'tcx>> {
+ let mut visitor = FindAssignments {
+ tcx,
+ body,
+ candidates: Vec::new(),
+ ever_borrowed_locals: ever_borrowed_locals(body),
+ locals_used_as_array_index: locals_used_as_array_index(body),
+ };
+ visitor.visit_body(body);
+ visitor.candidates
+}
+
+struct FindAssignments<'a, 'tcx> {
+ tcx: TyCtxt<'tcx>,
+ body: &'a Body<'tcx>,
+ candidates: Vec<CandidateAssignment<'tcx>>,
+ ever_borrowed_locals: BitSet<Local>,
+ locals_used_as_array_index: BitSet<Local>,
+}
+
+impl<'a, 'tcx> Visitor<'tcx> for FindAssignments<'a, 'tcx> {
+ fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
+ if let StatementKind::Assign(box (
+ dest,
+ Rvalue::Use(Operand::Copy(src) | Operand::Move(src)),
+ )) = &statement.kind
+ {
+ // `dest` must not have pointer indirection.
+ if dest.is_indirect() {
+ return;
+ }
+
+ // `src` must be a plain local.
+ if !src.projection.is_empty() {
+ return;
+ }
+
+ // Since we want to replace `src` with `dest`, `src` must not be required.
+ if is_local_required(src.local, self.body) {
+ return;
+ }
+
+ // Can't optimize if both locals ever have their address taken (can introduce
+ // aliasing).
+ // FIXME: This can be smarter and take `StorageDead` into account (which
+ // invalidates borrows).
+ if self.ever_borrowed_locals.contains(dest.local)
+ && self.ever_borrowed_locals.contains(src.local)
+ {
+ return;
+ }
+
+ assert_ne!(dest.local, src.local, "self-assignments are UB");
+
+ // We can't replace locals occurring in `PlaceElem::Index` for now.
+ if self.locals_used_as_array_index.contains(src.local) {
+ return;
+ }
+
+ // Handle the "subtle case" described above by rejecting any `dest` that is or
+ // projects through a union.
+ let is_union = |ty: Ty<'_>| {
+ if let ty::Adt(def, _) = ty.kind() {
+ if def.is_union() {
+ return true;
+ }
+ }
+
+ false
+ };
+ let mut place_ty = PlaceTy::from_ty(self.body.local_decls[dest.local].ty);
+ if is_union(place_ty.ty) {
+ return;
+ }
+ for elem in dest.projection {
+ if let PlaceElem::Index(_) = elem {
+ // `dest` contains an indexing projection.
+ return;
+ }
+
+ place_ty = place_ty.projection_ty(self.tcx, elem);
+ if is_union(place_ty.ty) {
+ return;
+ }
+ }
+
+ self.candidates.push(CandidateAssignment {
+ dest: *dest,
+ src: src.local,
+ loc: location,
+ });
+ }
+ }
+}
+
+/// Some locals are part of the function's interface and can not be removed.
+///
+/// Note that these locals *can* still be merged with non-required locals by removing that other
+/// local.
+fn is_local_required(local: Local, body: &Body<'_>) -> bool {
+ match body.local_kind(local) {
+ LocalKind::Arg | LocalKind::ReturnPointer => true,
+ LocalKind::Var | LocalKind::Temp => false,
+ }
+}
+
+/// Walks MIR to find all locals that have their address taken anywhere.
+fn ever_borrowed_locals(body: &Body<'_>) -> BitSet<Local> {
+ let mut visitor = BorrowCollector { locals: BitSet::new_empty(body.local_decls.len()) };
+ visitor.visit_body(body);
+ visitor.locals
+}
+
+struct BorrowCollector {
+ locals: BitSet<Local>,
+}
+
+impl<'tcx> Visitor<'tcx> for BorrowCollector {
+ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
+ self.super_rvalue(rvalue, location);
+
+ match rvalue {
+ Rvalue::AddressOf(_, borrowed_place) | Rvalue::Ref(_, _, borrowed_place) => {
+ if !borrowed_place.is_indirect() {
+ self.locals.insert(borrowed_place.local);
+ }
+ }
+
+ Rvalue::Cast(..)
+ | Rvalue::Use(..)
+ | Rvalue::Repeat(..)
+ | Rvalue::Len(..)
+ | Rvalue::BinaryOp(..)
+ | Rvalue::CheckedBinaryOp(..)
+ | Rvalue::NullaryOp(..)
+ | Rvalue::UnaryOp(..)
+ | Rvalue::Discriminant(..)
+ | Rvalue::Aggregate(..)
+ | Rvalue::ThreadLocalRef(..) => {}
+ }
+ }
+
+ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) {
+ self.super_terminator(terminator, location);
+
+ match terminator.kind {
+ TerminatorKind::Drop { place: dropped_place, .. }
+ | TerminatorKind::DropAndReplace { place: dropped_place, .. } => {
+ self.locals.insert(dropped_place.local);
+ }
+
+ TerminatorKind::Abort
+ | TerminatorKind::Assert { .. }
+ | TerminatorKind::Call { .. }
+ | TerminatorKind::FalseEdge { .. }
+ | TerminatorKind::FalseUnwind { .. }
+ | TerminatorKind::GeneratorDrop
+ | TerminatorKind::Goto { .. }
+ | TerminatorKind::Resume
+ | TerminatorKind::Return
+ | TerminatorKind::SwitchInt { .. }
+ | TerminatorKind::Unreachable
+ | TerminatorKind::Yield { .. }
+ | TerminatorKind::InlineAsm { .. } => {}
+ }
+ }
+}
+
+/// `PlaceElem::Index` only stores a `Local`, so we can't replace that with a full `Place`.
+///
+/// Collect locals used as indices so we don't generate candidates that are impossible to apply
+/// later.
+fn locals_used_as_array_index(body: &Body<'_>) -> BitSet<Local> {
+ let mut visitor = IndexCollector { locals: BitSet::new_empty(body.local_decls.len()) };
+ visitor.visit_body(body);
+ visitor.locals
+}
+
+struct IndexCollector {
+ locals: BitSet<Local>,
+}
+
+impl<'tcx> Visitor<'tcx> for IndexCollector {
+ fn visit_projection_elem(
+ &mut self,
+ local: Local,
+ proj_base: &[PlaceElem<'tcx>],
+ elem: PlaceElem<'tcx>,
+ context: PlaceContext,
+ location: Location,
+ ) {
+ if let PlaceElem::Index(i) = elem {
+ self.locals.insert(i);
+ }
+ self.super_projection_elem(local, proj_base, elem, context, location);
+ }
+}
pub mod const_prop;
pub mod copy_prop;
pub mod deaggregator;
+pub mod dest_prop;
pub mod dump_mir;
pub mod elaborate_drops;
pub mod generator;
// this point, before we steal the mir-const result.
// Also this means promotion can rely on all const checks having been done.
let _ = tcx.mir_const_qualif_opt_const_arg(def);
-
+ let _ = if let Some(param_did) = def.const_param_did {
+ tcx.mir_abstract_const_of_const_arg((def.did, param_did))
+ } else {
+ tcx.mir_abstract_const(def.did.to_def_id())
+ };
let mut body = tcx.mir_const(def).steal();
let mut required_consts = Vec::new();
&simplify_comparison_integral::SimplifyComparisonIntegral,
&simplify_try::SimplifyArmIdentity,
&simplify_try::SimplifyBranchSame,
+ &dest_prop::DestinationPropagation,
©_prop::CopyPropagation,
&simplify_branches::SimplifyBranches::new("after-copy-prop"),
&remove_noop_landing_pads::RemoveNoopLandingPads,
return;
}
+ if tcx.sess.opts.debugging_opts.mir_opt_level >= 2 {
+ // The `DestinationPropagation` pass runs at level 2, so this pass is redundant (and
+ // fails some asserts).
+ return;
+ }
+
let returned_local = match local_eligible_for_nrvo(body) {
Some(l) => l,
None => {
impl TempState {
pub fn is_promotable(&self) -> bool {
debug!("is_promotable: self={:?}", self);
- if let TempState::Defined { .. } = *self { true } else { false }
+ matches!(self, TempState::Defined { .. } )
}
}
struct Unpromotable;
impl<'tcx> Validator<'_, 'tcx> {
+ /// Determines if this code could be executed at runtime and thus is subject to codegen.
+ /// That means even unused constants need to be evaluated.
+ ///
+ /// `const_kind` should not be used in this file other than through this method!
+ fn maybe_runtime(&self) -> bool {
+ match self.const_kind {
+ None | Some(hir::ConstContext::ConstFn) => true,
+ Some(hir::ConstContext::Static(_) | hir::ConstContext::Const) => false,
+ }
+ }
+
fn validate_candidate(&self, candidate: Candidate) -> Result<(), Unpromotable> {
match candidate {
Candidate::Ref(loc) => {
// In theory, any zero-sized value could be borrowed
// mutably without consequences. However, only &mut []
- // is allowed right now, and only in functions.
+ // is allowed right now.
if let ty::Array(_, len) = ty.kind() {
- // FIXME(eddyb) the `self.is_non_const_fn` condition
- // seems unnecessary, given that this is merely a ZST.
match len.try_eval_usize(self.tcx, self.param_env) {
- Some(0) if self.const_kind.is_none() => {}
+ Some(0) => {}
_ => return Err(Unpromotable),
}
} else {
match place {
PlaceRef { local, projection: [] } => self.validate_local(local),
PlaceRef { local, projection: [proj_base @ .., elem] } => {
+ // Validate topmost projection, then recurse.
match *elem {
ProjectionElem::Deref => {
- let mut not_promotable = true;
+ let mut promotable = false;
// This is a special treatment for cases like *&STATIC where STATIC is a
// global static variable.
// This pattern is generated only when global static variables are directly
}) = def_stmt
{
if let Some(did) = c.check_static_ptr(self.tcx) {
+ // Evaluating a promoted may not read statics except if it got
+ // promoted from a static (this is a CTFE check). So we
+ // can only promote static accesses inside statics.
if let Some(hir::ConstContext::Static(..)) = self.const_kind {
// The `is_empty` predicate is introduced to exclude the case
// where the projection operations are [ .field, * ].
if proj_base.is_empty()
&& !self.tcx.is_thread_local_static(did)
{
- not_promotable = false;
+ promotable = true;
}
}
}
}
}
- if not_promotable {
+ if !promotable {
return Err(Unpromotable);
}
}
}
ProjectionElem::Field(..) => {
- if self.const_kind.is_none() {
+ if self.maybe_runtime() {
let base_ty =
Place::ty_from(place.local, proj_base, self.body, self.tcx).ty;
if let Some(def) = base_ty.ty_adt_def() {
if let Some(def_id) = c.check_static_ptr(self.tcx) {
// Only allow statics (not consts) to refer to other statics.
// FIXME(eddyb) does this matter at all for promotion?
+ // FIXME(RalfJung) it makes little sense to not promote this in `fn`/`const fn`,
+ // and in `const` this cannot occur anyway. The only concern is that we might
+ // promote even `let x = &STATIC` which would be useless, but this applies to
+ // promotion inside statics as well.
let is_static = matches!(self.const_kind, Some(hir::ConstContext::Static(_)));
if !is_static {
return Err(Unpromotable);
fn validate_rvalue(&self, rvalue: &Rvalue<'tcx>) -> Result<(), Unpromotable> {
match *rvalue {
- Rvalue::Cast(CastKind::Misc, ref operand, cast_ty) if self.const_kind.is_none() => {
+ Rvalue::Cast(CastKind::Misc, ref operand, cast_ty) => {
let operand_ty = operand.ty(self.body, self.tcx);
let cast_in = CastTy::from_ty(operand_ty).expect("bad input type for cast");
let cast_out = CastTy::from_ty(cast_ty).expect("bad output type for cast");
match (cast_in, cast_out) {
(CastTy::Ptr(_) | CastTy::FnPtr, CastTy::Int(_)) => {
- // in normal functions, mark such casts as not promotable
+ // ptr-to-int casts are not possible in consts and thus not promotable
return Err(Unpromotable);
}
_ => {}
}
}
- Rvalue::BinaryOp(op, ref lhs, _) if self.const_kind.is_none() => {
+ Rvalue::BinaryOp(op, ref lhs, _) => {
if let ty::RawPtr(_) | ty::FnPtr(..) = lhs.ty(self.body, self.tcx).kind() {
assert!(
op == BinOp::Eq
|| op == BinOp::Offset
);
- // raw pointer operations are not allowed inside promoteds
+ // raw pointer operations are not allowed inside consts and thus not promotable
return Err(Unpromotable);
}
}
Rvalue::NullaryOp(NullOp::Box, _) => return Err(Unpromotable),
+ // FIXME(RalfJung): the rest is *implicitly considered promotable*... that seems dangerous.
_ => {}
}
}
Rvalue::AddressOf(_, place) => {
- // Raw reborrows can come from reference to pointer coercions,
- // so are allowed.
+ // We accept `&raw *`, i.e., raw reborrows -- creating a raw pointer is
+ // no problem, only using it is.
if let [proj_base @ .., ProjectionElem::Deref] = place.projection.as_ref() {
let base_ty = Place::ty_from(place.local, proj_base, self.body, self.tcx).ty;
if let ty::Ref(..) = base_ty.kind() {
// In theory, any zero-sized value could be borrowed
// mutably without consequences. However, only &mut []
- // is allowed right now, and only in functions.
+ // is allowed right now.
if let ty::Array(_, len) = ty.kind() {
- // FIXME(eddyb): We only return `Unpromotable` for `&mut []` inside a
- // const context which seems unnecessary given that this is merely a ZST.
match len.try_eval_usize(self.tcx, self.param_env) {
- Some(0) if self.const_kind.is_none() => {}
+ Some(0) => {}
_ => return Err(Unpromotable),
}
} else {
) -> Result<(), Unpromotable> {
let fn_ty = callee.ty(self.body, self.tcx);
- if !self.explicit && self.const_kind.is_none() {
+ if !self.explicit && self.maybe_runtime() {
if let ty::FnDef(def_id, _) = *fn_ty.kind() {
// Never promote runtime `const fn` calls of
// functions without `#[rustc_promotable]`.
fn strip_nops(&mut self) {
for blk in self.basic_blocks.iter_mut() {
- blk.statements
- .retain(|stmt| if let StatementKind::Nop = stmt.kind { false } else { true })
+ blk.statements.retain(|stmt| !matches!(stmt.kind, StatementKind::Nop))
}
}
}
None => write!(w, " (deallocated)")?,
Some(GlobalAlloc::Function(inst)) => write!(w, " (fn: {})", inst)?,
Some(GlobalAlloc::Static(did)) if !tcx.is_foreign_item(did) => {
- match tcx.const_eval_poly(did) {
- Ok(ConstValue::ByRef { alloc, .. }) => {
+ match tcx.eval_static_initializer(did) {
+ Ok(alloc) => {
write!(w, " (static: {}, ", tcx.def_path_str(did))?;
write_allocation_track_relocs(w, alloc)?;
}
- Ok(_) => {
- span_bug!(tcx.def_span(did), " static item without `ByRef` initializer")
- }
Err(_) => write!(
w,
" (static: {}, error during initializer evaluation)",
);
}
StmtKind::Let { remainder_scope, init_scope, pattern, initializer, lint_level } => {
- let ignores_expr_result =
- if let PatKind::Wild = *pattern.kind { true } else { false };
+ let ignores_expr_result = matches!(*pattern.kind, PatKind::Wild);
this.block_context.push(BlockFrame::Statement { ignores_expr_result });
// Enter the remainder scope, i.e., the bindings' destruction scope.
.flat_map(|(bindings, _)| bindings)
.chain(&candidate.bindings)
.filter(|binding| {
- if let BindingMode::ByValue = binding.binding_mode { true } else { false }
+ matches!(binding.binding_mode, BindingMode::ByValue )
});
// Read all of the by reference bindings to ensure that the
// place they refer to can't be modified by the guard.
let tcx = self.hir.tcx();
let (min_length, exact_size) = match place.ty(&self.local_decls, tcx).ty.kind() {
ty::Array(_, length) => {
- (length.eval_usize(tcx, self.hir.param_env).try_into().unwrap(), true)
+ (length.eval_usize(tcx, self.hir.param_env), true)
}
_ => ((prefix.len() + suffix.len()).try_into().unwrap(), false),
};
//! Construction of MIR from HIR.
//!
//! This crate also contains the match exhaustiveness and usefulness checking.
-
+#![feature(array_windows)]
#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(const_fn)]
// interval into a constructor.
split_ctors.extend(
borders
- .windows(2)
- .filter_map(|window| match (window[0], window[1]) {
- (Border::JustBefore(n), Border::JustBefore(m)) => {
+ .array_windows()
+ .filter_map(|&pair| match pair {
+ [Border::JustBefore(n), Border::JustBefore(m)] => {
if n < m {
Some(IntRange { range: n..=(m - 1), ty, span })
} else {
None
}
}
- (Border::JustBefore(n), Border::AfterMax) => {
+ [Border::JustBefore(n), Border::AfterMax] => {
Some(IntRange { range: n..=u128::MAX, ty, span })
}
- (Border::AfterMax, _) => None,
+ [Border::AfterMax, _] => None,
})
.map(IntRange),
);
#![feature(bool_to_option)]
#![feature(crate_visibility_modifier)]
#![feature(bindings_after_at)]
-#![feature(try_blocks)]
#![feature(or_patterns)]
use rustc_ast as ast;
)]
#![feature(nll)]
#![feature(or_patterns)]
-#![feature(rustc_private)]
-#![feature(unicode_internals)]
#![feature(bool_to_option)]
pub use Alignment::*;
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
#![feature(in_band_lifetimes)]
#![feature(nll)]
-#![feature(or_patterns)]
#![recursion_limit = "256"]
use rustc_attr as attr;
ty.visit_with(self)
}
ty::PredicateAtom::RegionOutlives(..) => false,
+ ty::PredicateAtom::ConstEvaluatable(..)
+ if self.def_id_visitor.tcx().features().const_evaluatable_checked =>
+ {
+ // FIXME(const_evaluatable_checked): If the constant used here depends on a
+ // private function we may have to do something here...
+ //
+ // For now, let's just pretend that everything is fine.
+ false
+ }
_ => bug!("unexpected predicate: {:?}", predicate),
}
}
// so prefixes are prepended with crate root segment if necessary.
// The root is prepended lazily, when the first non-empty prefix or terminating glob
// appears, so imports in braced groups can have roots prepended independently.
- let is_glob = if let ast::UseTreeKind::Glob = use_tree.kind { true } else { false };
+ let is_glob = matches!(use_tree.kind, ast::UseTreeKind::Glob);
let crate_root = match prefix_iter.peek() {
Some(seg) if !seg.ident.is_path_segment_keyword() && seg.ident.span.rust_2015() => {
Some(seg.ident.span.ctxt())
let mut add_bindings_for_ns = |ns| {
let parent_rib = self.ribs[ns]
.iter()
- .rfind(|r| if let ItemRibKind(_) = r.kind { true } else { false })
+ .rfind(|r| matches!(r.kind, ItemRibKind(_)))
.expect("associated item outside of an item");
seen_bindings
.extend(parent_rib.bindings.iter().map(|(ident, _)| (*ident, ident.span)));
if snippet.starts_with('&') && !snippet.starts_with("&'") {
introduce_suggestion
.push((param.span, format!("&{} {}", lt_name, &snippet[1..])));
- } else if snippet.starts_with("&'_ ") {
+ } else if let Some(stripped) = snippet.strip_prefix("&'_ ") {
introduce_suggestion
- .push((param.span, format!("&{} {}", lt_name, &snippet[4..])));
+ .push((param.span, format!("&{} {}", lt_name, stripped)));
}
}
}
user_cfg
}
-pub fn build_target_config(opts: &Options, error_format: ErrorOutputType) -> Config {
- let target = Target::search(&opts.target_triple).unwrap_or_else(|e| {
+pub fn build_target_config(opts: &Options, target_override: Option<Target>) -> Config {
+ let target_result = target_override.map_or_else(|| Target::search(&opts.target_triple), Ok);
+ let target = target_result.unwrap_or_else(|e| {
early_error(
- error_format,
+ opts.error_format,
&format!(
"Error loading target specification: {}. \
Use `--print target-list` for a list of built-in targets",
"32" => 32,
"64" => 64,
w => early_error(
- error_format,
+ opts.error_format,
&format!(
"target specification was invalid: \
unrecognized target-pointer-width {}",
impl SearchPath {
pub fn from_cli_opt(path: &str, output: config::ErrorOutputType) -> Self {
- let (kind, path) = if path.starts_with("native=") {
- (PathKind::Native, &path["native=".len()..])
- } else if path.starts_with("crate=") {
- (PathKind::Crate, &path["crate=".len()..])
- } else if path.starts_with("dependency=") {
- (PathKind::Dependency, &path["dependency=".len()..])
- } else if path.starts_with("framework=") {
- (PathKind::Framework, &path["framework=".len()..])
- } else if path.starts_with("all=") {
- (PathKind::All, &path["all=".len()..])
+ let (kind, path) = if let Some(stripped) = path.strip_prefix("native=") {
+ (PathKind::Native, stripped)
+ } else if let Some(stripped) = path.strip_prefix("crate=") {
+ (PathKind::Crate, stripped)
+ } else if let Some(stripped) = path.strip_prefix("dependency=") {
+ (PathKind::Dependency, stripped)
+ } else if let Some(stripped) = path.strip_prefix("framework=") {
+ (PathKind::Framework, stripped)
+ } else if let Some(stripped) = path.strip_prefix("all=") {
+ (PathKind::All, stripped)
} else {
(PathKind::All, path)
};
diagnostics_output: DiagnosticOutput,
driver_lint_caps: FxHashMap<lint::LintId, lint::Level>,
file_loader: Option<Box<dyn FileLoader + Send + Sync + 'static>>,
+ target_override: Option<Target>,
) -> Session {
// FIXME: This is not general enough to make the warning lint completely override
// normal diagnostic warnings, since the warning lint can also be denied and changed
DiagnosticOutput::Raw(write) => Some(write),
};
- let target_cfg = config::build_target_config(&sopts, sopts.error_format);
+ let target_cfg = config::build_target_config(&sopts, target_override);
let host_triple = TargetTriple::from_triple(config::host_triple());
let host = Target::search(&host_triple).unwrap_or_else(|e| {
early_error(sopts.error_format, &format!("Error loading host specification: {}", e))
//! This API is completely unstable and subject to change.
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
+#![feature(array_windows)]
#![feature(crate_visibility_modifier)]
#![feature(const_fn)]
#![feature(const_panic)]
#![feature(negative_impls)]
#![feature(nll)]
-#![feature(optin_builtin_traits)]
#![feature(min_specialization)]
#![feature(option_expect_none)]
-#![feature(refcell_take)]
#[macro_use]
extern crate rustc_macros;
let max_line_length = if lines.len() == 1 {
0
} else {
- lines.windows(2).map(|w| w[1] - w[0]).map(|bp| bp.to_usize()).max().unwrap()
+ lines
+ .array_windows()
+ .map(|&[fst, snd]| snd - fst)
+ .map(|bp| bp.to_usize())
+ .max()
+ .unwrap()
};
let bytes_per_diff: u8 = match max_line_length {
// Encode the first element.
lines[0].encode(s)?;
- let diff_iter = (&lines[..]).windows(2).map(|w| (w[1] - w[0]));
+ let diff_iter = lines[..].array_windows().map(|&[fst, snd]| snd - fst);
match bytes_per_diff {
1 => {
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
#![feature(bool_to_option)]
+#![feature(box_patterns)]
#![feature(drain_filter)]
#![feature(in_band_lifetimes)]
#![feature(crate_visibility_modifier)]
+//! Checking that constant values used in types can be successfully evaluated.
+//!
+//! For concrete constants, this is fairly simple as we can just try and evaluate it.
+//!
+//! When dealing with polymorphic constants, for example `std::mem::size_of::<T>() - 1`,
+//! this is not as easy.
+//!
+//! In this case we try to build an abstract representation of this constant using
+//! `mir_abstract_const` which can then be checked for structural equality with other
+//! generic constants mentioned in the `caller_bounds` of the current environment.
use rustc_hir::def::DefKind;
+use rustc_index::bit_set::BitSet;
+use rustc_index::vec::IndexVec;
use rustc_infer::infer::InferCtxt;
+use rustc_middle::mir::abstract_const::{Node, NodeId};
use rustc_middle::mir::interpret::ErrorHandled;
+use rustc_middle::mir::{self, Rvalue, StatementKind, TerminatorKind};
+use rustc_middle::ty::subst::Subst;
use rustc_middle::ty::subst::SubstsRef;
-use rustc_middle::ty::{self, TypeFoldable};
+use rustc_middle::ty::{self, TyCtxt, TypeFoldable};
use rustc_session::lint;
-use rustc_span::def_id::DefId;
+use rustc_span::def_id::{DefId, LocalDefId};
use rustc_span::Span;
pub fn is_const_evaluatable<'cx, 'tcx>(
) -> Result<(), ErrorHandled> {
debug!("is_const_evaluatable({:?}, {:?})", def, substs);
if infcx.tcx.features().const_evaluatable_checked {
- // FIXME(const_evaluatable_checked): Actually look into generic constants to
- // implement const equality.
- for pred in param_env.caller_bounds() {
- match pred.skip_binders() {
- ty::PredicateAtom::ConstEvaluatable(b_def, b_substs) => {
- debug!("is_const_evaluatable: caller_bound={:?}, {:?}", b_def, b_substs);
- if b_def == def && b_substs == substs {
- debug!("is_const_evaluatable: caller_bound ~~> ok");
- return Ok(());
+ if let Some(ct) = AbstractConst::new(infcx.tcx, def, substs) {
+ for pred in param_env.caller_bounds() {
+ match pred.skip_binders() {
+ ty::PredicateAtom::ConstEvaluatable(b_def, b_substs) => {
+ debug!("is_const_evaluatable: caller_bound={:?}, {:?}", b_def, b_substs);
+ if b_def == def && b_substs == substs {
+ debug!("is_const_evaluatable: caller_bound ~~> ok");
+ return Ok(());
+ } else if AbstractConst::new(infcx.tcx, b_def, b_substs)
+ .map_or(false, |b_ct| try_unify(infcx.tcx, ct, b_ct))
+ {
+ debug!("is_const_evaluatable: abstract_const ~~> ok");
+ return Ok(());
+ }
}
+ _ => {} // don't care
}
- _ => {} // don't care
}
}
}
debug!(?concrete, "is_const_evaluatable");
concrete.map(drop)
}
+
+/// A tree representing an anonymous constant.
+///
+/// This is only able to represent a subset of `MIR`,
+/// and should not leak any information about desugarings.
+#[derive(Clone, Copy)]
+pub struct AbstractConst<'tcx> {
+ // FIXME: Consider adding something like `IndexSlice`
+ // and use this here.
+ inner: &'tcx [Node<'tcx>],
+ substs: SubstsRef<'tcx>,
+}
+
+impl AbstractConst<'tcx> {
+ pub fn new(
+ tcx: TyCtxt<'tcx>,
+ def: ty::WithOptConstParam<DefId>,
+ substs: SubstsRef<'tcx>,
+ ) -> Option<AbstractConst<'tcx>> {
+ let inner = match (def.did.as_local(), def.const_param_did) {
+ (Some(did), Some(param_did)) => {
+ tcx.mir_abstract_const_of_const_arg((did, param_did))?
+ }
+ _ => tcx.mir_abstract_const(def.did)?,
+ };
+
+ Some(AbstractConst { inner, substs })
+ }
+
+ #[inline]
+ pub fn subtree(self, node: NodeId) -> AbstractConst<'tcx> {
+ AbstractConst { inner: &self.inner[..=node.index()], substs: self.substs }
+ }
+
+ #[inline]
+ pub fn root(self) -> Node<'tcx> {
+ self.inner.last().copied().unwrap()
+ }
+}
+
+struct AbstractConstBuilder<'a, 'tcx> {
+ tcx: TyCtxt<'tcx>,
+ body: &'a mir::Body<'tcx>,
+ /// The current WIP node tree.
+ nodes: IndexVec<NodeId, Node<'tcx>>,
+ locals: IndexVec<mir::Local, NodeId>,
+ /// We only allow field accesses if they access
+ /// the result of a checked operation.
+ checked_op_locals: BitSet<mir::Local>,
+}
+
+impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
+ fn new(tcx: TyCtxt<'tcx>, body: &'a mir::Body<'tcx>) -> Option<AbstractConstBuilder<'a, 'tcx>> {
+ // We only allow consts without control flow, so
+ // we check for cycles here which simplifies the
+ // rest of this implementation.
+ if body.is_cfg_cyclic() {
+ return None;
+ }
+
+ // We don't have to look at concrete constants, as we
+ // can just evaluate them.
+ if !body.is_polymorphic {
+ return None;
+ }
+
+ Some(AbstractConstBuilder {
+ tcx,
+ body,
+ nodes: IndexVec::new(),
+ locals: IndexVec::from_elem(NodeId::MAX, &body.local_decls),
+ checked_op_locals: BitSet::new_empty(body.local_decls.len()),
+ })
+ }
+ fn operand_to_node(&mut self, op: &mir::Operand<'tcx>) -> Option<NodeId> {
+ debug!("operand_to_node: op={:?}", op);
+ const ZERO_FIELD: mir::Field = mir::Field::from_usize(0);
+ match op {
+ mir::Operand::Copy(p) | mir::Operand::Move(p) => {
+ // Do not allow any projections.
+ //
+ // One exception are field accesses on the result of checked operations,
+ // which are required to support things like `1 + 2`.
+ if let Some(p) = p.as_local() {
+ debug_assert!(!self.checked_op_locals.contains(p));
+ Some(self.locals[p])
+ } else if let &[mir::ProjectionElem::Field(ZERO_FIELD, _)] = p.projection.as_ref() {
+ // Only allow field accesses if the given local
+ // contains the result of a checked operation.
+ if self.checked_op_locals.contains(p.local) {
+ Some(self.locals[p.local])
+ } else {
+ None
+ }
+ } else {
+ None
+ }
+ }
+ mir::Operand::Constant(ct) => Some(self.nodes.push(Node::Leaf(ct.literal))),
+ }
+ }
+
+ /// We do not allow all binary operations in abstract consts, so filter disallowed ones.
+ fn check_binop(op: mir::BinOp) -> bool {
+ use mir::BinOp::*;
+ match op {
+ Add | Sub | Mul | Div | Rem | BitXor | BitAnd | BitOr | Shl | Shr | Eq | Lt | Le
+ | Ne | Ge | Gt => true,
+ Offset => false,
+ }
+ }
+
+ /// While we currently allow all unary operations, we still want to explicitly guard against
+ /// future changes here.
+ fn check_unop(op: mir::UnOp) -> bool {
+ use mir::UnOp::*;
+ match op {
+ Not | Neg => true,
+ }
+ }
+
+ fn build_statement(&mut self, stmt: &mir::Statement<'tcx>) -> Option<()> {
+ debug!("AbstractConstBuilder: stmt={:?}", stmt);
+ match stmt.kind {
+ StatementKind::Assign(box (ref place, ref rvalue)) => {
+ let local = place.as_local()?;
+ match *rvalue {
+ Rvalue::Use(ref operand) => {
+ self.locals[local] = self.operand_to_node(operand)?;
+ Some(())
+ }
+ Rvalue::BinaryOp(op, ref lhs, ref rhs) if Self::check_binop(op) => {
+ let lhs = self.operand_to_node(lhs)?;
+ let rhs = self.operand_to_node(rhs)?;
+ self.locals[local] = self.nodes.push(Node::Binop(op, lhs, rhs));
+ if op.is_checkable() {
+ bug!("unexpected unchecked checkable binary operation");
+ } else {
+ Some(())
+ }
+ }
+ Rvalue::CheckedBinaryOp(op, ref lhs, ref rhs) if Self::check_binop(op) => {
+ let lhs = self.operand_to_node(lhs)?;
+ let rhs = self.operand_to_node(rhs)?;
+ self.locals[local] = self.nodes.push(Node::Binop(op, lhs, rhs));
+ self.checked_op_locals.insert(local);
+ Some(())
+ }
+ Rvalue::UnaryOp(op, ref operand) if Self::check_unop(op) => {
+ let operand = self.operand_to_node(operand)?;
+ self.locals[local] = self.nodes.push(Node::UnaryOp(op, operand));
+ Some(())
+ }
+ _ => None,
+ }
+ }
+ // These are not actually relevant for us here, so we can ignore them.
+ StatementKind::StorageLive(_) | StatementKind::StorageDead(_) => Some(()),
+ _ => None,
+ }
+ }
+
+ /// Possible return values:
+ ///
+ /// - `None`: unsupported terminator, stop building
+ /// - `Some(None)`: supported terminator, finish building
+ /// - `Some(Some(block))`: support terminator, build `block` next
+ fn build_terminator(
+ &mut self,
+ terminator: &mir::Terminator<'tcx>,
+ ) -> Option<Option<mir::BasicBlock>> {
+ debug!("AbstractConstBuilder: terminator={:?}", terminator);
+ match terminator.kind {
+ TerminatorKind::Goto { target } => Some(Some(target)),
+ TerminatorKind::Return => Some(None),
+ TerminatorKind::Call {
+ ref func,
+ ref args,
+ destination: Some((ref place, target)),
+ // We do not care about `cleanup` here. Any branch which
+ // uses `cleanup` will fail const-eval and they therefore
+ // do not matter when checking for const evaluatability.
+ //
+ // Do note that even if `panic::catch_unwind` is made const,
+ // we still do not have to care about this, as we do not look
+ // into functions.
+ cleanup: _,
+ // Do not allow overloaded operators for now,
+ // we probably do want to allow this in the future.
+ //
+ // This is currently fairly irrelevant as it requires `const Trait`s.
+ from_hir_call: true,
+ fn_span: _,
+ } => {
+ let local = place.as_local()?;
+ let func = self.operand_to_node(func)?;
+ let args = self.tcx.arena.alloc_from_iter(
+ args.iter()
+ .map(|arg| self.operand_to_node(arg))
+ .collect::<Option<Vec<NodeId>>>()?,
+ );
+ self.locals[local] = self.nodes.push(Node::FunctionCall(func, args));
+ Some(Some(target))
+ }
+ // We only allow asserts for checked operations.
+ //
+ // These asserts seem to all have the form `!_local.0` so
+ // we only allow exactly that.
+ TerminatorKind::Assert { ref cond, expected: false, target, .. } => {
+ let p = match cond {
+ mir::Operand::Copy(p) | mir::Operand::Move(p) => p,
+ mir::Operand::Constant(_) => bug!("unexpected assert"),
+ };
+
+ const ONE_FIELD: mir::Field = mir::Field::from_usize(1);
+ debug!("proj: {:?}", p.projection);
+ if let &[mir::ProjectionElem::Field(ONE_FIELD, _)] = p.projection.as_ref() {
+ // Only allow asserts checking the result of a checked operation.
+ if self.checked_op_locals.contains(p.local) {
+ return Some(Some(target));
+ }
+ }
+
+ None
+ }
+ _ => None,
+ }
+ }
+
+ /// Builds the abstract const by walking the mir from start to finish
+ /// and bailing out when encountering an unsupported operation.
+ fn build(mut self) -> Option<&'tcx [Node<'tcx>]> {
+ let mut block = &self.body.basic_blocks()[mir::START_BLOCK];
+ // We checked for a cyclic cfg above, so this should terminate.
+ loop {
+ debug!("AbstractConstBuilder: block={:?}", block);
+ for stmt in block.statements.iter() {
+ self.build_statement(stmt)?;
+ }
+
+ if let Some(next) = self.build_terminator(block.terminator())? {
+ block = &self.body.basic_blocks()[next];
+ } else {
+ return Some(self.tcx.arena.alloc_from_iter(self.nodes));
+ }
+ }
+ }
+}
+
+/// Builds an abstract const, do not use this directly, but use `AbstractConst::new` instead.
+pub(super) fn mir_abstract_const<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ def: ty::WithOptConstParam<LocalDefId>,
+) -> Option<&'tcx [Node<'tcx>]> {
+ if tcx.features().const_evaluatable_checked {
+ match tcx.def_kind(def.did) {
+ // FIXME(const_evaluatable_checked): We currently only do this for anonymous constants,
+ // meaning that we do not look into associated constants. I(@lcnr) am not yet sure whether
+ // we want to look into them or treat them as opaque projections.
+ //
+ // Right now we do neither of that and simply always fail to unify them.
+ DefKind::AnonConst => (),
+ _ => return None,
+ }
+ let body = tcx.mir_const(def).borrow();
+ AbstractConstBuilder::new(tcx, &body)?.build()
+ } else {
+ None
+ }
+}
+
+pub(super) fn try_unify_abstract_consts<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ ((a, a_substs), (b, b_substs)): (
+ (ty::WithOptConstParam<DefId>, SubstsRef<'tcx>),
+ (ty::WithOptConstParam<DefId>, SubstsRef<'tcx>),
+ ),
+) -> bool {
+ if let Some(a) = AbstractConst::new(tcx, a, a_substs) {
+ if let Some(b) = AbstractConst::new(tcx, b, b_substs) {
+ return try_unify(tcx, a, b);
+ }
+ }
+
+ false
+}
+
+/// Tries to unify two abstract constants using structural equality.
+pub(super) fn try_unify<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ a: AbstractConst<'tcx>,
+ b: AbstractConst<'tcx>,
+) -> bool {
+ match (a.root(), b.root()) {
+ (Node::Leaf(a_ct), Node::Leaf(b_ct)) => {
+ let a_ct = a_ct.subst(tcx, a.substs);
+ let b_ct = b_ct.subst(tcx, b.substs);
+ match (a_ct.val, b_ct.val) {
+ // We can just unify errors with everything to reduce the amount of
+ // emitted errors here.
+ (ty::ConstKind::Error(_), _) | (_, ty::ConstKind::Error(_)) => true,
+ (ty::ConstKind::Param(a_param), ty::ConstKind::Param(b_param)) => {
+ a_param == b_param
+ }
+ (ty::ConstKind::Value(a_val), ty::ConstKind::Value(b_val)) => a_val == b_val,
+ // If we have `fn a<const N: usize>() -> [u8; N + 1]` and `fn b<const M: usize>() -> [u8; 1 + M]`
+ // we do not want to use `assert_eq!(a(), b())` to infer that `N` and `M` have to be `1`. This
+ // means that we only allow inference variables if they are equal.
+ (ty::ConstKind::Infer(a_val), ty::ConstKind::Infer(b_val)) => a_val == b_val,
+ // FIXME(const_evaluatable_checked): We may want to either actually try
+ // to evaluate `a_ct` and `b_ct` if they are are fully concrete or something like
+ // this, for now we just return false here.
+ _ => false,
+ }
+ }
+ (Node::Binop(a_op, al, ar), Node::Binop(b_op, bl, br)) if a_op == b_op => {
+ try_unify(tcx, a.subtree(al), b.subtree(bl))
+ && try_unify(tcx, a.subtree(ar), b.subtree(br))
+ }
+ (Node::UnaryOp(a_op, av), Node::UnaryOp(b_op, bv)) if a_op == b_op => {
+ try_unify(tcx, a.subtree(av), b.subtree(bv))
+ }
+ (Node::FunctionCall(a_f, a_args), Node::FunctionCall(b_f, b_args))
+ if a_args.len() == b_args.len() =>
+ {
+ try_unify(tcx, a.subtree(a_f), b.subtree(b_f))
+ && a_args
+ .iter()
+ .zip(b_args)
+ .all(|(&an, &bn)| try_unify(tcx, a.subtree(an), b.subtree(bn)))
+ }
+ _ => false,
+ }
+}
ty::PredicateAtom::ConstEquate(c1, c2) => {
debug!("equating consts: c1={:?} c2={:?}", c1, c2);
+ if self.selcx.tcx().features().const_evaluatable_checked {
+ // FIXME: we probably should only try to unify abstract constants
+ // if the constants depend on generic parameters.
+ //
+ // Let's just see where this breaks :shrug:
+ if let (
+ ty::ConstKind::Unevaluated(a_def, a_substs, None),
+ ty::ConstKind::Unevaluated(b_def, b_substs, None),
+ ) = (c1.val, c2.val)
+ {
+ if self
+ .selcx
+ .tcx()
+ .try_unify_abstract_consts(((a_def, a_substs), (b_def, b_substs)))
+ {
+ return ProcessResult::Changed(vec![]);
+ }
+ }
+ }
let stalled_on = &mut pending_obligation.stalled_on;
vtable_methods,
type_implements_trait,
subst_and_check_impossible_predicates,
+ mir_abstract_const: |tcx, def_id| {
+ let def_id = def_id.expect_local();
+ if let Some(def) = ty::WithOptConstParam::try_lookup(def_id, tcx) {
+ tcx.mir_abstract_const_of_const_arg(def)
+ } else {
+ const_evaluatable::mir_abstract_const(tcx, ty::WithOptConstParam::unknown(def_id))
+ }
+ },
+ mir_abstract_const_of_const_arg: |tcx, (did, param_did)| {
+ const_evaluatable::mir_abstract_const(
+ tcx,
+ ty::WithOptConstParam { did, const_param_did: Some(param_did) },
+ )
+ },
+ try_unify_abstract_consts: const_evaluatable::try_unify_abstract_consts,
..*providers
};
}
None => self.check_recursion_limit(&obligation, &obligation)?,
}
- match obligation.predicate.skip_binders() {
- ty::PredicateAtom::Trait(t, _) => {
- let t = ty::Binder::bind(t);
- debug_assert!(!t.has_escaping_bound_vars());
- let obligation = obligation.with(t);
- self.evaluate_trait_predicate_recursively(previous_stack, obligation)
- }
+ ensure_sufficient_stack(|| {
+ match obligation.predicate.skip_binders() {
+ ty::PredicateAtom::Trait(t, _) => {
+ let t = ty::Binder::bind(t);
+ debug_assert!(!t.has_escaping_bound_vars());
+ let obligation = obligation.with(t);
+ self.evaluate_trait_predicate_recursively(previous_stack, obligation)
+ }
+
+ ty::PredicateAtom::Subtype(p) => {
+ let p = ty::Binder::bind(p);
+ // Does this code ever run?
+ match self.infcx.subtype_predicate(&obligation.cause, obligation.param_env, p) {
+ Some(Ok(InferOk { mut obligations, .. })) => {
+ self.add_depth(obligations.iter_mut(), obligation.recursion_depth);
+ self.evaluate_predicates_recursively(
+ previous_stack,
+ obligations.into_iter(),
+ )
+ }
+ Some(Err(_)) => Ok(EvaluatedToErr),
+ None => Ok(EvaluatedToAmbig),
+ }
+ }
- ty::PredicateAtom::Subtype(p) => {
- let p = ty::Binder::bind(p);
- // Does this code ever run?
- match self.infcx.subtype_predicate(&obligation.cause, obligation.param_env, p) {
- Some(Ok(InferOk { mut obligations, .. })) => {
+ ty::PredicateAtom::WellFormed(arg) => match wf::obligations(
+ self.infcx,
+ obligation.param_env,
+ obligation.cause.body_id,
+ arg,
+ obligation.cause.span,
+ ) {
+ Some(mut obligations) => {
self.add_depth(obligations.iter_mut(), obligation.recursion_depth);
self.evaluate_predicates_recursively(
previous_stack,
obligations.into_iter(),
)
}
- Some(Err(_)) => Ok(EvaluatedToErr),
None => Ok(EvaluatedToAmbig),
- }
- }
+ },
- ty::PredicateAtom::WellFormed(arg) => match wf::obligations(
- self.infcx,
- obligation.param_env,
- obligation.cause.body_id,
- arg,
- obligation.cause.span,
- ) {
- Some(mut obligations) => {
- self.add_depth(obligations.iter_mut(), obligation.recursion_depth);
- self.evaluate_predicates_recursively(previous_stack, obligations.into_iter())
+ ty::PredicateAtom::TypeOutlives(..) | ty::PredicateAtom::RegionOutlives(..) => {
+ // We do not consider region relationships when evaluating trait matches.
+ Ok(EvaluatedToOkModuloRegions)
}
- None => Ok(EvaluatedToAmbig),
- },
-
- ty::PredicateAtom::TypeOutlives(..) | ty::PredicateAtom::RegionOutlives(..) => {
- // We do not consider region relationships when evaluating trait matches.
- Ok(EvaluatedToOkModuloRegions)
- }
- ty::PredicateAtom::ObjectSafe(trait_def_id) => {
- if self.tcx().is_object_safe(trait_def_id) {
- Ok(EvaluatedToOk)
- } else {
- Ok(EvaluatedToErr)
+ ty::PredicateAtom::ObjectSafe(trait_def_id) => {
+ if self.tcx().is_object_safe(trait_def_id) {
+ Ok(EvaluatedToOk)
+ } else {
+ Ok(EvaluatedToErr)
+ }
}
- }
- ty::PredicateAtom::Projection(data) => {
- let data = ty::Binder::bind(data);
- let project_obligation = obligation.with(data);
- match project::poly_project_and_unify_type(self, &project_obligation) {
- Ok(Ok(Some(mut subobligations))) => {
- self.add_depth(subobligations.iter_mut(), obligation.recursion_depth);
- let result = self.evaluate_predicates_recursively(
- previous_stack,
- subobligations.into_iter(),
- );
- if let Some(key) =
- ProjectionCacheKey::from_poly_projection_predicate(self, data)
- {
- self.infcx.inner.borrow_mut().projection_cache().complete(key);
+ ty::PredicateAtom::Projection(data) => {
+ let data = ty::Binder::bind(data);
+ let project_obligation = obligation.with(data);
+ match project::poly_project_and_unify_type(self, &project_obligation) {
+ Ok(Ok(Some(mut subobligations))) => {
+ self.add_depth(subobligations.iter_mut(), obligation.recursion_depth);
+ let result = self.evaluate_predicates_recursively(
+ previous_stack,
+ subobligations.into_iter(),
+ );
+ if let Some(key) =
+ ProjectionCacheKey::from_poly_projection_predicate(self, data)
+ {
+ self.infcx.inner.borrow_mut().projection_cache().complete(key);
+ }
+ result
}
- result
+ Ok(Ok(None)) => Ok(EvaluatedToAmbig),
+ // EvaluatedToRecur might also be acceptable here, but use
+ // Unknown for now because it means that we won't dismiss a
+ // selection candidate solely because it has a projection
+ // cycle. This is closest to the previous behavior of
+ // immediately erroring.
+ Ok(Err(project::InProgress)) => Ok(EvaluatedToUnknown),
+ Err(_) => Ok(EvaluatedToErr),
}
- Ok(Ok(None)) => Ok(EvaluatedToAmbig),
- // EvaluatedToRecur might also be acceptable here, but use
- // Unknown for now because it means that we won't dismiss a
- // selection candidate solely because it has a projection
- // cycle. This is closest to the previous behavior of
- // immediately erroring.
- Ok(Err(project::InProgress)) => Ok(EvaluatedToUnknown),
- Err(_) => Ok(EvaluatedToErr),
}
- }
- ty::PredicateAtom::ClosureKind(_, closure_substs, kind) => {
- match self.infcx.closure_kind(closure_substs) {
- Some(closure_kind) => {
- if closure_kind.extends(kind) {
- Ok(EvaluatedToOk)
- } else {
- Ok(EvaluatedToErr)
+ ty::PredicateAtom::ClosureKind(_, closure_substs, kind) => {
+ match self.infcx.closure_kind(closure_substs) {
+ Some(closure_kind) => {
+ if closure_kind.extends(kind) {
+ Ok(EvaluatedToOk)
+ } else {
+ Ok(EvaluatedToErr)
+ }
}
+ None => Ok(EvaluatedToAmbig),
}
- None => Ok(EvaluatedToAmbig),
}
- }
- ty::PredicateAtom::ConstEvaluatable(def_id, substs) => {
- match const_evaluatable::is_const_evaluatable(
- self.infcx,
- def_id,
- substs,
- obligation.param_env,
- obligation.cause.span,
- ) {
- Ok(()) => Ok(EvaluatedToOk),
- Err(ErrorHandled::TooGeneric) => Ok(EvaluatedToAmbig),
- Err(_) => Ok(EvaluatedToErr),
+ ty::PredicateAtom::ConstEvaluatable(def_id, substs) => {
+ match const_evaluatable::is_const_evaluatable(
+ self.infcx,
+ def_id,
+ substs,
+ obligation.param_env,
+ obligation.cause.span,
+ ) {
+ Ok(()) => Ok(EvaluatedToOk),
+ Err(ErrorHandled::TooGeneric) => Ok(EvaluatedToAmbig),
+ Err(_) => Ok(EvaluatedToErr),
+ }
}
- }
- ty::PredicateAtom::ConstEquate(c1, c2) => {
- debug!("evaluate_predicate_recursively: equating consts c1={:?} c2={:?}", c1, c2);
-
- let evaluate = |c: &'tcx ty::Const<'tcx>| {
- if let ty::ConstKind::Unevaluated(def, substs, promoted) = c.val {
- self.infcx
- .const_eval_resolve(
- obligation.param_env,
- def,
- substs,
- promoted,
- Some(obligation.cause.span),
- )
- .map(|val| ty::Const::from_value(self.tcx(), val, c.ty))
- } else {
- Ok(c)
- }
- };
+ ty::PredicateAtom::ConstEquate(c1, c2) => {
+ debug!(
+ "evaluate_predicate_recursively: equating consts c1={:?} c2={:?}",
+ c1, c2
+ );
- match (evaluate(c1), evaluate(c2)) {
- (Ok(c1), Ok(c2)) => {
- match self.infcx().at(&obligation.cause, obligation.param_env).eq(c1, c2) {
- Ok(_) => Ok(EvaluatedToOk),
- Err(_) => Ok(EvaluatedToErr),
+ let evaluate = |c: &'tcx ty::Const<'tcx>| {
+ if let ty::ConstKind::Unevaluated(def, substs, promoted) = c.val {
+ self.infcx
+ .const_eval_resolve(
+ obligation.param_env,
+ def,
+ substs,
+ promoted,
+ Some(obligation.cause.span),
+ )
+ .map(|val| ty::Const::from_value(self.tcx(), val, c.ty))
+ } else {
+ Ok(c)
+ }
+ };
+
+ match (evaluate(c1), evaluate(c2)) {
+ (Ok(c1), Ok(c2)) => {
+ match self
+ .infcx()
+ .at(&obligation.cause, obligation.param_env)
+ .eq(c1, c2)
+ {
+ Ok(_) => Ok(EvaluatedToOk),
+ Err(_) => Ok(EvaluatedToErr),
+ }
+ }
+ (Err(ErrorHandled::Reported(ErrorReported)), _)
+ | (_, Err(ErrorHandled::Reported(ErrorReported))) => Ok(EvaluatedToErr),
+ (Err(ErrorHandled::Linted), _) | (_, Err(ErrorHandled::Linted)) => {
+ span_bug!(
+ obligation.cause.span(self.tcx()),
+ "ConstEquate: const_eval_resolve returned an unexpected error"
+ )
+ }
+ (Err(ErrorHandled::TooGeneric), _) | (_, Err(ErrorHandled::TooGeneric)) => {
+ Ok(EvaluatedToAmbig)
}
- }
- (Err(ErrorHandled::Reported(ErrorReported)), _)
- | (_, Err(ErrorHandled::Reported(ErrorReported))) => Ok(EvaluatedToErr),
- (Err(ErrorHandled::Linted), _) | (_, Err(ErrorHandled::Linted)) => span_bug!(
- obligation.cause.span(self.tcx()),
- "ConstEquate: const_eval_resolve returned an unexpected error"
- ),
- (Err(ErrorHandled::TooGeneric), _) | (_, Err(ErrorHandled::TooGeneric)) => {
- Ok(EvaluatedToAmbig)
}
}
+ ty::PredicateAtom::TypeWellFormedFromEnv(..) => {
+ bug!("TypeWellFormedFromEnv is only used for chalk")
+ }
}
- ty::PredicateAtom::TypeWellFormedFromEnv(..) => {
- bug!("TypeWellFormedFromEnv is only used for chalk")
- }
- }
+ })
}
fn evaluate_trait_predicate_recursively<'o>(
#![feature(crate_visibility_modifier)]
#![feature(in_band_lifetimes)]
#![feature(nll)]
-#![feature(or_patterns)]
#![recursion_limit = "256"]
#[macro_use]
//! This API is completely unstable and subject to change.
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
-#![feature(bool_to_option)]
#![feature(nll)]
#![recursion_limit = "256"]
{
let s = s.as_ref();
let old = old.as_ref();
- if s.starts_with(old) { Some(new.as_ref().to_owned() + &s[old.len()..]) } else { None }
+ if let Some(stripped) = s.strip_prefix(old) {
+ Some(new.as_ref().to_owned() + stripped)
+ } else {
+ None
+ }
}
/// This function is used to determine potential "simple" improvements or users' errors and
// This is maybe too permissive, since it allows
// `let u = &raw const Box::new((1,)).0`, which creates an
// immediately dangling raw pointer.
- self.typeck_results.borrow().adjustments().get(base.hir_id).map_or(false, |x| {
- x.iter().any(|adj| if let Adjust::Deref(_) = adj.kind { true } else { false })
- })
+ self.typeck_results
+ .borrow()
+ .adjustments()
+ .get(base.hir_id)
+ .map_or(false, |x| x.iter().any(|adj| matches!(adj.kind, Adjust::Deref(_))))
});
if !is_named {
self.tcx.sess.emit_err(AddressOfTemporaryTaken { span: oprnd.span })
use rustc_infer::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
use rustc_infer::infer::{InferCtxt, InferOk, InferResult, RegionVariableOrigin, TyCtxtInferExt};
use rustc_middle::hir::map::blocks::FnLikeNode;
-use rustc_middle::mir::interpret::ConstValue;
use rustc_middle::ty::adjustment::{
Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability,
};
// `#[link_section]` may contain arbitrary, or even undefined bytes, but it is
// the consumer's responsibility to ensure all bytes that have been read
// have defined values.
- match tcx.const_eval_poly(id.to_def_id()) {
- Ok(ConstValue::ByRef { alloc, .. }) => {
+ match tcx.eval_static_initializer(id.to_def_id()) {
+ Ok(alloc) => {
if alloc.relocations().len() != 0 {
let msg = "statics with a custom `#[link_section]` must be a \
simple list of bytes on the wasm target with no \
tcx.sess.span_err(span, msg);
}
}
- Ok(_) => bug!("Matching on non-ByRef static"),
Err(_) => {}
}
}
} else {
msg
},
- if lstring.starts_with('&') {
+ if let Some(stripped) = lstring.strip_prefix('&') {
// let a = String::new();
// let _ = &a + "bar";
- lstring[1..].to_string()
+ stripped.to_string()
} else {
format!("{}.to_owned()", lstring)
},
is_assign,
) {
(Ok(l), Ok(r), IsAssign::No) => {
- let to_string = if l.starts_with('&') {
+ let to_string = if let Some(stripped) = l.strip_prefix('&') {
// let a = String::new(); let b = String::new();
// let _ = &a + b;
- l[1..].to_string()
+ stripped.to_string()
} else {
format!("{}.to_owned()", l)
};
use crate::check::FnCtxt;
use rustc_ast as ast;
+
use rustc_ast::util::lev_distance::find_best_match_for_name;
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder};
pat_ty
}
+ fn maybe_suggest_range_literal(
+ &self,
+ e: &mut DiagnosticBuilder<'_>,
+ opt_def_id: Option<hir::def_id::DefId>,
+ ident: Ident,
+ ) -> bool {
+ match opt_def_id {
+ Some(def_id) => match self.tcx.hir().get_if_local(def_id) {
+ Some(hir::Node::Item(hir::Item {
+ kind: hir::ItemKind::Const(_, body_id), ..
+ })) => match self.tcx.hir().get(body_id.hir_id) {
+ hir::Node::Expr(expr) => {
+ if hir::is_range_literal(expr) {
+ let span = self.tcx.hir().span(body_id.hir_id);
+ if let Ok(snip) = self.tcx.sess.source_map().span_to_snippet(span) {
+ e.span_suggestion_verbose(
+ ident.span,
+ "you may want to move the range into the match block",
+ snip,
+ Applicability::MachineApplicable,
+ );
+ return true;
+ }
+ }
+ }
+ _ => (),
+ },
+ _ => (),
+ },
+ _ => (),
+ }
+ false
+ }
+
fn emit_bad_pat_path(
&self,
mut e: DiagnosticBuilder<'_>,
);
}
_ => {
- let const_def_id = match pat_ty.kind() {
+ let (type_def_id, item_def_id) = match pat_ty.kind() {
Adt(def, _) => match res {
- Res::Def(DefKind::Const, _) => Some(def.did),
- _ => None,
+ Res::Def(DefKind::Const, def_id) => (Some(def.did), Some(def_id)),
+ _ => (None, None),
},
- _ => None,
+ _ => (None, None),
};
let ranges = &[
self.tcx.lang_items().range_inclusive_struct(),
self.tcx.lang_items().range_to_inclusive_struct(),
];
- if const_def_id != None && ranges.contains(&const_def_id) {
- let msg = "constants only support matching by type, \
- if you meant to match against a range of values, \
- consider using a range pattern like `min ..= max` in the match block";
- e.note(msg);
+ if type_def_id != None && ranges.contains(&type_def_id) {
+ if !self.maybe_suggest_range_literal(&mut e, item_def_id, *ident) {
+ let msg = "constants only support matching by type, \
+ if you meant to match against a range of values, \
+ consider using a range pattern like `min ..= max` in the match block";
+ e.note(msg);
+ }
} else {
let msg = "introduce a new binding instead";
let sugg = format!("other_{}", ident.as_str().to_lowercase());
) -> impl Iterator<Item = (ty::Predicate<'tcx>, Span)> {
#[derive(Default)]
struct ConstCollector<'tcx> {
- ct: SmallVec<[(ty::WithOptConstParam<DefId>, SubstsRef<'tcx>); 4]>,
+ ct: SmallVec<[(ty::WithOptConstParam<DefId>, SubstsRef<'tcx>, Span); 4]>,
+ curr_span: Span,
}
impl<'tcx> TypeVisitor<'tcx> for ConstCollector<'tcx> {
fn visit_const(&mut self, ct: &'tcx Const<'tcx>) -> bool {
if let ty::ConstKind::Unevaluated(def, substs, None) = ct.val {
- self.ct.push((def, substs));
+ self.ct.push((def, substs, self.curr_span));
}
false
}
}
let mut collector = ConstCollector::default();
- for (pred, _span) in predicates.predicates.iter() {
+ for &(pred, span) in predicates.predicates.iter() {
+ collector.curr_span = span;
pred.visit_with(&mut collector);
}
warn!("const_evaluatable_predicates_of({:?}) = {:?}", def_id, collector.ct);
- collector.ct.into_iter().map(move |(def_id, subst)| {
- (ty::PredicateAtom::ConstEvaluatable(def_id, subst).to_predicate(tcx), DUMMY_SP)
+ collector.ct.into_iter().map(move |(def_id, subst, span)| {
+ (ty::PredicateAtom::ConstEvaluatable(def_id, subst).to_predicate(tcx), span)
})
}
item.span(),
format!("`{}` is not valid for this target", feature),
);
- if feature.starts_with('+') {
- let valid = supported_target_features.contains_key(&feature[1..]);
+ if let Some(stripped) = feature.strip_prefix('+') {
+ let valid = supported_target_features.contains_key(stripped);
if valid {
err.help("consider removing the leading `+` in the feature name");
}
}
macro_rules! bench_in_place {
- (
- $($fname:ident, $type:ty , $count:expr, $init: expr);*
- ) => {
+ ($($fname:ident, $type:ty, $count:expr, $init:expr);*) => {
$(
#[bench]
fn $fname(b: &mut Bencher) {
let src: Vec<$type> = black_box(vec![$init; $count]);
let mut sink = src.into_iter()
.enumerate()
- .map(|(idx, e)| { (idx as $type) ^ e }).collect::<Vec<$type>>();
+ .map(|(idx, e)| idx as $type ^ e)
+ .collect::<Vec<$type>>();
black_box(sink.as_mut_ptr())
});
}
}
bench_in_place![
- bench_in_place_xxu8_i0_0010, u8, 10, 0;
- bench_in_place_xxu8_i0_0100, u8, 100, 0;
- bench_in_place_xxu8_i0_1000, u8, 1000, 0;
- bench_in_place_xxu8_i1_0010, u8, 10, 1;
- bench_in_place_xxu8_i1_0100, u8, 100, 1;
- bench_in_place_xxu8_i1_1000, u8, 1000, 1;
- bench_in_place_xu32_i0_0010, u32, 10, 0;
- bench_in_place_xu32_i0_0100, u32, 100, 0;
- bench_in_place_xu32_i0_1000, u32, 1000, 0;
- bench_in_place_xu32_i1_0010, u32, 10, 1;
- bench_in_place_xu32_i1_0100, u32, 100, 1;
- bench_in_place_xu32_i1_1000, u32, 1000, 1;
- bench_in_place_u128_i0_0010, u128, 10, 0;
- bench_in_place_u128_i0_0100, u128, 100, 0;
- bench_in_place_u128_i0_1000, u128, 1000, 0;
- bench_in_place_u128_i1_0010, u128, 10, 1;
- bench_in_place_u128_i1_0100, u128, 100, 1;
- bench_in_place_u128_i1_1000, u128, 1000, 1
+ bench_in_place_xxu8_0010_i0, u8, 10, 0;
+ bench_in_place_xxu8_0100_i0, u8, 100, 0;
+ bench_in_place_xxu8_1000_i0, u8, 1000, 0;
+ bench_in_place_xxu8_0010_i1, u8, 10, 1;
+ bench_in_place_xxu8_0100_i1, u8, 100, 1;
+ bench_in_place_xxu8_1000_i1, u8, 1000, 1;
+ bench_in_place_xu32_0010_i0, u32, 10, 0;
+ bench_in_place_xu32_0100_i0, u32, 100, 0;
+ bench_in_place_xu32_1000_i0, u32, 1000, 0;
+ bench_in_place_xu32_0010_i1, u32, 10, 1;
+ bench_in_place_xu32_0100_i1, u32, 100, 1;
+ bench_in_place_xu32_1000_i1, u32, 1000, 1;
+ bench_in_place_u128_0010_i0, u128, 10, 0;
+ bench_in_place_u128_0100_i0, u128, 100, 0;
+ bench_in_place_u128_1000_i0, u128, 1000, 0;
+ bench_in_place_u128_0010_i1, u128, 10, 1;
+ bench_in_place_u128_0100_i1, u128, 100, 1;
+ bench_in_place_u128_1000_i1, u128, 1000, 1
];
#[bench]
//! [dijkstra]: https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm
//! [sssp]: https://en.wikipedia.org/wiki/Shortest_path_problem
//! [dir_graph]: https://en.wikipedia.org/wiki/Directed_graph
-//! [`BinaryHeap`]: struct.BinaryHeap.html
//!
//! ```
//! use std::cmp::Ordering;
use core::fmt;
use core::iter::{FromIterator, FusedIterator, InPlaceIterable, SourceIter, TrustedLen};
-use core::mem::{self, size_of, swap, ManuallyDrop};
+use core::mem::{self, swap, ManuallyDrop};
use core::ops::{Deref, DerefMut};
use core::ptr;
/// The value for `push` is an expected cost; the method documentation gives a
/// more detailed analysis.
///
-/// [push]: #method.push
-/// [pop]: #method.pop
-/// [peek]: #method.peek
-/// [peek\_mut]: #method.peek_mut
+/// [push]: BinaryHeap::push
+/// [pop]: BinaryHeap::pop
+/// [peek]: BinaryHeap::peek
+/// [peek\_mut]: BinaryHeap::peek_mut
#[stable(feature = "rust1", since = "1.0.0")]
pub struct BinaryHeap<T> {
data: Vec<T>,
/// This `struct` is created by the [`peek_mut`] method on [`BinaryHeap`]. See
/// its documentation for more.
///
-/// [`peek_mut`]: struct.BinaryHeap.html#method.peek_mut
-/// [`BinaryHeap`]: struct.BinaryHeap.html
+/// [`peek_mut`]: BinaryHeap::peek_mut
#[stable(feature = "binary_heap_peek_mut", since = "1.12.0")]
pub struct PeekMut<'a, T: 'a + Ord> {
heap: &'a mut BinaryHeap<T>,
#[inline(always)]
fn log2_fast(x: usize) -> usize {
- 8 * size_of::<usize>() - (x.leading_zeros() as usize) - 1
+ (usize::BITS - x.leading_zeros() - 1) as usize
}
// `rebuild` takes O(len1 + len2) operations
/// heap.push(4);
/// ```
///
- /// [`reserve`]: #method.reserve
+ /// [`reserve`]: BinaryHeap::reserve
#[stable(feature = "rust1", since = "1.0.0")]
pub fn reserve_exact(&mut self, additional: usize) {
self.data.reserve_exact(additional);
/// An iterator over the elements of a `BinaryHeap`.
///
-/// This `struct` is created by the [`iter`] method on [`BinaryHeap`]. See its
+/// This `struct` is created by [`BinaryHeap::iter()`]. See its
/// documentation for more.
///
-/// [`iter`]: struct.BinaryHeap.html#method.iter
-/// [`BinaryHeap`]: struct.BinaryHeap.html
+/// [`iter`]: BinaryHeap::iter
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Iter<'a, T: 'a> {
iter: slice::Iter<'a, T>,
/// An owning iterator over the elements of a `BinaryHeap`.
///
-/// This `struct` is created by the [`into_iter`] method on [`BinaryHeap`]
+/// This `struct` is created by [`BinaryHeap::into_iter()`]
/// (provided by the `IntoIterator` trait). See its documentation for more.
///
-/// [`into_iter`]: struct.BinaryHeap.html#method.into_iter
-/// [`BinaryHeap`]: struct.BinaryHeap.html
+/// [`into_iter`]: BinaryHeap::into_iter
#[stable(feature = "rust1", since = "1.0.0")]
#[derive(Clone)]
pub struct IntoIter<T> {
/// A draining iterator over the elements of a `BinaryHeap`.
///
-/// This `struct` is created by the [`drain`] method on [`BinaryHeap`]. See its
+/// This `struct` is created by [`BinaryHeap::drain()`]. See its
/// documentation for more.
///
-/// [`drain`]: struct.BinaryHeap.html#method.drain
-/// [`BinaryHeap`]: struct.BinaryHeap.html
+/// [`drain`]: BinaryHeap::drain
#[stable(feature = "drain", since = "1.6.0")]
#[derive(Debug)]
pub struct Drain<'a, T: 'a> {
/// A draining iterator over the elements of a `BinaryHeap`.
///
-/// This `struct` is created by the [`drain_sorted`] method on [`BinaryHeap`]. See its
+/// This `struct` is created by [`BinaryHeap::drain_sorted()`]. See its
/// documentation for more.
///
-/// [`drain_sorted`]: struct.BinaryHeap.html#method.drain_sorted
-/// [`BinaryHeap`]: struct.BinaryHeap.html
+/// [`drain_sorted`]: BinaryHeap::drain_sorted
#[unstable(feature = "binary_heap_drain_sorted", issue = "59278")]
#[derive(Debug)]
pub struct DrainSorted<'a, T: Ord> {
_marker: PhantomData<&'a mut T>,
}
+unsafe impl<'a, T> Sync for DormantMutRef<'a, T> where &'a mut T: Sync {}
+unsafe impl<'a, T> Send for DormantMutRef<'a, T> where &'a mut T: Send {}
+
impl<'a, T> DormantMutRef<'a, T> {
/// Capture a unique borrow, and immediately reborrow it. For the compiler,
/// the lifetime of the new reference is the same as the lifetime of the
/// any other key, as determined by the [`Ord`] trait, changes while it is in the map. This is
/// normally only possible through [`Cell`], [`RefCell`], global state, I/O, or unsafe code.
///
-/// [`Ord`]: core::cmp::Ord
/// [`Cell`]: core::cell::Cell
/// [`RefCell`]: core::cell::RefCell
///
/// }
/// ```
///
-/// `BTreeMap` also implements an [`Entry API`](#method.entry), which allows
-/// for more complex methods of getting, setting, updating and removing keys and
-/// their values:
+/// `BTreeMap` also implements an [`Entry API`], which allows for more complex
+/// methods of getting, setting, updating and removing keys and their values:
+///
+/// [`Entry API`]: BTreeMap::entry
///
/// ```
/// use std::collections::BTreeMap;
/// A view into a vacant entry in a `BTreeMap`.
/// It is part of the [`Entry`] enum.
-///
-/// [`Entry`]: enum.Entry.html
#[stable(feature = "rust1", since = "1.0.0")]
pub struct VacantEntry<'a, K: 'a, V: 'a> {
key: K,
/// A view into an occupied entry in a `BTreeMap`.
/// It is part of the [`Entry`] enum.
-///
-/// [`Entry`]: enum.Entry.html
#[stable(feature = "rust1", since = "1.0.0")]
pub struct OccupiedEntry<'a, K: 'a, V: 'a> {
handle: Handle<NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInternal>, marker::KV>,
/// types that can be `==` without being identical. See the [module-level
/// documentation] for more.
///
- /// [module-level documentation]: index.html#insert-and-complex-keys
+ /// [module-level documentation]: crate::collections#insert-and-complex-keys
///
/// # Examples
///
/// If you need a reference to the `OccupiedEntry` that may outlive the
/// destruction of the `Entry` value, see [`into_mut`].
///
- /// [`into_mut`]: #method.into_mut
+ /// [`into_mut`]: OccupiedEntry::into_mut
///
/// # Examples
///
///
/// If you need multiple references to the `OccupiedEntry`, see [`get_mut`].
///
- /// [`get_mut`]: #method.get_mut
+ /// [`get_mut`]: OccupiedEntry::get_mut
///
/// # Examples
///
}
}
+#[test]
+#[allow(dead_code)]
+fn test_sync() {
+ fn map<T: Sync>(v: &BTreeMap<T, T>) -> impl Sync + '_ {
+ v
+ }
+
+ fn into_iter<T: Sync>(v: BTreeMap<T, T>) -> impl Sync {
+ v.into_iter()
+ }
+
+ fn into_keys<T: Sync + Ord>(v: BTreeMap<T, T>) -> impl Sync {
+ v.into_keys()
+ }
+
+ fn into_values<T: Sync + Ord>(v: BTreeMap<T, T>) -> impl Sync {
+ v.into_values()
+ }
+
+ fn drain_filter<T: Sync + Ord>(v: &mut BTreeMap<T, T>) -> impl Sync + '_ {
+ v.drain_filter(|_, _| false)
+ }
+
+ fn iter<T: Sync>(v: &BTreeMap<T, T>) -> impl Sync + '_ {
+ v.iter()
+ }
+
+ fn iter_mut<T: Sync>(v: &mut BTreeMap<T, T>) -> impl Sync + '_ {
+ v.iter_mut()
+ }
+
+ fn keys<T: Sync>(v: &BTreeMap<T, T>) -> impl Sync + '_ {
+ v.keys()
+ }
+
+ fn values<T: Sync>(v: &BTreeMap<T, T>) -> impl Sync + '_ {
+ v.values()
+ }
+
+ fn values_mut<T: Sync>(v: &mut BTreeMap<T, T>) -> impl Sync + '_ {
+ v.values_mut()
+ }
+
+ fn range<T: Sync + Ord>(v: &BTreeMap<T, T>) -> impl Sync + '_ {
+ v.range(..)
+ }
+
+ fn range_mut<T: Sync + Ord>(v: &mut BTreeMap<T, T>) -> impl Sync + '_ {
+ v.range_mut(..)
+ }
+
+ fn entry<T: Sync + Ord + Default>(v: &mut BTreeMap<T, T>) -> impl Sync + '_ {
+ v.entry(Default::default())
+ }
+
+ fn occupied_entry<T: Sync + Ord + Default>(v: &mut BTreeMap<T, T>) -> impl Sync + '_ {
+ match v.entry(Default::default()) {
+ Occupied(entry) => entry,
+ _ => unreachable!(),
+ }
+ }
+
+ fn vacant_entry<T: Sync + Ord + Default>(v: &mut BTreeMap<T, T>) -> impl Sync + '_ {
+ match v.entry(Default::default()) {
+ Vacant(entry) => entry,
+ _ => unreachable!(),
+ }
+ }
+}
+
+#[test]
+#[allow(dead_code)]
+fn test_send() {
+ fn map<T: Send>(v: BTreeMap<T, T>) -> impl Send {
+ v
+ }
+
+ fn into_iter<T: Send>(v: BTreeMap<T, T>) -> impl Send {
+ v.into_iter()
+ }
+
+ fn into_keys<T: Send + Ord>(v: BTreeMap<T, T>) -> impl Send {
+ v.into_keys()
+ }
+
+ fn into_values<T: Send + Ord>(v: BTreeMap<T, T>) -> impl Send {
+ v.into_values()
+ }
+
+ fn drain_filter<T: Send + Ord>(v: &mut BTreeMap<T, T>) -> impl Send + '_ {
+ v.drain_filter(|_, _| false)
+ }
+
+ fn iter<T: Send + Sync>(v: &BTreeMap<T, T>) -> impl Send + '_ {
+ v.iter()
+ }
+
+ fn iter_mut<T: Send + Sync>(v: &mut BTreeMap<T, T>) -> impl Send + '_ {
+ v.iter_mut()
+ }
+
+ fn keys<T: Send + Sync>(v: &BTreeMap<T, T>) -> impl Send + '_ {
+ v.keys()
+ }
+
+ fn values<T: Send + Sync>(v: &BTreeMap<T, T>) -> impl Send + '_ {
+ v.values()
+ }
+
+ fn values_mut<T: Send + Sync>(v: &mut BTreeMap<T, T>) -> impl Send + '_ {
+ v.values_mut()
+ }
+
+ fn range<T: Send + Sync + Ord>(v: &BTreeMap<T, T>) -> impl Send + '_ {
+ v.range(..)
+ }
+
+ fn range_mut<T: Send + Sync + Ord>(v: &mut BTreeMap<T, T>) -> impl Send + '_ {
+ v.range_mut(..)
+ }
+
+ fn entry<T: Send + Ord + Default>(v: &mut BTreeMap<T, T>) -> impl Send + '_ {
+ v.entry(Default::default())
+ }
+
+ fn occupied_entry<T: Send + Ord + Default>(v: &mut BTreeMap<T, T>) -> impl Send + '_ {
+ match v.entry(Default::default()) {
+ Occupied(entry) => entry,
+ _ => unreachable!(),
+ }
+ }
+
+ fn vacant_entry<T: Send + Ord + Default>(v: &mut BTreeMap<T, T>) -> impl Send + '_ {
+ match v.entry(Default::default()) {
+ Vacant(entry) => entry,
+ _ => unreachable!(),
+ }
+ }
+}
+
#[test]
fn test_occupied_entry_key() {
let mut a = BTreeMap::new();
// edges: if height > 0 {
// [Box<Node<K, V, height - 1>>; 2 * B]
// } else { () },
-// parent: *const Node<K, V, height + 1>,
+// parent: Option<NonNull<Node<K, V, height + 1>>>,
// parent_idx: u16,
// len: u16,
// }
/// The underlying representation of leaf nodes.
#[repr(C)]
struct LeafNode<K, V> {
- /// We use `*const` as opposed to `*mut` so as to be covariant in `K` and `V`.
- /// This either points to an actual node or is null.
- parent: *const InternalNode<K, V>,
+ /// We want to be covariant in `K` and `V`.
+ parent: Option<NonNull<InternalNode<K, V>>>,
/// This node's index into the parent node's `edges` array.
/// `*node.parent.edges[node.parent_idx]` should be the same thing as `node`.
// be both slightly faster and easier to track in Valgrind.
keys: MaybeUninit::uninit_array(),
vals: MaybeUninit::uninit_array(),
- parent: ptr::null(),
+ parent: None,
parent_idx: MaybeUninit::uninit(),
len: 0,
}
)
};
self.height -= 1;
- self.node_as_mut().as_leaf_mut().parent = ptr::null();
+ self.node_as_mut().as_leaf_mut().parent = None;
unsafe {
Global.dealloc(NonNull::from(top).cast(), Layout::new::<InternalNode<K, V>>());
pub fn len(&self) -> usize {
// Crucially, we only access the `len` field here. If BorrowType is marker::ValMut,
// there might be outstanding mutable references to values that we must not invalidate.
- unsafe { (*self.as_leaf_ptr()).len as usize }
+ unsafe { usize::from((*self.as_leaf_ptr()).len) }
}
/// Returns the height of this node in the whole tree. Zero height denotes the
) -> Result<Handle<NodeRef<BorrowType, K, V, marker::Internal>, marker::Edge>, Self> {
// We need to use raw pointers to nodes because, if BorrowType is marker::ValMut,
// there might be outstanding mutable references to values that we must not invalidate.
- let parent_as_leaf = unsafe { (*self.as_leaf_ptr()).parent as *const LeafNode<K, V> };
- if let Some(non_zero) = NonNull::new(parent_as_leaf as *mut _) {
- Ok(Handle {
- node: NodeRef { height: self.height + 1, node: non_zero, _marker: PhantomData },
- idx: unsafe { usize::from(*(*self.as_leaf_ptr()).parent_idx.as_ptr()) },
+ let leaf_ptr = self.as_leaf_ptr();
+ unsafe { (*leaf_ptr).parent }
+ .as_ref()
+ .map(|parent| Handle {
+ node: NodeRef {
+ height: self.height + 1,
+ node: parent.cast(),
+ _marker: PhantomData,
+ },
+ idx: unsafe { usize::from((*leaf_ptr).parent_idx.assume_init()) },
_marker: PhantomData,
})
- } else {
- Err(self)
- }
+ .ok_or(self)
}
pub fn first_edge(self) -> Handle<Self, marker::Edge> {
/// Adds a key/value pair to the end of the node.
pub fn push(&mut self, key: K, val: V) {
let len = &mut self.as_leaf_mut().len;
- let idx = *len as usize;
+ let idx = usize::from(*len);
assert!(idx < CAPACITY);
*len += 1;
unsafe {
assert!(edge.height == self.height - 1);
let len = &mut self.as_leaf_mut().len;
- let idx = *len as usize;
+ let idx = usize::from(*len);
assert!(idx < CAPACITY);
*len += 1;
unsafe {
let edge =
ptr::read(internal.as_internal().edges.get_unchecked(idx + 1).as_ptr());
let mut new_root = Root { node: edge, height: internal.height - 1 };
- new_root.node_as_mut().as_leaf_mut().parent = ptr::null();
+ new_root.node_as_mut().as_leaf_mut().parent = None;
Some(new_root)
}
};
);
let mut new_root = Root { node: edge, height: internal.height - 1 };
- new_root.node_as_mut().as_leaf_mut().parent = ptr::null();
+ new_root.node_as_mut().as_leaf_mut().parent = None;
for i in 0..old_len {
Handle::new_edge(internal.reborrow_mut(), i).correct_parent_link();
/// when the ordering of edges has been changed, such as in the various `insert` methods.
fn correct_parent_link(mut self) {
let idx = self.idx as u16;
- let ptr = self.node.as_internal_mut() as *mut _;
+ let ptr = NonNull::new(self.node.as_internal_mut());
let mut child = self.descend();
child.as_leaf_mut().parent = ptr;
child.as_leaf_mut().parent_idx.write(idx);
/// This `struct` is created by the [`into_iter`] method on [`LinkedList`]
/// (provided by the `IntoIterator` trait). See its documentation for more.
///
-/// [`into_iter`]: struct.LinkedList.html#method.into_iter
+/// [`into_iter`]: LinkedList::into_iter
#[derive(Clone)]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct IntoIter<T> {
/// so that its elements do not wrap, and returns a mutable slice to the
/// now-contiguous element sequence.
///
-/// [`push_back`]: #method.push_back
-/// [`pop_front`]: #method.pop_front
-/// [`extend`]: #method.extend
-/// [`append`]: #method.append
-/// [`make_contiguous`]: #method.make_contiguous
+/// [`push_back`]: VecDeque::push_back
+/// [`pop_front`]: VecDeque::pop_front
+/// [`extend`]: VecDeque::extend
+/// [`append`]: VecDeque::append
+/// [`make_contiguous`]: VecDeque::make_contiguous
#[cfg_attr(not(test), rustc_diagnostic_item = "vecdeque_type")]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct VecDeque<T> {
/// assert!(buf.capacity() >= 11);
/// ```
///
- /// [`reserve`]: #method.reserve
+ /// [`reserve`]: VecDeque::reserve
#[stable(feature = "rust1", since = "1.0.0")]
pub fn reserve_exact(&mut self, additional: usize) {
self.reserve(additional);
/// Returns a pair of slices which contain, in order, the contents of the
/// `VecDeque`.
///
- /// If [`make_contiguous`](#method.make_contiguous) was previously called, all elements
- /// of the `VecDeque` will be in the first slice and the second slice will be empty.
+ /// If [`make_contiguous`] was previously called, all elements of the
+ /// `VecDeque` will be in the first slice and the second slice will be empty.
+ ///
+ /// [`make_contiguous`]: VecDeque::make_contiguous
///
/// # Examples
///
/// Returns a pair of slices which contain, in order, the contents of the
/// `VecDeque`.
///
- /// If [`make_contiguous`](#method.make_contiguous) was previously called, all elements
- /// of the `VecDeque` will be in the first slice and the second slice will be empty.
+ /// If [`make_contiguous`] was previously called, all elements of the
+ /// `VecDeque` will be in the first slice and the second slice will be empty.
+ ///
+ /// [`make_contiguous`]: VecDeque::make_contiguous
///
/// # Examples
///
}
}
- /// Rearranges the internal storage of this deque so it is one contiguous slice, which is then returned.
+ /// Rearranges the internal storage of this deque so it is one contiguous
+ /// slice, which is then returned.
///
- /// This method does not allocate and does not change the order of the inserted elements.
- /// As it returns a mutable slice, this can be used to sort or binary search a deque.
+ /// This method does not allocate and does not change the order of the
+ /// inserted elements. As it returns a mutable slice, this can be used to
+ /// sort or binary search a deque.
///
- /// Once the internal storage is contiguous, the [`as_slices`](#method.as_slices) and
- /// [`as_mut_slices`](#method.as_mut_slices) methods will return the entire contents of the
+ /// Once the internal storage is contiguous, the [`as_slices`] and
+ /// [`as_mut_slices`] methods will return the entire contents of the
/// `VecDeque` in a single slice.
///
+ /// [`as_slices`]: VecDeque::as_slices
+ /// [`as_mut_slices`]: VecDeque::as_mut_slices
+ ///
/// # Examples
///
/// Sorting the content of a deque.
/// This `struct` is created by the [`iter`] method on [`VecDeque`]. See its
/// documentation for more.
///
-/// [`iter`]: struct.VecDeque.html#method.iter
-/// [`VecDeque`]: struct.VecDeque.html
+/// [`iter`]: VecDeque::iter
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Iter<'a, T: 'a> {
ring: &'a [T],
/// This `struct` is created by the [`iter_mut`] method on [`VecDeque`]. See its
/// documentation for more.
///
-/// [`iter_mut`]: struct.VecDeque.html#method.iter_mut
-/// [`VecDeque`]: struct.VecDeque.html
+/// [`iter_mut`]: VecDeque::iter_mut
#[stable(feature = "rust1", since = "1.0.0")]
pub struct IterMut<'a, T: 'a> {
ring: &'a mut [T],
/// This `struct` is created by the [`into_iter`] method on [`VecDeque`]
/// (provided by the `IntoIterator` trait). See its documentation for more.
///
-/// [`into_iter`]: struct.VecDeque.html#method.into_iter
-/// [`VecDeque`]: struct.VecDeque.html
+/// [`into_iter`]: VecDeque::into_iter
#[derive(Clone)]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct IntoIter<T> {
/// This `struct` is created by the [`drain`] method on [`VecDeque`]. See its
/// documentation for more.
///
-/// [`drain`]: struct.VecDeque.html#method.drain
-/// [`VecDeque`]: struct.VecDeque.html
+/// [`drain`]: VecDeque::drain
#[stable(feature = "drain", since = "1.6.0")]
pub struct Drain<'a, T: 'a> {
pub(crate) after_tail: usize,
#![deny(unsafe_op_in_unsafe_fn)]
#![cfg_attr(not(test), feature(generator_trait))]
#![cfg_attr(test, feature(test))]
+#![cfg_attr(test, feature(new_uninit))]
#![feature(allocator_api)]
#![feature(array_chunks)]
#![feature(array_windows)]
#![feature(arbitrary_self_types)]
#![feature(box_patterns)]
#![feature(box_syntax)]
-#![feature(btree_drain_filter)]
#![feature(cfg_sanitize)]
#![feature(cfg_target_has_atomic)]
#![feature(coerce_unsized)]
#![feature(const_generics)]
#![feature(const_in_array_repeat_expressions)]
#![feature(cow_is_borrowed)]
-#![feature(deque_range)]
#![feature(dispatch_from_dyn)]
#![feature(core_intrinsics)]
-#![feature(container_error_extra)]
#![feature(dropck_eyepatch)]
#![feature(exact_size_is_empty)]
#![feature(exclusive_range_pattern)]
#![feature(fn_traits)]
#![feature(fundamental)]
#![feature(inplace_iteration)]
+#![feature(int_bits_const)]
#![feature(lang_items)]
#![feature(layout_for_ptr)]
-#![feature(libc)]
-#![feature(map_first_last)]
-#![feature(map_into_keys_values)]
#![feature(maybe_uninit_ref)]
#![feature(negative_impls)]
#![feature(never_type)]
-#![feature(new_uninit)]
#![feature(nll)]
#![feature(nonnull_slice_from_raw_parts)]
#![feature(optin_builtin_traits)]
#![feature(slice_ptr_get)]
#![feature(slice_ptr_len)]
#![feature(staged_api)]
-#![feature(std_internals)]
#![feature(str_internals)]
#![feature(trusted_len)]
-#![feature(try_reserve)]
#![feature(unboxed_closures)]
#![feature(unicode_internals)]
#![feature(unsafe_block_in_unsafe_fn)]
#[inline]
fn alloc_guard(alloc_size: usize) -> Result<(), TryReserveError> {
- if mem::size_of::<usize>() < 8 && alloc_size > isize::MAX as usize {
+ if usize::BITS < 64 && alloc_size > isize::MAX as usize {
Err(CapacityOverflow)
} else {
Ok(())
#[stable(feature = "collection_debug", since = "1.17.0")]
impl fmt::Debug for Drain<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.pad("Drain { .. }")
+ f.debug_tuple("Drain").field(&self.as_str()).finish()
}
}
}
}
+impl<'a> Drain<'a> {
+ /// Returns the remaining (sub)string of this iterator as a slice.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(string_drain_as_str)]
+ /// let mut s = String::from("abc");
+ /// let mut drain = s.drain(..);
+ /// assert_eq!(drain.as_str(), "abc");
+ /// let _ = drain.next().unwrap();
+ /// assert_eq!(drain.as_str(), "bc");
+ /// ```
+ #[unstable(feature = "string_drain_as_str", issue = "76905")] // Note: uncomment AsRef impls below when stabilizing.
+ pub fn as_str(&self) -> &str {
+ self.iter.as_str()
+ }
+}
+
+// Uncomment when stabilizing `string_drain_as_str`.
+// #[unstable(feature = "string_drain_as_str", issue = "76905")]
+// impl<'a> AsRef<str> for Drain<'a> {
+// fn as_ref(&self) -> &str {
+// self.as_str()
+// }
+// }
+//
+// #[unstable(feature = "string_drain_as_str", issue = "76905")]
+// impl<'a> AsRef<[u8]> for Drain<'a> {
+// fn as_ref(&self) -> &[u8] {
+// self.as_str().as_bytes()
+// }
+// }
+
#[stable(feature = "drain", since = "1.6.0")]
impl Iterator for Drain<'_> {
type Item = char;
#![stable(feature = "rust1", since = "1.0.0")]
use core::cmp::{self, Ordering};
+use core::convert::TryFrom;
use core::fmt;
use core::hash::{Hash, Hasher};
use core::intrinsics::{arith_offset, assume};
}
}
+#[stable(feature = "array_try_from_vec", since = "1.48.0")]
+impl<T, const N: usize> TryFrom<Vec<T>> for [T; N] {
+ type Error = Vec<T>;
+
+ /// Gets the entire contents of the `Vec<T>` as an array,
+ /// if its size exactly matches that of the requested array.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::convert::TryInto;
+ /// assert_eq!(vec![1, 2, 3].try_into(), Ok([1, 2, 3]));
+ /// assert_eq!(<Vec<i32>>::new().try_into(), Ok([]));
+ /// ```
+ ///
+ /// If the length doesn't match, the input comes back in `Err`:
+ /// ```
+ /// use std::convert::TryInto;
+ /// let r: Result<[i32; 4], _> = (0..10).collect::<Vec<_>>().try_into();
+ /// assert_eq!(r, Err(vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9]));
+ /// ```
+ ///
+ /// If you're fine with just getting a prefix of the `Vec<T>`,
+ /// you can call [`.truncate(N)`](Vec::truncate) first.
+ /// ```
+ /// use std::convert::TryInto;
+ /// let mut v = String::from("hello world").into_bytes();
+ /// v.sort();
+ /// v.truncate(2);
+ /// let [a, b]: [_; 2] = v.try_into().unwrap();
+ /// assert_eq!(a, b' ');
+ /// assert_eq!(b, b'd');
+ /// ```
+ fn try_from(mut vec: Vec<T>) -> Result<[T; N], Vec<T>> {
+ if vec.len() != N {
+ return Err(vec);
+ }
+
+ // SAFETY: `.set_len(0)` is always sound.
+ unsafe { vec.set_len(0) };
+
+ // SAFETY: A `Vec`'s pointer is always aligned properly, and
+ // the alignment the array needs is the same as the items.
+ // We checked earlier that we have sufficient items.
+ // The items will not double-drop as the `set_len`
+ // tells the `Vec` not to also drop them.
+ let array = unsafe { ptr::read(vec.as_ptr() as *const [T; N]) };
+ Ok(array)
+ }
+}
+
////////////////////////////////////////////////////////////////////////////////
// Clone-on-write
////////////////////////////////////////////////////////////////////////////////
#![feature(deque_range)]
#![feature(inplace_iteration)]
#![feature(iter_map_while)]
+#![feature(int_bits_const)]
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
use std::borrow::Cow;
use std::collections::TryReserveError::*;
-use std::mem::size_of;
use std::ops::Bound::*;
pub trait IntoCow<'a, B: ?Sized>
// on 64-bit, we assume the OS will give an OOM for such a ridiculous size.
// Any platform that succeeds for these requests is technically broken with
// ptr::offset because LLVM is the worst.
- let guards_against_isize = size_of::<usize>() < 8;
+ let guards_against_isize = usize::BITS < 64;
{
// Note: basic stuff is checked by test_reserve
const MAX_CAP: usize = isize::MAX as usize;
const MAX_USIZE: usize = usize::MAX;
- let guards_against_isize = size_of::<usize>() < 8;
+ let guards_against_isize = usize::BITS < 64;
{
let mut empty_string: String = String::new();
// on 64-bit, we assume the OS will give an OOM for such a ridiculous size.
// Any platform that succeeds for these requests is technically broken with
// ptr::offset because LLVM is the worst.
- let guards_against_isize = size_of::<usize>() < 8;
+ let guards_against_isize = usize::BITS < 64;
{
// Note: basic stuff is checked by test_reserve
//!
//! The [`escape_default`] function provides an iterator over the bytes of an
//! escaped version of the character given.
-//!
-//! [`escape_default`]: fn.escape_default.html
#![stable(feature = "core_ascii", since = "1.26.0")]
///
/// This `struct` is created by the [`escape_default`] function. See its
/// documentation for more.
-///
-/// [`escape_default`]: fn.escape_default.html
#[stable(feature = "rust1", since = "1.0.0")]
#[derive(Clone)]
pub struct EscapeDefault {
f.flags |= 1 << (FlagV1::SignAwareZeroPad as u32);
if f.width.is_none() {
- f.width = Some(((mem::size_of::<usize>() * 8) / 4) + 2);
+ f.width = Some((usize::BITS / 4) as usize + 2);
}
}
f.flags |= 1 << (FlagV1::Alternate as u32);
/// Creates a future which never resolves, representing a computation that never
/// finishes.
///
-/// This `struct` is created by the [`pending`] function. See its
+/// This `struct` is created by [`pending()`]. See its
/// documentation for more.
-///
-/// [`pending`]: fn.pending.html
#[stable(feature = "future_readiness_fns", since = "1.48.0")]
#[must_use = "futures do nothing unless you `.await` or poll them"]
pub struct Pending<T> {
/// A Future that wraps a function returning `Poll`.
///
-/// This `struct` is created by the [`poll_fn`] function. See its
+/// This `struct` is created by [`poll_fn()`]. See its
/// documentation for more.
-///
-/// [`poll_fn`]: fn.poll_fn.html
#[must_use = "futures do nothing unless you `.await` or poll them"]
#[unstable(feature = "future_poll_fn", issue = "72302")]
pub struct PollFn<F> {
/// Creates a future that is immediately ready with a value.
///
-/// This `struct` is created by the [`ready`] function. See its
+/// This `struct` is created by [`ready()`]. See its
/// documentation for more.
-///
-/// [`ready`]: fn.ready.html
#[stable(feature = "future_readiness_fns", since = "1.48.0")]
#[derive(Debug, Clone)]
#[must_use = "futures do nothing unless you `.await` or poll them"]
/// Note however, that `black_box` is only (and can only be) provided on a "best-effort" basis. The
/// extent to which it can block optimisations may vary depending upon the platform and code-gen
/// backend used. Programs cannot rely on `black_box` for *correctness* in any way.
-#[inline]
+#[cfg_attr(not(miri), inline)]
+#[cfg_attr(miri, inline(never))]
#[unstable(feature = "test", issue = "50297")]
-#[allow(unreachable_code)] // this makes #[cfg] a bit easier below.
+#[cfg_attr(miri, allow(unused_mut))]
pub fn black_box<T>(mut dummy: T) -> T {
// We need to "use" the argument in some way LLVM can't introspect, and on
// targets that support it we can typically leverage inline assembly to do
#![feature(allow_internal_unstable)]
#![feature(arbitrary_self_types)]
#![feature(asm)]
-#![feature(bound_cloned)]
#![feature(cfg_target_has_atomic)]
-#![feature(concat_idents)]
#![feature(const_alloc_layout)]
#![feature(const_discriminant)]
#![feature(const_checked_int_methods)]
#![feature(extern_types)]
#![feature(fundamental)]
#![feature(intrinsics)]
-#![feature(try_find)]
-#![feature(is_sorted)]
#![feature(lang_items)]
#![feature(link_llvm_intrinsics)]
#![feature(llvm_asm)]
#![feature(optin_builtin_traits)]
#![feature(or_patterns)]
#![feature(prelude_import)]
-#![feature(ptr_as_uninit)]
#![feature(repr_simd, platform_intrinsics)]
#![feature(rustc_attrs)]
#![feature(simd_ffi)]
#![feature(const_fn_transmute)]
#![feature(abi_unadjusted)]
#![feature(adx_target_feature)]
-#![feature(maybe_uninit_slice)]
-#![feature(maybe_uninit_extra)]
#![feature(external_doc)]
#![feature(associated_type_bounds)]
#![feature(const_caller_location)]
#[macro_use]
mod internal_macros;
-#[path = "num/int_macros.rs"]
+#[path = "num/shells/int_macros.rs"]
#[macro_use]
mod int_macros;
-#[path = "num/i128.rs"]
+#[path = "num/shells/i128.rs"]
pub mod i128;
-#[path = "num/i16.rs"]
+#[path = "num/shells/i16.rs"]
pub mod i16;
-#[path = "num/i32.rs"]
+#[path = "num/shells/i32.rs"]
pub mod i32;
-#[path = "num/i64.rs"]
+#[path = "num/shells/i64.rs"]
pub mod i64;
-#[path = "num/i8.rs"]
+#[path = "num/shells/i8.rs"]
pub mod i8;
-#[path = "num/isize.rs"]
+#[path = "num/shells/isize.rs"]
pub mod isize;
-#[path = "num/u128.rs"]
+#[path = "num/shells/u128.rs"]
pub mod u128;
-#[path = "num/u16.rs"]
+#[path = "num/shells/u16.rs"]
pub mod u16;
-#[path = "num/u32.rs"]
+#[path = "num/shells/u32.rs"]
pub mod u32;
-#[path = "num/u64.rs"]
+#[path = "num/shells/u64.rs"]
pub mod u64;
-#[path = "num/u8.rs"]
+#[path = "num/shells/u8.rs"]
pub mod u8;
-#[path = "num/usize.rs"]
+#[path = "num/shells/usize.rs"]
pub mod usize;
#[path = "num/f32.rs"]
#![macro_use]
use crate::intrinsics;
-use crate::mem;
/// Arithmetic operations required by bignums.
pub trait FullOps: Sized {
// This cannot overflow;
// the output is between `0` and `2^nbits * (2^nbits - 1)`.
// FIXME: will LLVM optimize this into ADC or similar?
- let nbits = mem::size_of::<$ty>() * 8;
let v = (self as $bigty) * (other as $bigty) + (carry as $bigty);
- ((v >> nbits) as $ty, v as $ty)
+ ((v >> <$ty>::BITS) as $ty, v as $ty)
}
fn full_mul_add(self, other: $ty, other2: $ty, carry: $ty) -> ($ty, $ty) {
// This cannot overflow;
// the output is between `0` and `2^nbits * (2^nbits - 1)`.
- let nbits = mem::size_of::<$ty>() * 8;
let v = (self as $bigty) * (other as $bigty) + (other2 as $bigty) +
(carry as $bigty);
- ((v >> nbits) as $ty, v as $ty)
+ ((v >> <$ty>::BITS) as $ty, v as $ty)
}
fn full_div_rem(self, other: $ty, borrow: $ty) -> ($ty, $ty) {
debug_assert!(borrow < other);
// This cannot overflow; the output is between `0` and `other * (2^nbits - 1)`.
- let nbits = mem::size_of::<$ty>() * 8;
- let lhs = ((borrow as $bigty) << nbits) | (self as $bigty);
+ let lhs = ((borrow as $bigty) << <$ty>::BITS) | (self as $bigty);
let rhs = other as $bigty;
((lhs / rhs) as $ty, (lhs % rhs) as $ty)
}
/// Makes a bignum from `u64` value.
pub fn from_u64(mut v: u64) -> $name {
- use crate::mem;
-
let mut base = [0; $n];
let mut sz = 0;
while v > 0 {
base[sz] = v as $ty;
- v >>= mem::size_of::<$ty>() * 8;
+ v >>= <$ty>::BITS;
sz += 1;
}
$name { size: sz, base: base }
/// Returns the `i`-th bit where bit 0 is the least significant one.
/// In other words, the bit with weight `2^i`.
pub fn get_bit(&self, i: usize) -> u8 {
- use crate::mem;
-
- let digitbits = mem::size_of::<$ty>() * 8;
+ let digitbits = <$ty>::BITS as usize;
let d = i / digitbits;
let b = i % digitbits;
((self.base[d] >> b) & 1) as u8
/// Returns the number of bits necessary to represent this value. Note that zero
/// is considered to need 0 bits.
pub fn bit_length(&self) -> usize {
- use crate::mem;
-
// Skip over the most significant digits which are zero.
let digits = self.digits();
let zeros = digits.iter().rev().take_while(|&&x| x == 0).count();
}
// This could be optimized with leading_zeros() and bit shifts, but that's
// probably not worth the hassle.
- let digitbits = mem::size_of::<$ty>() * 8;
+ let digitbits = <$ty>::BITS as usize;
let mut i = nonzero.len() * digitbits - 1;
while self.get_bit(i) == 0 {
i -= 1;
/// Multiplies itself by `2^bits` and returns its own mutable reference.
pub fn mul_pow2(&mut self, bits: usize) -> &mut $name {
- use crate::mem;
-
- let digitbits = mem::size_of::<$ty>() * 8;
+ let digitbits = <$ty>::BITS as usize;
let digits = bits / digitbits;
let bits = bits % digitbits;
/// Divide self by another bignum, overwriting `q` with the quotient and `r` with the
/// remainder.
pub fn div_rem(&self, d: &$name, q: &mut $name, r: &mut $name) {
- use crate::mem;
-
// Stupid slow base-2 long division taken from
// https://en.wikipedia.org/wiki/Division_algorithm
// FIXME use a greater base ($ty) for the long division.
assert!(!d.is_zero());
- let digitbits = mem::size_of::<$ty>() * 8;
+ let digitbits = <$ty>::BITS as usize;
for digit in &mut q.base[..] {
*digit = 0;
}
impl crate::fmt::Debug for $name {
fn fmt(&self, f: &mut crate::fmt::Formatter<'_>) -> crate::fmt::Result {
- use crate::mem;
-
let sz = if self.size < 1 { 1 } else { self.size };
- let digitlen = mem::size_of::<$ty>() * 2;
+ let digitlen = <$ty>::BITS as usize / 4;
write!(f, "{:#x}", self.base[sz - 1])?;
for &v in self.base[..sz - 1].iter().rev() {
--- /dev/null
+//! Error types for conversion to integral types.
+
+use crate::convert::Infallible;
+use crate::fmt;
+
+/// The error type returned when a checked integral type conversion fails.
+#[stable(feature = "try_from", since = "1.34.0")]
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub struct TryFromIntError(pub(crate) ());
+
+impl TryFromIntError {
+ #[unstable(
+ feature = "int_error_internals",
+ reason = "available through Error trait and this method should \
+ not be exposed publicly",
+ issue = "none"
+ )]
+ #[doc(hidden)]
+ pub fn __description(&self) -> &str {
+ "out of range integral type conversion attempted"
+ }
+}
+
+#[stable(feature = "try_from", since = "1.34.0")]
+impl fmt::Display for TryFromIntError {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ self.__description().fmt(fmt)
+ }
+}
+
+#[stable(feature = "try_from", since = "1.34.0")]
+impl From<Infallible> for TryFromIntError {
+ fn from(x: Infallible) -> TryFromIntError {
+ match x {}
+ }
+}
+
+#[unstable(feature = "never_type", issue = "35121")]
+impl From<!> for TryFromIntError {
+ fn from(never: !) -> TryFromIntError {
+ // Match rather than coerce to make sure that code like
+ // `From<Infallible> for TryFromIntError` above will keep working
+ // when `Infallible` becomes an alias to `!`.
+ match never {}
+ }
+}
+
+/// An error which can be returned when parsing an integer.
+///
+/// This error is used as the error type for the `from_str_radix()` functions
+/// on the primitive integer types, such as [`i8::from_str_radix`].
+///
+/// # Potential causes
+///
+/// Among other causes, `ParseIntError` can be thrown because of leading or trailing whitespace
+/// in the string e.g., when it is obtained from the standard input.
+/// Using the [`str.trim()`] method ensures that no whitespace remains before parsing.
+///
+/// [`str.trim()`]: ../../std/primitive.str.html#method.trim
+/// [`i8::from_str_radix`]: ../../std/primitive.i8.html#method.from_str_radix
+///
+/// # Example
+///
+/// ```
+/// if let Err(e) = i32::from_str_radix("a12", 10) {
+/// println!("Failed conversion to i32: {}", e);
+/// }
+/// ```
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct ParseIntError {
+ pub(super) kind: IntErrorKind,
+}
+
+/// Enum to store the various types of errors that can cause parsing an integer to fail.
+///
+/// # Example
+///
+/// ```
+/// #![feature(int_error_matching)]
+///
+/// # fn main() {
+/// if let Err(e) = i32::from_str_radix("a12", 10) {
+/// println!("Failed conversion to i32: {:?}", e.kind());
+/// }
+/// # }
+/// ```
+#[unstable(
+ feature = "int_error_matching",
+ reason = "it can be useful to match errors when making error messages \
+ for integer parsing",
+ issue = "22639"
+)]
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[non_exhaustive]
+pub enum IntErrorKind {
+ /// Value being parsed is empty.
+ ///
+ /// Among other causes, this variant will be constructed when parsing an empty string.
+ Empty,
+ /// Contains an invalid digit.
+ ///
+ /// Among other causes, this variant will be constructed when parsing a string that
+ /// contains a letter.
+ InvalidDigit,
+ /// Integer is too large to store in target integer type.
+ Overflow,
+ /// Integer is too small to store in target integer type.
+ Underflow,
+ /// Value was Zero
+ ///
+ /// This variant will be emitted when the parsing string has a value of zero, which
+ /// would be illegal for non-zero types.
+ Zero,
+}
+
+impl ParseIntError {
+ /// Outputs the detailed cause of parsing an integer failing.
+ #[unstable(
+ feature = "int_error_matching",
+ reason = "it can be useful to match errors when making error messages \
+ for integer parsing",
+ issue = "22639"
+ )]
+ pub fn kind(&self) -> &IntErrorKind {
+ &self.kind
+ }
+ #[unstable(
+ feature = "int_error_internals",
+ reason = "available through Error trait and this method should \
+ not be exposed publicly",
+ issue = "none"
+ )]
+ #[doc(hidden)]
+ pub fn __description(&self) -> &str {
+ match self.kind {
+ IntErrorKind::Empty => "cannot parse integer from empty string",
+ IntErrorKind::InvalidDigit => "invalid digit found in string",
+ IntErrorKind::Overflow => "number too large to fit in target type",
+ IntErrorKind::Underflow => "number too small to fit in target type",
+ IntErrorKind::Zero => "number would be zero for non-zero type",
+ }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl fmt::Display for ParseIntError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ self.__description().fmt(f)
+ }
+}
+++ /dev/null
-//! The 128-bit signed integer type.
-//!
-//! *[See also the `i128` primitive type](../../std/primitive.i128.html).*
-//!
-//! Although using these constants won’t cause compilation warnings,
-//! new code should use the associated constants directly on the primitive type.
-
-#![stable(feature = "i128", since = "1.26.0")]
-
-int_module! { i128, #[stable(feature = "i128", since="1.26.0")] }
+++ /dev/null
-//! The 16-bit signed integer type.
-//!
-//! *[See also the `i16` primitive type](../../std/primitive.i16.html).*
-//!
-//! Although using these constants won’t cause compilation warnings,
-//! new code should use the associated constants directly on the primitive type.
-
-#![stable(feature = "rust1", since = "1.0.0")]
-
-int_module! { i16 }
+++ /dev/null
-//! The 32-bit signed integer type.
-//!
-//! *[See also the `i32` primitive type](../../std/primitive.i32.html).*
-//!
-//! Although using these constants won’t cause compilation warnings,
-//! new code should use the associated constants directly on the primitive type.
-
-#![stable(feature = "rust1", since = "1.0.0")]
-
-int_module! { i32 }
+++ /dev/null
-//! The 64-bit signed integer type.
-//!
-//! *[See also the `i64` primitive type](../../std/primitive.i64.html).*
-//!
-//! Although using these constants won’t cause compilation warnings,
-//! new code should use the associated constants directly on the primitive type.
-
-#![stable(feature = "rust1", since = "1.0.0")]
-
-int_module! { i64 }
+++ /dev/null
-//! The 8-bit signed integer type.
-//!
-//! *[See also the `i8` primitive type](../../std/primitive.i8.html).*
-//!
-//! Although using these constants won’t cause compilation warnings,
-//! new code should use the associated constants directly on the primitive type.
-
-#![stable(feature = "rust1", since = "1.0.0")]
-
-int_module! { i8 }
-#![doc(hidden)]
-
-macro_rules! doc_comment {
- ($x:expr, $($tt:tt)*) => {
- #[doc = $x]
- $($tt)*
- };
-}
-
-macro_rules! int_module {
- ($T:ident) => (int_module!($T, #[stable(feature = "rust1", since = "1.0.0")]););
- ($T:ident, #[$attr:meta]) => (
+macro_rules! int_impl {
+ ($SelfT:ty, $ActualT:ident, $UnsignedT:ty, $BITS:expr, $Min:expr, $Max:expr, $Feature:expr,
+ $EndFeature:expr, $rot:expr, $rot_op:expr, $rot_result:expr, $swap_op:expr, $swapped:expr,
+ $reversed:expr, $le_bytes:expr, $be_bytes:expr,
+ $to_xe_bytes_doc:expr, $from_xe_bytes_doc:expr) => {
doc_comment! {
concat!("The smallest value that can be represented by this integer type.
-Use [`", stringify!($T), "::MIN", "`](../../std/primitive.", stringify!($T), ".html#associatedconstant.MIN) instead.
# Examples
-```rust
-// deprecated way
-let min = std::", stringify!($T), "::MIN;
+Basic usage:
-// intended way
-let min = ", stringify!($T), "::MIN;
```
-"),
- #[$attr]
- pub const MIN: $T = $T::MIN;
+", $Feature, "assert_eq!(", stringify!($SelfT), "::MIN, ", stringify!($Min), ");",
+$EndFeature, "
+```"),
+ #[stable(feature = "assoc_int_consts", since = "1.43.0")]
+ pub const MIN: Self = !0 ^ ((!0 as $UnsignedT) >> 1) as Self;
}
doc_comment! {
concat!("The largest value that can be represented by this integer type.
-Use [`", stringify!($T), "::MAX", "`](../../std/primitive.", stringify!($T), ".html#associatedconstant.MAX) instead.
# Examples
-```rust
-// deprecated way
-let max = std::", stringify!($T), "::MAX;
+Basic usage:
+
+```
+", $Feature, "assert_eq!(", stringify!($SelfT), "::MAX, ", stringify!($Max), ");",
+$EndFeature, "
+```"),
+ #[stable(feature = "assoc_int_consts", since = "1.43.0")]
+ pub const MAX: Self = !Self::MIN;
+ }
+
+ doc_comment! {
+ concat!("The size of this integer type in bits.
+
+# Examples
+
+```
+", $Feature, "#![feature(int_bits_const)]
+assert_eq!(", stringify!($SelfT), "::BITS, ", stringify!($BITS), ");",
+$EndFeature, "
+```"),
+ #[unstable(feature = "int_bits_const", issue = "76904")]
+ pub const BITS: u32 = $BITS;
+ }
+
+ doc_comment! {
+ concat!("Converts a string slice in a given base to an integer.
+
+The string is expected to be an optional `+` or `-` sign followed by digits.
+Leading and trailing whitespace represent an error. Digits are a subset of these characters,
+depending on `radix`:
+
+ * `0-9`
+ * `a-z`
+ * `A-Z`
+
+# Panics
+
+This function panics if `radix` is not in the range from 2 to 36.
+
+# Examples
+
+Basic usage:
+
+```
+", $Feature, "assert_eq!(", stringify!($SelfT), "::from_str_radix(\"A\", 16), Ok(10));",
+$EndFeature, "
+```"),
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn from_str_radix(src: &str, radix: u32) -> Result<Self, ParseIntError> {
+ from_str_radix(src, radix)
+ }
+ }
+
+ doc_comment! {
+ concat!("Returns the number of ones in the binary representation of `self`.
+
+# Examples
+
+Basic usage:
+
+```
+", $Feature, "let n = 0b100_0000", stringify!($SelfT), ";
-// intended way
-let max = ", stringify!($T), "::MAX;
+assert_eq!(n.count_ones(), 1);",
+$EndFeature, "
```
"),
- #[$attr]
- pub const MAX: $T = $T::MAX;
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
+ #[inline]
+ pub const fn count_ones(self) -> u32 { (self as $UnsignedT).count_ones() }
+ }
+
+ doc_comment! {
+ concat!("Returns the number of zeros in the binary representation of `self`.
+
+# Examples
+
+Basic usage:
+
+```
+", $Feature, "assert_eq!(", stringify!($SelfT), "::MAX.count_zeros(), 1);", $EndFeature, "
+```"),
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
+ #[inline]
+ pub const fn count_zeros(self) -> u32 {
+ (!self).count_ones()
+ }
+ }
+
+ doc_comment! {
+ concat!("Returns the number of leading zeros in the binary representation of `self`.
+
+# Examples
+
+Basic usage:
+
+```
+", $Feature, "let n = -1", stringify!($SelfT), ";
+
+assert_eq!(n.leading_zeros(), 0);",
+$EndFeature, "
+```"),
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
+ #[inline]
+ pub const fn leading_zeros(self) -> u32 {
+ (self as $UnsignedT).leading_zeros()
+ }
+ }
+
+ doc_comment! {
+ concat!("Returns the number of trailing zeros in the binary representation of `self`.
+
+# Examples
+
+Basic usage:
+
+```
+", $Feature, "let n = -4", stringify!($SelfT), ";
+
+assert_eq!(n.trailing_zeros(), 2);",
+$EndFeature, "
+```"),
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
+ #[inline]
+ pub const fn trailing_zeros(self) -> u32 {
+ (self as $UnsignedT).trailing_zeros()
+ }
+ }
+
+ doc_comment! {
+ concat!("Returns the number of leading ones in the binary representation of `self`.
+
+# Examples
+
+Basic usage:
+
+```
+", $Feature, "let n = -1", stringify!($SelfT), ";
+
+assert_eq!(n.leading_ones(), ", stringify!($BITS), ");",
+$EndFeature, "
+```"),
+ #[stable(feature = "leading_trailing_ones", since = "1.46.0")]
+ #[rustc_const_stable(feature = "leading_trailing_ones", since = "1.46.0")]
+ #[inline]
+ pub const fn leading_ones(self) -> u32 {
+ (self as $UnsignedT).leading_ones()
+ }
+ }
+
+ doc_comment! {
+ concat!("Returns the number of trailing ones in the binary representation of `self`.
+
+# Examples
+
+Basic usage:
+
+```
+", $Feature, "let n = 3", stringify!($SelfT), ";
+
+assert_eq!(n.trailing_ones(), 2);",
+$EndFeature, "
+```"),
+ #[stable(feature = "leading_trailing_ones", since = "1.46.0")]
+ #[rustc_const_stable(feature = "leading_trailing_ones", since = "1.46.0")]
+ #[inline]
+ pub const fn trailing_ones(self) -> u32 {
+ (self as $UnsignedT).trailing_ones()
+ }
+ }
+
+ doc_comment! {
+ concat!("Shifts the bits to the left by a specified amount, `n`,
+wrapping the truncated bits to the end of the resulting integer.
+
+Please note this isn't the same operation as the `<<` shifting operator!
+
+# Examples
+
+Basic usage:
+
+```
+let n = ", $rot_op, stringify!($SelfT), ";
+let m = ", $rot_result, ";
+
+assert_eq!(n.rotate_left(", $rot, "), m);
+```"),
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn rotate_left(self, n: u32) -> Self {
+ (self as $UnsignedT).rotate_left(n) as Self
+ }
+ }
+
+ doc_comment! {
+ concat!("Shifts the bits to the right by a specified amount, `n`,
+wrapping the truncated bits to the beginning of the resulting
+integer.
+
+Please note this isn't the same operation as the `>>` shifting operator!
+
+# Examples
+
+Basic usage:
+
+```
+let n = ", $rot_result, stringify!($SelfT), ";
+let m = ", $rot_op, ";
+
+assert_eq!(n.rotate_right(", $rot, "), m);
+```"),
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn rotate_right(self, n: u32) -> Self {
+ (self as $UnsignedT).rotate_right(n) as Self
+ }
+ }
+
+ doc_comment! {
+ concat!("Reverses the byte order of the integer.
+
+# Examples
+
+Basic usage:
+
+```
+let n = ", $swap_op, stringify!($SelfT), ";
+
+let m = n.swap_bytes();
+
+assert_eq!(m, ", $swapped, ");
+```"),
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
+ #[inline]
+ pub const fn swap_bytes(self) -> Self {
+ (self as $UnsignedT).swap_bytes() as Self
+ }
+ }
+
+ doc_comment! {
+ concat!("Reverses the bit pattern of the integer.
+
+# Examples
+
+Basic usage:
+
+```
+let n = ", $swap_op, stringify!($SelfT), ";
+let m = n.reverse_bits();
+
+assert_eq!(m, ", $reversed, ");
+```"),
+ #[stable(feature = "reverse_bits", since = "1.37.0")]
+ #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
+ #[inline]
+ #[must_use]
+ pub const fn reverse_bits(self) -> Self {
+ (self as $UnsignedT).reverse_bits() as Self
+ }
+ }
+
+ doc_comment! {
+ concat!("Converts an integer from big endian to the target's endianness.
+
+On big endian this is a no-op. On little endian the bytes are swapped.
+
+# Examples
+
+Basic usage:
+
+```
+", $Feature, "let n = 0x1A", stringify!($SelfT), ";
+
+if cfg!(target_endian = \"big\") {
+ assert_eq!(", stringify!($SelfT), "::from_be(n), n)
+} else {
+ assert_eq!(", stringify!($SelfT), "::from_be(n), n.swap_bytes())
+}",
+$EndFeature, "
+```"),
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_stable(feature = "const_int_conversions", since = "1.32.0")]
+ #[inline]
+ pub const fn from_be(x: Self) -> Self {
+ #[cfg(target_endian = "big")]
+ {
+ x
+ }
+ #[cfg(not(target_endian = "big"))]
+ {
+ x.swap_bytes()
+ }
+ }
+ }
+
+ doc_comment! {
+ concat!("Converts an integer from little endian to the target's endianness.
+
+On little endian this is a no-op. On big endian the bytes are swapped.
+
+# Examples
+
+Basic usage:
+
+```
+", $Feature, "let n = 0x1A", stringify!($SelfT), ";
+
+if cfg!(target_endian = \"little\") {
+ assert_eq!(", stringify!($SelfT), "::from_le(n), n)
+} else {
+ assert_eq!(", stringify!($SelfT), "::from_le(n), n.swap_bytes())
+}",
+$EndFeature, "
+```"),
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_stable(feature = "const_int_conversions", since = "1.32.0")]
+ #[inline]
+ pub const fn from_le(x: Self) -> Self {
+ #[cfg(target_endian = "little")]
+ {
+ x
+ }
+ #[cfg(not(target_endian = "little"))]
+ {
+ x.swap_bytes()
+ }
+ }
+ }
+
+ doc_comment! {
+ concat!("Converts `self` to big endian from the target's endianness.
+
+On big endian this is a no-op. On little endian the bytes are swapped.
+
+# Examples
+
+Basic usage:
+
+```
+", $Feature, "let n = 0x1A", stringify!($SelfT), ";
+
+if cfg!(target_endian = \"big\") {
+ assert_eq!(n.to_be(), n)
+} else {
+ assert_eq!(n.to_be(), n.swap_bytes())
+}",
+$EndFeature, "
+```"),
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_stable(feature = "const_int_conversions", since = "1.32.0")]
+ #[inline]
+ pub const fn to_be(self) -> Self { // or not to be?
+ #[cfg(target_endian = "big")]
+ {
+ self
+ }
+ #[cfg(not(target_endian = "big"))]
+ {
+ self.swap_bytes()
+ }
+ }
+ }
+
+ doc_comment! {
+ concat!("Converts `self` to little endian from the target's endianness.
+
+On little endian this is a no-op. On big endian the bytes are swapped.
+
+# Examples
+
+Basic usage:
+
+```
+", $Feature, "let n = 0x1A", stringify!($SelfT), ";
+
+if cfg!(target_endian = \"little\") {
+ assert_eq!(n.to_le(), n)
+} else {
+ assert_eq!(n.to_le(), n.swap_bytes())
+}",
+$EndFeature, "
+```"),
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_stable(feature = "const_int_conversions", since = "1.32.0")]
+ #[inline]
+ pub const fn to_le(self) -> Self {
+ #[cfg(target_endian = "little")]
+ {
+ self
+ }
+ #[cfg(not(target_endian = "little"))]
+ {
+ self.swap_bytes()
+ }
+ }
+ }
+
+ doc_comment! {
+ concat!("Checked integer addition. Computes `self + rhs`, returning `None`
+if overflow occurred.
+
+# Examples
+
+Basic usage:
+
+```
+", $Feature, "assert_eq!((", stringify!($SelfT),
+"::MAX - 2).checked_add(1), Some(", stringify!($SelfT), "::MAX - 1));
+assert_eq!((", stringify!($SelfT), "::MAX - 2).checked_add(3), None);",
+$EndFeature, "
+```"),
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn checked_add(self, rhs: Self) -> Option<Self> {
+ let (a, b) = self.overflowing_add(rhs);
+ if unlikely!(b) {None} else {Some(a)}
+ }
+ }
+
+ doc_comment! {
+ concat!("Unchecked integer addition. Computes `self + rhs`, assuming overflow
+cannot occur. This results in undefined behavior when `self + rhs > ", stringify!($SelfT),
+"::MAX` or `self + rhs < ", stringify!($SelfT), "::MIN`."),
+ #[unstable(
+ feature = "unchecked_math",
+ reason = "niche optimization path",
+ issue = "none",
+ )]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub unsafe fn unchecked_add(self, rhs: Self) -> Self {
+ // SAFETY: the caller must uphold the safety contract for
+ // `unchecked_add`.
+ unsafe { intrinsics::unchecked_add(self, rhs) }
+ }
+ }
+
+ doc_comment! {
+ concat!("Checked integer subtraction. Computes `self - rhs`, returning `None` if
+overflow occurred.
+
+# Examples
+
+Basic usage:
+
+```
+", $Feature, "assert_eq!((", stringify!($SelfT),
+"::MIN + 2).checked_sub(1), Some(", stringify!($SelfT), "::MIN + 1));
+assert_eq!((", stringify!($SelfT), "::MIN + 2).checked_sub(3), None);",
+$EndFeature, "
+```"),
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn checked_sub(self, rhs: Self) -> Option<Self> {
+ let (a, b) = self.overflowing_sub(rhs);
+ if unlikely!(b) {None} else {Some(a)}
+ }
+ }
+
+ doc_comment! {
+ concat!("Unchecked integer subtraction. Computes `self - rhs`, assuming overflow
+cannot occur. This results in undefined behavior when `self - rhs > ", stringify!($SelfT),
+"::MAX` or `self - rhs < ", stringify!($SelfT), "::MIN`."),
+ #[unstable(
+ feature = "unchecked_math",
+ reason = "niche optimization path",
+ issue = "none",
+ )]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub unsafe fn unchecked_sub(self, rhs: Self) -> Self {
+ // SAFETY: the caller must uphold the safety contract for
+ // `unchecked_sub`.
+ unsafe { intrinsics::unchecked_sub(self, rhs) }
+ }
+ }
+
+ doc_comment! {
+ concat!("Checked integer multiplication. Computes `self * rhs`, returning `None` if
+overflow occurred.
+
+# Examples
+
+Basic usage:
+
+```
+", $Feature, "assert_eq!(", stringify!($SelfT),
+"::MAX.checked_mul(1), Some(", stringify!($SelfT), "::MAX));
+assert_eq!(", stringify!($SelfT), "::MAX.checked_mul(2), None);",
+$EndFeature, "
+```"),
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn checked_mul(self, rhs: Self) -> Option<Self> {
+ let (a, b) = self.overflowing_mul(rhs);
+ if unlikely!(b) {None} else {Some(a)}
+ }
+ }
+
+ doc_comment! {
+ concat!("Unchecked integer multiplication. Computes `self * rhs`, assuming overflow
+cannot occur. This results in undefined behavior when `self * rhs > ", stringify!($SelfT),
+"::MAX` or `self * rhs < ", stringify!($SelfT), "::MIN`."),
+ #[unstable(
+ feature = "unchecked_math",
+ reason = "niche optimization path",
+ issue = "none",
+ )]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub unsafe fn unchecked_mul(self, rhs: Self) -> Self {
+ // SAFETY: the caller must uphold the safety contract for
+ // `unchecked_mul`.
+ unsafe { intrinsics::unchecked_mul(self, rhs) }
+ }
+ }
+
+ doc_comment! {
+ concat!("Checked integer division. Computes `self / rhs`, returning `None` if `rhs == 0`
+or the division results in overflow.
+
+# Examples
+
+Basic usage:
+
+```
+", $Feature, "assert_eq!((", stringify!($SelfT),
+"::MIN + 1).checked_div(-1), Some(", stringify!($Max), "));
+assert_eq!(", stringify!($SelfT), "::MIN.checked_div(-1), None);
+assert_eq!((1", stringify!($SelfT), ").checked_div(0), None);",
+$EndFeature, "
+```"),
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_unstable(feature = "const_checked_int_methods", issue = "53718")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn checked_div(self, rhs: Self) -> Option<Self> {
+ if unlikely!(rhs == 0 || (self == Self::MIN && rhs == -1)) {
+ None
+ } else {
+ // SAFETY: div by zero and by INT_MIN have been checked above
+ Some(unsafe { intrinsics::unchecked_div(self, rhs) })
+ }
+ }
+ }
+
+ doc_comment! {
+ concat!("Checked Euclidean division. Computes `self.div_euclid(rhs)`,
+returning `None` if `rhs == 0` or the division results in overflow.
+
+# Examples
+
+Basic usage:
+
+```
+assert_eq!((", stringify!($SelfT),
+"::MIN + 1).checked_div_euclid(-1), Some(", stringify!($Max), "));
+assert_eq!(", stringify!($SelfT), "::MIN.checked_div_euclid(-1), None);
+assert_eq!((1", stringify!($SelfT), ").checked_div_euclid(0), None);
+```"),
+ #[stable(feature = "euclidean_division", since = "1.38.0")]
+ #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn checked_div_euclid(self, rhs: Self) -> Option<Self> {
+ if unlikely!(rhs == 0 || (self == Self::MIN && rhs == -1)) {
+ None
+ } else {
+ Some(self.div_euclid(rhs))
+ }
+ }
+ }
+
+ doc_comment! {
+ concat!("Checked integer remainder. Computes `self % rhs`, returning `None` if
+`rhs == 0` or the division results in overflow.
+
+# Examples
+
+Basic usage:
+
+```
+", $Feature, "
+assert_eq!(5", stringify!($SelfT), ".checked_rem(2), Some(1));
+assert_eq!(5", stringify!($SelfT), ".checked_rem(0), None);
+assert_eq!(", stringify!($SelfT), "::MIN.checked_rem(-1), None);",
+$EndFeature, "
+```"),
+ #[stable(feature = "wrapping", since = "1.7.0")]
+ #[rustc_const_unstable(feature = "const_checked_int_methods", issue = "53718")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn checked_rem(self, rhs: Self) -> Option<Self> {
+ if unlikely!(rhs == 0 || (self == Self::MIN && rhs == -1)) {
+ None
+ } else {
+ // SAFETY: div by zero and by INT_MIN have been checked above
+ Some(unsafe { intrinsics::unchecked_rem(self, rhs) })
+ }
+ }
+ }
+
+ doc_comment! {
+ concat!("Checked Euclidean remainder. Computes `self.rem_euclid(rhs)`, returning `None`
+if `rhs == 0` or the division results in overflow.
+
+# Examples
+
+Basic usage:
+
+```
+assert_eq!(5", stringify!($SelfT), ".checked_rem_euclid(2), Some(1));
+assert_eq!(5", stringify!($SelfT), ".checked_rem_euclid(0), None);
+assert_eq!(", stringify!($SelfT), "::MIN.checked_rem_euclid(-1), None);
+```"),
+ #[stable(feature = "euclidean_division", since = "1.38.0")]
+ #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn checked_rem_euclid(self, rhs: Self) -> Option<Self> {
+ if unlikely!(rhs == 0 || (self == Self::MIN && rhs == -1)) {
+ None
+ } else {
+ Some(self.rem_euclid(rhs))
+ }
+ }
+ }
+
+ doc_comment! {
+ concat!("Checked negation. Computes `-self`, returning `None` if `self == MIN`.
+
+# Examples
+
+Basic usage:
+
+```
+", $Feature, "
+assert_eq!(5", stringify!($SelfT), ".checked_neg(), Some(-5));
+assert_eq!(", stringify!($SelfT), "::MIN.checked_neg(), None);",
+$EndFeature, "
+```"),
+ #[stable(feature = "wrapping", since = "1.7.0")]
+ #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")]
+ #[inline]
+ pub const fn checked_neg(self) -> Option<Self> {
+ let (a, b) = self.overflowing_neg();
+ if unlikely!(b) {None} else {Some(a)}
+ }
+ }
+
+ doc_comment! {
+ concat!("Checked shift left. Computes `self << rhs`, returning `None` if `rhs` is larger
+than or equal to the number of bits in `self`.
+
+# Examples
+
+Basic usage:
+
+```
+", $Feature, "assert_eq!(0x1", stringify!($SelfT), ".checked_shl(4), Some(0x10));
+assert_eq!(0x1", stringify!($SelfT), ".checked_shl(129), None);",
+$EndFeature, "
+```"),
+ #[stable(feature = "wrapping", since = "1.7.0")]
+ #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn checked_shl(self, rhs: u32) -> Option<Self> {
+ let (a, b) = self.overflowing_shl(rhs);
+ if unlikely!(b) {None} else {Some(a)}
+ }
+ }
+
+ doc_comment! {
+ concat!("Checked shift right. Computes `self >> rhs`, returning `None` if `rhs` is
+larger than or equal to the number of bits in `self`.
+
+# Examples
+
+Basic usage:
+
+```
+", $Feature, "assert_eq!(0x10", stringify!($SelfT), ".checked_shr(4), Some(0x1));
+assert_eq!(0x10", stringify!($SelfT), ".checked_shr(128), None);",
+$EndFeature, "
+```"),
+ #[stable(feature = "wrapping", since = "1.7.0")]
+ #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn checked_shr(self, rhs: u32) -> Option<Self> {
+ let (a, b) = self.overflowing_shr(rhs);
+ if unlikely!(b) {None} else {Some(a)}
+ }
+ }
+
+ doc_comment! {
+ concat!("Checked absolute value. Computes `self.abs()`, returning `None` if
+`self == MIN`.
+
+# Examples
+
+Basic usage:
+
+```
+", $Feature, "
+assert_eq!((-5", stringify!($SelfT), ").checked_abs(), Some(5));
+assert_eq!(", stringify!($SelfT), "::MIN.checked_abs(), None);",
+$EndFeature, "
+```"),
+ #[stable(feature = "no_panic_abs", since = "1.13.0")]
+ #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")]
+ #[inline]
+ pub const fn checked_abs(self) -> Option<Self> {
+ if self.is_negative() {
+ self.checked_neg()
+ } else {
+ Some(self)
+ }
+ }
+ }
+
+ doc_comment! {
+ concat!("Checked exponentiation. Computes `self.pow(exp)`, returning `None` if
+overflow occurred.
+
+# Examples
+
+Basic usage:
+
+```
+", $Feature, "assert_eq!(8", stringify!($SelfT), ".checked_pow(2), Some(64));
+assert_eq!(", stringify!($SelfT), "::MAX.checked_pow(2), None);",
+$EndFeature, "
+```"),
+
+ #[stable(feature = "no_panic_pow", since = "1.34.0")]
+ #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn checked_pow(self, mut exp: u32) -> Option<Self> {
+ if exp == 0 {
+ return Some(1);
+ }
+ let mut base = self;
+ let mut acc: Self = 1;
+
+ while exp > 1 {
+ if (exp & 1) == 1 {
+ acc = try_opt!(acc.checked_mul(base));
+ }
+ exp /= 2;
+ base = try_opt!(base.checked_mul(base));
+ }
+ // since exp!=0, finally the exp must be 1.
+ // Deal with the final bit of the exponent separately, since
+ // squaring the base afterwards is not necessary and may cause a
+ // needless overflow.
+ Some(try_opt!(acc.checked_mul(base)))
+ }
+ }
+
+ doc_comment! {
+ concat!("Saturating integer addition. Computes `self + rhs`, saturating at the numeric
+bounds instead of overflowing.
+
+# Examples
+
+Basic usage:
+
+```
+", $Feature, "assert_eq!(100", stringify!($SelfT), ".saturating_add(1), 101);
+assert_eq!(", stringify!($SelfT), "::MAX.saturating_add(100), ", stringify!($SelfT),
+"::MAX);
+assert_eq!(", stringify!($SelfT), "::MIN.saturating_add(-1), ", stringify!($SelfT),
+"::MIN);",
+$EndFeature, "
+```"),
+
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn saturating_add(self, rhs: Self) -> Self {
+ intrinsics::saturating_add(self, rhs)
+ }
+ }
+
+ doc_comment! {
+ concat!("Saturating integer subtraction. Computes `self - rhs`, saturating at the
+numeric bounds instead of overflowing.
+
+# Examples
+
+Basic usage:
+
+```
+", $Feature, "assert_eq!(100", stringify!($SelfT), ".saturating_sub(127), -27);
+assert_eq!(", stringify!($SelfT), "::MIN.saturating_sub(100), ", stringify!($SelfT),
+"::MIN);
+assert_eq!(", stringify!($SelfT), "::MAX.saturating_sub(-1), ", stringify!($SelfT),
+"::MAX);",
+$EndFeature, "
+```"),
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn saturating_sub(self, rhs: Self) -> Self {
+ intrinsics::saturating_sub(self, rhs)
+ }
+ }
+
+ doc_comment! {
+ concat!("Saturating integer negation. Computes `-self`, returning `MAX` if `self == MIN`
+instead of overflowing.
+
+# Examples
+
+Basic usage:
+
+```
+", $Feature, "assert_eq!(100", stringify!($SelfT), ".saturating_neg(), -100);
+assert_eq!((-100", stringify!($SelfT), ").saturating_neg(), 100);
+assert_eq!(", stringify!($SelfT), "::MIN.saturating_neg(), ", stringify!($SelfT),
+"::MAX);
+assert_eq!(", stringify!($SelfT), "::MAX.saturating_neg(), ", stringify!($SelfT),
+"::MIN + 1);",
+$EndFeature, "
+```"),
+
+ #[stable(feature = "saturating_neg", since = "1.45.0")]
+ #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")]
+ #[inline]
+ pub const fn saturating_neg(self) -> Self {
+ intrinsics::saturating_sub(0, self)
+ }
+ }
+
+ doc_comment! {
+ concat!("Saturating absolute value. Computes `self.abs()`, returning `MAX` if `self ==
+MIN` instead of overflowing.
+
+# Examples
+
+Basic usage:
+
+```
+", $Feature, "assert_eq!(100", stringify!($SelfT), ".saturating_abs(), 100);
+assert_eq!((-100", stringify!($SelfT), ").saturating_abs(), 100);
+assert_eq!(", stringify!($SelfT), "::MIN.saturating_abs(), ", stringify!($SelfT),
+"::MAX);
+assert_eq!((", stringify!($SelfT), "::MIN + 1).saturating_abs(), ", stringify!($SelfT),
+"::MAX);",
+$EndFeature, "
+```"),
+
+ #[stable(feature = "saturating_neg", since = "1.45.0")]
+ #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")]
+ #[inline]
+ pub const fn saturating_abs(self) -> Self {
+ if self.is_negative() {
+ self.saturating_neg()
+ } else {
+ self
+ }
+ }
+ }
+
+ doc_comment! {
+ concat!("Saturating integer multiplication. Computes `self * rhs`, saturating at the
+numeric bounds instead of overflowing.
+
+# Examples
+
+Basic usage:
+
+```
+", $Feature, "
+assert_eq!(10", stringify!($SelfT), ".saturating_mul(12), 120);
+assert_eq!(", stringify!($SelfT), "::MAX.saturating_mul(10), ", stringify!($SelfT), "::MAX);
+assert_eq!(", stringify!($SelfT), "::MIN.saturating_mul(10), ", stringify!($SelfT), "::MIN);",
+$EndFeature, "
+```"),
+ #[stable(feature = "wrapping", since = "1.7.0")]
+ #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn saturating_mul(self, rhs: Self) -> Self {
+ match self.checked_mul(rhs) {
+ Some(x) => x,
+ None => if (self < 0) == (rhs < 0) {
+ Self::MAX
+ } else {
+ Self::MIN
+ }
+ }
+ }
+ }
+
+ doc_comment! {
+ concat!("Saturating integer exponentiation. Computes `self.pow(exp)`,
+saturating at the numeric bounds instead of overflowing.
+
+# Examples
+
+Basic usage:
+
+```
+", $Feature, "
+assert_eq!((-4", stringify!($SelfT), ").saturating_pow(3), -64);
+assert_eq!(", stringify!($SelfT), "::MIN.saturating_pow(2), ", stringify!($SelfT), "::MAX);
+assert_eq!(", stringify!($SelfT), "::MIN.saturating_pow(3), ", stringify!($SelfT), "::MIN);",
+$EndFeature, "
+```"),
+ #[stable(feature = "no_panic_pow", since = "1.34.0")]
+ #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn saturating_pow(self, exp: u32) -> Self {
+ match self.checked_pow(exp) {
+ Some(x) => x,
+ None if self < 0 && exp % 2 == 1 => Self::MIN,
+ None => Self::MAX,
+ }
+ }
+ }
+
+ doc_comment! {
+ concat!("Wrapping (modular) addition. Computes `self + rhs`, wrapping around at the
+boundary of the type.
+
+# Examples
+
+Basic usage:
+
+```
+", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_add(27), 127);
+assert_eq!(", stringify!($SelfT), "::MAX.wrapping_add(2), ", stringify!($SelfT),
+"::MIN + 1);",
+$EndFeature, "
+```"),
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn wrapping_add(self, rhs: Self) -> Self {
+ intrinsics::wrapping_add(self, rhs)
+ }
+ }
+
+ doc_comment! {
+ concat!("Wrapping (modular) subtraction. Computes `self - rhs`, wrapping around at the
+boundary of the type.
+
+# Examples
+
+Basic usage:
+
+```
+", $Feature, "assert_eq!(0", stringify!($SelfT), ".wrapping_sub(127), -127);
+assert_eq!((-2", stringify!($SelfT), ").wrapping_sub(", stringify!($SelfT), "::MAX), ",
+stringify!($SelfT), "::MAX);",
+$EndFeature, "
+```"),
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn wrapping_sub(self, rhs: Self) -> Self {
+ intrinsics::wrapping_sub(self, rhs)
+ }
+ }
+
+ doc_comment! {
+ concat!("Wrapping (modular) multiplication. Computes `self * rhs`, wrapping around at
+the boundary of the type.
+
+# Examples
+
+Basic usage:
+
+```
+", $Feature, "assert_eq!(10", stringify!($SelfT), ".wrapping_mul(12), 120);
+assert_eq!(11i8.wrapping_mul(12), -124);",
+$EndFeature, "
+```"),
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn wrapping_mul(self, rhs: Self) -> Self {
+ intrinsics::wrapping_mul(self, rhs)
+ }
+ }
+
+ doc_comment! {
+ concat!("Wrapping (modular) division. Computes `self / rhs`, wrapping around at the
+boundary of the type.
+
+The only case where such wrapping can occur is when one divides `MIN / -1` on a signed type (where
+`MIN` is the negative minimal value for the type); this is equivalent to `-MIN`, a positive value
+that is too large to represent in the type. In such a case, this function returns `MIN` itself.
+
+# Panics
+
+This function will panic if `rhs` is 0.
+
+# Examples
+
+Basic usage:
+
+```
+", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_div(10), 10);
+assert_eq!((-128i8).wrapping_div(-1), -128);",
+$EndFeature, "
+```"),
+ #[stable(feature = "num_wrapping", since = "1.2.0")]
+ #[rustc_const_unstable(feature = "const_wrapping_int_methods", issue = "53718")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn wrapping_div(self, rhs: Self) -> Self {
+ self.overflowing_div(rhs).0
+ }
+ }
+
+ doc_comment! {
+ concat!("Wrapping Euclidean division. Computes `self.div_euclid(rhs)`,
+wrapping around at the boundary of the type.
+
+Wrapping will only occur in `MIN / -1` on a signed type (where `MIN` is the negative minimal value
+for the type). This is equivalent to `-MIN`, a positive value that is too large to represent in the
+type. In this case, this method returns `MIN` itself.
+
+# Panics
+
+This function will panic if `rhs` is 0.
+
+# Examples
+
+Basic usage:
+
+```
+assert_eq!(100", stringify!($SelfT), ".wrapping_div_euclid(10), 10);
+assert_eq!((-128i8).wrapping_div_euclid(-1), -128);
+```"),
+ #[stable(feature = "euclidean_division", since = "1.38.0")]
+ #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn wrapping_div_euclid(self, rhs: Self) -> Self {
+ self.overflowing_div_euclid(rhs).0
+ }
+ }
+
+ doc_comment! {
+ concat!("Wrapping (modular) remainder. Computes `self % rhs`, wrapping around at the
+boundary of the type.
+
+Such wrap-around never actually occurs mathematically; implementation artifacts make `x % y`
+invalid for `MIN / -1` on a signed type (where `MIN` is the negative minimal value). In such a case,
+this function returns `0`.
+
+# Panics
+
+This function will panic if `rhs` is 0.
+
+# Examples
+
+Basic usage:
+
+```
+", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_rem(10), 0);
+assert_eq!((-128i8).wrapping_rem(-1), 0);",
+$EndFeature, "
+```"),
+ #[stable(feature = "num_wrapping", since = "1.2.0")]
+ #[rustc_const_unstable(feature = "const_wrapping_int_methods", issue = "53718")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn wrapping_rem(self, rhs: Self) -> Self {
+ self.overflowing_rem(rhs).0
+ }
+ }
+
+ doc_comment! {
+ concat!("Wrapping Euclidean remainder. Computes `self.rem_euclid(rhs)`, wrapping around
+at the boundary of the type.
+
+Wrapping will only occur in `MIN % -1` on a signed type (where `MIN` is the negative minimal value
+for the type). In this case, this method returns 0.
+
+# Panics
+
+This function will panic if `rhs` is 0.
+
+# Examples
+
+Basic usage:
+
+```
+assert_eq!(100", stringify!($SelfT), ".wrapping_rem_euclid(10), 0);
+assert_eq!((-128i8).wrapping_rem_euclid(-1), 0);
+```"),
+ #[stable(feature = "euclidean_division", since = "1.38.0")]
+ #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn wrapping_rem_euclid(self, rhs: Self) -> Self {
+ self.overflowing_rem_euclid(rhs).0
+ }
+ }
+
+ doc_comment! {
+ concat!("Wrapping (modular) negation. Computes `-self`, wrapping around at the boundary
+of the type.
+
+The only case where such wrapping can occur is when one negates `MIN` on a signed type (where `MIN`
+is the negative minimal value for the type); this is a positive value that is too large to represent
+in the type. In such a case, this function returns `MIN` itself.
+
+# Examples
+
+Basic usage:
+
+```
+", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_neg(), -100);
+assert_eq!(", stringify!($SelfT), "::MIN.wrapping_neg(), ", stringify!($SelfT),
+"::MIN);",
+$EndFeature, "
+```"),
+ #[stable(feature = "num_wrapping", since = "1.2.0")]
+ #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
+ #[inline]
+ pub const fn wrapping_neg(self) -> Self {
+ self.overflowing_neg().0
+ }
+ }
+
+ doc_comment! {
+ concat!("Panic-free bitwise shift-left; yields `self << mask(rhs)`, where `mask` removes
+any high-order bits of `rhs` that would cause the shift to exceed the bitwidth of the type.
+
+Note that this is *not* the same as a rotate-left; the RHS of a wrapping shift-left is restricted to
+the range of the type, rather than the bits shifted out of the LHS being returned to the other end.
+The primitive integer types all implement a `[`rotate_left`](#method.rotate_left) function,
+which may be what you want instead.
+
+# Examples
+
+Basic usage:
+
+```
+", $Feature, "assert_eq!((-1", stringify!($SelfT), ").wrapping_shl(7), -128);
+assert_eq!((-1", stringify!($SelfT), ").wrapping_shl(128), -1);",
+$EndFeature, "
+```"),
+ #[stable(feature = "num_wrapping", since = "1.2.0")]
+ #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn wrapping_shl(self, rhs: u32) -> Self {
+ // SAFETY: the masking by the bitsize of the type ensures that we do not shift
+ // out of bounds
+ unsafe {
+ intrinsics::unchecked_shl(self, (rhs & ($BITS - 1)) as $SelfT)
+ }
+ }
+ }
+
+ doc_comment! {
+ concat!("Panic-free bitwise shift-right; yields `self >> mask(rhs)`, where `mask`
+removes any high-order bits of `rhs` that would cause the shift to exceed the bitwidth of the type.
+
+Note that this is *not* the same as a rotate-right; the RHS of a wrapping shift-right is restricted
+to the range of the type, rather than the bits shifted out of the LHS being returned to the other
+end. The primitive integer types all implement a [`rotate_right`](#method.rotate_right) function,
+which may be what you want instead.
+
+# Examples
+
+Basic usage:
+
+```
+", $Feature, "assert_eq!((-128", stringify!($SelfT), ").wrapping_shr(7), -1);
+assert_eq!((-128i16).wrapping_shr(64), -128);",
+$EndFeature, "
+```"),
+ #[stable(feature = "num_wrapping", since = "1.2.0")]
+ #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn wrapping_shr(self, rhs: u32) -> Self {
+ // SAFETY: the masking by the bitsize of the type ensures that we do not shift
+ // out of bounds
+ unsafe {
+ intrinsics::unchecked_shr(self, (rhs & ($BITS - 1)) as $SelfT)
+ }
+ }
+ }
+
+ doc_comment! {
+ concat!("Wrapping (modular) absolute value. Computes `self.abs()`, wrapping around at
+the boundary of the type.
+
+The only case where such wrapping can occur is when one takes the absolute value of the negative
+minimal value for the type; this is a positive value that is too large to represent in the type. In
+such a case, this function returns `MIN` itself.
+
+# Examples
+
+Basic usage:
+
+```
+", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_abs(), 100);
+assert_eq!((-100", stringify!($SelfT), ").wrapping_abs(), 100);
+assert_eq!(", stringify!($SelfT), "::MIN.wrapping_abs(), ", stringify!($SelfT),
+"::MIN);
+assert_eq!((-128i8).wrapping_abs() as u8, 128);",
+$EndFeature, "
+```"),
+ #[stable(feature = "no_panic_abs", since = "1.13.0")]
+ #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
+ #[allow(unused_attributes)]
+ #[inline]
+ pub const fn wrapping_abs(self) -> Self {
+ if self.is_negative() {
+ self.wrapping_neg()
+ } else {
+ self
+ }
+ }
+ }
+
+ doc_comment! {
+ concat!("Computes the absolute value of `self` without any wrapping
+or panicking.
+
+
+# Examples
+
+Basic usage:
+
+```
+", $Feature, "#![feature(unsigned_abs)]
+assert_eq!(100", stringify!($SelfT), ".unsigned_abs(), 100", stringify!($UnsignedT), ");
+assert_eq!((-100", stringify!($SelfT), ").unsigned_abs(), 100", stringify!($UnsignedT), ");
+assert_eq!((-128i8).unsigned_abs(), 128u8);",
+$EndFeature, "
+```"),
+ #[unstable(feature = "unsigned_abs", issue = "74913")]
+ #[inline]
+ pub const fn unsigned_abs(self) -> $UnsignedT {
+ self.wrapping_abs() as $UnsignedT
+ }
+ }
+
+ doc_comment! {
+ concat!("Wrapping (modular) exponentiation. Computes `self.pow(exp)`,
+wrapping around at the boundary of the type.
+
+# Examples
+
+Basic usage:
+
+```
+", $Feature, "assert_eq!(3", stringify!($SelfT), ".wrapping_pow(4), 81);
+assert_eq!(3i8.wrapping_pow(5), -13);
+assert_eq!(3i8.wrapping_pow(6), -39);",
+$EndFeature, "
+```"),
+ #[stable(feature = "no_panic_pow", since = "1.34.0")]
+ #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn wrapping_pow(self, mut exp: u32) -> Self {
+ if exp == 0 {
+ return 1;
+ }
+ let mut base = self;
+ let mut acc: Self = 1;
+
+ while exp > 1 {
+ if (exp & 1) == 1 {
+ acc = acc.wrapping_mul(base);
+ }
+ exp /= 2;
+ base = base.wrapping_mul(base);
+ }
+
+ // since exp!=0, finally the exp must be 1.
+ // Deal with the final bit of the exponent separately, since
+ // squaring the base afterwards is not necessary and may cause a
+ // needless overflow.
+ acc.wrapping_mul(base)
+ }
+ }
+
+ doc_comment! {
+ concat!("Calculates `self` + `rhs`
+
+Returns a tuple of the addition along with a boolean indicating whether an arithmetic overflow would
+occur. If an overflow would have occurred then the wrapped value is returned.
+
+# Examples
+
+Basic usage:
+
+```
+", $Feature, "
+assert_eq!(5", stringify!($SelfT), ".overflowing_add(2), (7, false));
+assert_eq!(", stringify!($SelfT), "::MAX.overflowing_add(1), (", stringify!($SelfT),
+"::MIN, true));", $EndFeature, "
+```"),
+ #[stable(feature = "wrapping", since = "1.7.0")]
+ #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn overflowing_add(self, rhs: Self) -> (Self, bool) {
+ let (a, b) = intrinsics::add_with_overflow(self as $ActualT, rhs as $ActualT);
+ (a as Self, b)
+ }
+ }
+
+ doc_comment! {
+ concat!("Calculates `self` - `rhs`
+
+Returns a tuple of the subtraction along with a boolean indicating whether an arithmetic overflow
+would occur. If an overflow would have occurred then the wrapped value is returned.
+
+# Examples
+
+Basic usage:
+
+```
+", $Feature, "
+assert_eq!(5", stringify!($SelfT), ".overflowing_sub(2), (3, false));
+assert_eq!(", stringify!($SelfT), "::MIN.overflowing_sub(1), (", stringify!($SelfT),
+"::MAX, true));", $EndFeature, "
+```"),
+ #[stable(feature = "wrapping", since = "1.7.0")]
+ #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn overflowing_sub(self, rhs: Self) -> (Self, bool) {
+ let (a, b) = intrinsics::sub_with_overflow(self as $ActualT, rhs as $ActualT);
+ (a as Self, b)
+ }
+ }
+
+ doc_comment! {
+ concat!("Calculates the multiplication of `self` and `rhs`.
+
+Returns a tuple of the multiplication along with a boolean indicating whether an arithmetic overflow
+would occur. If an overflow would have occurred then the wrapped value is returned.
+
+# Examples
+
+Basic usage:
+
+```
+", $Feature, "assert_eq!(5", stringify!($SelfT), ".overflowing_mul(2), (10, false));
+assert_eq!(1_000_000_000i32.overflowing_mul(10), (1410065408, true));",
+$EndFeature, "
+```"),
+ #[stable(feature = "wrapping", since = "1.7.0")]
+ #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn overflowing_mul(self, rhs: Self) -> (Self, bool) {
+ let (a, b) = intrinsics::mul_with_overflow(self as $ActualT, rhs as $ActualT);
+ (a as Self, b)
+ }
+ }
+
+ doc_comment! {
+ concat!("Calculates the divisor when `self` is divided by `rhs`.
+
+Returns a tuple of the divisor along with a boolean indicating whether an arithmetic overflow would
+occur. If an overflow would occur then self is returned.
+
+# Panics
+
+This function will panic if `rhs` is 0.
+
+# Examples
+
+Basic usage:
+
+```
+", $Feature, "
+assert_eq!(5", stringify!($SelfT), ".overflowing_div(2), (2, false));
+assert_eq!(", stringify!($SelfT), "::MIN.overflowing_div(-1), (", stringify!($SelfT),
+"::MIN, true));",
+$EndFeature, "
+```"),
+ #[inline]
+ #[stable(feature = "wrapping", since = "1.7.0")]
+ #[rustc_const_unstable(feature = "const_overflowing_int_methods", issue = "53718")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ pub const fn overflowing_div(self, rhs: Self) -> (Self, bool) {
+ if unlikely!(self == Self::MIN && rhs == -1) {
+ (self, true)
+ } else {
+ (self / rhs, false)
+ }
+ }
+ }
+
+ doc_comment! {
+ concat!("Calculates the quotient of Euclidean division `self.div_euclid(rhs)`.
+
+Returns a tuple of the divisor along with a boolean indicating whether an arithmetic overflow would
+occur. If an overflow would occur then `self` is returned.
+
+# Panics
+
+This function will panic if `rhs` is 0.
+
+# Examples
+
+Basic usage:
+
+```
+assert_eq!(5", stringify!($SelfT), ".overflowing_div_euclid(2), (2, false));
+assert_eq!(", stringify!($SelfT), "::MIN.overflowing_div_euclid(-1), (", stringify!($SelfT),
+"::MIN, true));
+```"),
+ #[inline]
+ #[stable(feature = "euclidean_division", since = "1.38.0")]
+ #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ pub const fn overflowing_div_euclid(self, rhs: Self) -> (Self, bool) {
+ if unlikely!(self == Self::MIN && rhs == -1) {
+ (self, true)
+ } else {
+ (self.div_euclid(rhs), false)
+ }
+ }
+ }
+
+ doc_comment! {
+ concat!("Calculates the remainder when `self` is divided by `rhs`.
+
+Returns a tuple of the remainder after dividing along with a boolean indicating whether an
+arithmetic overflow would occur. If an overflow would occur then 0 is returned.
+
+# Panics
+
+This function will panic if `rhs` is 0.
+
+# Examples
+
+Basic usage:
+
+```
+", $Feature, "
+assert_eq!(5", stringify!($SelfT), ".overflowing_rem(2), (1, false));
+assert_eq!(", stringify!($SelfT), "::MIN.overflowing_rem(-1), (0, true));",
+$EndFeature, "
+```"),
+ #[inline]
+ #[stable(feature = "wrapping", since = "1.7.0")]
+ #[rustc_const_unstable(feature = "const_overflowing_int_methods", issue = "53718")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ pub const fn overflowing_rem(self, rhs: Self) -> (Self, bool) {
+ if unlikely!(self == Self::MIN && rhs == -1) {
+ (0, true)
+ } else {
+ (self % rhs, false)
+ }
+ }
+ }
+
+
+ doc_comment! {
+ concat!("Overflowing Euclidean remainder. Calculates `self.rem_euclid(rhs)`.
+
+Returns a tuple of the remainder after dividing along with a boolean indicating whether an
+arithmetic overflow would occur. If an overflow would occur then 0 is returned.
+
+# Panics
+
+This function will panic if `rhs` is 0.
+
+# Examples
+
+Basic usage:
+
+```
+assert_eq!(5", stringify!($SelfT), ".overflowing_rem_euclid(2), (1, false));
+assert_eq!(", stringify!($SelfT), "::MIN.overflowing_rem_euclid(-1), (0, true));
+```"),
+ #[stable(feature = "euclidean_division", since = "1.38.0")]
+ #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn overflowing_rem_euclid(self, rhs: Self) -> (Self, bool) {
+ if unlikely!(self == Self::MIN && rhs == -1) {
+ (0, true)
+ } else {
+ (self.rem_euclid(rhs), false)
+ }
+ }
+ }
+
+
+ doc_comment! {
+ concat!("Negates self, overflowing if this is equal to the minimum value.
+
+Returns a tuple of the negated version of self along with a boolean indicating whether an overflow
+happened. If `self` is the minimum value (e.g., `i32::MIN` for values of type `i32`), then the
+minimum value will be returned again and `true` will be returned for an overflow happening.
+
+# Examples
+
+Basic usage:
+
+```
+assert_eq!(2", stringify!($SelfT), ".overflowing_neg(), (-2, false));
+assert_eq!(", stringify!($SelfT), "::MIN.overflowing_neg(), (", stringify!($SelfT),
+"::MIN, true));", $EndFeature, "
+```"),
+ #[inline]
+ #[stable(feature = "wrapping", since = "1.7.0")]
+ #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
+ #[allow(unused_attributes)]
+ pub const fn overflowing_neg(self) -> (Self, bool) {
+ if unlikely!(self == Self::MIN) {
+ (Self::MIN, true)
+ } else {
+ (-self, false)
+ }
+ }
+ }
+
+ doc_comment! {
+ concat!("Shifts self left by `rhs` bits.
+
+Returns a tuple of the shifted version of self along with a boolean indicating whether the shift
+value was larger than or equal to the number of bits. If the shift value is too large, then value is
+masked (N-1) where N is the number of bits, and this value is then used to perform the shift.
+
+# Examples
+
+Basic usage:
+
+```
+", $Feature, "assert_eq!(0x1", stringify!($SelfT),".overflowing_shl(4), (0x10, false));
+assert_eq!(0x1i32.overflowing_shl(36), (0x10, true));",
+$EndFeature, "
+```"),
+ #[stable(feature = "wrapping", since = "1.7.0")]
+ #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn overflowing_shl(self, rhs: u32) -> (Self, bool) {
+ (self.wrapping_shl(rhs), (rhs > ($BITS - 1)))
+ }
+ }
+
+ doc_comment! {
+ concat!("Shifts self right by `rhs` bits.
+
+Returns a tuple of the shifted version of self along with a boolean indicating whether the shift
+value was larger than or equal to the number of bits. If the shift value is too large, then value is
+masked (N-1) where N is the number of bits, and this value is then used to perform the shift.
+
+# Examples
+
+Basic usage:
+
+```
+", $Feature, "assert_eq!(0x10", stringify!($SelfT), ".overflowing_shr(4), (0x1, false));
+assert_eq!(0x10i32.overflowing_shr(36), (0x1, true));",
+$EndFeature, "
+```"),
+ #[stable(feature = "wrapping", since = "1.7.0")]
+ #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn overflowing_shr(self, rhs: u32) -> (Self, bool) {
+ (self.wrapping_shr(rhs), (rhs > ($BITS - 1)))
+ }
+ }
+
+ doc_comment! {
+ concat!("Computes the absolute value of `self`.
+
+Returns a tuple of the absolute version of self along with a boolean indicating whether an overflow
+happened. If self is the minimum value (e.g., ", stringify!($SelfT), "::MIN for values of type
+ ", stringify!($SelfT), "), then the minimum value will be returned again and true will be returned
+for an overflow happening.
+
+# Examples
+
+Basic usage:
+
+```
+", $Feature, "assert_eq!(10", stringify!($SelfT), ".overflowing_abs(), (10, false));
+assert_eq!((-10", stringify!($SelfT), ").overflowing_abs(), (10, false));
+assert_eq!((", stringify!($SelfT), "::MIN).overflowing_abs(), (", stringify!($SelfT),
+"::MIN, true));",
+$EndFeature, "
+```"),
+ #[stable(feature = "no_panic_abs", since = "1.13.0")]
+ #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
+ #[inline]
+ pub const fn overflowing_abs(self) -> (Self, bool) {
+ (self.wrapping_abs(), self == Self::MIN)
+ }
+ }
+
+ doc_comment! {
+ concat!("Raises self to the power of `exp`, using exponentiation by squaring.
+
+Returns a tuple of the exponentiation along with a bool indicating
+whether an overflow happened.
+
+# Examples
+
+Basic usage:
+
+```
+", $Feature, "assert_eq!(3", stringify!($SelfT), ".overflowing_pow(4), (81, false));
+assert_eq!(3i8.overflowing_pow(5), (-13, true));",
+$EndFeature, "
+```"),
+ #[stable(feature = "no_panic_pow", since = "1.34.0")]
+ #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn overflowing_pow(self, mut exp: u32) -> (Self, bool) {
+ if exp == 0 {
+ return (1,false);
+ }
+ let mut base = self;
+ let mut acc: Self = 1;
+ let mut overflown = false;
+ // Scratch space for storing results of overflowing_mul.
+ let mut r;
+
+ while exp > 1 {
+ if (exp & 1) == 1 {
+ r = acc.overflowing_mul(base);
+ acc = r.0;
+ overflown |= r.1;
+ }
+ exp /= 2;
+ r = base.overflowing_mul(base);
+ base = r.0;
+ overflown |= r.1;
+ }
+
+ // since exp!=0, finally the exp must be 1.
+ // Deal with the final bit of the exponent separately, since
+ // squaring the base afterwards is not necessary and may cause a
+ // needless overflow.
+ r = acc.overflowing_mul(base);
+ r.1 |= overflown;
+ r
+ }
+ }
+
+ doc_comment! {
+ concat!("Raises self to the power of `exp`, using exponentiation by squaring.
+
+# Examples
+
+Basic usage:
+
+```
+", $Feature, "let x: ", stringify!($SelfT), " = 2; // or any other integer type
+
+assert_eq!(x.pow(5), 32);",
+$EndFeature, "
+```"),
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ #[rustc_inherit_overflow_checks]
+ pub const fn pow(self, mut exp: u32) -> Self {
+ if exp == 0 {
+ return 1;
+ }
+ let mut base = self;
+ let mut acc = 1;
+
+ while exp > 1 {
+ if (exp & 1) == 1 {
+ acc = acc * base;
+ }
+ exp /= 2;
+ base = base * base;
+ }
+
+ // since exp!=0, finally the exp must be 1.
+ // Deal with the final bit of the exponent separately, since
+ // squaring the base afterwards is not necessary and may cause a
+ // needless overflow.
+ acc * base
+ }
+ }
+
+ doc_comment! {
+ concat!("Calculates the quotient of Euclidean division of `self` by `rhs`.
+
+This computes the integer `n` such that `self = n * rhs + self.rem_euclid(rhs)`,
+with `0 <= self.rem_euclid(rhs) < rhs`.
+
+In other words, the result is `self / rhs` rounded to the integer `n`
+such that `self >= n * rhs`.
+If `self > 0`, this is equal to round towards zero (the default in Rust);
+if `self < 0`, this is equal to round towards +/- infinity.
+
+# Panics
+
+This function will panic if `rhs` is 0 or the division results in overflow.
+
+# Examples
+
+Basic usage:
+
+```
+let a: ", stringify!($SelfT), " = 7; // or any other integer type
+let b = 4;
+
+assert_eq!(a.div_euclid(b), 1); // 7 >= 4 * 1
+assert_eq!(a.div_euclid(-b), -1); // 7 >= -4 * -1
+assert_eq!((-a).div_euclid(b), -2); // -7 >= 4 * -2
+assert_eq!((-a).div_euclid(-b), 2); // -7 >= -4 * 2
+```"),
+ #[stable(feature = "euclidean_division", since = "1.38.0")]
+ #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ #[rustc_inherit_overflow_checks]
+ pub const fn div_euclid(self, rhs: Self) -> Self {
+ let q = self / rhs;
+ if self % rhs < 0 {
+ return if rhs > 0 { q - 1 } else { q + 1 }
+ }
+ q
+ }
+ }
+
+
+ doc_comment! {
+ concat!("Calculates the least nonnegative remainder of `self (mod rhs)`.
+
+This is done as if by the Euclidean division algorithm -- given
+`r = self.rem_euclid(rhs)`, `self = rhs * self.div_euclid(rhs) + r`, and
+`0 <= r < abs(rhs)`.
+
+# Panics
+
+This function will panic if `rhs` is 0 or the division results in overflow.
+
+# Examples
+
+Basic usage:
+
+```
+let a: ", stringify!($SelfT), " = 7; // or any other integer type
+let b = 4;
+
+assert_eq!(a.rem_euclid(b), 3);
+assert_eq!((-a).rem_euclid(b), 1);
+assert_eq!(a.rem_euclid(-b), 3);
+assert_eq!((-a).rem_euclid(-b), 1);
+```"),
+ #[stable(feature = "euclidean_division", since = "1.38.0")]
+ #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ #[rustc_inherit_overflow_checks]
+ pub const fn rem_euclid(self, rhs: Self) -> Self {
+ let r = self % rhs;
+ if r < 0 {
+ if rhs < 0 {
+ r - rhs
+ } else {
+ r + rhs
+ }
+ } else {
+ r
+ }
+ }
+ }
+
+ doc_comment! {
+ concat!("Computes the absolute value of `self`.
+
+# Overflow behavior
+
+The absolute value of `", stringify!($SelfT), "::MIN` cannot be represented as an
+`", stringify!($SelfT), "`, and attempting to calculate it will cause an overflow. This means that
+code in debug mode will trigger a panic on this case and optimized code will return `",
+stringify!($SelfT), "::MIN` without a panic.
+
+# Examples
+
+Basic usage:
+
+```
+", $Feature, "assert_eq!(10", stringify!($SelfT), ".abs(), 10);
+assert_eq!((-10", stringify!($SelfT), ").abs(), 10);",
+$EndFeature, "
+```"),
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
+ #[allow(unused_attributes)]
+ #[inline]
+ #[rustc_inherit_overflow_checks]
+ pub const fn abs(self) -> Self {
+ // Note that the #[inline] above means that the overflow
+ // semantics of the subtraction depend on the crate we're being
+ // inlined into.
+ if self.is_negative() {
+ -self
+ } else {
+ self
+ }
+ }
+ }
+
+ doc_comment! {
+ concat!("Returns a number representing sign of `self`.
+
+ - `0` if the number is zero
+ - `1` if the number is positive
+ - `-1` if the number is negative
+
+# Examples
+
+Basic usage:
+
+```
+", $Feature, "assert_eq!(10", stringify!($SelfT), ".signum(), 1);
+assert_eq!(0", stringify!($SelfT), ".signum(), 0);
+assert_eq!((-10", stringify!($SelfT), ").signum(), -1);",
+$EndFeature, "
+```"),
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_stable(feature = "const_int_sign", since = "1.47.0")]
+ #[inline]
+ pub const fn signum(self) -> Self {
+ match self {
+ n if n > 0 => 1,
+ 0 => 0,
+ _ => -1,
+ }
+ }
+ }
+
+ doc_comment! {
+ concat!("Returns `true` if `self` is positive and `false` if the number is zero or
+negative.
+
+# Examples
+
+Basic usage:
+
+```
+", $Feature, "assert!(10", stringify!($SelfT), ".is_positive());
+assert!(!(-10", stringify!($SelfT), ").is_positive());",
+$EndFeature, "
+```"),
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
+ #[inline]
+ pub const fn is_positive(self) -> bool { self > 0 }
+ }
+
+ doc_comment! {
+ concat!("Returns `true` if `self` is negative and `false` if the number is zero or
+positive.
+
+# Examples
+
+Basic usage:
+
+```
+", $Feature, "assert!((-10", stringify!($SelfT), ").is_negative());
+assert!(!10", stringify!($SelfT), ".is_negative());",
+$EndFeature, "
+```"),
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
+ #[inline]
+ pub const fn is_negative(self) -> bool { self < 0 }
+ }
+
+ doc_comment! {
+ concat!("Return the memory representation of this integer as a byte array in
+big-endian (network) byte order.
+",
+$to_xe_bytes_doc,
+"
+# Examples
+
+```
+let bytes = ", $swap_op, stringify!($SelfT), ".to_be_bytes();
+assert_eq!(bytes, ", $be_bytes, ");
+```"),
+ #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
+ #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")]
+ #[inline]
+ pub const fn to_be_bytes(self) -> [u8; mem::size_of::<Self>()] {
+ self.to_be().to_ne_bytes()
+ }
+ }
+
+doc_comment! {
+ concat!("Return the memory representation of this integer as a byte array in
+little-endian byte order.
+",
+$to_xe_bytes_doc,
+"
+# Examples
+
+```
+let bytes = ", $swap_op, stringify!($SelfT), ".to_le_bytes();
+assert_eq!(bytes, ", $le_bytes, ");
+```"),
+ #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
+ #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")]
+ #[inline]
+ pub const fn to_le_bytes(self) -> [u8; mem::size_of::<Self>()] {
+ self.to_le().to_ne_bytes()
+ }
+ }
+
+ doc_comment! {
+ concat!("
+Return the memory representation of this integer as a byte array in
+native byte order.
+
+As the target platform's native endianness is used, portable code
+should use [`to_be_bytes`] or [`to_le_bytes`], as appropriate,
+instead.
+",
+$to_xe_bytes_doc,
+"
+[`to_be_bytes`]: #method.to_be_bytes
+[`to_le_bytes`]: #method.to_le_bytes
+
+# Examples
+
+```
+let bytes = ", $swap_op, stringify!($SelfT), ".to_ne_bytes();
+assert_eq!(
+ bytes,
+ if cfg!(target_endian = \"big\") {
+ ", $be_bytes, "
+ } else {
+ ", $le_bytes, "
+ }
+);
+```"),
+ #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
+ #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")]
+ // SAFETY: const sound because integers are plain old datatypes so we can always
+ // transmute them to arrays of bytes
+ #[allow_internal_unstable(const_fn_transmute)]
+ #[inline]
+ pub const fn to_ne_bytes(self) -> [u8; mem::size_of::<Self>()] {
+ // SAFETY: integers are plain old datatypes so we can always transmute them to
+ // arrays of bytes
+ unsafe { mem::transmute(self) }
+ }
+ }
+
+doc_comment! {
+ concat!("Create an integer value from its representation as a byte array in
+big endian.
+",
+$from_xe_bytes_doc,
+"
+# Examples
+
+```
+let value = ", stringify!($SelfT), "::from_be_bytes(", $be_bytes, ");
+assert_eq!(value, ", $swap_op, ");
+```
+
+When starting from a slice rather than an array, fallible conversion APIs can be used:
+
+```
+use std::convert::TryInto;
+
+fn read_be_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " {
+ let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">());
+ *input = rest;
+ ", stringify!($SelfT), "::from_be_bytes(int_bytes.try_into().unwrap())
+}
+```"),
+ #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
+ #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")]
+ #[inline]
+ pub const fn from_be_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
+ Self::from_be(Self::from_ne_bytes(bytes))
+ }
+ }
+
+doc_comment! {
+ concat!("
+Create an integer value from its representation as a byte array in
+little endian.
+",
+$from_xe_bytes_doc,
+"
+# Examples
+
+```
+let value = ", stringify!($SelfT), "::from_le_bytes(", $le_bytes, ");
+assert_eq!(value, ", $swap_op, ");
+```
+
+When starting from a slice rather than an array, fallible conversion APIs can be used:
+
+```
+use std::convert::TryInto;
+
+fn read_le_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " {
+ let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">());
+ *input = rest;
+ ", stringify!($SelfT), "::from_le_bytes(int_bytes.try_into().unwrap())
+}
+```"),
+ #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
+ #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")]
+ #[inline]
+ pub const fn from_le_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
+ Self::from_le(Self::from_ne_bytes(bytes))
+ }
+ }
+
+ doc_comment! {
+ concat!("Create an integer value from its memory representation as a byte
+array in native endianness.
+
+As the target platform's native endianness is used, portable code
+likely wants to use [`from_be_bytes`] or [`from_le_bytes`], as
+appropriate instead.
+
+[`from_be_bytes`]: #method.from_be_bytes
+[`from_le_bytes`]: #method.from_le_bytes
+",
+$from_xe_bytes_doc,
+"
+# Examples
+
+```
+let value = ", stringify!($SelfT), "::from_ne_bytes(if cfg!(target_endian = \"big\") {
+ ", $be_bytes, "
+} else {
+ ", $le_bytes, "
+});
+assert_eq!(value, ", $swap_op, ");
+```
+
+When starting from a slice rather than an array, fallible conversion APIs can be used:
+
+```
+use std::convert::TryInto;
+
+fn read_ne_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " {
+ let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">());
+ *input = rest;
+ ", stringify!($SelfT), "::from_ne_bytes(int_bytes.try_into().unwrap())
+}
+```"),
+ #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
+ #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")]
+ // SAFETY: const sound because integers are plain old datatypes so we can always
+ // transmute to them
+ #[allow_internal_unstable(const_fn_transmute)]
+ #[inline]
+ pub const fn from_ne_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
+ // SAFETY: integers are plain old datatypes so we can always transmute to them
+ unsafe { mem::transmute(bytes) }
+ }
+ }
+
+ doc_comment! {
+ concat!("**This method is soft-deprecated.**
+
+Although using it won’t cause a compilation warning,
+new code should use [`", stringify!($SelfT), "::MIN", "`](#associatedconstant.MIN) instead.
+
+Returns the smallest value that can be represented by this integer type."),
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline(always)]
+ #[rustc_promotable]
+ #[rustc_const_stable(feature = "const_min_value", since = "1.32.0")]
+ pub const fn min_value() -> Self {
+ Self::MIN
+ }
+ }
+
+ doc_comment! {
+ concat!("**This method is soft-deprecated.**
+
+Although using it won’t cause a compilation warning,
+new code should use [`", stringify!($SelfT), "::MAX", "`](#associatedconstant.MAX) instead.
+
+Returns the largest value that can be represented by this integer type."),
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline(always)]
+ #[rustc_promotable]
+ #[rustc_const_stable(feature = "const_max_value", since = "1.32.0")]
+ pub const fn max_value() -> Self {
+ Self::MAX
+ }
}
- )
+ }
}
+++ /dev/null
-//! The pointer-sized signed integer type.
-//!
-//! *[See also the `isize` primitive type](../../std/primitive.isize.html).*
-//!
-//! Although using these constants won’t cause compilation warnings,
-//! new code should use the associated constants directly on the primitive type.
-
-#![stable(feature = "rust1", since = "1.0.0")]
-
-int_module! { isize }
-// ignore-tidy-filelength
-
-//! Numeric traits and functions for the built-in numeric types.
-
-#![stable(feature = "rust1", since = "1.0.0")]
-
-use crate::convert::Infallible;
-use crate::fmt;
-use crate::intrinsics;
-use crate::mem;
-use crate::ops::{BitOr, BitOrAssign};
-use crate::str::FromStr;
-
-// Used because the `?` operator is not allowed in a const context.
-macro_rules! try_opt {
- ($e:expr) => {
- match $e {
- Some(x) => x,
- None => return None,
- }
- };
-}
-
-#[allow_internal_unstable(const_likely)]
-macro_rules! unlikely {
- ($e: expr) => {
- intrinsics::unlikely($e)
- };
-}
-
-macro_rules! impl_nonzero_fmt {
- ( #[$stability: meta] ( $( $Trait: ident ),+ ) for $Ty: ident ) => {
- $(
- #[$stability]
- impl fmt::$Trait for $Ty {
- #[inline]
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- self.get().fmt(f)
- }
- }
- )+
- }
-}
-
-macro_rules! doc_comment {
- ($x:expr, $($tt:tt)*) => {
- #[doc = $x]
- $($tt)*
- };
-}
-
-macro_rules! nonzero_integers {
- ( $( #[$stability: meta] $Ty: ident($Int: ty); )+ ) => {
- $(
- doc_comment! {
- concat!("An integer that is known not to equal zero.
-
-This enables some memory layout optimization.
-For example, `Option<", stringify!($Ty), ">` is the same size as `", stringify!($Int), "`:
-
-```rust
-use std::mem::size_of;
-assert_eq!(size_of::<Option<core::num::", stringify!($Ty), ">>(), size_of::<", stringify!($Int),
-">());
-```"),
- #[$stability]
- #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
- #[repr(transparent)]
- #[rustc_layout_scalar_valid_range_start(1)]
- #[rustc_nonnull_optimization_guaranteed]
- pub struct $Ty($Int);
- }
-
- impl $Ty {
- /// Creates a non-zero without checking the value.
- ///
- /// # Safety
- ///
- /// The value must not be zero.
- #[$stability]
- #[rustc_const_stable(feature = "nonzero", since = "1.34.0")]
- #[inline]
- pub const unsafe fn new_unchecked(n: $Int) -> Self {
- // SAFETY: this is guaranteed to be safe by the caller.
- unsafe { Self(n) }
- }
-
- /// Creates a non-zero if the given value is not zero.
- #[$stability]
- #[rustc_const_stable(feature = "const_nonzero_int_methods", since = "1.47.0")]
- #[inline]
- pub const fn new(n: $Int) -> Option<Self> {
- if n != 0 {
- // SAFETY: we just checked that there's no `0`
- Some(unsafe { Self(n) })
- } else {
- None
- }
- }
-
- /// Returns the value as a primitive type.
- #[$stability]
- #[inline]
- #[rustc_const_stable(feature = "nonzero", since = "1.34.0")]
- pub const fn get(self) -> $Int {
- self.0
- }
-
- }
-
- #[stable(feature = "from_nonzero", since = "1.31.0")]
- impl From<$Ty> for $Int {
- doc_comment! {
- concat!(
-"Converts a `", stringify!($Ty), "` into an `", stringify!($Int), "`"),
- fn from(nonzero: $Ty) -> Self {
- nonzero.0
- }
- }
- }
-
- #[stable(feature = "nonzero_bitor", since = "1.45.0")]
- impl BitOr for $Ty {
- type Output = Self;
- #[inline]
- fn bitor(self, rhs: Self) -> Self::Output {
- // SAFETY: since `self` and `rhs` are both nonzero, the
- // result of the bitwise-or will be nonzero.
- unsafe { $Ty::new_unchecked(self.get() | rhs.get()) }
- }
- }
-
- #[stable(feature = "nonzero_bitor", since = "1.45.0")]
- impl BitOr<$Int> for $Ty {
- type Output = Self;
- #[inline]
- fn bitor(self, rhs: $Int) -> Self::Output {
- // SAFETY: since `self` is nonzero, the result of the
- // bitwise-or will be nonzero regardless of the value of
- // `rhs`.
- unsafe { $Ty::new_unchecked(self.get() | rhs) }
- }
- }
-
- #[stable(feature = "nonzero_bitor", since = "1.45.0")]
- impl BitOr<$Ty> for $Int {
- type Output = $Ty;
- #[inline]
- fn bitor(self, rhs: $Ty) -> Self::Output {
- // SAFETY: since `rhs` is nonzero, the result of the
- // bitwise-or will be nonzero regardless of the value of
- // `self`.
- unsafe { $Ty::new_unchecked(self | rhs.get()) }
- }
- }
-
- #[stable(feature = "nonzero_bitor", since = "1.45.0")]
- impl BitOrAssign for $Ty {
- #[inline]
- fn bitor_assign(&mut self, rhs: Self) {
- *self = *self | rhs;
- }
- }
-
- #[stable(feature = "nonzero_bitor", since = "1.45.0")]
- impl BitOrAssign<$Int> for $Ty {
- #[inline]
- fn bitor_assign(&mut self, rhs: $Int) {
- *self = *self | rhs;
- }
- }
-
- impl_nonzero_fmt! {
- #[$stability] (Debug, Display, Binary, Octal, LowerHex, UpperHex) for $Ty
- }
- )+
- }
-}
-
-nonzero_integers! {
- #[stable(feature = "nonzero", since = "1.28.0")] NonZeroU8(u8);
- #[stable(feature = "nonzero", since = "1.28.0")] NonZeroU16(u16);
- #[stable(feature = "nonzero", since = "1.28.0")] NonZeroU32(u32);
- #[stable(feature = "nonzero", since = "1.28.0")] NonZeroU64(u64);
- #[stable(feature = "nonzero", since = "1.28.0")] NonZeroU128(u128);
- #[stable(feature = "nonzero", since = "1.28.0")] NonZeroUsize(usize);
- #[stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI8(i8);
- #[stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI16(i16);
- #[stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI32(i32);
- #[stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI64(i64);
- #[stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI128(i128);
- #[stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroIsize(isize);
-}
-
-macro_rules! from_str_radix_nzint_impl {
- ($($t:ty)*) => {$(
- #[stable(feature = "nonzero_parse", since = "1.35.0")]
- impl FromStr for $t {
- type Err = ParseIntError;
- fn from_str(src: &str) -> Result<Self, Self::Err> {
- Self::new(from_str_radix(src, 10)?)
- .ok_or(ParseIntError {
- kind: IntErrorKind::Zero
- })
- }
- }
- )*}
-}
-
-from_str_radix_nzint_impl! { NonZeroU8 NonZeroU16 NonZeroU32 NonZeroU64 NonZeroU128 NonZeroUsize
-NonZeroI8 NonZeroI16 NonZeroI32 NonZeroI64 NonZeroI128 NonZeroIsize }
-
-/// Provides intentionally-wrapped arithmetic on `T`.
-///
-/// Operations like `+` on `u32` values are intended to never overflow,
-/// and in some debug configurations overflow is detected and results
-/// in a panic. While most arithmetic falls into this category, some
-/// code explicitly expects and relies upon modular arithmetic (e.g.,
-/// hashing).
-///
-/// Wrapping arithmetic can be achieved either through methods like
-/// `wrapping_add`, or through the `Wrapping<T>` type, which says that
-/// all standard arithmetic operations on the underlying value are
-/// intended to have wrapping semantics.
-///
-/// The underlying value can be retrieved through the `.0` index of the
-/// `Wrapping` tuple.
-///
-/// # Examples
-///
-/// ```
-/// use std::num::Wrapping;
-///
-/// let zero = Wrapping(0u32);
-/// let one = Wrapping(1u32);
-///
-/// assert_eq!(u32::MAX, (zero - one).0);
-/// ```
-#[stable(feature = "rust1", since = "1.0.0")]
-#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Default, Hash)]
-#[repr(transparent)]
-pub struct Wrapping<T>(#[stable(feature = "rust1", since = "1.0.0")] pub T);
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: fmt::Debug> fmt::Debug for Wrapping<T> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- self.0.fmt(f)
- }
-}
-
-#[stable(feature = "wrapping_display", since = "1.10.0")]
-impl<T: fmt::Display> fmt::Display for Wrapping<T> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- self.0.fmt(f)
- }
-}
-
-#[stable(feature = "wrapping_fmt", since = "1.11.0")]
-impl<T: fmt::Binary> fmt::Binary for Wrapping<T> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- self.0.fmt(f)
- }
-}
-
-#[stable(feature = "wrapping_fmt", since = "1.11.0")]
-impl<T: fmt::Octal> fmt::Octal for Wrapping<T> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- self.0.fmt(f)
- }
-}
-
-#[stable(feature = "wrapping_fmt", since = "1.11.0")]
-impl<T: fmt::LowerHex> fmt::LowerHex for Wrapping<T> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- self.0.fmt(f)
- }
-}
-
-#[stable(feature = "wrapping_fmt", since = "1.11.0")]
-impl<T: fmt::UpperHex> fmt::UpperHex for Wrapping<T> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- self.0.fmt(f)
- }
-}
-
-// All these modules are technically private and only exposed for coretests:
-pub mod bignum;
-pub mod dec2flt;
-pub mod diy_float;
-pub mod flt2dec;
-
-mod wrapping;
-
-macro_rules! usize_isize_to_xe_bytes_doc {
- () => {
- "
-
-**Note**: This function returns an array of length 2, 4 or 8 bytes
-depending on the target pointer size.
-
-"
- };
-}
-
-macro_rules! usize_isize_from_xe_bytes_doc {
- () => {
- "
-
-**Note**: This function takes an array of length 2, 4 or 8 bytes
-depending on the target pointer size.
-
-"
- };
-}
-
-macro_rules! int_impl {
- ($SelfT:ty, $ActualT:ident, $UnsignedT:ty, $BITS:expr, $Min:expr, $Max:expr, $Feature:expr,
- $EndFeature:expr, $rot:expr, $rot_op:expr, $rot_result:expr, $swap_op:expr, $swapped:expr,
- $reversed:expr, $le_bytes:expr, $be_bytes:expr,
- $to_xe_bytes_doc:expr, $from_xe_bytes_doc:expr) => {
- doc_comment! {
- concat!("The smallest value that can be represented by this integer type.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(", stringify!($SelfT), "::MIN, ", stringify!($Min), ");",
-$EndFeature, "
-```"),
- #[stable(feature = "assoc_int_consts", since = "1.43.0")]
- pub const MIN: Self = !0 ^ ((!0 as $UnsignedT) >> 1) as Self;
- }
-
- doc_comment! {
- concat!("The largest value that can be represented by this integer type.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(", stringify!($SelfT), "::MAX, ", stringify!($Max), ");",
-$EndFeature, "
-```"),
- #[stable(feature = "assoc_int_consts", since = "1.43.0")]
- pub const MAX: Self = !Self::MIN;
- }
-
- doc_comment! {
- concat!("Converts a string slice in a given base to an integer.
-
-The string is expected to be an optional `+` or `-` sign followed by digits.
-Leading and trailing whitespace represent an error. Digits are a subset of these characters,
-depending on `radix`:
-
- * `0-9`
- * `a-z`
- * `A-Z`
-
-# Panics
-
-This function panics if `radix` is not in the range from 2 to 36.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(", stringify!($SelfT), "::from_str_radix(\"A\", 16), Ok(10));",
-$EndFeature, "
-```"),
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn from_str_radix(src: &str, radix: u32) -> Result<Self, ParseIntError> {
- from_str_radix(src, radix)
- }
- }
-
- doc_comment! {
- concat!("Returns the number of ones in the binary representation of `self`.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "let n = 0b100_0000", stringify!($SelfT), ";
-
-assert_eq!(n.count_ones(), 1);",
-$EndFeature, "
-```
-"),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
- #[inline]
- pub const fn count_ones(self) -> u32 { (self as $UnsignedT).count_ones() }
- }
-
- doc_comment! {
- concat!("Returns the number of zeros in the binary representation of `self`.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(", stringify!($SelfT), "::MAX.count_zeros(), 1);", $EndFeature, "
-```"),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
- #[inline]
- pub const fn count_zeros(self) -> u32 {
- (!self).count_ones()
- }
- }
-
- doc_comment! {
- concat!("Returns the number of leading zeros in the binary representation of `self`.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "let n = -1", stringify!($SelfT), ";
-
-assert_eq!(n.leading_zeros(), 0);",
-$EndFeature, "
-```"),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
- #[inline]
- pub const fn leading_zeros(self) -> u32 {
- (self as $UnsignedT).leading_zeros()
- }
- }
-
- doc_comment! {
- concat!("Returns the number of trailing zeros in the binary representation of `self`.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "let n = -4", stringify!($SelfT), ";
-
-assert_eq!(n.trailing_zeros(), 2);",
-$EndFeature, "
-```"),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
- #[inline]
- pub const fn trailing_zeros(self) -> u32 {
- (self as $UnsignedT).trailing_zeros()
- }
- }
-
- doc_comment! {
- concat!("Returns the number of leading ones in the binary representation of `self`.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "let n = -1", stringify!($SelfT), ";
-
-assert_eq!(n.leading_ones(), ", stringify!($BITS), ");",
-$EndFeature, "
-```"),
- #[stable(feature = "leading_trailing_ones", since = "1.46.0")]
- #[rustc_const_stable(feature = "leading_trailing_ones", since = "1.46.0")]
- #[inline]
- pub const fn leading_ones(self) -> u32 {
- (self as $UnsignedT).leading_ones()
- }
- }
-
- doc_comment! {
- concat!("Returns the number of trailing ones in the binary representation of `self`.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "let n = 3", stringify!($SelfT), ";
-
-assert_eq!(n.trailing_ones(), 2);",
-$EndFeature, "
-```"),
- #[stable(feature = "leading_trailing_ones", since = "1.46.0")]
- #[rustc_const_stable(feature = "leading_trailing_ones", since = "1.46.0")]
- #[inline]
- pub const fn trailing_ones(self) -> u32 {
- (self as $UnsignedT).trailing_ones()
- }
- }
-
- doc_comment! {
- concat!("Shifts the bits to the left by a specified amount, `n`,
-wrapping the truncated bits to the end of the resulting integer.
-
-Please note this isn't the same operation as the `<<` shifting operator!
-
-# Examples
-
-Basic usage:
-
-```
-let n = ", $rot_op, stringify!($SelfT), ";
-let m = ", $rot_result, ";
-
-assert_eq!(n.rotate_left(", $rot, "), m);
-```"),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn rotate_left(self, n: u32) -> Self {
- (self as $UnsignedT).rotate_left(n) as Self
- }
- }
-
- doc_comment! {
- concat!("Shifts the bits to the right by a specified amount, `n`,
-wrapping the truncated bits to the beginning of the resulting
-integer.
-
-Please note this isn't the same operation as the `>>` shifting operator!
-
-# Examples
-
-Basic usage:
-
-```
-let n = ", $rot_result, stringify!($SelfT), ";
-let m = ", $rot_op, ";
-
-assert_eq!(n.rotate_right(", $rot, "), m);
-```"),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn rotate_right(self, n: u32) -> Self {
- (self as $UnsignedT).rotate_right(n) as Self
- }
- }
-
- doc_comment! {
- concat!("Reverses the byte order of the integer.
-
-# Examples
-
-Basic usage:
-
-```
-let n = ", $swap_op, stringify!($SelfT), ";
-
-let m = n.swap_bytes();
-
-assert_eq!(m, ", $swapped, ");
-```"),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
- #[inline]
- pub const fn swap_bytes(self) -> Self {
- (self as $UnsignedT).swap_bytes() as Self
- }
- }
-
- doc_comment! {
- concat!("Reverses the bit pattern of the integer.
-
-# Examples
-
-Basic usage:
-
-```
-let n = ", $swap_op, stringify!($SelfT), ";
-let m = n.reverse_bits();
-
-assert_eq!(m, ", $reversed, ");
-```"),
- #[stable(feature = "reverse_bits", since = "1.37.0")]
- #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
- #[inline]
- #[must_use]
- pub const fn reverse_bits(self) -> Self {
- (self as $UnsignedT).reverse_bits() as Self
- }
- }
-
- doc_comment! {
- concat!("Converts an integer from big endian to the target's endianness.
-
-On big endian this is a no-op. On little endian the bytes are swapped.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "let n = 0x1A", stringify!($SelfT), ";
-
-if cfg!(target_endian = \"big\") {
- assert_eq!(", stringify!($SelfT), "::from_be(n), n)
-} else {
- assert_eq!(", stringify!($SelfT), "::from_be(n), n.swap_bytes())
-}",
-$EndFeature, "
-```"),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_stable(feature = "const_int_conversions", since = "1.32.0")]
- #[inline]
- pub const fn from_be(x: Self) -> Self {
- #[cfg(target_endian = "big")]
- {
- x
- }
- #[cfg(not(target_endian = "big"))]
- {
- x.swap_bytes()
- }
- }
- }
-
- doc_comment! {
- concat!("Converts an integer from little endian to the target's endianness.
-
-On little endian this is a no-op. On big endian the bytes are swapped.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "let n = 0x1A", stringify!($SelfT), ";
-
-if cfg!(target_endian = \"little\") {
- assert_eq!(", stringify!($SelfT), "::from_le(n), n)
-} else {
- assert_eq!(", stringify!($SelfT), "::from_le(n), n.swap_bytes())
-}",
-$EndFeature, "
-```"),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_stable(feature = "const_int_conversions", since = "1.32.0")]
- #[inline]
- pub const fn from_le(x: Self) -> Self {
- #[cfg(target_endian = "little")]
- {
- x
- }
- #[cfg(not(target_endian = "little"))]
- {
- x.swap_bytes()
- }
- }
- }
-
- doc_comment! {
- concat!("Converts `self` to big endian from the target's endianness.
-
-On big endian this is a no-op. On little endian the bytes are swapped.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "let n = 0x1A", stringify!($SelfT), ";
-
-if cfg!(target_endian = \"big\") {
- assert_eq!(n.to_be(), n)
-} else {
- assert_eq!(n.to_be(), n.swap_bytes())
-}",
-$EndFeature, "
-```"),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_stable(feature = "const_int_conversions", since = "1.32.0")]
- #[inline]
- pub const fn to_be(self) -> Self { // or not to be?
- #[cfg(target_endian = "big")]
- {
- self
- }
- #[cfg(not(target_endian = "big"))]
- {
- self.swap_bytes()
- }
- }
- }
-
- doc_comment! {
- concat!("Converts `self` to little endian from the target's endianness.
-
-On little endian this is a no-op. On big endian the bytes are swapped.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "let n = 0x1A", stringify!($SelfT), ";
-
-if cfg!(target_endian = \"little\") {
- assert_eq!(n.to_le(), n)
-} else {
- assert_eq!(n.to_le(), n.swap_bytes())
-}",
-$EndFeature, "
-```"),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_stable(feature = "const_int_conversions", since = "1.32.0")]
- #[inline]
- pub const fn to_le(self) -> Self {
- #[cfg(target_endian = "little")]
- {
- self
- }
- #[cfg(not(target_endian = "little"))]
- {
- self.swap_bytes()
- }
- }
- }
-
- doc_comment! {
- concat!("Checked integer addition. Computes `self + rhs`, returning `None`
-if overflow occurred.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!((", stringify!($SelfT),
-"::MAX - 2).checked_add(1), Some(", stringify!($SelfT), "::MAX - 1));
-assert_eq!((", stringify!($SelfT), "::MAX - 2).checked_add(3), None);",
-$EndFeature, "
-```"),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn checked_add(self, rhs: Self) -> Option<Self> {
- let (a, b) = self.overflowing_add(rhs);
- if unlikely!(b) {None} else {Some(a)}
- }
- }
-
- doc_comment! {
- concat!("Unchecked integer addition. Computes `self + rhs`, assuming overflow
-cannot occur. This results in undefined behavior when `self + rhs > ", stringify!($SelfT),
-"::MAX` or `self + rhs < ", stringify!($SelfT), "::MIN`."),
- #[unstable(
- feature = "unchecked_math",
- reason = "niche optimization path",
- issue = "none",
- )]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub unsafe fn unchecked_add(self, rhs: Self) -> Self {
- // SAFETY: the caller must uphold the safety contract for
- // `unchecked_add`.
- unsafe { intrinsics::unchecked_add(self, rhs) }
- }
- }
-
- doc_comment! {
- concat!("Checked integer subtraction. Computes `self - rhs`, returning `None` if
-overflow occurred.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!((", stringify!($SelfT),
-"::MIN + 2).checked_sub(1), Some(", stringify!($SelfT), "::MIN + 1));
-assert_eq!((", stringify!($SelfT), "::MIN + 2).checked_sub(3), None);",
-$EndFeature, "
-```"),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn checked_sub(self, rhs: Self) -> Option<Self> {
- let (a, b) = self.overflowing_sub(rhs);
- if unlikely!(b) {None} else {Some(a)}
- }
- }
-
- doc_comment! {
- concat!("Unchecked integer subtraction. Computes `self - rhs`, assuming overflow
-cannot occur. This results in undefined behavior when `self - rhs > ", stringify!($SelfT),
-"::MAX` or `self - rhs < ", stringify!($SelfT), "::MIN`."),
- #[unstable(
- feature = "unchecked_math",
- reason = "niche optimization path",
- issue = "none",
- )]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub unsafe fn unchecked_sub(self, rhs: Self) -> Self {
- // SAFETY: the caller must uphold the safety contract for
- // `unchecked_sub`.
- unsafe { intrinsics::unchecked_sub(self, rhs) }
- }
- }
-
- doc_comment! {
- concat!("Checked integer multiplication. Computes `self * rhs`, returning `None` if
-overflow occurred.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(", stringify!($SelfT),
-"::MAX.checked_mul(1), Some(", stringify!($SelfT), "::MAX));
-assert_eq!(", stringify!($SelfT), "::MAX.checked_mul(2), None);",
-$EndFeature, "
-```"),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn checked_mul(self, rhs: Self) -> Option<Self> {
- let (a, b) = self.overflowing_mul(rhs);
- if unlikely!(b) {None} else {Some(a)}
- }
- }
-
- doc_comment! {
- concat!("Unchecked integer multiplication. Computes `self * rhs`, assuming overflow
-cannot occur. This results in undefined behavior when `self * rhs > ", stringify!($SelfT),
-"::MAX` or `self * rhs < ", stringify!($SelfT), "::MIN`."),
- #[unstable(
- feature = "unchecked_math",
- reason = "niche optimization path",
- issue = "none",
- )]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub unsafe fn unchecked_mul(self, rhs: Self) -> Self {
- // SAFETY: the caller must uphold the safety contract for
- // `unchecked_mul`.
- unsafe { intrinsics::unchecked_mul(self, rhs) }
- }
- }
-
- doc_comment! {
- concat!("Checked integer division. Computes `self / rhs`, returning `None` if `rhs == 0`
-or the division results in overflow.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!((", stringify!($SelfT),
-"::MIN + 1).checked_div(-1), Some(", stringify!($Max), "));
-assert_eq!(", stringify!($SelfT), "::MIN.checked_div(-1), None);
-assert_eq!((1", stringify!($SelfT), ").checked_div(0), None);",
-$EndFeature, "
-```"),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_checked_int_methods", issue = "53718")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn checked_div(self, rhs: Self) -> Option<Self> {
- if unlikely!(rhs == 0 || (self == Self::MIN && rhs == -1)) {
- None
- } else {
- // SAFETY: div by zero and by INT_MIN have been checked above
- Some(unsafe { intrinsics::unchecked_div(self, rhs) })
- }
- }
- }
-
- doc_comment! {
- concat!("Checked Euclidean division. Computes `self.div_euclid(rhs)`,
-returning `None` if `rhs == 0` or the division results in overflow.
-
-# Examples
-
-Basic usage:
-
-```
-assert_eq!((", stringify!($SelfT),
-"::MIN + 1).checked_div_euclid(-1), Some(", stringify!($Max), "));
-assert_eq!(", stringify!($SelfT), "::MIN.checked_div_euclid(-1), None);
-assert_eq!((1", stringify!($SelfT), ").checked_div_euclid(0), None);
-```"),
- #[stable(feature = "euclidean_division", since = "1.38.0")]
- #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn checked_div_euclid(self, rhs: Self) -> Option<Self> {
- if unlikely!(rhs == 0 || (self == Self::MIN && rhs == -1)) {
- None
- } else {
- Some(self.div_euclid(rhs))
- }
- }
- }
-
- doc_comment! {
- concat!("Checked integer remainder. Computes `self % rhs`, returning `None` if
-`rhs == 0` or the division results in overflow.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "
-assert_eq!(5", stringify!($SelfT), ".checked_rem(2), Some(1));
-assert_eq!(5", stringify!($SelfT), ".checked_rem(0), None);
-assert_eq!(", stringify!($SelfT), "::MIN.checked_rem(-1), None);",
-$EndFeature, "
-```"),
- #[stable(feature = "wrapping", since = "1.7.0")]
- #[rustc_const_unstable(feature = "const_checked_int_methods", issue = "53718")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn checked_rem(self, rhs: Self) -> Option<Self> {
- if unlikely!(rhs == 0 || (self == Self::MIN && rhs == -1)) {
- None
- } else {
- // SAFETY: div by zero and by INT_MIN have been checked above
- Some(unsafe { intrinsics::unchecked_rem(self, rhs) })
- }
- }
- }
-
- doc_comment! {
- concat!("Checked Euclidean remainder. Computes `self.rem_euclid(rhs)`, returning `None`
-if `rhs == 0` or the division results in overflow.
-
-# Examples
-
-Basic usage:
-
-```
-assert_eq!(5", stringify!($SelfT), ".checked_rem_euclid(2), Some(1));
-assert_eq!(5", stringify!($SelfT), ".checked_rem_euclid(0), None);
-assert_eq!(", stringify!($SelfT), "::MIN.checked_rem_euclid(-1), None);
-```"),
- #[stable(feature = "euclidean_division", since = "1.38.0")]
- #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn checked_rem_euclid(self, rhs: Self) -> Option<Self> {
- if unlikely!(rhs == 0 || (self == Self::MIN && rhs == -1)) {
- None
- } else {
- Some(self.rem_euclid(rhs))
- }
- }
- }
-
- doc_comment! {
- concat!("Checked negation. Computes `-self`, returning `None` if `self == MIN`.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "
-assert_eq!(5", stringify!($SelfT), ".checked_neg(), Some(-5));
-assert_eq!(", stringify!($SelfT), "::MIN.checked_neg(), None);",
-$EndFeature, "
-```"),
- #[stable(feature = "wrapping", since = "1.7.0")]
- #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")]
- #[inline]
- pub const fn checked_neg(self) -> Option<Self> {
- let (a, b) = self.overflowing_neg();
- if unlikely!(b) {None} else {Some(a)}
- }
- }
-
- doc_comment! {
- concat!("Checked shift left. Computes `self << rhs`, returning `None` if `rhs` is larger
-than or equal to the number of bits in `self`.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(0x1", stringify!($SelfT), ".checked_shl(4), Some(0x10));
-assert_eq!(0x1", stringify!($SelfT), ".checked_shl(129), None);",
-$EndFeature, "
-```"),
- #[stable(feature = "wrapping", since = "1.7.0")]
- #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn checked_shl(self, rhs: u32) -> Option<Self> {
- let (a, b) = self.overflowing_shl(rhs);
- if unlikely!(b) {None} else {Some(a)}
- }
- }
-
- doc_comment! {
- concat!("Checked shift right. Computes `self >> rhs`, returning `None` if `rhs` is
-larger than or equal to the number of bits in `self`.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(0x10", stringify!($SelfT), ".checked_shr(4), Some(0x1));
-assert_eq!(0x10", stringify!($SelfT), ".checked_shr(128), None);",
-$EndFeature, "
-```"),
- #[stable(feature = "wrapping", since = "1.7.0")]
- #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn checked_shr(self, rhs: u32) -> Option<Self> {
- let (a, b) = self.overflowing_shr(rhs);
- if unlikely!(b) {None} else {Some(a)}
- }
- }
-
- doc_comment! {
- concat!("Checked absolute value. Computes `self.abs()`, returning `None` if
-`self == MIN`.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "
-assert_eq!((-5", stringify!($SelfT), ").checked_abs(), Some(5));
-assert_eq!(", stringify!($SelfT), "::MIN.checked_abs(), None);",
-$EndFeature, "
-```"),
- #[stable(feature = "no_panic_abs", since = "1.13.0")]
- #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")]
- #[inline]
- pub const fn checked_abs(self) -> Option<Self> {
- if self.is_negative() {
- self.checked_neg()
- } else {
- Some(self)
- }
- }
- }
-
- doc_comment! {
- concat!("Checked exponentiation. Computes `self.pow(exp)`, returning `None` if
-overflow occurred.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(8", stringify!($SelfT), ".checked_pow(2), Some(64));
-assert_eq!(", stringify!($SelfT), "::MAX.checked_pow(2), None);",
-$EndFeature, "
-```"),
-
- #[stable(feature = "no_panic_pow", since = "1.34.0")]
- #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn checked_pow(self, mut exp: u32) -> Option<Self> {
- if exp == 0 {
- return Some(1);
- }
- let mut base = self;
- let mut acc: Self = 1;
-
- while exp > 1 {
- if (exp & 1) == 1 {
- acc = try_opt!(acc.checked_mul(base));
- }
- exp /= 2;
- base = try_opt!(base.checked_mul(base));
- }
- // since exp!=0, finally the exp must be 1.
- // Deal with the final bit of the exponent separately, since
- // squaring the base afterwards is not necessary and may cause a
- // needless overflow.
- Some(try_opt!(acc.checked_mul(base)))
- }
- }
-
- doc_comment! {
- concat!("Saturating integer addition. Computes `self + rhs`, saturating at the numeric
-bounds instead of overflowing.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(100", stringify!($SelfT), ".saturating_add(1), 101);
-assert_eq!(", stringify!($SelfT), "::MAX.saturating_add(100), ", stringify!($SelfT),
-"::MAX);
-assert_eq!(", stringify!($SelfT), "::MIN.saturating_add(-1), ", stringify!($SelfT),
-"::MIN);",
-$EndFeature, "
-```"),
-
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn saturating_add(self, rhs: Self) -> Self {
- intrinsics::saturating_add(self, rhs)
- }
- }
-
- doc_comment! {
- concat!("Saturating integer subtraction. Computes `self - rhs`, saturating at the
-numeric bounds instead of overflowing.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(100", stringify!($SelfT), ".saturating_sub(127), -27);
-assert_eq!(", stringify!($SelfT), "::MIN.saturating_sub(100), ", stringify!($SelfT),
-"::MIN);
-assert_eq!(", stringify!($SelfT), "::MAX.saturating_sub(-1), ", stringify!($SelfT),
-"::MAX);",
-$EndFeature, "
-```"),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn saturating_sub(self, rhs: Self) -> Self {
- intrinsics::saturating_sub(self, rhs)
- }
- }
-
- doc_comment! {
- concat!("Saturating integer negation. Computes `-self`, returning `MAX` if `self == MIN`
-instead of overflowing.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(100", stringify!($SelfT), ".saturating_neg(), -100);
-assert_eq!((-100", stringify!($SelfT), ").saturating_neg(), 100);
-assert_eq!(", stringify!($SelfT), "::MIN.saturating_neg(), ", stringify!($SelfT),
-"::MAX);
-assert_eq!(", stringify!($SelfT), "::MAX.saturating_neg(), ", stringify!($SelfT),
-"::MIN + 1);",
-$EndFeature, "
-```"),
-
- #[stable(feature = "saturating_neg", since = "1.45.0")]
- #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")]
- #[inline]
- pub const fn saturating_neg(self) -> Self {
- intrinsics::saturating_sub(0, self)
- }
- }
-
- doc_comment! {
- concat!("Saturating absolute value. Computes `self.abs()`, returning `MAX` if `self ==
-MIN` instead of overflowing.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(100", stringify!($SelfT), ".saturating_abs(), 100);
-assert_eq!((-100", stringify!($SelfT), ").saturating_abs(), 100);
-assert_eq!(", stringify!($SelfT), "::MIN.saturating_abs(), ", stringify!($SelfT),
-"::MAX);
-assert_eq!((", stringify!($SelfT), "::MIN + 1).saturating_abs(), ", stringify!($SelfT),
-"::MAX);",
-$EndFeature, "
-```"),
-
- #[stable(feature = "saturating_neg", since = "1.45.0")]
- #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")]
- #[inline]
- pub const fn saturating_abs(self) -> Self {
- if self.is_negative() {
- self.saturating_neg()
- } else {
- self
- }
- }
- }
-
- doc_comment! {
- concat!("Saturating integer multiplication. Computes `self * rhs`, saturating at the
-numeric bounds instead of overflowing.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "
-assert_eq!(10", stringify!($SelfT), ".saturating_mul(12), 120);
-assert_eq!(", stringify!($SelfT), "::MAX.saturating_mul(10), ", stringify!($SelfT), "::MAX);
-assert_eq!(", stringify!($SelfT), "::MIN.saturating_mul(10), ", stringify!($SelfT), "::MIN);",
-$EndFeature, "
-```"),
- #[stable(feature = "wrapping", since = "1.7.0")]
- #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn saturating_mul(self, rhs: Self) -> Self {
- match self.checked_mul(rhs) {
- Some(x) => x,
- None => if (self < 0) == (rhs < 0) {
- Self::MAX
- } else {
- Self::MIN
- }
- }
- }
- }
-
- doc_comment! {
- concat!("Saturating integer exponentiation. Computes `self.pow(exp)`,
-saturating at the numeric bounds instead of overflowing.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "
-assert_eq!((-4", stringify!($SelfT), ").saturating_pow(3), -64);
-assert_eq!(", stringify!($SelfT), "::MIN.saturating_pow(2), ", stringify!($SelfT), "::MAX);
-assert_eq!(", stringify!($SelfT), "::MIN.saturating_pow(3), ", stringify!($SelfT), "::MIN);",
-$EndFeature, "
-```"),
- #[stable(feature = "no_panic_pow", since = "1.34.0")]
- #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn saturating_pow(self, exp: u32) -> Self {
- match self.checked_pow(exp) {
- Some(x) => x,
- None if self < 0 && exp % 2 == 1 => Self::MIN,
- None => Self::MAX,
- }
- }
- }
-
- doc_comment! {
- concat!("Wrapping (modular) addition. Computes `self + rhs`, wrapping around at the
-boundary of the type.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_add(27), 127);
-assert_eq!(", stringify!($SelfT), "::MAX.wrapping_add(2), ", stringify!($SelfT),
-"::MIN + 1);",
-$EndFeature, "
-```"),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn wrapping_add(self, rhs: Self) -> Self {
- intrinsics::wrapping_add(self, rhs)
- }
- }
-
- doc_comment! {
- concat!("Wrapping (modular) subtraction. Computes `self - rhs`, wrapping around at the
-boundary of the type.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(0", stringify!($SelfT), ".wrapping_sub(127), -127);
-assert_eq!((-2", stringify!($SelfT), ").wrapping_sub(", stringify!($SelfT), "::MAX), ",
-stringify!($SelfT), "::MAX);",
-$EndFeature, "
-```"),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn wrapping_sub(self, rhs: Self) -> Self {
- intrinsics::wrapping_sub(self, rhs)
- }
- }
-
- doc_comment! {
- concat!("Wrapping (modular) multiplication. Computes `self * rhs`, wrapping around at
-the boundary of the type.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(10", stringify!($SelfT), ".wrapping_mul(12), 120);
-assert_eq!(11i8.wrapping_mul(12), -124);",
-$EndFeature, "
-```"),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn wrapping_mul(self, rhs: Self) -> Self {
- intrinsics::wrapping_mul(self, rhs)
- }
- }
-
- doc_comment! {
- concat!("Wrapping (modular) division. Computes `self / rhs`, wrapping around at the
-boundary of the type.
-
-The only case where such wrapping can occur is when one divides `MIN / -1` on a signed type (where
-`MIN` is the negative minimal value for the type); this is equivalent to `-MIN`, a positive value
-that is too large to represent in the type. In such a case, this function returns `MIN` itself.
-
-# Panics
-
-This function will panic if `rhs` is 0.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_div(10), 10);
-assert_eq!((-128i8).wrapping_div(-1), -128);",
-$EndFeature, "
-```"),
- #[stable(feature = "num_wrapping", since = "1.2.0")]
- #[rustc_const_unstable(feature = "const_wrapping_int_methods", issue = "53718")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn wrapping_div(self, rhs: Self) -> Self {
- self.overflowing_div(rhs).0
- }
- }
-
- doc_comment! {
- concat!("Wrapping Euclidean division. Computes `self.div_euclid(rhs)`,
-wrapping around at the boundary of the type.
-
-Wrapping will only occur in `MIN / -1` on a signed type (where `MIN` is the negative minimal value
-for the type). This is equivalent to `-MIN`, a positive value that is too large to represent in the
-type. In this case, this method returns `MIN` itself.
-
-# Panics
-
-This function will panic if `rhs` is 0.
-
-# Examples
-
-Basic usage:
-
-```
-assert_eq!(100", stringify!($SelfT), ".wrapping_div_euclid(10), 10);
-assert_eq!((-128i8).wrapping_div_euclid(-1), -128);
-```"),
- #[stable(feature = "euclidean_division", since = "1.38.0")]
- #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn wrapping_div_euclid(self, rhs: Self) -> Self {
- self.overflowing_div_euclid(rhs).0
- }
- }
-
- doc_comment! {
- concat!("Wrapping (modular) remainder. Computes `self % rhs`, wrapping around at the
-boundary of the type.
-
-Such wrap-around never actually occurs mathematically; implementation artifacts make `x % y`
-invalid for `MIN / -1` on a signed type (where `MIN` is the negative minimal value). In such a case,
-this function returns `0`.
-
-# Panics
-
-This function will panic if `rhs` is 0.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_rem(10), 0);
-assert_eq!((-128i8).wrapping_rem(-1), 0);",
-$EndFeature, "
-```"),
- #[stable(feature = "num_wrapping", since = "1.2.0")]
- #[rustc_const_unstable(feature = "const_wrapping_int_methods", issue = "53718")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn wrapping_rem(self, rhs: Self) -> Self {
- self.overflowing_rem(rhs).0
- }
- }
-
- doc_comment! {
- concat!("Wrapping Euclidean remainder. Computes `self.rem_euclid(rhs)`, wrapping around
-at the boundary of the type.
-
-Wrapping will only occur in `MIN % -1` on a signed type (where `MIN` is the negative minimal value
-for the type). In this case, this method returns 0.
-
-# Panics
-
-This function will panic if `rhs` is 0.
-
-# Examples
-
-Basic usage:
-
-```
-assert_eq!(100", stringify!($SelfT), ".wrapping_rem_euclid(10), 0);
-assert_eq!((-128i8).wrapping_rem_euclid(-1), 0);
-```"),
- #[stable(feature = "euclidean_division", since = "1.38.0")]
- #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn wrapping_rem_euclid(self, rhs: Self) -> Self {
- self.overflowing_rem_euclid(rhs).0
- }
- }
-
- doc_comment! {
- concat!("Wrapping (modular) negation. Computes `-self`, wrapping around at the boundary
-of the type.
-
-The only case where such wrapping can occur is when one negates `MIN` on a signed type (where `MIN`
-is the negative minimal value for the type); this is a positive value that is too large to represent
-in the type. In such a case, this function returns `MIN` itself.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_neg(), -100);
-assert_eq!(", stringify!($SelfT), "::MIN.wrapping_neg(), ", stringify!($SelfT),
-"::MIN);",
-$EndFeature, "
-```"),
- #[stable(feature = "num_wrapping", since = "1.2.0")]
- #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
- #[inline]
- pub const fn wrapping_neg(self) -> Self {
- self.overflowing_neg().0
- }
- }
-
- doc_comment! {
- concat!("Panic-free bitwise shift-left; yields `self << mask(rhs)`, where `mask` removes
-any high-order bits of `rhs` that would cause the shift to exceed the bitwidth of the type.
-
-Note that this is *not* the same as a rotate-left; the RHS of a wrapping shift-left is restricted to
-the range of the type, rather than the bits shifted out of the LHS being returned to the other end.
-The primitive integer types all implement a `[`rotate_left`](#method.rotate_left) function,
-which may be what you want instead.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!((-1", stringify!($SelfT), ").wrapping_shl(7), -128);
-assert_eq!((-1", stringify!($SelfT), ").wrapping_shl(128), -1);",
-$EndFeature, "
-```"),
- #[stable(feature = "num_wrapping", since = "1.2.0")]
- #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn wrapping_shl(self, rhs: u32) -> Self {
- // SAFETY: the masking by the bitsize of the type ensures that we do not shift
- // out of bounds
- unsafe {
- intrinsics::unchecked_shl(self, (rhs & ($BITS - 1)) as $SelfT)
- }
- }
- }
-
- doc_comment! {
- concat!("Panic-free bitwise shift-right; yields `self >> mask(rhs)`, where `mask`
-removes any high-order bits of `rhs` that would cause the shift to exceed the bitwidth of the type.
-
-Note that this is *not* the same as a rotate-right; the RHS of a wrapping shift-right is restricted
-to the range of the type, rather than the bits shifted out of the LHS being returned to the other
-end. The primitive integer types all implement a [`rotate_right`](#method.rotate_right) function,
-which may be what you want instead.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!((-128", stringify!($SelfT), ").wrapping_shr(7), -1);
-assert_eq!((-128i16).wrapping_shr(64), -128);",
-$EndFeature, "
-```"),
- #[stable(feature = "num_wrapping", since = "1.2.0")]
- #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn wrapping_shr(self, rhs: u32) -> Self {
- // SAFETY: the masking by the bitsize of the type ensures that we do not shift
- // out of bounds
- unsafe {
- intrinsics::unchecked_shr(self, (rhs & ($BITS - 1)) as $SelfT)
- }
- }
- }
-
- doc_comment! {
- concat!("Wrapping (modular) absolute value. Computes `self.abs()`, wrapping around at
-the boundary of the type.
-
-The only case where such wrapping can occur is when one takes the absolute value of the negative
-minimal value for the type; this is a positive value that is too large to represent in the type. In
-such a case, this function returns `MIN` itself.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_abs(), 100);
-assert_eq!((-100", stringify!($SelfT), ").wrapping_abs(), 100);
-assert_eq!(", stringify!($SelfT), "::MIN.wrapping_abs(), ", stringify!($SelfT),
-"::MIN);
-assert_eq!((-128i8).wrapping_abs() as u8, 128);",
-$EndFeature, "
-```"),
- #[stable(feature = "no_panic_abs", since = "1.13.0")]
- #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
- #[allow(unused_attributes)]
- #[inline]
- pub const fn wrapping_abs(self) -> Self {
- if self.is_negative() {
- self.wrapping_neg()
- } else {
- self
- }
- }
- }
-
- doc_comment! {
- concat!("Computes the absolute value of `self` without any wrapping
-or panicking.
-
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "#![feature(unsigned_abs)]
-assert_eq!(100", stringify!($SelfT), ".unsigned_abs(), 100", stringify!($UnsignedT), ");
-assert_eq!((-100", stringify!($SelfT), ").unsigned_abs(), 100", stringify!($UnsignedT), ");
-assert_eq!((-128i8).unsigned_abs(), 128u8);",
-$EndFeature, "
-```"),
- #[unstable(feature = "unsigned_abs", issue = "74913")]
- #[inline]
- pub const fn unsigned_abs(self) -> $UnsignedT {
- self.wrapping_abs() as $UnsignedT
- }
- }
-
- doc_comment! {
- concat!("Wrapping (modular) exponentiation. Computes `self.pow(exp)`,
-wrapping around at the boundary of the type.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(3", stringify!($SelfT), ".wrapping_pow(4), 81);
-assert_eq!(3i8.wrapping_pow(5), -13);
-assert_eq!(3i8.wrapping_pow(6), -39);",
-$EndFeature, "
-```"),
- #[stable(feature = "no_panic_pow", since = "1.34.0")]
- #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn wrapping_pow(self, mut exp: u32) -> Self {
- if exp == 0 {
- return 1;
- }
- let mut base = self;
- let mut acc: Self = 1;
-
- while exp > 1 {
- if (exp & 1) == 1 {
- acc = acc.wrapping_mul(base);
- }
- exp /= 2;
- base = base.wrapping_mul(base);
- }
-
- // since exp!=0, finally the exp must be 1.
- // Deal with the final bit of the exponent separately, since
- // squaring the base afterwards is not necessary and may cause a
- // needless overflow.
- acc.wrapping_mul(base)
- }
- }
-
- doc_comment! {
- concat!("Calculates `self` + `rhs`
-
-Returns a tuple of the addition along with a boolean indicating whether an arithmetic overflow would
-occur. If an overflow would have occurred then the wrapped value is returned.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "
-assert_eq!(5", stringify!($SelfT), ".overflowing_add(2), (7, false));
-assert_eq!(", stringify!($SelfT), "::MAX.overflowing_add(1), (", stringify!($SelfT),
-"::MIN, true));", $EndFeature, "
-```"),
- #[stable(feature = "wrapping", since = "1.7.0")]
- #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn overflowing_add(self, rhs: Self) -> (Self, bool) {
- let (a, b) = intrinsics::add_with_overflow(self as $ActualT, rhs as $ActualT);
- (a as Self, b)
- }
- }
-
- doc_comment! {
- concat!("Calculates `self` - `rhs`
-
-Returns a tuple of the subtraction along with a boolean indicating whether an arithmetic overflow
-would occur. If an overflow would have occurred then the wrapped value is returned.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "
-assert_eq!(5", stringify!($SelfT), ".overflowing_sub(2), (3, false));
-assert_eq!(", stringify!($SelfT), "::MIN.overflowing_sub(1), (", stringify!($SelfT),
-"::MAX, true));", $EndFeature, "
-```"),
- #[stable(feature = "wrapping", since = "1.7.0")]
- #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn overflowing_sub(self, rhs: Self) -> (Self, bool) {
- let (a, b) = intrinsics::sub_with_overflow(self as $ActualT, rhs as $ActualT);
- (a as Self, b)
- }
- }
-
- doc_comment! {
- concat!("Calculates the multiplication of `self` and `rhs`.
-
-Returns a tuple of the multiplication along with a boolean indicating whether an arithmetic overflow
-would occur. If an overflow would have occurred then the wrapped value is returned.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(5", stringify!($SelfT), ".overflowing_mul(2), (10, false));
-assert_eq!(1_000_000_000i32.overflowing_mul(10), (1410065408, true));",
-$EndFeature, "
-```"),
- #[stable(feature = "wrapping", since = "1.7.0")]
- #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn overflowing_mul(self, rhs: Self) -> (Self, bool) {
- let (a, b) = intrinsics::mul_with_overflow(self as $ActualT, rhs as $ActualT);
- (a as Self, b)
- }
- }
-
- doc_comment! {
- concat!("Calculates the divisor when `self` is divided by `rhs`.
-
-Returns a tuple of the divisor along with a boolean indicating whether an arithmetic overflow would
-occur. If an overflow would occur then self is returned.
-
-# Panics
-
-This function will panic if `rhs` is 0.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "
-assert_eq!(5", stringify!($SelfT), ".overflowing_div(2), (2, false));
-assert_eq!(", stringify!($SelfT), "::MIN.overflowing_div(-1), (", stringify!($SelfT),
-"::MIN, true));",
-$EndFeature, "
-```"),
- #[inline]
- #[stable(feature = "wrapping", since = "1.7.0")]
- #[rustc_const_unstable(feature = "const_overflowing_int_methods", issue = "53718")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- pub const fn overflowing_div(self, rhs: Self) -> (Self, bool) {
- if unlikely!(self == Self::MIN && rhs == -1) {
- (self, true)
- } else {
- (self / rhs, false)
- }
- }
- }
-
- doc_comment! {
- concat!("Calculates the quotient of Euclidean division `self.div_euclid(rhs)`.
-
-Returns a tuple of the divisor along with a boolean indicating whether an arithmetic overflow would
-occur. If an overflow would occur then `self` is returned.
-
-# Panics
-
-This function will panic if `rhs` is 0.
-
-# Examples
-
-Basic usage:
-
-```
-assert_eq!(5", stringify!($SelfT), ".overflowing_div_euclid(2), (2, false));
-assert_eq!(", stringify!($SelfT), "::MIN.overflowing_div_euclid(-1), (", stringify!($SelfT),
-"::MIN, true));
-```"),
- #[inline]
- #[stable(feature = "euclidean_division", since = "1.38.0")]
- #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- pub const fn overflowing_div_euclid(self, rhs: Self) -> (Self, bool) {
- if unlikely!(self == Self::MIN && rhs == -1) {
- (self, true)
- } else {
- (self.div_euclid(rhs), false)
- }
- }
- }
-
- doc_comment! {
- concat!("Calculates the remainder when `self` is divided by `rhs`.
-
-Returns a tuple of the remainder after dividing along with a boolean indicating whether an
-arithmetic overflow would occur. If an overflow would occur then 0 is returned.
-
-# Panics
-
-This function will panic if `rhs` is 0.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "
-assert_eq!(5", stringify!($SelfT), ".overflowing_rem(2), (1, false));
-assert_eq!(", stringify!($SelfT), "::MIN.overflowing_rem(-1), (0, true));",
-$EndFeature, "
-```"),
- #[inline]
- #[stable(feature = "wrapping", since = "1.7.0")]
- #[rustc_const_unstable(feature = "const_overflowing_int_methods", issue = "53718")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- pub const fn overflowing_rem(self, rhs: Self) -> (Self, bool) {
- if unlikely!(self == Self::MIN && rhs == -1) {
- (0, true)
- } else {
- (self % rhs, false)
- }
- }
- }
-
-
- doc_comment! {
- concat!("Overflowing Euclidean remainder. Calculates `self.rem_euclid(rhs)`.
-
-Returns a tuple of the remainder after dividing along with a boolean indicating whether an
-arithmetic overflow would occur. If an overflow would occur then 0 is returned.
-
-# Panics
-
-This function will panic if `rhs` is 0.
-
-# Examples
-
-Basic usage:
-
-```
-assert_eq!(5", stringify!($SelfT), ".overflowing_rem_euclid(2), (1, false));
-assert_eq!(", stringify!($SelfT), "::MIN.overflowing_rem_euclid(-1), (0, true));
-```"),
- #[stable(feature = "euclidean_division", since = "1.38.0")]
- #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn overflowing_rem_euclid(self, rhs: Self) -> (Self, bool) {
- if unlikely!(self == Self::MIN && rhs == -1) {
- (0, true)
- } else {
- (self.rem_euclid(rhs), false)
- }
- }
- }
-
-
- doc_comment! {
- concat!("Negates self, overflowing if this is equal to the minimum value.
-
-Returns a tuple of the negated version of self along with a boolean indicating whether an overflow
-happened. If `self` is the minimum value (e.g., `i32::MIN` for values of type `i32`), then the
-minimum value will be returned again and `true` will be returned for an overflow happening.
-
-# Examples
-
-Basic usage:
-
-```
-assert_eq!(2", stringify!($SelfT), ".overflowing_neg(), (-2, false));
-assert_eq!(", stringify!($SelfT), "::MIN.overflowing_neg(), (", stringify!($SelfT),
-"::MIN, true));", $EndFeature, "
-```"),
- #[inline]
- #[stable(feature = "wrapping", since = "1.7.0")]
- #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
- #[allow(unused_attributes)]
- pub const fn overflowing_neg(self) -> (Self, bool) {
- if unlikely!(self == Self::MIN) {
- (Self::MIN, true)
- } else {
- (-self, false)
- }
- }
- }
-
- doc_comment! {
- concat!("Shifts self left by `rhs` bits.
-
-Returns a tuple of the shifted version of self along with a boolean indicating whether the shift
-value was larger than or equal to the number of bits. If the shift value is too large, then value is
-masked (N-1) where N is the number of bits, and this value is then used to perform the shift.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(0x1", stringify!($SelfT),".overflowing_shl(4), (0x10, false));
-assert_eq!(0x1i32.overflowing_shl(36), (0x10, true));",
-$EndFeature, "
-```"),
- #[stable(feature = "wrapping", since = "1.7.0")]
- #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn overflowing_shl(self, rhs: u32) -> (Self, bool) {
- (self.wrapping_shl(rhs), (rhs > ($BITS - 1)))
- }
- }
-
- doc_comment! {
- concat!("Shifts self right by `rhs` bits.
-
-Returns a tuple of the shifted version of self along with a boolean indicating whether the shift
-value was larger than or equal to the number of bits. If the shift value is too large, then value is
-masked (N-1) where N is the number of bits, and this value is then used to perform the shift.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(0x10", stringify!($SelfT), ".overflowing_shr(4), (0x1, false));
-assert_eq!(0x10i32.overflowing_shr(36), (0x1, true));",
-$EndFeature, "
-```"),
- #[stable(feature = "wrapping", since = "1.7.0")]
- #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn overflowing_shr(self, rhs: u32) -> (Self, bool) {
- (self.wrapping_shr(rhs), (rhs > ($BITS - 1)))
- }
- }
-
- doc_comment! {
- concat!("Computes the absolute value of `self`.
-
-Returns a tuple of the absolute version of self along with a boolean indicating whether an overflow
-happened. If self is the minimum value (e.g., ", stringify!($SelfT), "::MIN for values of type
- ", stringify!($SelfT), "), then the minimum value will be returned again and true will be returned
-for an overflow happening.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(10", stringify!($SelfT), ".overflowing_abs(), (10, false));
-assert_eq!((-10", stringify!($SelfT), ").overflowing_abs(), (10, false));
-assert_eq!((", stringify!($SelfT), "::MIN).overflowing_abs(), (", stringify!($SelfT),
-"::MIN, true));",
-$EndFeature, "
-```"),
- #[stable(feature = "no_panic_abs", since = "1.13.0")]
- #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
- #[inline]
- pub const fn overflowing_abs(self) -> (Self, bool) {
- (self.wrapping_abs(), self == Self::MIN)
- }
- }
-
- doc_comment! {
- concat!("Raises self to the power of `exp`, using exponentiation by squaring.
-
-Returns a tuple of the exponentiation along with a bool indicating
-whether an overflow happened.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(3", stringify!($SelfT), ".overflowing_pow(4), (81, false));
-assert_eq!(3i8.overflowing_pow(5), (-13, true));",
-$EndFeature, "
-```"),
- #[stable(feature = "no_panic_pow", since = "1.34.0")]
- #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn overflowing_pow(self, mut exp: u32) -> (Self, bool) {
- if exp == 0 {
- return (1,false);
- }
- let mut base = self;
- let mut acc: Self = 1;
- let mut overflown = false;
- // Scratch space for storing results of overflowing_mul.
- let mut r;
-
- while exp > 1 {
- if (exp & 1) == 1 {
- r = acc.overflowing_mul(base);
- acc = r.0;
- overflown |= r.1;
- }
- exp /= 2;
- r = base.overflowing_mul(base);
- base = r.0;
- overflown |= r.1;
- }
-
- // since exp!=0, finally the exp must be 1.
- // Deal with the final bit of the exponent separately, since
- // squaring the base afterwards is not necessary and may cause a
- // needless overflow.
- r = acc.overflowing_mul(base);
- r.1 |= overflown;
- r
- }
- }
-
- doc_comment! {
- concat!("Raises self to the power of `exp`, using exponentiation by squaring.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "let x: ", stringify!($SelfT), " = 2; // or any other integer type
-
-assert_eq!(x.pow(5), 32);",
-$EndFeature, "
-```"),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- #[rustc_inherit_overflow_checks]
- pub const fn pow(self, mut exp: u32) -> Self {
- if exp == 0 {
- return 1;
- }
- let mut base = self;
- let mut acc = 1;
-
- while exp > 1 {
- if (exp & 1) == 1 {
- acc = acc * base;
- }
- exp /= 2;
- base = base * base;
- }
-
- // since exp!=0, finally the exp must be 1.
- // Deal with the final bit of the exponent separately, since
- // squaring the base afterwards is not necessary and may cause a
- // needless overflow.
- acc * base
- }
- }
-
- doc_comment! {
- concat!("Calculates the quotient of Euclidean division of `self` by `rhs`.
-
-This computes the integer `n` such that `self = n * rhs + self.rem_euclid(rhs)`,
-with `0 <= self.rem_euclid(rhs) < rhs`.
-
-In other words, the result is `self / rhs` rounded to the integer `n`
-such that `self >= n * rhs`.
-If `self > 0`, this is equal to round towards zero (the default in Rust);
-if `self < 0`, this is equal to round towards +/- infinity.
-
-# Panics
-
-This function will panic if `rhs` is 0 or the division results in overflow.
-
-# Examples
-
-Basic usage:
-
-```
-let a: ", stringify!($SelfT), " = 7; // or any other integer type
-let b = 4;
-
-assert_eq!(a.div_euclid(b), 1); // 7 >= 4 * 1
-assert_eq!(a.div_euclid(-b), -1); // 7 >= -4 * -1
-assert_eq!((-a).div_euclid(b), -2); // -7 >= 4 * -2
-assert_eq!((-a).div_euclid(-b), 2); // -7 >= -4 * 2
-```"),
- #[stable(feature = "euclidean_division", since = "1.38.0")]
- #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- #[rustc_inherit_overflow_checks]
- pub const fn div_euclid(self, rhs: Self) -> Self {
- let q = self / rhs;
- if self % rhs < 0 {
- return if rhs > 0 { q - 1 } else { q + 1 }
- }
- q
- }
- }
-
-
- doc_comment! {
- concat!("Calculates the least nonnegative remainder of `self (mod rhs)`.
-
-This is done as if by the Euclidean division algorithm -- given
-`r = self.rem_euclid(rhs)`, `self = rhs * self.div_euclid(rhs) + r`, and
-`0 <= r < abs(rhs)`.
-
-# Panics
-
-This function will panic if `rhs` is 0 or the division results in overflow.
-
-# Examples
-
-Basic usage:
-
-```
-let a: ", stringify!($SelfT), " = 7; // or any other integer type
-let b = 4;
-
-assert_eq!(a.rem_euclid(b), 3);
-assert_eq!((-a).rem_euclid(b), 1);
-assert_eq!(a.rem_euclid(-b), 3);
-assert_eq!((-a).rem_euclid(-b), 1);
-```"),
- #[stable(feature = "euclidean_division", since = "1.38.0")]
- #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- #[rustc_inherit_overflow_checks]
- pub const fn rem_euclid(self, rhs: Self) -> Self {
- let r = self % rhs;
- if r < 0 {
- if rhs < 0 {
- r - rhs
- } else {
- r + rhs
- }
- } else {
- r
- }
- }
- }
-
- doc_comment! {
- concat!("Computes the absolute value of `self`.
-
-# Overflow behavior
-
-The absolute value of `", stringify!($SelfT), "::MIN` cannot be represented as an
-`", stringify!($SelfT), "`, and attempting to calculate it will cause an overflow. This means that
-code in debug mode will trigger a panic on this case and optimized code will return `",
-stringify!($SelfT), "::MIN` without a panic.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(10", stringify!($SelfT), ".abs(), 10);
-assert_eq!((-10", stringify!($SelfT), ").abs(), 10);",
-$EndFeature, "
-```"),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
- #[allow(unused_attributes)]
- #[inline]
- #[rustc_inherit_overflow_checks]
- pub const fn abs(self) -> Self {
- // Note that the #[inline] above means that the overflow
- // semantics of the subtraction depend on the crate we're being
- // inlined into.
- if self.is_negative() {
- -self
- } else {
- self
- }
- }
- }
-
- doc_comment! {
- concat!("Returns a number representing sign of `self`.
-
- - `0` if the number is zero
- - `1` if the number is positive
- - `-1` if the number is negative
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(10", stringify!($SelfT), ".signum(), 1);
-assert_eq!(0", stringify!($SelfT), ".signum(), 0);
-assert_eq!((-10", stringify!($SelfT), ").signum(), -1);",
-$EndFeature, "
-```"),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_stable(feature = "const_int_sign", since = "1.47.0")]
- #[inline]
- pub const fn signum(self) -> Self {
- match self {
- n if n > 0 => 1,
- 0 => 0,
- _ => -1,
- }
- }
- }
-
- doc_comment! {
- concat!("Returns `true` if `self` is positive and `false` if the number is zero or
-negative.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert!(10", stringify!($SelfT), ".is_positive());
-assert!(!(-10", stringify!($SelfT), ").is_positive());",
-$EndFeature, "
-```"),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
- #[inline]
- pub const fn is_positive(self) -> bool { self > 0 }
- }
-
- doc_comment! {
- concat!("Returns `true` if `self` is negative and `false` if the number is zero or
-positive.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert!((-10", stringify!($SelfT), ").is_negative());
-assert!(!10", stringify!($SelfT), ".is_negative());",
-$EndFeature, "
-```"),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
- #[inline]
- pub const fn is_negative(self) -> bool { self < 0 }
- }
-
- doc_comment! {
- concat!("Return the memory representation of this integer as a byte array in
-big-endian (network) byte order.
-",
-$to_xe_bytes_doc,
-"
-# Examples
-
-```
-let bytes = ", $swap_op, stringify!($SelfT), ".to_be_bytes();
-assert_eq!(bytes, ", $be_bytes, ");
-```"),
- #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
- #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")]
- #[inline]
- pub const fn to_be_bytes(self) -> [u8; mem::size_of::<Self>()] {
- self.to_be().to_ne_bytes()
- }
- }
-
-doc_comment! {
- concat!("Return the memory representation of this integer as a byte array in
-little-endian byte order.
-",
-$to_xe_bytes_doc,
-"
-# Examples
-
-```
-let bytes = ", $swap_op, stringify!($SelfT), ".to_le_bytes();
-assert_eq!(bytes, ", $le_bytes, ");
-```"),
- #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
- #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")]
- #[inline]
- pub const fn to_le_bytes(self) -> [u8; mem::size_of::<Self>()] {
- self.to_le().to_ne_bytes()
- }
- }
-
- doc_comment! {
- concat!("
-Return the memory representation of this integer as a byte array in
-native byte order.
-
-As the target platform's native endianness is used, portable code
-should use [`to_be_bytes`] or [`to_le_bytes`], as appropriate,
-instead.
-",
-$to_xe_bytes_doc,
-"
-[`to_be_bytes`]: #method.to_be_bytes
-[`to_le_bytes`]: #method.to_le_bytes
-
-# Examples
-
-```
-let bytes = ", $swap_op, stringify!($SelfT), ".to_ne_bytes();
-assert_eq!(
- bytes,
- if cfg!(target_endian = \"big\") {
- ", $be_bytes, "
- } else {
- ", $le_bytes, "
- }
-);
-```"),
- #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
- #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")]
- // SAFETY: const sound because integers are plain old datatypes so we can always
- // transmute them to arrays of bytes
- #[allow_internal_unstable(const_fn_transmute)]
- #[inline]
- pub const fn to_ne_bytes(self) -> [u8; mem::size_of::<Self>()] {
- // SAFETY: integers are plain old datatypes so we can always transmute them to
- // arrays of bytes
- unsafe { mem::transmute(self) }
- }
- }
-
-doc_comment! {
- concat!("Create an integer value from its representation as a byte array in
-big endian.
-",
-$from_xe_bytes_doc,
-"
-# Examples
-
-```
-let value = ", stringify!($SelfT), "::from_be_bytes(", $be_bytes, ");
-assert_eq!(value, ", $swap_op, ");
-```
-
-When starting from a slice rather than an array, fallible conversion APIs can be used:
-
-```
-use std::convert::TryInto;
-
-fn read_be_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " {
- let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">());
- *input = rest;
- ", stringify!($SelfT), "::from_be_bytes(int_bytes.try_into().unwrap())
-}
-```"),
- #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
- #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")]
- #[inline]
- pub const fn from_be_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
- Self::from_be(Self::from_ne_bytes(bytes))
- }
- }
-
-doc_comment! {
- concat!("
-Create an integer value from its representation as a byte array in
-little endian.
-",
-$from_xe_bytes_doc,
-"
-# Examples
-
-```
-let value = ", stringify!($SelfT), "::from_le_bytes(", $le_bytes, ");
-assert_eq!(value, ", $swap_op, ");
-```
-
-When starting from a slice rather than an array, fallible conversion APIs can be used:
-
-```
-use std::convert::TryInto;
-
-fn read_le_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " {
- let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">());
- *input = rest;
- ", stringify!($SelfT), "::from_le_bytes(int_bytes.try_into().unwrap())
-}
-```"),
- #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
- #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")]
- #[inline]
- pub const fn from_le_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
- Self::from_le(Self::from_ne_bytes(bytes))
- }
- }
-
- doc_comment! {
- concat!("Create an integer value from its memory representation as a byte
-array in native endianness.
-
-As the target platform's native endianness is used, portable code
-likely wants to use [`from_be_bytes`] or [`from_le_bytes`], as
-appropriate instead.
-
-[`from_be_bytes`]: #method.from_be_bytes
-[`from_le_bytes`]: #method.from_le_bytes
-",
-$from_xe_bytes_doc,
-"
-# Examples
-
-```
-let value = ", stringify!($SelfT), "::from_ne_bytes(if cfg!(target_endian = \"big\") {
- ", $be_bytes, "
-} else {
- ", $le_bytes, "
-});
-assert_eq!(value, ", $swap_op, ");
-```
-
-When starting from a slice rather than an array, fallible conversion APIs can be used:
-
-```
-use std::convert::TryInto;
-
-fn read_ne_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " {
- let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">());
- *input = rest;
- ", stringify!($SelfT), "::from_ne_bytes(int_bytes.try_into().unwrap())
-}
-```"),
- #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
- #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")]
- // SAFETY: const sound because integers are plain old datatypes so we can always
- // transmute to them
- #[allow_internal_unstable(const_fn_transmute)]
- #[inline]
- pub const fn from_ne_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
- // SAFETY: integers are plain old datatypes so we can always transmute to them
- unsafe { mem::transmute(bytes) }
- }
- }
-
- doc_comment! {
- concat!("**This method is soft-deprecated.**
-
-Although using it won’t cause a compilation warning,
-new code should use [`", stringify!($SelfT), "::MIN", "`](#associatedconstant.MIN) instead.
-
-Returns the smallest value that can be represented by this integer type."),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline(always)]
- #[rustc_promotable]
- #[rustc_const_stable(feature = "const_min_value", since = "1.32.0")]
- pub const fn min_value() -> Self {
- Self::MIN
- }
- }
-
- doc_comment! {
- concat!("**This method is soft-deprecated.**
-
-Although using it won’t cause a compilation warning,
-new code should use [`", stringify!($SelfT), "::MAX", "`](#associatedconstant.MAX) instead.
-
-Returns the largest value that can be represented by this integer type."),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline(always)]
- #[rustc_promotable]
- #[rustc_const_stable(feature = "const_max_value", since = "1.32.0")]
- pub const fn max_value() -> Self {
- Self::MAX
- }
- }
- }
-}
-
-#[lang = "i8"]
-impl i8 {
- int_impl! { i8, i8, u8, 8, -128, 127, "", "", 2, "-0x7e", "0xa", "0x12", "0x12", "0x48",
- "[0x12]", "[0x12]", "", "" }
-}
-
-#[lang = "i16"]
-impl i16 {
- int_impl! { i16, i16, u16, 16, -32768, 32767, "", "", 4, "-0x5ffd", "0x3a", "0x1234", "0x3412",
- "0x2c48", "[0x34, 0x12]", "[0x12, 0x34]", "", "" }
-}
-
-#[lang = "i32"]
-impl i32 {
- int_impl! { i32, i32, u32, 32, -2147483648, 2147483647, "", "", 8, "0x10000b3", "0xb301",
- "0x12345678", "0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]",
- "[0x12, 0x34, 0x56, 0x78]", "", "" }
-}
-
-#[lang = "i64"]
-impl i64 {
- int_impl! { i64, i64, u64, 64, -9223372036854775808, 9223372036854775807, "", "", 12,
- "0xaa00000000006e1", "0x6e10aa", "0x1234567890123456", "0x5634129078563412",
- "0x6a2c48091e6a2c48", "[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]",
- "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]", "", "" }
-}
-
-#[lang = "i128"]
-impl i128 {
- int_impl! { i128, i128, u128, 128, -170141183460469231731687303715884105728,
- 170141183460469231731687303715884105727, "", "", 16,
- "0x13f40000000000000000000000004f76", "0x4f7613f4", "0x12345678901234567890123456789012",
- "0x12907856341290785634129078563412", "0x48091e6a2c48091e6a2c48091e6a2c48",
- "[0x12, 0x90, 0x78, 0x56, 0x34, 0x12, 0x90, 0x78, \
- 0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]",
- "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, \
- 0x78, 0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12]", "", "" }
-}
-
-#[cfg(target_pointer_width = "16")]
-#[lang = "isize"]
-impl isize {
- int_impl! { isize, i16, u16, 16, -32768, 32767, "", "", 4, "-0x5ffd", "0x3a", "0x1234",
- "0x3412", "0x2c48", "[0x34, 0x12]", "[0x12, 0x34]",
- usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() }
-}
-
-#[cfg(target_pointer_width = "32")]
-#[lang = "isize"]
-impl isize {
- int_impl! { isize, i32, u32, 32, -2147483648, 2147483647, "", "", 8, "0x10000b3", "0xb301",
- "0x12345678", "0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]",
- "[0x12, 0x34, 0x56, 0x78]",
- usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() }
-}
-
-#[cfg(target_pointer_width = "64")]
-#[lang = "isize"]
-impl isize {
- int_impl! { isize, i64, u64, 64, -9223372036854775808, 9223372036854775807, "", "",
- 12, "0xaa00000000006e1", "0x6e10aa", "0x1234567890123456", "0x5634129078563412",
- "0x6a2c48091e6a2c48", "[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]",
- "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]",
- usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() }
-}
-
-macro_rules! uint_impl {
- ($SelfT:ty, $ActualT:ty, $BITS:expr, $MaxV:expr, $Feature:expr, $EndFeature:expr,
- $rot:expr, $rot_op:expr, $rot_result:expr, $swap_op:expr, $swapped:expr,
- $reversed:expr, $le_bytes:expr, $be_bytes:expr,
- $to_xe_bytes_doc:expr, $from_xe_bytes_doc:expr) => {
- doc_comment! {
- concat!("The smallest value that can be represented by this integer type.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(", stringify!($SelfT), "::MIN, 0);", $EndFeature, "
-```"),
- #[stable(feature = "assoc_int_consts", since = "1.43.0")]
- pub const MIN: Self = 0;
- }
-
- doc_comment! {
- concat!("The largest value that can be represented by this integer type.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(", stringify!($SelfT), "::MAX, ", stringify!($MaxV), ");",
-$EndFeature, "
-```"),
- #[stable(feature = "assoc_int_consts", since = "1.43.0")]
- pub const MAX: Self = !0;
- }
-
- doc_comment! {
- concat!("Converts a string slice in a given base to an integer.
-
-The string is expected to be an optional `+` sign
-followed by digits.
-Leading and trailing whitespace represent an error.
-Digits are a subset of these characters, depending on `radix`:
-
-* `0-9`
-* `a-z`
-* `A-Z`
-
-# Panics
-
-This function panics if `radix` is not in the range from 2 to 36.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(", stringify!($SelfT), "::from_str_radix(\"A\", 16), Ok(10));",
-$EndFeature, "
-```"),
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn from_str_radix(src: &str, radix: u32) -> Result<Self, ParseIntError> {
- from_str_radix(src, radix)
- }
- }
-
- doc_comment! {
- concat!("Returns the number of ones in the binary representation of `self`.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "let n = 0b01001100", stringify!($SelfT), ";
-
-assert_eq!(n.count_ones(), 3);", $EndFeature, "
-```"),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_stable(feature = "const_math", since = "1.32.0")]
- #[inline]
- pub const fn count_ones(self) -> u32 {
- intrinsics::ctpop(self as $ActualT) as u32
- }
- }
-
- doc_comment! {
- concat!("Returns the number of zeros in the binary representation of `self`.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(", stringify!($SelfT), "::MAX.count_zeros(), 0);", $EndFeature, "
-```"),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_stable(feature = "const_math", since = "1.32.0")]
- #[inline]
- pub const fn count_zeros(self) -> u32 {
- (!self).count_ones()
- }
- }
-
- doc_comment! {
- concat!("Returns the number of leading zeros in the binary representation of `self`.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "let n = ", stringify!($SelfT), "::MAX >> 2;
-
-assert_eq!(n.leading_zeros(), 2);", $EndFeature, "
-```"),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_stable(feature = "const_math", since = "1.32.0")]
- #[inline]
- pub const fn leading_zeros(self) -> u32 {
- intrinsics::ctlz(self as $ActualT) as u32
- }
- }
-
- doc_comment! {
- concat!("Returns the number of trailing zeros in the binary representation
-of `self`.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "let n = 0b0101000", stringify!($SelfT), ";
-
-assert_eq!(n.trailing_zeros(), 3);", $EndFeature, "
-```"),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_stable(feature = "const_math", since = "1.32.0")]
- #[inline]
- pub const fn trailing_zeros(self) -> u32 {
- intrinsics::cttz(self) as u32
- }
- }
-
- doc_comment! {
- concat!("Returns the number of leading ones in the binary representation of `self`.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "let n = !(", stringify!($SelfT), "::MAX >> 2);
-
-assert_eq!(n.leading_ones(), 2);", $EndFeature, "
-```"),
- #[stable(feature = "leading_trailing_ones", since = "1.46.0")]
- #[rustc_const_stable(feature = "leading_trailing_ones", since = "1.46.0")]
- #[inline]
- pub const fn leading_ones(self) -> u32 {
- (!self).leading_zeros()
- }
- }
-
- doc_comment! {
- concat!("Returns the number of trailing ones in the binary representation
-of `self`.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "let n = 0b1010111", stringify!($SelfT), ";
-
-assert_eq!(n.trailing_ones(), 3);", $EndFeature, "
-```"),
- #[stable(feature = "leading_trailing_ones", since = "1.46.0")]
- #[rustc_const_stable(feature = "leading_trailing_ones", since = "1.46.0")]
- #[inline]
- pub const fn trailing_ones(self) -> u32 {
- (!self).trailing_zeros()
- }
- }
-
- doc_comment! {
- concat!("Shifts the bits to the left by a specified amount, `n`,
-wrapping the truncated bits to the end of the resulting integer.
-
-Please note this isn't the same operation as the `<<` shifting operator!
-
-# Examples
-
-Basic usage:
-
-```
-let n = ", $rot_op, stringify!($SelfT), ";
-let m = ", $rot_result, ";
-
-assert_eq!(n.rotate_left(", $rot, "), m);
-```"),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_stable(feature = "const_math", since = "1.32.0")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn rotate_left(self, n: u32) -> Self {
- intrinsics::rotate_left(self, n as $SelfT)
- }
- }
-
- doc_comment! {
- concat!("Shifts the bits to the right by a specified amount, `n`,
-wrapping the truncated bits to the beginning of the resulting
-integer.
-
-Please note this isn't the same operation as the `>>` shifting operator!
-
-# Examples
-
-Basic usage:
-
-```
-let n = ", $rot_result, stringify!($SelfT), ";
-let m = ", $rot_op, ";
-
-assert_eq!(n.rotate_right(", $rot, "), m);
-```"),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_stable(feature = "const_math", since = "1.32.0")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn rotate_right(self, n: u32) -> Self {
- intrinsics::rotate_right(self, n as $SelfT)
- }
- }
-
- doc_comment! {
- concat!("
-Reverses the byte order of the integer.
-
-# Examples
-
-Basic usage:
-
-```
-let n = ", $swap_op, stringify!($SelfT), ";
-let m = n.swap_bytes();
-
-assert_eq!(m, ", $swapped, ");
-```"),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_stable(feature = "const_math", since = "1.32.0")]
- #[inline]
- pub const fn swap_bytes(self) -> Self {
- intrinsics::bswap(self as $ActualT) as Self
- }
- }
-
- doc_comment! {
- concat!("Reverses the bit pattern of the integer.
-
-# Examples
-
-Basic usage:
-
-```
-let n = ", $swap_op, stringify!($SelfT), ";
-let m = n.reverse_bits();
-
-assert_eq!(m, ", $reversed, ");
-```"),
- #[stable(feature = "reverse_bits", since = "1.37.0")]
- #[rustc_const_stable(feature = "const_math", since = "1.32.0")]
- #[inline]
- #[must_use]
- pub const fn reverse_bits(self) -> Self {
- intrinsics::bitreverse(self as $ActualT) as Self
- }
- }
-
- doc_comment! {
- concat!("Converts an integer from big endian to the target's endianness.
-
-On big endian this is a no-op. On little endian the bytes are
-swapped.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "let n = 0x1A", stringify!($SelfT), ";
-
-if cfg!(target_endian = \"big\") {
- assert_eq!(", stringify!($SelfT), "::from_be(n), n)
-} else {
- assert_eq!(", stringify!($SelfT), "::from_be(n), n.swap_bytes())
-}", $EndFeature, "
-```"),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_stable(feature = "const_math", since = "1.32.0")]
- #[inline]
- pub const fn from_be(x: Self) -> Self {
- #[cfg(target_endian = "big")]
- {
- x
- }
- #[cfg(not(target_endian = "big"))]
- {
- x.swap_bytes()
- }
- }
- }
-
- doc_comment! {
- concat!("Converts an integer from little endian to the target's endianness.
-
-On little endian this is a no-op. On big endian the bytes are
-swapped.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "let n = 0x1A", stringify!($SelfT), ";
-
-if cfg!(target_endian = \"little\") {
- assert_eq!(", stringify!($SelfT), "::from_le(n), n)
-} else {
- assert_eq!(", stringify!($SelfT), "::from_le(n), n.swap_bytes())
-}", $EndFeature, "
-```"),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_stable(feature = "const_math", since = "1.32.0")]
- #[inline]
- pub const fn from_le(x: Self) -> Self {
- #[cfg(target_endian = "little")]
- {
- x
- }
- #[cfg(not(target_endian = "little"))]
- {
- x.swap_bytes()
- }
- }
- }
-
- doc_comment! {
- concat!("Converts `self` to big endian from the target's endianness.
-
-On big endian this is a no-op. On little endian the bytes are
-swapped.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "let n = 0x1A", stringify!($SelfT), ";
-
-if cfg!(target_endian = \"big\") {
- assert_eq!(n.to_be(), n)
-} else {
- assert_eq!(n.to_be(), n.swap_bytes())
-}", $EndFeature, "
-```"),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_stable(feature = "const_math", since = "1.32.0")]
- #[inline]
- pub const fn to_be(self) -> Self { // or not to be?
- #[cfg(target_endian = "big")]
- {
- self
- }
- #[cfg(not(target_endian = "big"))]
- {
- self.swap_bytes()
- }
- }
- }
-
- doc_comment! {
- concat!("Converts `self` to little endian from the target's endianness.
-
-On little endian this is a no-op. On big endian the bytes are
-swapped.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "let n = 0x1A", stringify!($SelfT), ";
-
-if cfg!(target_endian = \"little\") {
- assert_eq!(n.to_le(), n)
-} else {
- assert_eq!(n.to_le(), n.swap_bytes())
-}", $EndFeature, "
-```"),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_stable(feature = "const_math", since = "1.32.0")]
- #[inline]
- pub const fn to_le(self) -> Self {
- #[cfg(target_endian = "little")]
- {
- self
- }
- #[cfg(not(target_endian = "little"))]
- {
- self.swap_bytes()
- }
- }
- }
-
- doc_comment! {
- concat!("Checked integer addition. Computes `self + rhs`, returning `None`
-if overflow occurred.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!((", stringify!($SelfT), "::MAX - 2).checked_add(1), ",
-"Some(", stringify!($SelfT), "::MAX - 1));
-assert_eq!((", stringify!($SelfT), "::MAX - 2).checked_add(3), None);", $EndFeature, "
-```"),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn checked_add(self, rhs: Self) -> Option<Self> {
- let (a, b) = self.overflowing_add(rhs);
- if unlikely!(b) {None} else {Some(a)}
- }
- }
-
- doc_comment! {
- concat!("Unchecked integer addition. Computes `self + rhs`, assuming overflow
-cannot occur. This results in undefined behavior when `self + rhs > ", stringify!($SelfT),
-"::MAX` or `self + rhs < ", stringify!($SelfT), "::MIN`."),
- #[unstable(
- feature = "unchecked_math",
- reason = "niche optimization path",
- issue = "none",
- )]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub unsafe fn unchecked_add(self, rhs: Self) -> Self {
- // SAFETY: the caller must uphold the safety contract for
- // `unchecked_add`.
- unsafe { intrinsics::unchecked_add(self, rhs) }
- }
- }
-
- doc_comment! {
- concat!("Checked integer subtraction. Computes `self - rhs`, returning
-`None` if overflow occurred.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(1", stringify!($SelfT), ".checked_sub(1), Some(0));
-assert_eq!(0", stringify!($SelfT), ".checked_sub(1), None);", $EndFeature, "
-```"),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn checked_sub(self, rhs: Self) -> Option<Self> {
- let (a, b) = self.overflowing_sub(rhs);
- if unlikely!(b) {None} else {Some(a)}
- }
- }
-
- doc_comment! {
- concat!("Unchecked integer subtraction. Computes `self - rhs`, assuming overflow
-cannot occur. This results in undefined behavior when `self - rhs > ", stringify!($SelfT),
-"::MAX` or `self - rhs < ", stringify!($SelfT), "::MIN`."),
- #[unstable(
- feature = "unchecked_math",
- reason = "niche optimization path",
- issue = "none",
- )]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub unsafe fn unchecked_sub(self, rhs: Self) -> Self {
- // SAFETY: the caller must uphold the safety contract for
- // `unchecked_sub`.
- unsafe { intrinsics::unchecked_sub(self, rhs) }
- }
- }
-
- doc_comment! {
- concat!("Checked integer multiplication. Computes `self * rhs`, returning
-`None` if overflow occurred.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(5", stringify!($SelfT), ".checked_mul(1), Some(5));
-assert_eq!(", stringify!($SelfT), "::MAX.checked_mul(2), None);", $EndFeature, "
-```"),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn checked_mul(self, rhs: Self) -> Option<Self> {
- let (a, b) = self.overflowing_mul(rhs);
- if unlikely!(b) {None} else {Some(a)}
- }
- }
-
- doc_comment! {
- concat!("Unchecked integer multiplication. Computes `self * rhs`, assuming overflow
-cannot occur. This results in undefined behavior when `self * rhs > ", stringify!($SelfT),
-"::MAX` or `self * rhs < ", stringify!($SelfT), "::MIN`."),
- #[unstable(
- feature = "unchecked_math",
- reason = "niche optimization path",
- issue = "none",
- )]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub unsafe fn unchecked_mul(self, rhs: Self) -> Self {
- // SAFETY: the caller must uphold the safety contract for
- // `unchecked_mul`.
- unsafe { intrinsics::unchecked_mul(self, rhs) }
- }
- }
-
- doc_comment! {
- concat!("Checked integer division. Computes `self / rhs`, returning `None`
-if `rhs == 0`.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(128", stringify!($SelfT), ".checked_div(2), Some(64));
-assert_eq!(1", stringify!($SelfT), ".checked_div(0), None);", $EndFeature, "
-```"),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_checked_int_methods", issue = "53718")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn checked_div(self, rhs: Self) -> Option<Self> {
- if unlikely!(rhs == 0) {
- None
- } else {
- // SAFETY: div by zero has been checked above and unsigned types have no other
- // failure modes for division
- Some(unsafe { intrinsics::unchecked_div(self, rhs) })
- }
- }
- }
-
- doc_comment! {
- concat!("Checked Euclidean division. Computes `self.div_euclid(rhs)`, returning `None`
-if `rhs == 0`.
-
-# Examples
-
-Basic usage:
-
-```
-assert_eq!(128", stringify!($SelfT), ".checked_div_euclid(2), Some(64));
-assert_eq!(1", stringify!($SelfT), ".checked_div_euclid(0), None);
-```"),
- #[stable(feature = "euclidean_division", since = "1.38.0")]
- #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn checked_div_euclid(self, rhs: Self) -> Option<Self> {
- if unlikely!(rhs == 0) {
- None
- } else {
- Some(self.div_euclid(rhs))
- }
- }
- }
-
-
- doc_comment! {
- concat!("Checked integer remainder. Computes `self % rhs`, returning `None`
-if `rhs == 0`.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(5", stringify!($SelfT), ".checked_rem(2), Some(1));
-assert_eq!(5", stringify!($SelfT), ".checked_rem(0), None);", $EndFeature, "
-```"),
- #[stable(feature = "wrapping", since = "1.7.0")]
- #[rustc_const_unstable(feature = "const_checked_int_methods", issue = "53718")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn checked_rem(self, rhs: Self) -> Option<Self> {
- if unlikely!(rhs == 0) {
- None
- } else {
- // SAFETY: div by zero has been checked above and unsigned types have no other
- // failure modes for division
- Some(unsafe { intrinsics::unchecked_rem(self, rhs) })
- }
- }
- }
-
- doc_comment! {
- concat!("Checked Euclidean modulo. Computes `self.rem_euclid(rhs)`, returning `None`
-if `rhs == 0`.
-
-# Examples
-
-Basic usage:
-
-```
-assert_eq!(5", stringify!($SelfT), ".checked_rem_euclid(2), Some(1));
-assert_eq!(5", stringify!($SelfT), ".checked_rem_euclid(0), None);
-```"),
- #[stable(feature = "euclidean_division", since = "1.38.0")]
- #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn checked_rem_euclid(self, rhs: Self) -> Option<Self> {
- if unlikely!(rhs == 0) {
- None
- } else {
- Some(self.rem_euclid(rhs))
- }
- }
- }
-
- doc_comment! {
- concat!("Checked negation. Computes `-self`, returning `None` unless `self ==
-0`.
-
-Note that negating any positive integer will overflow.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(0", stringify!($SelfT), ".checked_neg(), Some(0));
-assert_eq!(1", stringify!($SelfT), ".checked_neg(), None);", $EndFeature, "
-```"),
- #[stable(feature = "wrapping", since = "1.7.0")]
- #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")]
- #[inline]
- pub const fn checked_neg(self) -> Option<Self> {
- let (a, b) = self.overflowing_neg();
- if unlikely!(b) {None} else {Some(a)}
- }
- }
-
- doc_comment! {
- concat!("Checked shift left. Computes `self << rhs`, returning `None`
-if `rhs` is larger than or equal to the number of bits in `self`.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(0x1", stringify!($SelfT), ".checked_shl(4), Some(0x10));
-assert_eq!(0x10", stringify!($SelfT), ".checked_shl(129), None);", $EndFeature, "
-```"),
- #[stable(feature = "wrapping", since = "1.7.0")]
- #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn checked_shl(self, rhs: u32) -> Option<Self> {
- let (a, b) = self.overflowing_shl(rhs);
- if unlikely!(b) {None} else {Some(a)}
- }
- }
-
- doc_comment! {
- concat!("Checked shift right. Computes `self >> rhs`, returning `None`
-if `rhs` is larger than or equal to the number of bits in `self`.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(0x10", stringify!($SelfT), ".checked_shr(4), Some(0x1));
-assert_eq!(0x10", stringify!($SelfT), ".checked_shr(129), None);", $EndFeature, "
-```"),
- #[stable(feature = "wrapping", since = "1.7.0")]
- #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn checked_shr(self, rhs: u32) -> Option<Self> {
- let (a, b) = self.overflowing_shr(rhs);
- if unlikely!(b) {None} else {Some(a)}
- }
- }
-
- doc_comment! {
- concat!("Checked exponentiation. Computes `self.pow(exp)`, returning `None` if
-overflow occurred.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(2", stringify!($SelfT), ".checked_pow(5), Some(32));
-assert_eq!(", stringify!($SelfT), "::MAX.checked_pow(2), None);", $EndFeature, "
-```"),
- #[stable(feature = "no_panic_pow", since = "1.34.0")]
- #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn checked_pow(self, mut exp: u32) -> Option<Self> {
- if exp == 0 {
- return Some(1);
- }
- let mut base = self;
- let mut acc: Self = 1;
-
- while exp > 1 {
- if (exp & 1) == 1 {
- acc = try_opt!(acc.checked_mul(base));
- }
- exp /= 2;
- base = try_opt!(base.checked_mul(base));
- }
-
- // since exp!=0, finally the exp must be 1.
- // Deal with the final bit of the exponent separately, since
- // squaring the base afterwards is not necessary and may cause a
- // needless overflow.
-
- Some(try_opt!(acc.checked_mul(base)))
- }
- }
-
- doc_comment! {
- concat!("Saturating integer addition. Computes `self + rhs`, saturating at
-the numeric bounds instead of overflowing.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(100", stringify!($SelfT), ".saturating_add(1), 101);
-assert_eq!(", stringify!($SelfT), "::MAX.saturating_add(127), ", stringify!($SelfT), "::MAX);",
-$EndFeature, "
-```"),
-
- #[stable(feature = "rust1", since = "1.0.0")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")]
- #[inline]
- pub const fn saturating_add(self, rhs: Self) -> Self {
- intrinsics::saturating_add(self, rhs)
- }
- }
-
- doc_comment! {
- concat!("Saturating integer subtraction. Computes `self - rhs`, saturating
-at the numeric bounds instead of overflowing.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(100", stringify!($SelfT), ".saturating_sub(27), 73);
-assert_eq!(13", stringify!($SelfT), ".saturating_sub(127), 0);", $EndFeature, "
-```"),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")]
- #[inline]
- pub const fn saturating_sub(self, rhs: Self) -> Self {
- intrinsics::saturating_sub(self, rhs)
- }
- }
-
- doc_comment! {
- concat!("Saturating integer multiplication. Computes `self * rhs`,
-saturating at the numeric bounds instead of overflowing.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "
-assert_eq!(2", stringify!($SelfT), ".saturating_mul(10), 20);
-assert_eq!((", stringify!($SelfT), "::MAX).saturating_mul(10), ", stringify!($SelfT),
-"::MAX);", $EndFeature, "
-```"),
- #[stable(feature = "wrapping", since = "1.7.0")]
- #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn saturating_mul(self, rhs: Self) -> Self {
- match self.checked_mul(rhs) {
- Some(x) => x,
- None => Self::MAX,
- }
- }
- }
-
- doc_comment! {
- concat!("Saturating integer exponentiation. Computes `self.pow(exp)`,
-saturating at the numeric bounds instead of overflowing.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "
-assert_eq!(4", stringify!($SelfT), ".saturating_pow(3), 64);
-assert_eq!(", stringify!($SelfT), "::MAX.saturating_pow(2), ", stringify!($SelfT), "::MAX);",
-$EndFeature, "
-```"),
- #[stable(feature = "no_panic_pow", since = "1.34.0")]
- #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn saturating_pow(self, exp: u32) -> Self {
- match self.checked_pow(exp) {
- Some(x) => x,
- None => Self::MAX,
- }
- }
- }
-
- doc_comment! {
- concat!("Wrapping (modular) addition. Computes `self + rhs`,
-wrapping around at the boundary of the type.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(200", stringify!($SelfT), ".wrapping_add(55), 255);
-assert_eq!(200", stringify!($SelfT), ".wrapping_add(", stringify!($SelfT), "::MAX), 199);",
-$EndFeature, "
-```"),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn wrapping_add(self, rhs: Self) -> Self {
- intrinsics::wrapping_add(self, rhs)
- }
- }
-
- doc_comment! {
- concat!("Wrapping (modular) subtraction. Computes `self - rhs`,
-wrapping around at the boundary of the type.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_sub(100), 0);
-assert_eq!(100", stringify!($SelfT), ".wrapping_sub(", stringify!($SelfT), "::MAX), 101);",
-$EndFeature, "
-```"),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn wrapping_sub(self, rhs: Self) -> Self {
- intrinsics::wrapping_sub(self, rhs)
- }
- }
-
- /// Wrapping (modular) multiplication. Computes `self *
- /// rhs`, wrapping around at the boundary of the type.
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// Please note that this example is shared between integer types.
- /// Which explains why `u8` is used here.
- ///
- /// ```
- /// assert_eq!(10u8.wrapping_mul(12), 120);
- /// assert_eq!(25u8.wrapping_mul(12), 44);
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn wrapping_mul(self, rhs: Self) -> Self {
- intrinsics::wrapping_mul(self, rhs)
- }
-
- doc_comment! {
- concat!("Wrapping (modular) division. Computes `self / rhs`.
-Wrapped division on unsigned types is just normal division.
-There's no way wrapping could ever happen.
-This function exists, so that all operations
-are accounted for in the wrapping operations.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_div(10), 10);", $EndFeature, "
-```"),
- #[stable(feature = "num_wrapping", since = "1.2.0")]
- #[rustc_const_unstable(feature = "const_wrapping_int_methods", issue = "53718")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn wrapping_div(self, rhs: Self) -> Self {
- self / rhs
- }
- }
-
- doc_comment! {
- concat!("Wrapping Euclidean division. Computes `self.div_euclid(rhs)`.
-Wrapped division on unsigned types is just normal division.
-There's no way wrapping could ever happen.
-This function exists, so that all operations
-are accounted for in the wrapping operations.
-Since, for the positive integers, all common
-definitions of division are equal, this
-is exactly equal to `self.wrapping_div(rhs)`.
-
-# Examples
-
-Basic usage:
-
-```
-assert_eq!(100", stringify!($SelfT), ".wrapping_div_euclid(10), 10);
-```"),
- #[stable(feature = "euclidean_division", since = "1.38.0")]
- #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn wrapping_div_euclid(self, rhs: Self) -> Self {
- self / rhs
- }
- }
-
- doc_comment! {
- concat!("Wrapping (modular) remainder. Computes `self % rhs`.
-Wrapped remainder calculation on unsigned types is
-just the regular remainder calculation.
-There's no way wrapping could ever happen.
-This function exists, so that all operations
-are accounted for in the wrapping operations.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_rem(10), 0);", $EndFeature, "
-```"),
- #[stable(feature = "num_wrapping", since = "1.2.0")]
- #[rustc_const_unstable(feature = "const_wrapping_int_methods", issue = "53718")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn wrapping_rem(self, rhs: Self) -> Self {
- self % rhs
- }
- }
-
- doc_comment! {
- concat!("Wrapping Euclidean modulo. Computes `self.rem_euclid(rhs)`.
-Wrapped modulo calculation on unsigned types is
-just the regular remainder calculation.
-There's no way wrapping could ever happen.
-This function exists, so that all operations
-are accounted for in the wrapping operations.
-Since, for the positive integers, all common
-definitions of division are equal, this
-is exactly equal to `self.wrapping_rem(rhs)`.
-
-# Examples
-
-Basic usage:
-
-```
-assert_eq!(100", stringify!($SelfT), ".wrapping_rem_euclid(10), 0);
-```"),
- #[stable(feature = "euclidean_division", since = "1.38.0")]
- #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn wrapping_rem_euclid(self, rhs: Self) -> Self {
- self % rhs
- }
- }
-
- /// Wrapping (modular) negation. Computes `-self`,
- /// wrapping around at the boundary of the type.
- ///
- /// Since unsigned types do not have negative equivalents
- /// all applications of this function will wrap (except for `-0`).
- /// For values smaller than the corresponding signed type's maximum
- /// the result is the same as casting the corresponding signed value.
- /// Any larger values are equivalent to `MAX + 1 - (val - MAX - 1)` where
- /// `MAX` is the corresponding signed type's maximum.
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// Please note that this example is shared between integer types.
- /// Which explains why `i8` is used here.
- ///
- /// ```
- /// assert_eq!(100i8.wrapping_neg(), -100);
- /// assert_eq!((-128i8).wrapping_neg(), -128);
- /// ```
- #[stable(feature = "num_wrapping", since = "1.2.0")]
- #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")]
- #[inline]
- pub const fn wrapping_neg(self) -> Self {
- self.overflowing_neg().0
- }
-
- doc_comment! {
- concat!("Panic-free bitwise shift-left; yields `self << mask(rhs)`,
-where `mask` removes any high-order bits of `rhs` that
-would cause the shift to exceed the bitwidth of the type.
-
-Note that this is *not* the same as a rotate-left; the
-RHS of a wrapping shift-left is restricted to the range
-of the type, rather than the bits shifted out of the LHS
-being returned to the other end. The primitive integer
-types all implement a [`rotate_left`](#method.rotate_left) function,
-which may be what you want instead.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(1", stringify!($SelfT), ".wrapping_shl(7), 128);
-assert_eq!(1", stringify!($SelfT), ".wrapping_shl(128), 1);", $EndFeature, "
-```"),
- #[stable(feature = "num_wrapping", since = "1.2.0")]
- #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn wrapping_shl(self, rhs: u32) -> Self {
- // SAFETY: the masking by the bitsize of the type ensures that we do not shift
- // out of bounds
- unsafe {
- intrinsics::unchecked_shl(self, (rhs & ($BITS - 1)) as $SelfT)
- }
- }
- }
-
- doc_comment! {
- concat!("Panic-free bitwise shift-right; yields `self >> mask(rhs)`,
-where `mask` removes any high-order bits of `rhs` that
-would cause the shift to exceed the bitwidth of the type.
-
-Note that this is *not* the same as a rotate-right; the
-RHS of a wrapping shift-right is restricted to the range
-of the type, rather than the bits shifted out of the LHS
-being returned to the other end. The primitive integer
-types all implement a [`rotate_right`](#method.rotate_right) function,
-which may be what you want instead.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(128", stringify!($SelfT), ".wrapping_shr(7), 1);
-assert_eq!(128", stringify!($SelfT), ".wrapping_shr(128), 128);", $EndFeature, "
-```"),
- #[stable(feature = "num_wrapping", since = "1.2.0")]
- #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn wrapping_shr(self, rhs: u32) -> Self {
- // SAFETY: the masking by the bitsize of the type ensures that we do not shift
- // out of bounds
- unsafe {
- intrinsics::unchecked_shr(self, (rhs & ($BITS - 1)) as $SelfT)
- }
- }
- }
-
- doc_comment! {
- concat!("Wrapping (modular) exponentiation. Computes `self.pow(exp)`,
-wrapping around at the boundary of the type.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(3", stringify!($SelfT), ".wrapping_pow(5), 243);
-assert_eq!(3u8.wrapping_pow(6), 217);", $EndFeature, "
-```"),
- #[stable(feature = "no_panic_pow", since = "1.34.0")]
- #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn wrapping_pow(self, mut exp: u32) -> Self {
- if exp == 0 {
- return 1;
- }
- let mut base = self;
- let mut acc: Self = 1;
-
- while exp > 1 {
- if (exp & 1) == 1 {
- acc = acc.wrapping_mul(base);
- }
- exp /= 2;
- base = base.wrapping_mul(base);
- }
-
- // since exp!=0, finally the exp must be 1.
- // Deal with the final bit of the exponent separately, since
- // squaring the base afterwards is not necessary and may cause a
- // needless overflow.
- acc.wrapping_mul(base)
- }
- }
-
- doc_comment! {
- concat!("Calculates `self` + `rhs`
-
-Returns a tuple of the addition along with a boolean indicating
-whether an arithmetic overflow would occur. If an overflow would
-have occurred then the wrapped value is returned.
-
-# Examples
-
-Basic usage
-
-```
-", $Feature, "
-assert_eq!(5", stringify!($SelfT), ".overflowing_add(2), (7, false));
-assert_eq!(", stringify!($SelfT), "::MAX.overflowing_add(1), (0, true));", $EndFeature, "
-```"),
- #[stable(feature = "wrapping", since = "1.7.0")]
- #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn overflowing_add(self, rhs: Self) -> (Self, bool) {
- let (a, b) = intrinsics::add_with_overflow(self as $ActualT, rhs as $ActualT);
- (a as Self, b)
- }
- }
-
- doc_comment! {
- concat!("Calculates `self` - `rhs`
-
-Returns a tuple of the subtraction along with a boolean indicating
-whether an arithmetic overflow would occur. If an overflow would
-have occurred then the wrapped value is returned.
-
-# Examples
-
-Basic usage
-
-```
-", $Feature, "
-assert_eq!(5", stringify!($SelfT), ".overflowing_sub(2), (3, false));
-assert_eq!(0", stringify!($SelfT), ".overflowing_sub(1), (", stringify!($SelfT), "::MAX, true));",
-$EndFeature, "
-```"),
- #[stable(feature = "wrapping", since = "1.7.0")]
- #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn overflowing_sub(self, rhs: Self) -> (Self, bool) {
- let (a, b) = intrinsics::sub_with_overflow(self as $ActualT, rhs as $ActualT);
- (a as Self, b)
- }
- }
-
- /// Calculates the multiplication of `self` and `rhs`.
- ///
- /// Returns a tuple of the multiplication along with a boolean
- /// indicating whether an arithmetic overflow would occur. If an
- /// overflow would have occurred then the wrapped value is returned.
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// Please note that this example is shared between integer types.
- /// Which explains why `u32` is used here.
- ///
- /// ```
- /// assert_eq!(5u32.overflowing_mul(2), (10, false));
- /// assert_eq!(1_000_000_000u32.overflowing_mul(10), (1410065408, true));
- /// ```
- #[stable(feature = "wrapping", since = "1.7.0")]
- #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn overflowing_mul(self, rhs: Self) -> (Self, bool) {
- let (a, b) = intrinsics::mul_with_overflow(self as $ActualT, rhs as $ActualT);
- (a as Self, b)
- }
-
- doc_comment! {
- concat!("Calculates the divisor when `self` is divided by `rhs`.
-
-Returns a tuple of the divisor along with a boolean indicating
-whether an arithmetic overflow would occur. Note that for unsigned
-integers overflow never occurs, so the second value is always
-`false`.
-
-# Panics
-
-This function will panic if `rhs` is 0.
-
-# Examples
-
-Basic usage
-
-```
-", $Feature, "assert_eq!(5", stringify!($SelfT), ".overflowing_div(2), (2, false));", $EndFeature, "
-```"),
- #[inline]
- #[stable(feature = "wrapping", since = "1.7.0")]
- #[rustc_const_unstable(feature = "const_overflowing_int_methods", issue = "53718")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- pub const fn overflowing_div(self, rhs: Self) -> (Self, bool) {
- (self / rhs, false)
- }
- }
-
- doc_comment! {
- concat!("Calculates the quotient of Euclidean division `self.div_euclid(rhs)`.
-
-Returns a tuple of the divisor along with a boolean indicating
-whether an arithmetic overflow would occur. Note that for unsigned
-integers overflow never occurs, so the second value is always
-`false`.
-Since, for the positive integers, all common
-definitions of division are equal, this
-is exactly equal to `self.overflowing_div(rhs)`.
-
-# Panics
-
-This function will panic if `rhs` is 0.
-
-# Examples
-
-Basic usage
-
-```
-assert_eq!(5", stringify!($SelfT), ".overflowing_div_euclid(2), (2, false));
-```"),
- #[inline]
- #[stable(feature = "euclidean_division", since = "1.38.0")]
- #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- pub const fn overflowing_div_euclid(self, rhs: Self) -> (Self, bool) {
- (self / rhs, false)
- }
- }
-
- doc_comment! {
- concat!("Calculates the remainder when `self` is divided by `rhs`.
-
-Returns a tuple of the remainder after dividing along with a boolean
-indicating whether an arithmetic overflow would occur. Note that for
-unsigned integers overflow never occurs, so the second value is
-always `false`.
-
-# Panics
-
-This function will panic if `rhs` is 0.
-
-# Examples
-
-Basic usage
-
-```
-", $Feature, "assert_eq!(5", stringify!($SelfT), ".overflowing_rem(2), (1, false));", $EndFeature, "
-```"),
- #[inline]
- #[stable(feature = "wrapping", since = "1.7.0")]
- #[rustc_const_unstable(feature = "const_overflowing_int_methods", issue = "53718")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- pub const fn overflowing_rem(self, rhs: Self) -> (Self, bool) {
- (self % rhs, false)
- }
- }
-
- doc_comment! {
- concat!("Calculates the remainder `self.rem_euclid(rhs)` as if by Euclidean division.
-
-Returns a tuple of the modulo after dividing along with a boolean
-indicating whether an arithmetic overflow would occur. Note that for
-unsigned integers overflow never occurs, so the second value is
-always `false`.
-Since, for the positive integers, all common
-definitions of division are equal, this operation
-is exactly equal to `self.overflowing_rem(rhs)`.
-
-# Panics
-
-This function will panic if `rhs` is 0.
-
-# Examples
-
-Basic usage
-
-```
-assert_eq!(5", stringify!($SelfT), ".overflowing_rem_euclid(2), (1, false));
-```"),
- #[inline]
- #[stable(feature = "euclidean_division", since = "1.38.0")]
- #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- pub const fn overflowing_rem_euclid(self, rhs: Self) -> (Self, bool) {
- (self % rhs, false)
- }
- }
-
- doc_comment! {
- concat!("Negates self in an overflowing fashion.
-
-Returns `!self + 1` using wrapping operations to return the value
-that represents the negation of this unsigned value. Note that for
-positive unsigned values overflow always occurs, but negating 0 does
-not overflow.
-
-# Examples
-
-Basic usage
-
-```
-", $Feature, "assert_eq!(0", stringify!($SelfT), ".overflowing_neg(), (0, false));
-assert_eq!(2", stringify!($SelfT), ".overflowing_neg(), (-2i32 as ", stringify!($SelfT),
-", true));", $EndFeature, "
-```"),
- #[inline]
- #[stable(feature = "wrapping", since = "1.7.0")]
- #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")]
- pub const fn overflowing_neg(self) -> (Self, bool) {
- ((!self).wrapping_add(1), self != 0)
- }
- }
-
- doc_comment! {
- concat!("Shifts self left by `rhs` bits.
-
-Returns a tuple of the shifted version of self along with a boolean
-indicating whether the shift value was larger than or equal to the
-number of bits. If the shift value is too large, then value is
-masked (N-1) where N is the number of bits, and this value is then
-used to perform the shift.
-
-# Examples
-
-Basic usage
-
-```
-", $Feature, "assert_eq!(0x1", stringify!($SelfT), ".overflowing_shl(4), (0x10, false));
-assert_eq!(0x1", stringify!($SelfT), ".overflowing_shl(132), (0x10, true));", $EndFeature, "
-```"),
- #[stable(feature = "wrapping", since = "1.7.0")]
- #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn overflowing_shl(self, rhs: u32) -> (Self, bool) {
- (self.wrapping_shl(rhs), (rhs > ($BITS - 1)))
- }
- }
-
- doc_comment! {
- concat!("Shifts self right by `rhs` bits.
-
-Returns a tuple of the shifted version of self along with a boolean
-indicating whether the shift value was larger than or equal to the
-number of bits. If the shift value is too large, then value is
-masked (N-1) where N is the number of bits, and this value is then
-used to perform the shift.
-
-# Examples
-
-Basic usage
-
-```
-", $Feature, "assert_eq!(0x10", stringify!($SelfT), ".overflowing_shr(4), (0x1, false));
-assert_eq!(0x10", stringify!($SelfT), ".overflowing_shr(132), (0x1, true));", $EndFeature, "
-```"),
- #[stable(feature = "wrapping", since = "1.7.0")]
- #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn overflowing_shr(self, rhs: u32) -> (Self, bool) {
- (self.wrapping_shr(rhs), (rhs > ($BITS - 1)))
- }
- }
-
- doc_comment! {
- concat!("Raises self to the power of `exp`, using exponentiation by squaring.
-
-Returns a tuple of the exponentiation along with a bool indicating
-whether an overflow happened.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(3", stringify!($SelfT), ".overflowing_pow(5), (243, false));
-assert_eq!(3u8.overflowing_pow(6), (217, true));", $EndFeature, "
-```"),
- #[stable(feature = "no_panic_pow", since = "1.34.0")]
- #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn overflowing_pow(self, mut exp: u32) -> (Self, bool) {
- if exp == 0{
- return (1,false);
- }
- let mut base = self;
- let mut acc: Self = 1;
- let mut overflown = false;
- // Scratch space for storing results of overflowing_mul.
- let mut r;
-
- while exp > 1 {
- if (exp & 1) == 1 {
- r = acc.overflowing_mul(base);
- acc = r.0;
- overflown |= r.1;
- }
- exp /= 2;
- r = base.overflowing_mul(base);
- base = r.0;
- overflown |= r.1;
- }
-
- // since exp!=0, finally the exp must be 1.
- // Deal with the final bit of the exponent separately, since
- // squaring the base afterwards is not necessary and may cause a
- // needless overflow.
- r = acc.overflowing_mul(base);
- r.1 |= overflown;
-
- r
- }
- }
-
- doc_comment! {
- concat!("Raises self to the power of `exp`, using exponentiation by squaring.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(2", stringify!($SelfT), ".pow(5), 32);", $EndFeature, "
-```"),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- #[rustc_inherit_overflow_checks]
- pub const fn pow(self, mut exp: u32) -> Self {
- if exp == 0 {
- return 1;
- }
- let mut base = self;
- let mut acc = 1;
-
- while exp > 1 {
- if (exp & 1) == 1 {
- acc = acc * base;
- }
- exp /= 2;
- base = base * base;
- }
-
- // since exp!=0, finally the exp must be 1.
- // Deal with the final bit of the exponent separately, since
- // squaring the base afterwards is not necessary and may cause a
- // needless overflow.
- acc * base
- }
- }
-
- doc_comment! {
- concat!("Performs Euclidean division.
-
-Since, for the positive integers, all common
-definitions of division are equal, this
-is exactly equal to `self / rhs`.
-
-# Panics
-
-This function will panic if `rhs` is 0.
-
-# Examples
-
-Basic usage:
-
-```
-assert_eq!(7", stringify!($SelfT), ".div_euclid(4), 1); // or any other integer type
-```"),
- #[stable(feature = "euclidean_division", since = "1.38.0")]
- #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- #[rustc_inherit_overflow_checks]
- pub const fn div_euclid(self, rhs: Self) -> Self {
- self / rhs
- }
- }
-
-
- doc_comment! {
- concat!("Calculates the least remainder of `self (mod rhs)`.
-
-Since, for the positive integers, all common
-definitions of division are equal, this
-is exactly equal to `self % rhs`.
-
-# Panics
-
-This function will panic if `rhs` is 0.
-
-# Examples
-
-Basic usage:
-
-```
-assert_eq!(7", stringify!($SelfT), ".rem_euclid(4), 3); // or any other integer type
-```"),
- #[stable(feature = "euclidean_division", since = "1.38.0")]
- #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- #[rustc_inherit_overflow_checks]
- pub const fn rem_euclid(self, rhs: Self) -> Self {
- self % rhs
- }
- }
-
- doc_comment! {
- concat!("Returns `true` if and only if `self == 2^k` for some `k`.
-
-# Examples
-
-Basic usage:
+//! Numeric traits and functions for the built-in numeric types.
-```
-", $Feature, "assert!(16", stringify!($SelfT), ".is_power_of_two());
-assert!(!10", stringify!($SelfT), ".is_power_of_two());", $EndFeature, "
-```"),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_stable(feature = "const_is_power_of_two", since = "1.32.0")]
- #[inline]
- pub const fn is_power_of_two(self) -> bool {
- self.count_ones() == 1
- }
- }
+#![stable(feature = "rust1", since = "1.0.0")]
- // Returns one less than next power of two.
- // (For 8u8 next power of two is 8u8 and for 6u8 it is 8u8)
- //
- // 8u8.one_less_than_next_power_of_two() == 7
- // 6u8.one_less_than_next_power_of_two() == 7
- //
- // This method cannot overflow, as in the `next_power_of_two`
- // overflow cases it instead ends up returning the maximum value
- // of the type, and can return 0 for 0.
- #[inline]
- #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")]
- const fn one_less_than_next_power_of_two(self) -> Self {
- if self <= 1 { return 0; }
+use crate::intrinsics;
+use crate::mem;
+use crate::str::FromStr;
- let p = self - 1;
- // SAFETY: Because `p > 0`, it cannot consist entirely of leading zeros.
- // That means the shift is always in-bounds, and some processors
- // (such as intel pre-haswell) have more efficient ctlz
- // intrinsics when the argument is non-zero.
- let z = unsafe { intrinsics::ctlz_nonzero(p) };
- <$SelfT>::MAX >> z
+// Used because the `?` operator is not allowed in a const context.
+macro_rules! try_opt {
+ ($e:expr) => {
+ match $e {
+ Some(x) => x,
+ None => return None,
}
+ };
+}
- doc_comment! {
- concat!("Returns the smallest power of two greater than or equal to `self`.
-
-When return value overflows (i.e., `self > (1 << (N-1))` for type
-`uN`), it panics in debug mode and return value is wrapped to 0 in
-release mode (the only situation in which method can return 0).
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(2", stringify!($SelfT), ".next_power_of_two(), 2);
-assert_eq!(3", stringify!($SelfT), ".next_power_of_two(), 4);", $EndFeature, "
-```"),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")]
- #[inline]
- #[rustc_inherit_overflow_checks]
- pub const fn next_power_of_two(self) -> Self {
- self.one_less_than_next_power_of_two() + 1
- }
- }
+#[allow_internal_unstable(const_likely)]
+macro_rules! unlikely {
+ ($e: expr) => {
+ intrinsics::unlikely($e)
+ };
+}
- doc_comment! {
- concat!("Returns the smallest power of two greater than or equal to `n`. If
-the next power of two is greater than the type's maximum value,
-`None` is returned, otherwise the power of two is wrapped in `Some`.
+macro_rules! doc_comment {
+ ($x:expr, $($tt:tt)*) => {
+ #[doc = $x]
+ $($tt)*
+ };
+}
-# Examples
+// All these modules are technically private and only exposed for coretests:
+pub mod bignum;
+pub mod dec2flt;
+pub mod diy_float;
+pub mod flt2dec;
-Basic usage:
+#[macro_use]
+mod int_macros; // import int_impl!
+#[macro_use]
+mod uint_macros; // import uint_impl!
-```
-", $Feature, "assert_eq!(2", stringify!($SelfT),
-".checked_next_power_of_two(), Some(2));
-assert_eq!(3", stringify!($SelfT), ".checked_next_power_of_two(), Some(4));
-assert_eq!(", stringify!($SelfT), "::MAX.checked_next_power_of_two(), None);",
-$EndFeature, "
-```"),
- #[inline]
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")]
- pub const fn checked_next_power_of_two(self) -> Option<Self> {
- self.one_less_than_next_power_of_two().checked_add(1)
- }
- }
+mod error;
+mod nonzero;
+mod wrapping;
- doc_comment! {
- concat!("Returns the smallest power of two greater than or equal to `n`. If
-the next power of two is greater than the type's maximum value,
-the return value is wrapped to `0`.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use wrapping::Wrapping;
-# Examples
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use dec2flt::ParseFloatError;
-Basic usage:
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use error::ParseIntError;
-```
-#![feature(wrapping_next_power_of_two)]
-", $Feature, "
-assert_eq!(2", stringify!($SelfT), ".wrapping_next_power_of_two(), 2);
-assert_eq!(3", stringify!($SelfT), ".wrapping_next_power_of_two(), 4);
-assert_eq!(", stringify!($SelfT), "::MAX.wrapping_next_power_of_two(), 0);",
-$EndFeature, "
-```"),
- #[unstable(feature = "wrapping_next_power_of_two", issue = "32463",
- reason = "needs decision on wrapping behaviour")]
- #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")]
- pub const fn wrapping_next_power_of_two(self) -> Self {
- self.one_less_than_next_power_of_two().wrapping_add(1)
- }
- }
+#[stable(feature = "nonzero", since = "1.28.0")]
+pub use nonzero::{NonZeroU128, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize};
- doc_comment! {
- concat!("Return the memory representation of this integer as a byte array in
-big-endian (network) byte order.
-",
-$to_xe_bytes_doc,
-"
-# Examples
+#[stable(feature = "signed_nonzero", since = "1.34.0")]
+pub use nonzero::{NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize};
-```
-let bytes = ", $swap_op, stringify!($SelfT), ".to_be_bytes();
-assert_eq!(bytes, ", $be_bytes, ");
-```"),
- #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
- #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")]
- #[inline]
- pub const fn to_be_bytes(self) -> [u8; mem::size_of::<Self>()] {
- self.to_be().to_ne_bytes()
- }
- }
+#[stable(feature = "try_from", since = "1.34.0")]
+pub use error::TryFromIntError;
- doc_comment! {
- concat!("Return the memory representation of this integer as a byte array in
-little-endian byte order.
-",
-$to_xe_bytes_doc,
-"
-# Examples
+#[unstable(feature = "int_error_matching", issue = "22639")]
+pub use error::IntErrorKind;
-```
-let bytes = ", $swap_op, stringify!($SelfT), ".to_le_bytes();
-assert_eq!(bytes, ", $le_bytes, ");
-```"),
- #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
- #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")]
- #[inline]
- pub const fn to_le_bytes(self) -> [u8; mem::size_of::<Self>()] {
- self.to_le().to_ne_bytes()
- }
- }
+macro_rules! usize_isize_to_xe_bytes_doc {
+ () => {
+ "
- doc_comment! {
- concat!("
-Return the memory representation of this integer as a byte array in
-native byte order.
+**Note**: This function returns an array of length 2, 4 or 8 bytes
+depending on the target pointer size.
-As the target platform's native endianness is used, portable code
-should use [`to_be_bytes`] or [`to_le_bytes`], as appropriate,
-instead.
-",
-$to_xe_bytes_doc,
"
-[`to_be_bytes`]: #method.to_be_bytes
-[`to_le_bytes`]: #method.to_le_bytes
+ };
+}
-# Examples
+macro_rules! usize_isize_from_xe_bytes_doc {
+ () => {
+ "
-```
-let bytes = ", $swap_op, stringify!($SelfT), ".to_ne_bytes();
-assert_eq!(
- bytes,
- if cfg!(target_endian = \"big\") {
- ", $be_bytes, "
- } else {
- ", $le_bytes, "
- }
-);
-```"),
- #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
- #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")]
- // SAFETY: const sound because integers are plain old datatypes so we can always
- // transmute them to arrays of bytes
- #[allow_internal_unstable(const_fn_transmute)]
- #[inline]
- pub const fn to_ne_bytes(self) -> [u8; mem::size_of::<Self>()] {
- // SAFETY: integers are plain old datatypes so we can always transmute them to
- // arrays of bytes
- unsafe { mem::transmute(self) }
- }
- }
+**Note**: This function takes an array of length 2, 4 or 8 bytes
+depending on the target pointer size.
- doc_comment! {
- concat!("Create a native endian integer value from its representation
-as a byte array in big endian.
-",
-$from_xe_bytes_doc,
"
-# Examples
-
-```
-let value = ", stringify!($SelfT), "::from_be_bytes(", $be_bytes, ");
-assert_eq!(value, ", $swap_op, ");
-```
-
-When starting from a slice rather than an array, fallible conversion APIs can be used:
-
-```
-use std::convert::TryInto;
-
-fn read_be_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " {
- let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">());
- *input = rest;
- ", stringify!($SelfT), "::from_be_bytes(int_bytes.try_into().unwrap())
+ };
}
-```"),
- #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
- #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")]
- #[inline]
- pub const fn from_be_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
- Self::from_be(Self::from_ne_bytes(bytes))
- }
- }
-
- doc_comment! {
- concat!("
-Create a native endian integer value from its representation
-as a byte array in little endian.
-",
-$from_xe_bytes_doc,
-"
-# Examples
-
-```
-let value = ", stringify!($SelfT), "::from_le_bytes(", $le_bytes, ");
-assert_eq!(value, ", $swap_op, ");
-```
-When starting from a slice rather than an array, fallible conversion APIs can be used:
-
-```
-use std::convert::TryInto;
-
-fn read_le_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " {
- let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">());
- *input = rest;
- ", stringify!($SelfT), "::from_le_bytes(int_bytes.try_into().unwrap())
+#[lang = "i8"]
+impl i8 {
+ int_impl! { i8, i8, u8, 8, -128, 127, "", "", 2, "-0x7e", "0xa", "0x12", "0x12", "0x48",
+ "[0x12]", "[0x12]", "", "" }
}
-```"),
- #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
- #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")]
- #[inline]
- pub const fn from_le_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
- Self::from_le(Self::from_ne_bytes(bytes))
- }
- }
-
- doc_comment! {
- concat!("Create a native endian integer value from its memory representation
-as a byte array in native endianness.
-
-As the target platform's native endianness is used, portable code
-likely wants to use [`from_be_bytes`] or [`from_le_bytes`], as
-appropriate instead.
-
-[`from_be_bytes`]: #method.from_be_bytes
-[`from_le_bytes`]: #method.from_le_bytes
-",
-$from_xe_bytes_doc,
-"
-# Examples
-```
-let value = ", stringify!($SelfT), "::from_ne_bytes(if cfg!(target_endian = \"big\") {
- ", $be_bytes, "
-} else {
- ", $le_bytes, "
-});
-assert_eq!(value, ", $swap_op, ");
-```
-
-When starting from a slice rather than an array, fallible conversion APIs can be used:
-
-```
-use std::convert::TryInto;
-
-fn read_ne_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " {
- let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">());
- *input = rest;
- ", stringify!($SelfT), "::from_ne_bytes(int_bytes.try_into().unwrap())
+#[lang = "i16"]
+impl i16 {
+ int_impl! { i16, i16, u16, 16, -32768, 32767, "", "", 4, "-0x5ffd", "0x3a", "0x1234", "0x3412",
+ "0x2c48", "[0x34, 0x12]", "[0x12, 0x34]", "", "" }
}
-```"),
- #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
- #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")]
- // SAFETY: const sound because integers are plain old datatypes so we can always
- // transmute to them
- #[allow_internal_unstable(const_fn_transmute)]
- #[inline]
- pub const fn from_ne_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
- // SAFETY: integers are plain old datatypes so we can always transmute to them
- unsafe { mem::transmute(bytes) }
- }
- }
- doc_comment! {
- concat!("**This method is soft-deprecated.**
+#[lang = "i32"]
+impl i32 {
+ int_impl! { i32, i32, u32, 32, -2147483648, 2147483647, "", "", 8, "0x10000b3", "0xb301",
+ "0x12345678", "0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]",
+ "[0x12, 0x34, 0x56, 0x78]", "", "" }
+}
-Although using it won’t cause compilation warning,
-new code should use [`", stringify!($SelfT), "::MIN", "`](#associatedconstant.MIN) instead.
+#[lang = "i64"]
+impl i64 {
+ int_impl! { i64, i64, u64, 64, -9223372036854775808, 9223372036854775807, "", "", 12,
+ "0xaa00000000006e1", "0x6e10aa", "0x1234567890123456", "0x5634129078563412",
+ "0x6a2c48091e6a2c48", "[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]",
+ "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]", "", "" }
+}
-Returns the smallest value that can be represented by this integer type."),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_promotable]
- #[inline(always)]
- #[rustc_const_stable(feature = "const_max_value", since = "1.32.0")]
- pub const fn min_value() -> Self { Self::MIN }
- }
+#[lang = "i128"]
+impl i128 {
+ int_impl! { i128, i128, u128, 128, -170141183460469231731687303715884105728,
+ 170141183460469231731687303715884105727, "", "", 16,
+ "0x13f40000000000000000000000004f76", "0x4f7613f4", "0x12345678901234567890123456789012",
+ "0x12907856341290785634129078563412", "0x48091e6a2c48091e6a2c48091e6a2c48",
+ "[0x12, 0x90, 0x78, 0x56, 0x34, 0x12, 0x90, 0x78, \
+ 0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]",
+ "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, \
+ 0x78, 0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12]", "", "" }
+}
- doc_comment! {
- concat!("**This method is soft-deprecated.**
+#[cfg(target_pointer_width = "16")]
+#[lang = "isize"]
+impl isize {
+ int_impl! { isize, i16, u16, 16, -32768, 32767, "", "", 4, "-0x5ffd", "0x3a", "0x1234",
+ "0x3412", "0x2c48", "[0x34, 0x12]", "[0x12, 0x34]",
+ usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() }
+}
-Although using it won’t cause compilation warning,
-new code should use [`", stringify!($SelfT), "::MAX", "`](#associatedconstant.MAX) instead.
+#[cfg(target_pointer_width = "32")]
+#[lang = "isize"]
+impl isize {
+ int_impl! { isize, i32, u32, 32, -2147483648, 2147483647, "", "", 8, "0x10000b3", "0xb301",
+ "0x12345678", "0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]",
+ "[0x12, 0x34, 0x56, 0x78]",
+ usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() }
+}
-Returns the largest value that can be represented by this integer type."),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_promotable]
- #[inline(always)]
- #[rustc_const_stable(feature = "const_max_value", since = "1.32.0")]
- pub const fn max_value() -> Self { Self::MAX }
- }
- }
+#[cfg(target_pointer_width = "64")]
+#[lang = "isize"]
+impl isize {
+ int_impl! { isize, i64, u64, 64, -9223372036854775808, 9223372036854775807, "", "",
+ 12, "0xaa00000000006e1", "0x6e10aa", "0x1234567890123456", "0x5634129078563412",
+ "0x6a2c48091e6a2c48", "[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]",
+ "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]",
+ usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() }
}
#[lang = "u8"]
Normal,
}
+#[doc(hidden)]
+trait FromStrRadixHelper: PartialOrd + Copy {
+ fn min_value() -> Self;
+ fn max_value() -> Self;
+ fn from_u32(u: u32) -> Self;
+ fn checked_mul(&self, other: u32) -> Option<Self>;
+ fn checked_sub(&self, other: u32) -> Option<Self>;
+ fn checked_add(&self, other: u32) -> Option<Self>;
+}
+
macro_rules! from_str_radix_int_impl {
($($t:ty)*) => {$(
#[stable(feature = "rust1", since = "1.0.0")]
}
from_str_radix_int_impl! { isize i8 i16 i32 i64 i128 usize u8 u16 u32 u64 u128 }
-/// The error type returned when a checked integral type conversion fails.
-#[stable(feature = "try_from", since = "1.34.0")]
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-pub struct TryFromIntError(pub(crate) ());
-
-impl TryFromIntError {
- #[unstable(
- feature = "int_error_internals",
- reason = "available through Error trait and this method should \
- not be exposed publicly",
- issue = "none"
- )]
- #[doc(hidden)]
- pub fn __description(&self) -> &str {
- "out of range integral type conversion attempted"
- }
-}
-
-#[stable(feature = "try_from", since = "1.34.0")]
-impl fmt::Display for TryFromIntError {
- fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
- self.__description().fmt(fmt)
- }
-}
-
-#[stable(feature = "try_from", since = "1.34.0")]
-impl From<Infallible> for TryFromIntError {
- fn from(x: Infallible) -> TryFromIntError {
- match x {}
- }
-}
-
-#[unstable(feature = "never_type", issue = "35121")]
-impl From<!> for TryFromIntError {
- fn from(never: !) -> TryFromIntError {
- // Match rather than coerce to make sure that code like
- // `From<Infallible> for TryFromIntError` above will keep working
- // when `Infallible` becomes an alias to `!`.
- match never {}
- }
-}
-
-#[doc(hidden)]
-trait FromStrRadixHelper: PartialOrd + Copy {
- fn min_value() -> Self;
- fn max_value() -> Self;
- fn from_u32(u: u32) -> Self;
- fn checked_mul(&self, other: u32) -> Option<Self>;
- fn checked_sub(&self, other: u32) -> Option<Self>;
- fn checked_add(&self, other: u32) -> Option<Self>;
-}
-
macro_rules! doit {
($($t:ty)*) => ($(impl FromStrRadixHelper for $t {
#[inline]
}
Ok(result)
}
-
-/// An error which can be returned when parsing an integer.
-///
-/// This error is used as the error type for the `from_str_radix()` functions
-/// on the primitive integer types, such as [`i8::from_str_radix`].
-///
-/// # Potential causes
-///
-/// Among other causes, `ParseIntError` can be thrown because of leading or trailing whitespace
-/// in the string e.g., when it is obtained from the standard input.
-/// Using the [`str.trim()`] method ensures that no whitespace remains before parsing.
-///
-/// [`str.trim()`]: ../../std/primitive.str.html#method.trim
-/// [`i8::from_str_radix`]: ../../std/primitive.i8.html#method.from_str_radix
-///
-/// # Example
-///
-/// ```
-/// if let Err(e) = i32::from_str_radix("a12", 10) {
-/// println!("Failed conversion to i32: {}", e);
-/// }
-/// ```
-#[derive(Debug, Clone, PartialEq, Eq)]
-#[stable(feature = "rust1", since = "1.0.0")]
-pub struct ParseIntError {
- kind: IntErrorKind,
-}
-
-/// Enum to store the various types of errors that can cause parsing an integer to fail.
-///
-/// # Example
-///
-/// ```
-/// #![feature(int_error_matching)]
-///
-/// # fn main() {
-/// if let Err(e) = i32::from_str_radix("a12", 10) {
-/// println!("Failed conversion to i32: {:?}", e.kind());
-/// }
-/// # }
-/// ```
-#[unstable(
- feature = "int_error_matching",
- reason = "it can be useful to match errors when making error messages \
- for integer parsing",
- issue = "22639"
-)]
-#[derive(Debug, Clone, PartialEq, Eq)]
-#[non_exhaustive]
-pub enum IntErrorKind {
- /// Value being parsed is empty.
- ///
- /// Among other causes, this variant will be constructed when parsing an empty string.
- Empty,
- /// Contains an invalid digit.
- ///
- /// Among other causes, this variant will be constructed when parsing a string that
- /// contains a letter.
- InvalidDigit,
- /// Integer is too large to store in target integer type.
- Overflow,
- /// Integer is too small to store in target integer type.
- Underflow,
- /// Value was Zero
- ///
- /// This variant will be emitted when the parsing string has a value of zero, which
- /// would be illegal for non-zero types.
- Zero,
-}
-
-impl ParseIntError {
- /// Outputs the detailed cause of parsing an integer failing.
- #[unstable(
- feature = "int_error_matching",
- reason = "it can be useful to match errors when making error messages \
- for integer parsing",
- issue = "22639"
- )]
- pub fn kind(&self) -> &IntErrorKind {
- &self.kind
- }
- #[unstable(
- feature = "int_error_internals",
- reason = "available through Error trait and this method should \
- not be exposed publicly",
- issue = "none"
- )]
- #[doc(hidden)]
- pub fn __description(&self) -> &str {
- match self.kind {
- IntErrorKind::Empty => "cannot parse integer from empty string",
- IntErrorKind::InvalidDigit => "invalid digit found in string",
- IntErrorKind::Overflow => "number too large to fit in target type",
- IntErrorKind::Underflow => "number too small to fit in target type",
- IntErrorKind::Zero => "number would be zero for non-zero type",
- }
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl fmt::Display for ParseIntError {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- self.__description().fmt(f)
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-pub use crate::num::dec2flt::ParseFloatError;
--- /dev/null
+//! Definitions of integer that is known not to equal zero.
+
+use crate::fmt;
+use crate::ops::{BitOr, BitOrAssign};
+use crate::str::FromStr;
+
+use super::from_str_radix;
+use super::{IntErrorKind, ParseIntError};
+
+macro_rules! doc_comment {
+ ($x:expr, $($tt:tt)*) => {
+ #[doc = $x]
+ $($tt)*
+ };
+}
+
+macro_rules! impl_nonzero_fmt {
+ ( #[$stability: meta] ( $( $Trait: ident ),+ ) for $Ty: ident ) => {
+ $(
+ #[$stability]
+ impl fmt::$Trait for $Ty {
+ #[inline]
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ self.get().fmt(f)
+ }
+ }
+ )+
+ }
+}
+
+macro_rules! nonzero_integers {
+ ( $( #[$stability: meta] $Ty: ident($Int: ty); )+ ) => {
+ $(
+ doc_comment! {
+ concat!("An integer that is known not to equal zero.
+
+This enables some memory layout optimization.
+For example, `Option<", stringify!($Ty), ">` is the same size as `", stringify!($Int), "`:
+
+```rust
+use std::mem::size_of;
+assert_eq!(size_of::<Option<core::num::", stringify!($Ty), ">>(), size_of::<", stringify!($Int),
+">());
+```"),
+ #[$stability]
+ #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
+ #[repr(transparent)]
+ #[rustc_layout_scalar_valid_range_start(1)]
+ #[rustc_nonnull_optimization_guaranteed]
+ pub struct $Ty($Int);
+ }
+
+ impl $Ty {
+ /// Creates a non-zero without checking the value.
+ ///
+ /// # Safety
+ ///
+ /// The value must not be zero.
+ #[$stability]
+ #[rustc_const_stable(feature = "nonzero", since = "1.34.0")]
+ #[inline]
+ pub const unsafe fn new_unchecked(n: $Int) -> Self {
+ // SAFETY: this is guaranteed to be safe by the caller.
+ unsafe { Self(n) }
+ }
+
+ /// Creates a non-zero if the given value is not zero.
+ #[$stability]
+ #[rustc_const_stable(feature = "const_nonzero_int_methods", since = "1.47.0")]
+ #[inline]
+ pub const fn new(n: $Int) -> Option<Self> {
+ if n != 0 {
+ // SAFETY: we just checked that there's no `0`
+ Some(unsafe { Self(n) })
+ } else {
+ None
+ }
+ }
+
+ /// Returns the value as a primitive type.
+ #[$stability]
+ #[inline]
+ #[rustc_const_stable(feature = "nonzero", since = "1.34.0")]
+ pub const fn get(self) -> $Int {
+ self.0
+ }
+
+ }
+
+ #[stable(feature = "from_nonzero", since = "1.31.0")]
+ impl From<$Ty> for $Int {
+ doc_comment! {
+ concat!(
+"Converts a `", stringify!($Ty), "` into an `", stringify!($Int), "`"),
+ fn from(nonzero: $Ty) -> Self {
+ nonzero.0
+ }
+ }
+ }
+
+ #[stable(feature = "nonzero_bitor", since = "1.45.0")]
+ impl BitOr for $Ty {
+ type Output = Self;
+ #[inline]
+ fn bitor(self, rhs: Self) -> Self::Output {
+ // SAFETY: since `self` and `rhs` are both nonzero, the
+ // result of the bitwise-or will be nonzero.
+ unsafe { $Ty::new_unchecked(self.get() | rhs.get()) }
+ }
+ }
+
+ #[stable(feature = "nonzero_bitor", since = "1.45.0")]
+ impl BitOr<$Int> for $Ty {
+ type Output = Self;
+ #[inline]
+ fn bitor(self, rhs: $Int) -> Self::Output {
+ // SAFETY: since `self` is nonzero, the result of the
+ // bitwise-or will be nonzero regardless of the value of
+ // `rhs`.
+ unsafe { $Ty::new_unchecked(self.get() | rhs) }
+ }
+ }
+
+ #[stable(feature = "nonzero_bitor", since = "1.45.0")]
+ impl BitOr<$Ty> for $Int {
+ type Output = $Ty;
+ #[inline]
+ fn bitor(self, rhs: $Ty) -> Self::Output {
+ // SAFETY: since `rhs` is nonzero, the result of the
+ // bitwise-or will be nonzero regardless of the value of
+ // `self`.
+ unsafe { $Ty::new_unchecked(self | rhs.get()) }
+ }
+ }
+
+ #[stable(feature = "nonzero_bitor", since = "1.45.0")]
+ impl BitOrAssign for $Ty {
+ #[inline]
+ fn bitor_assign(&mut self, rhs: Self) {
+ *self = *self | rhs;
+ }
+ }
+
+ #[stable(feature = "nonzero_bitor", since = "1.45.0")]
+ impl BitOrAssign<$Int> for $Ty {
+ #[inline]
+ fn bitor_assign(&mut self, rhs: $Int) {
+ *self = *self | rhs;
+ }
+ }
+
+ impl_nonzero_fmt! {
+ #[$stability] (Debug, Display, Binary, Octal, LowerHex, UpperHex) for $Ty
+ }
+ )+
+ }
+}
+
+nonzero_integers! {
+ #[stable(feature = "nonzero", since = "1.28.0")] NonZeroU8(u8);
+ #[stable(feature = "nonzero", since = "1.28.0")] NonZeroU16(u16);
+ #[stable(feature = "nonzero", since = "1.28.0")] NonZeroU32(u32);
+ #[stable(feature = "nonzero", since = "1.28.0")] NonZeroU64(u64);
+ #[stable(feature = "nonzero", since = "1.28.0")] NonZeroU128(u128);
+ #[stable(feature = "nonzero", since = "1.28.0")] NonZeroUsize(usize);
+ #[stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI8(i8);
+ #[stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI16(i16);
+ #[stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI32(i32);
+ #[stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI64(i64);
+ #[stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI128(i128);
+ #[stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroIsize(isize);
+}
+
+macro_rules! from_str_radix_nzint_impl {
+ ($($t:ty)*) => {$(
+ #[stable(feature = "nonzero_parse", since = "1.35.0")]
+ impl FromStr for $t {
+ type Err = ParseIntError;
+ fn from_str(src: &str) -> Result<Self, Self::Err> {
+ Self::new(from_str_radix(src, 10)?)
+ .ok_or(ParseIntError {
+ kind: IntErrorKind::Zero
+ })
+ }
+ }
+ )*}
+}
+
+from_str_radix_nzint_impl! { NonZeroU8 NonZeroU16 NonZeroU32 NonZeroU64 NonZeroU128 NonZeroUsize
+NonZeroI8 NonZeroI16 NonZeroI32 NonZeroI64 NonZeroI128 NonZeroIsize }
--- /dev/null
+//! The 128-bit signed integer type.
+//!
+//! *[See also the `i128` primitive type](../../std/primitive.i128.html).*
+//!
+//! Although using these constants won’t cause compilation warnings,
+//! new code should use the associated constants directly on the primitive type.
+
+#![stable(feature = "i128", since = "1.26.0")]
+
+int_module! { i128, #[stable(feature = "i128", since="1.26.0")] }
--- /dev/null
+//! The 16-bit signed integer type.
+//!
+//! *[See also the `i16` primitive type](../../std/primitive.i16.html).*
+//!
+//! Although using these constants won’t cause compilation warnings,
+//! new code should use the associated constants directly on the primitive type.
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+int_module! { i16 }
--- /dev/null
+//! The 32-bit signed integer type.
+//!
+//! *[See also the `i32` primitive type](../../std/primitive.i32.html).*
+//!
+//! Although using these constants won’t cause compilation warnings,
+//! new code should use the associated constants directly on the primitive type.
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+int_module! { i32 }
--- /dev/null
+//! The 64-bit signed integer type.
+//!
+//! *[See also the `i64` primitive type](../../std/primitive.i64.html).*
+//!
+//! Although using these constants won’t cause compilation warnings,
+//! new code should use the associated constants directly on the primitive type.
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+int_module! { i64 }
--- /dev/null
+//! The 8-bit signed integer type.
+//!
+//! *[See also the `i8` primitive type](../../std/primitive.i8.html).*
+//!
+//! Although using these constants won’t cause compilation warnings,
+//! new code should use the associated constants directly on the primitive type.
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+int_module! { i8 }
--- /dev/null
+#![doc(hidden)]
+
+macro_rules! doc_comment {
+ ($x:expr, $($tt:tt)*) => {
+ #[doc = $x]
+ $($tt)*
+ };
+}
+
+macro_rules! int_module {
+ ($T:ident) => (int_module!($T, #[stable(feature = "rust1", since = "1.0.0")]););
+ ($T:ident, #[$attr:meta]) => (
+ doc_comment! {
+ concat!("The smallest value that can be represented by this integer type.
+Use [`", stringify!($T), "::MIN", "`](../../std/primitive.", stringify!($T), ".html#associatedconstant.MIN) instead.
+
+# Examples
+
+```rust
+// deprecated way
+let min = std::", stringify!($T), "::MIN;
+
+// intended way
+let min = ", stringify!($T), "::MIN;
+```
+"),
+ #[$attr]
+ pub const MIN: $T = $T::MIN;
+ }
+
+ doc_comment! {
+ concat!("The largest value that can be represented by this integer type.
+Use [`", stringify!($T), "::MAX", "`](../../std/primitive.", stringify!($T), ".html#associatedconstant.MAX) instead.
+
+# Examples
+
+```rust
+// deprecated way
+let max = std::", stringify!($T), "::MAX;
+
+// intended way
+let max = ", stringify!($T), "::MAX;
+```
+"),
+ #[$attr]
+ pub const MAX: $T = $T::MAX;
+ }
+ )
+}
--- /dev/null
+//! The pointer-sized signed integer type.
+//!
+//! *[See also the `isize` primitive type](../../std/primitive.isize.html).*
+//!
+//! Although using these constants won’t cause compilation warnings,
+//! new code should use the associated constants directly on the primitive type.
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+int_module! { isize }
--- /dev/null
+//! The 128-bit unsigned integer type.
+//!
+//! *[See also the `u128` primitive type](../../std/primitive.u128.html).*
+//!
+//! Although using these constants won’t cause compilation warnings,
+//! new code should use the associated constants directly on the primitive type.
+
+#![stable(feature = "i128", since = "1.26.0")]
+int_module! { u128, #[stable(feature = "i128", since="1.26.0")] }
--- /dev/null
+//! The 16-bit unsigned integer type.
+//!
+//! *[See also the `u16` primitive type](../../std/primitive.u16.html).*
+//!
+//! Although using these constants won’t cause compilation warnings,
+//! new code should use the associated constants directly on the primitive type.
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+int_module! { u16 }
--- /dev/null
+//! The 32-bit unsigned integer type.
+//!
+//! *[See also the `u32` primitive type](../../std/primitive.u32.html).*
+//!
+//! Although using these constants won’t cause compilation warnings,
+//! new code should use the associated constants directly on the primitive type.
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+int_module! { u32 }
--- /dev/null
+//! The 64-bit unsigned integer type.
+//!
+//! *[See also the `u64` primitive type](../../std/primitive.u64.html).*
+//!
+//! Although using these constants won’t cause compilation warnings,
+//! new code should use the associated constants directly on the primitive type.
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+int_module! { u64 }
--- /dev/null
+//! The 8-bit unsigned integer type.
+//!
+//! *[See also the `u8` primitive type](../../std/primitive.u8.html).*
+//!
+//! Although using these constants won’t cause compilation warnings,
+//! new code should use the associated constants directly on the primitive type.
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+int_module! { u8 }
--- /dev/null
+//! The pointer-sized unsigned integer type.
+//!
+//! *[See also the `usize` primitive type](../../std/primitive.usize.html).*
+//!
+//! Although using these constants won’t cause compilation warnings,
+//! new code should use the associated constants directly on the primitive type.
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+int_module! { usize }
+++ /dev/null
-//! The 128-bit unsigned integer type.
-//!
-//! *[See also the `u128` primitive type](../../std/primitive.u128.html).*
-//!
-//! Although using these constants won’t cause compilation warnings,
-//! new code should use the associated constants directly on the primitive type.
-
-#![stable(feature = "i128", since = "1.26.0")]
-int_module! { u128, #[stable(feature = "i128", since="1.26.0")] }
+++ /dev/null
-//! The 16-bit unsigned integer type.
-//!
-//! *[See also the `u16` primitive type](../../std/primitive.u16.html).*
-//!
-//! Although using these constants won’t cause compilation warnings,
-//! new code should use the associated constants directly on the primitive type.
-
-#![stable(feature = "rust1", since = "1.0.0")]
-
-int_module! { u16 }
+++ /dev/null
-//! The 32-bit unsigned integer type.
-//!
-//! *[See also the `u32` primitive type](../../std/primitive.u32.html).*
-//!
-//! Although using these constants won’t cause compilation warnings,
-//! new code should use the associated constants directly on the primitive type.
-
-#![stable(feature = "rust1", since = "1.0.0")]
-
-int_module! { u32 }
+++ /dev/null
-//! The 64-bit unsigned integer type.
-//!
-//! *[See also the `u64` primitive type](../../std/primitive.u64.html).*
-//!
-//! Although using these constants won’t cause compilation warnings,
-//! new code should use the associated constants directly on the primitive type.
-
-#![stable(feature = "rust1", since = "1.0.0")]
-
-int_module! { u64 }
+++ /dev/null
-//! The 8-bit unsigned integer type.
-//!
-//! *[See also the `u8` primitive type](../../std/primitive.u8.html).*
-//!
-//! Although using these constants won’t cause compilation warnings,
-//! new code should use the associated constants directly on the primitive type.
-
-#![stable(feature = "rust1", since = "1.0.0")]
-
-int_module! { u8 }
--- /dev/null
+macro_rules! uint_impl {
+ ($SelfT:ty, $ActualT:ty, $BITS:expr, $MaxV:expr, $Feature:expr, $EndFeature:expr,
+ $rot:expr, $rot_op:expr, $rot_result:expr, $swap_op:expr, $swapped:expr,
+ $reversed:expr, $le_bytes:expr, $be_bytes:expr,
+ $to_xe_bytes_doc:expr, $from_xe_bytes_doc:expr) => {
+ doc_comment! {
+ concat!("The smallest value that can be represented by this integer type.
+
+# Examples
+
+Basic usage:
+
+```
+", $Feature, "assert_eq!(", stringify!($SelfT), "::MIN, 0);", $EndFeature, "
+```"),
+ #[stable(feature = "assoc_int_consts", since = "1.43.0")]
+ pub const MIN: Self = 0;
+ }
+
+ doc_comment! {
+ concat!("The largest value that can be represented by this integer type.
+
+# Examples
+
+Basic usage:
+
+```
+", $Feature, "assert_eq!(", stringify!($SelfT), "::MAX, ", stringify!($MaxV), ");",
+$EndFeature, "
+```"),
+ #[stable(feature = "assoc_int_consts", since = "1.43.0")]
+ pub const MAX: Self = !0;
+ }
+
+ doc_comment! {
+ concat!("The size of this integer type in bits.
+
+# Examples
+
+```
+", $Feature, "#![feature(int_bits_const)]
+assert_eq!(", stringify!($SelfT), "::BITS, ", stringify!($BITS), ");",
+$EndFeature, "
+```"),
+ #[unstable(feature = "int_bits_const", issue = "76904")]
+ pub const BITS: u32 = $BITS;
+ }
+
+ doc_comment! {
+ concat!("Converts a string slice in a given base to an integer.
+
+The string is expected to be an optional `+` sign
+followed by digits.
+Leading and trailing whitespace represent an error.
+Digits are a subset of these characters, depending on `radix`:
+
+* `0-9`
+* `a-z`
+* `A-Z`
+
+# Panics
+
+This function panics if `radix` is not in the range from 2 to 36.
+
+# Examples
+
+Basic usage:
+
+```
+", $Feature, "assert_eq!(", stringify!($SelfT), "::from_str_radix(\"A\", 16), Ok(10));",
+$EndFeature, "
+```"),
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn from_str_radix(src: &str, radix: u32) -> Result<Self, ParseIntError> {
+ from_str_radix(src, radix)
+ }
+ }
+
+ doc_comment! {
+ concat!("Returns the number of ones in the binary representation of `self`.
+
+# Examples
+
+Basic usage:
+
+```
+", $Feature, "let n = 0b01001100", stringify!($SelfT), ";
+
+assert_eq!(n.count_ones(), 3);", $EndFeature, "
+```"),
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_stable(feature = "const_math", since = "1.32.0")]
+ #[inline]
+ pub const fn count_ones(self) -> u32 {
+ intrinsics::ctpop(self as $ActualT) as u32
+ }
+ }
+
+ doc_comment! {
+ concat!("Returns the number of zeros in the binary representation of `self`.
+
+# Examples
+
+Basic usage:
+
+```
+", $Feature, "assert_eq!(", stringify!($SelfT), "::MAX.count_zeros(), 0);", $EndFeature, "
+```"),
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_stable(feature = "const_math", since = "1.32.0")]
+ #[inline]
+ pub const fn count_zeros(self) -> u32 {
+ (!self).count_ones()
+ }
+ }
+
+ doc_comment! {
+ concat!("Returns the number of leading zeros in the binary representation of `self`.
+
+# Examples
+
+Basic usage:
+
+```
+", $Feature, "let n = ", stringify!($SelfT), "::MAX >> 2;
+
+assert_eq!(n.leading_zeros(), 2);", $EndFeature, "
+```"),
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_stable(feature = "const_math", since = "1.32.0")]
+ #[inline]
+ pub const fn leading_zeros(self) -> u32 {
+ intrinsics::ctlz(self as $ActualT) as u32
+ }
+ }
+
+ doc_comment! {
+ concat!("Returns the number of trailing zeros in the binary representation
+of `self`.
+
+# Examples
+
+Basic usage:
+
+```
+", $Feature, "let n = 0b0101000", stringify!($SelfT), ";
+
+assert_eq!(n.trailing_zeros(), 3);", $EndFeature, "
+```"),
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_stable(feature = "const_math", since = "1.32.0")]
+ #[inline]
+ pub const fn trailing_zeros(self) -> u32 {
+ intrinsics::cttz(self) as u32
+ }
+ }
+
+ doc_comment! {
+ concat!("Returns the number of leading ones in the binary representation of `self`.
+
+# Examples
+
+Basic usage:
+
+```
+", $Feature, "let n = !(", stringify!($SelfT), "::MAX >> 2);
+
+assert_eq!(n.leading_ones(), 2);", $EndFeature, "
+```"),
+ #[stable(feature = "leading_trailing_ones", since = "1.46.0")]
+ #[rustc_const_stable(feature = "leading_trailing_ones", since = "1.46.0")]
+ #[inline]
+ pub const fn leading_ones(self) -> u32 {
+ (!self).leading_zeros()
+ }
+ }
+
+ doc_comment! {
+ concat!("Returns the number of trailing ones in the binary representation
+of `self`.
+
+# Examples
+
+Basic usage:
+
+```
+", $Feature, "let n = 0b1010111", stringify!($SelfT), ";
+
+assert_eq!(n.trailing_ones(), 3);", $EndFeature, "
+```"),
+ #[stable(feature = "leading_trailing_ones", since = "1.46.0")]
+ #[rustc_const_stable(feature = "leading_trailing_ones", since = "1.46.0")]
+ #[inline]
+ pub const fn trailing_ones(self) -> u32 {
+ (!self).trailing_zeros()
+ }
+ }
+
+ doc_comment! {
+ concat!("Shifts the bits to the left by a specified amount, `n`,
+wrapping the truncated bits to the end of the resulting integer.
+
+Please note this isn't the same operation as the `<<` shifting operator!
+
+# Examples
+
+Basic usage:
+
+```
+let n = ", $rot_op, stringify!($SelfT), ";
+let m = ", $rot_result, ";
+
+assert_eq!(n.rotate_left(", $rot, "), m);
+```"),
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_stable(feature = "const_math", since = "1.32.0")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn rotate_left(self, n: u32) -> Self {
+ intrinsics::rotate_left(self, n as $SelfT)
+ }
+ }
+
+ doc_comment! {
+ concat!("Shifts the bits to the right by a specified amount, `n`,
+wrapping the truncated bits to the beginning of the resulting
+integer.
+
+Please note this isn't the same operation as the `>>` shifting operator!
+
+# Examples
+
+Basic usage:
+
+```
+let n = ", $rot_result, stringify!($SelfT), ";
+let m = ", $rot_op, ";
+
+assert_eq!(n.rotate_right(", $rot, "), m);
+```"),
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_stable(feature = "const_math", since = "1.32.0")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn rotate_right(self, n: u32) -> Self {
+ intrinsics::rotate_right(self, n as $SelfT)
+ }
+ }
+
+ doc_comment! {
+ concat!("
+Reverses the byte order of the integer.
+
+# Examples
+
+Basic usage:
+
+```
+let n = ", $swap_op, stringify!($SelfT), ";
+let m = n.swap_bytes();
+
+assert_eq!(m, ", $swapped, ");
+```"),
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_stable(feature = "const_math", since = "1.32.0")]
+ #[inline]
+ pub const fn swap_bytes(self) -> Self {
+ intrinsics::bswap(self as $ActualT) as Self
+ }
+ }
+
+ doc_comment! {
+ concat!("Reverses the bit pattern of the integer.
+
+# Examples
+
+Basic usage:
+
+```
+let n = ", $swap_op, stringify!($SelfT), ";
+let m = n.reverse_bits();
+
+assert_eq!(m, ", $reversed, ");
+```"),
+ #[stable(feature = "reverse_bits", since = "1.37.0")]
+ #[rustc_const_stable(feature = "const_math", since = "1.32.0")]
+ #[inline]
+ #[must_use]
+ pub const fn reverse_bits(self) -> Self {
+ intrinsics::bitreverse(self as $ActualT) as Self
+ }
+ }
+
+ doc_comment! {
+ concat!("Converts an integer from big endian to the target's endianness.
+
+On big endian this is a no-op. On little endian the bytes are
+swapped.
+
+# Examples
+
+Basic usage:
+
+```
+", $Feature, "let n = 0x1A", stringify!($SelfT), ";
+
+if cfg!(target_endian = \"big\") {
+ assert_eq!(", stringify!($SelfT), "::from_be(n), n)
+} else {
+ assert_eq!(", stringify!($SelfT), "::from_be(n), n.swap_bytes())
+}", $EndFeature, "
+```"),
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_stable(feature = "const_math", since = "1.32.0")]
+ #[inline]
+ pub const fn from_be(x: Self) -> Self {
+ #[cfg(target_endian = "big")]
+ {
+ x
+ }
+ #[cfg(not(target_endian = "big"))]
+ {
+ x.swap_bytes()
+ }
+ }
+ }
+
+ doc_comment! {
+ concat!("Converts an integer from little endian to the target's endianness.
+
+On little endian this is a no-op. On big endian the bytes are
+swapped.
+
+# Examples
+
+Basic usage:
+
+```
+", $Feature, "let n = 0x1A", stringify!($SelfT), ";
+
+if cfg!(target_endian = \"little\") {
+ assert_eq!(", stringify!($SelfT), "::from_le(n), n)
+} else {
+ assert_eq!(", stringify!($SelfT), "::from_le(n), n.swap_bytes())
+}", $EndFeature, "
+```"),
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_stable(feature = "const_math", since = "1.32.0")]
+ #[inline]
+ pub const fn from_le(x: Self) -> Self {
+ #[cfg(target_endian = "little")]
+ {
+ x
+ }
+ #[cfg(not(target_endian = "little"))]
+ {
+ x.swap_bytes()
+ }
+ }
+ }
+
+ doc_comment! {
+ concat!("Converts `self` to big endian from the target's endianness.
+
+On big endian this is a no-op. On little endian the bytes are
+swapped.
+
+# Examples
+
+Basic usage:
+
+```
+", $Feature, "let n = 0x1A", stringify!($SelfT), ";
+
+if cfg!(target_endian = \"big\") {
+ assert_eq!(n.to_be(), n)
+} else {
+ assert_eq!(n.to_be(), n.swap_bytes())
+}", $EndFeature, "
+```"),
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_stable(feature = "const_math", since = "1.32.0")]
+ #[inline]
+ pub const fn to_be(self) -> Self { // or not to be?
+ #[cfg(target_endian = "big")]
+ {
+ self
+ }
+ #[cfg(not(target_endian = "big"))]
+ {
+ self.swap_bytes()
+ }
+ }
+ }
+
+ doc_comment! {
+ concat!("Converts `self` to little endian from the target's endianness.
+
+On little endian this is a no-op. On big endian the bytes are
+swapped.
+
+# Examples
+
+Basic usage:
+
+```
+", $Feature, "let n = 0x1A", stringify!($SelfT), ";
+
+if cfg!(target_endian = \"little\") {
+ assert_eq!(n.to_le(), n)
+} else {
+ assert_eq!(n.to_le(), n.swap_bytes())
+}", $EndFeature, "
+```"),
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_stable(feature = "const_math", since = "1.32.0")]
+ #[inline]
+ pub const fn to_le(self) -> Self {
+ #[cfg(target_endian = "little")]
+ {
+ self
+ }
+ #[cfg(not(target_endian = "little"))]
+ {
+ self.swap_bytes()
+ }
+ }
+ }
+
+ doc_comment! {
+ concat!("Checked integer addition. Computes `self + rhs`, returning `None`
+if overflow occurred.
+
+# Examples
+
+Basic usage:
+
+```
+", $Feature, "assert_eq!((", stringify!($SelfT), "::MAX - 2).checked_add(1), ",
+"Some(", stringify!($SelfT), "::MAX - 1));
+assert_eq!((", stringify!($SelfT), "::MAX - 2).checked_add(3), None);", $EndFeature, "
+```"),
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn checked_add(self, rhs: Self) -> Option<Self> {
+ let (a, b) = self.overflowing_add(rhs);
+ if unlikely!(b) {None} else {Some(a)}
+ }
+ }
+
+ doc_comment! {
+ concat!("Unchecked integer addition. Computes `self + rhs`, assuming overflow
+cannot occur. This results in undefined behavior when `self + rhs > ", stringify!($SelfT),
+"::MAX` or `self + rhs < ", stringify!($SelfT), "::MIN`."),
+ #[unstable(
+ feature = "unchecked_math",
+ reason = "niche optimization path",
+ issue = "none",
+ )]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub unsafe fn unchecked_add(self, rhs: Self) -> Self {
+ // SAFETY: the caller must uphold the safety contract for
+ // `unchecked_add`.
+ unsafe { intrinsics::unchecked_add(self, rhs) }
+ }
+ }
+
+ doc_comment! {
+ concat!("Checked integer subtraction. Computes `self - rhs`, returning
+`None` if overflow occurred.
+
+# Examples
+
+Basic usage:
+
+```
+", $Feature, "assert_eq!(1", stringify!($SelfT), ".checked_sub(1), Some(0));
+assert_eq!(0", stringify!($SelfT), ".checked_sub(1), None);", $EndFeature, "
+```"),
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn checked_sub(self, rhs: Self) -> Option<Self> {
+ let (a, b) = self.overflowing_sub(rhs);
+ if unlikely!(b) {None} else {Some(a)}
+ }
+ }
+
+ doc_comment! {
+ concat!("Unchecked integer subtraction. Computes `self - rhs`, assuming overflow
+cannot occur. This results in undefined behavior when `self - rhs > ", stringify!($SelfT),
+"::MAX` or `self - rhs < ", stringify!($SelfT), "::MIN`."),
+ #[unstable(
+ feature = "unchecked_math",
+ reason = "niche optimization path",
+ issue = "none",
+ )]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub unsafe fn unchecked_sub(self, rhs: Self) -> Self {
+ // SAFETY: the caller must uphold the safety contract for
+ // `unchecked_sub`.
+ unsafe { intrinsics::unchecked_sub(self, rhs) }
+ }
+ }
+
+ doc_comment! {
+ concat!("Checked integer multiplication. Computes `self * rhs`, returning
+`None` if overflow occurred.
+
+# Examples
+
+Basic usage:
+
+```
+", $Feature, "assert_eq!(5", stringify!($SelfT), ".checked_mul(1), Some(5));
+assert_eq!(", stringify!($SelfT), "::MAX.checked_mul(2), None);", $EndFeature, "
+```"),
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn checked_mul(self, rhs: Self) -> Option<Self> {
+ let (a, b) = self.overflowing_mul(rhs);
+ if unlikely!(b) {None} else {Some(a)}
+ }
+ }
+
+ doc_comment! {
+ concat!("Unchecked integer multiplication. Computes `self * rhs`, assuming overflow
+cannot occur. This results in undefined behavior when `self * rhs > ", stringify!($SelfT),
+"::MAX` or `self * rhs < ", stringify!($SelfT), "::MIN`."),
+ #[unstable(
+ feature = "unchecked_math",
+ reason = "niche optimization path",
+ issue = "none",
+ )]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub unsafe fn unchecked_mul(self, rhs: Self) -> Self {
+ // SAFETY: the caller must uphold the safety contract for
+ // `unchecked_mul`.
+ unsafe { intrinsics::unchecked_mul(self, rhs) }
+ }
+ }
+
+ doc_comment! {
+ concat!("Checked integer division. Computes `self / rhs`, returning `None`
+if `rhs == 0`.
+
+# Examples
+
+Basic usage:
+
+```
+", $Feature, "assert_eq!(128", stringify!($SelfT), ".checked_div(2), Some(64));
+assert_eq!(1", stringify!($SelfT), ".checked_div(0), None);", $EndFeature, "
+```"),
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_unstable(feature = "const_checked_int_methods", issue = "53718")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn checked_div(self, rhs: Self) -> Option<Self> {
+ if unlikely!(rhs == 0) {
+ None
+ } else {
+ // SAFETY: div by zero has been checked above and unsigned types have no other
+ // failure modes for division
+ Some(unsafe { intrinsics::unchecked_div(self, rhs) })
+ }
+ }
+ }
+
+ doc_comment! {
+ concat!("Checked Euclidean division. Computes `self.div_euclid(rhs)`, returning `None`
+if `rhs == 0`.
+
+# Examples
+
+Basic usage:
+
+```
+assert_eq!(128", stringify!($SelfT), ".checked_div_euclid(2), Some(64));
+assert_eq!(1", stringify!($SelfT), ".checked_div_euclid(0), None);
+```"),
+ #[stable(feature = "euclidean_division", since = "1.38.0")]
+ #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn checked_div_euclid(self, rhs: Self) -> Option<Self> {
+ if unlikely!(rhs == 0) {
+ None
+ } else {
+ Some(self.div_euclid(rhs))
+ }
+ }
+ }
+
+
+ doc_comment! {
+ concat!("Checked integer remainder. Computes `self % rhs`, returning `None`
+if `rhs == 0`.
+
+# Examples
+
+Basic usage:
+
+```
+", $Feature, "assert_eq!(5", stringify!($SelfT), ".checked_rem(2), Some(1));
+assert_eq!(5", stringify!($SelfT), ".checked_rem(0), None);", $EndFeature, "
+```"),
+ #[stable(feature = "wrapping", since = "1.7.0")]
+ #[rustc_const_unstable(feature = "const_checked_int_methods", issue = "53718")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn checked_rem(self, rhs: Self) -> Option<Self> {
+ if unlikely!(rhs == 0) {
+ None
+ } else {
+ // SAFETY: div by zero has been checked above and unsigned types have no other
+ // failure modes for division
+ Some(unsafe { intrinsics::unchecked_rem(self, rhs) })
+ }
+ }
+ }
+
+ doc_comment! {
+ concat!("Checked Euclidean modulo. Computes `self.rem_euclid(rhs)`, returning `None`
+if `rhs == 0`.
+
+# Examples
+
+Basic usage:
+
+```
+assert_eq!(5", stringify!($SelfT), ".checked_rem_euclid(2), Some(1));
+assert_eq!(5", stringify!($SelfT), ".checked_rem_euclid(0), None);
+```"),
+ #[stable(feature = "euclidean_division", since = "1.38.0")]
+ #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn checked_rem_euclid(self, rhs: Self) -> Option<Self> {
+ if unlikely!(rhs == 0) {
+ None
+ } else {
+ Some(self.rem_euclid(rhs))
+ }
+ }
+ }
+
+ doc_comment! {
+ concat!("Checked negation. Computes `-self`, returning `None` unless `self ==
+0`.
+
+Note that negating any positive integer will overflow.
+
+# Examples
+
+Basic usage:
+
+```
+", $Feature, "assert_eq!(0", stringify!($SelfT), ".checked_neg(), Some(0));
+assert_eq!(1", stringify!($SelfT), ".checked_neg(), None);", $EndFeature, "
+```"),
+ #[stable(feature = "wrapping", since = "1.7.0")]
+ #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")]
+ #[inline]
+ pub const fn checked_neg(self) -> Option<Self> {
+ let (a, b) = self.overflowing_neg();
+ if unlikely!(b) {None} else {Some(a)}
+ }
+ }
+
+ doc_comment! {
+ concat!("Checked shift left. Computes `self << rhs`, returning `None`
+if `rhs` is larger than or equal to the number of bits in `self`.
+
+# Examples
+
+Basic usage:
+
+```
+", $Feature, "assert_eq!(0x1", stringify!($SelfT), ".checked_shl(4), Some(0x10));
+assert_eq!(0x10", stringify!($SelfT), ".checked_shl(129), None);", $EndFeature, "
+```"),
+ #[stable(feature = "wrapping", since = "1.7.0")]
+ #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn checked_shl(self, rhs: u32) -> Option<Self> {
+ let (a, b) = self.overflowing_shl(rhs);
+ if unlikely!(b) {None} else {Some(a)}
+ }
+ }
+
+ doc_comment! {
+ concat!("Checked shift right. Computes `self >> rhs`, returning `None`
+if `rhs` is larger than or equal to the number of bits in `self`.
+
+# Examples
+
+Basic usage:
+
+```
+", $Feature, "assert_eq!(0x10", stringify!($SelfT), ".checked_shr(4), Some(0x1));
+assert_eq!(0x10", stringify!($SelfT), ".checked_shr(129), None);", $EndFeature, "
+```"),
+ #[stable(feature = "wrapping", since = "1.7.0")]
+ #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn checked_shr(self, rhs: u32) -> Option<Self> {
+ let (a, b) = self.overflowing_shr(rhs);
+ if unlikely!(b) {None} else {Some(a)}
+ }
+ }
+
+ doc_comment! {
+ concat!("Checked exponentiation. Computes `self.pow(exp)`, returning `None` if
+overflow occurred.
+
+# Examples
+
+Basic usage:
+
+```
+", $Feature, "assert_eq!(2", stringify!($SelfT), ".checked_pow(5), Some(32));
+assert_eq!(", stringify!($SelfT), "::MAX.checked_pow(2), None);", $EndFeature, "
+```"),
+ #[stable(feature = "no_panic_pow", since = "1.34.0")]
+ #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn checked_pow(self, mut exp: u32) -> Option<Self> {
+ if exp == 0 {
+ return Some(1);
+ }
+ let mut base = self;
+ let mut acc: Self = 1;
+
+ while exp > 1 {
+ if (exp & 1) == 1 {
+ acc = try_opt!(acc.checked_mul(base));
+ }
+ exp /= 2;
+ base = try_opt!(base.checked_mul(base));
+ }
+
+ // since exp!=0, finally the exp must be 1.
+ // Deal with the final bit of the exponent separately, since
+ // squaring the base afterwards is not necessary and may cause a
+ // needless overflow.
+
+ Some(try_opt!(acc.checked_mul(base)))
+ }
+ }
+
+ doc_comment! {
+ concat!("Saturating integer addition. Computes `self + rhs`, saturating at
+the numeric bounds instead of overflowing.
+
+# Examples
+
+Basic usage:
+
+```
+", $Feature, "assert_eq!(100", stringify!($SelfT), ".saturating_add(1), 101);
+assert_eq!(", stringify!($SelfT), "::MAX.saturating_add(127), ", stringify!($SelfT), "::MAX);",
+$EndFeature, "
+```"),
+
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")]
+ #[inline]
+ pub const fn saturating_add(self, rhs: Self) -> Self {
+ intrinsics::saturating_add(self, rhs)
+ }
+ }
+
+ doc_comment! {
+ concat!("Saturating integer subtraction. Computes `self - rhs`, saturating
+at the numeric bounds instead of overflowing.
+
+# Examples
+
+Basic usage:
+
+```
+", $Feature, "assert_eq!(100", stringify!($SelfT), ".saturating_sub(27), 73);
+assert_eq!(13", stringify!($SelfT), ".saturating_sub(127), 0);", $EndFeature, "
+```"),
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")]
+ #[inline]
+ pub const fn saturating_sub(self, rhs: Self) -> Self {
+ intrinsics::saturating_sub(self, rhs)
+ }
+ }
+
+ doc_comment! {
+ concat!("Saturating integer multiplication. Computes `self * rhs`,
+saturating at the numeric bounds instead of overflowing.
+
+# Examples
+
+Basic usage:
+
+```
+", $Feature, "
+assert_eq!(2", stringify!($SelfT), ".saturating_mul(10), 20);
+assert_eq!((", stringify!($SelfT), "::MAX).saturating_mul(10), ", stringify!($SelfT),
+"::MAX);", $EndFeature, "
+```"),
+ #[stable(feature = "wrapping", since = "1.7.0")]
+ #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn saturating_mul(self, rhs: Self) -> Self {
+ match self.checked_mul(rhs) {
+ Some(x) => x,
+ None => Self::MAX,
+ }
+ }
+ }
+
+ doc_comment! {
+ concat!("Saturating integer exponentiation. Computes `self.pow(exp)`,
+saturating at the numeric bounds instead of overflowing.
+
+# Examples
+
+Basic usage:
+
+```
+", $Feature, "
+assert_eq!(4", stringify!($SelfT), ".saturating_pow(3), 64);
+assert_eq!(", stringify!($SelfT), "::MAX.saturating_pow(2), ", stringify!($SelfT), "::MAX);",
+$EndFeature, "
+```"),
+ #[stable(feature = "no_panic_pow", since = "1.34.0")]
+ #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn saturating_pow(self, exp: u32) -> Self {
+ match self.checked_pow(exp) {
+ Some(x) => x,
+ None => Self::MAX,
+ }
+ }
+ }
+
+ doc_comment! {
+ concat!("Wrapping (modular) addition. Computes `self + rhs`,
+wrapping around at the boundary of the type.
+
+# Examples
+
+Basic usage:
+
+```
+", $Feature, "assert_eq!(200", stringify!($SelfT), ".wrapping_add(55), 255);
+assert_eq!(200", stringify!($SelfT), ".wrapping_add(", stringify!($SelfT), "::MAX), 199);",
+$EndFeature, "
+```"),
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn wrapping_add(self, rhs: Self) -> Self {
+ intrinsics::wrapping_add(self, rhs)
+ }
+ }
+
+ doc_comment! {
+ concat!("Wrapping (modular) subtraction. Computes `self - rhs`,
+wrapping around at the boundary of the type.
+
+# Examples
+
+Basic usage:
+
+```
+", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_sub(100), 0);
+assert_eq!(100", stringify!($SelfT), ".wrapping_sub(", stringify!($SelfT), "::MAX), 101);",
+$EndFeature, "
+```"),
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn wrapping_sub(self, rhs: Self) -> Self {
+ intrinsics::wrapping_sub(self, rhs)
+ }
+ }
+
+ /// Wrapping (modular) multiplication. Computes `self *
+ /// rhs`, wrapping around at the boundary of the type.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// Please note that this example is shared between integer types.
+ /// Which explains why `u8` is used here.
+ ///
+ /// ```
+ /// assert_eq!(10u8.wrapping_mul(12), 120);
+ /// assert_eq!(25u8.wrapping_mul(12), 44);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn wrapping_mul(self, rhs: Self) -> Self {
+ intrinsics::wrapping_mul(self, rhs)
+ }
+
+ doc_comment! {
+ concat!("Wrapping (modular) division. Computes `self / rhs`.
+Wrapped division on unsigned types is just normal division.
+There's no way wrapping could ever happen.
+This function exists, so that all operations
+are accounted for in the wrapping operations.
+
+# Examples
+
+Basic usage:
+
+```
+", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_div(10), 10);", $EndFeature, "
+```"),
+ #[stable(feature = "num_wrapping", since = "1.2.0")]
+ #[rustc_const_unstable(feature = "const_wrapping_int_methods", issue = "53718")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn wrapping_div(self, rhs: Self) -> Self {
+ self / rhs
+ }
+ }
+
+ doc_comment! {
+ concat!("Wrapping Euclidean division. Computes `self.div_euclid(rhs)`.
+Wrapped division on unsigned types is just normal division.
+There's no way wrapping could ever happen.
+This function exists, so that all operations
+are accounted for in the wrapping operations.
+Since, for the positive integers, all common
+definitions of division are equal, this
+is exactly equal to `self.wrapping_div(rhs)`.
+
+# Examples
+
+Basic usage:
+
+```
+assert_eq!(100", stringify!($SelfT), ".wrapping_div_euclid(10), 10);
+```"),
+ #[stable(feature = "euclidean_division", since = "1.38.0")]
+ #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn wrapping_div_euclid(self, rhs: Self) -> Self {
+ self / rhs
+ }
+ }
+
+ doc_comment! {
+ concat!("Wrapping (modular) remainder. Computes `self % rhs`.
+Wrapped remainder calculation on unsigned types is
+just the regular remainder calculation.
+There's no way wrapping could ever happen.
+This function exists, so that all operations
+are accounted for in the wrapping operations.
+
+# Examples
+
+Basic usage:
+
+```
+", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_rem(10), 0);", $EndFeature, "
+```"),
+ #[stable(feature = "num_wrapping", since = "1.2.0")]
+ #[rustc_const_unstable(feature = "const_wrapping_int_methods", issue = "53718")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn wrapping_rem(self, rhs: Self) -> Self {
+ self % rhs
+ }
+ }
+
+ doc_comment! {
+ concat!("Wrapping Euclidean modulo. Computes `self.rem_euclid(rhs)`.
+Wrapped modulo calculation on unsigned types is
+just the regular remainder calculation.
+There's no way wrapping could ever happen.
+This function exists, so that all operations
+are accounted for in the wrapping operations.
+Since, for the positive integers, all common
+definitions of division are equal, this
+is exactly equal to `self.wrapping_rem(rhs)`.
+
+# Examples
+
+Basic usage:
+
+```
+assert_eq!(100", stringify!($SelfT), ".wrapping_rem_euclid(10), 0);
+```"),
+ #[stable(feature = "euclidean_division", since = "1.38.0")]
+ #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn wrapping_rem_euclid(self, rhs: Self) -> Self {
+ self % rhs
+ }
+ }
+
+ /// Wrapping (modular) negation. Computes `-self`,
+ /// wrapping around at the boundary of the type.
+ ///
+ /// Since unsigned types do not have negative equivalents
+ /// all applications of this function will wrap (except for `-0`).
+ /// For values smaller than the corresponding signed type's maximum
+ /// the result is the same as casting the corresponding signed value.
+ /// Any larger values are equivalent to `MAX + 1 - (val - MAX - 1)` where
+ /// `MAX` is the corresponding signed type's maximum.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// Please note that this example is shared between integer types.
+ /// Which explains why `i8` is used here.
+ ///
+ /// ```
+ /// assert_eq!(100i8.wrapping_neg(), -100);
+ /// assert_eq!((-128i8).wrapping_neg(), -128);
+ /// ```
+ #[stable(feature = "num_wrapping", since = "1.2.0")]
+ #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")]
+ #[inline]
+ pub const fn wrapping_neg(self) -> Self {
+ self.overflowing_neg().0
+ }
+
+ doc_comment! {
+ concat!("Panic-free bitwise shift-left; yields `self << mask(rhs)`,
+where `mask` removes any high-order bits of `rhs` that
+would cause the shift to exceed the bitwidth of the type.
+
+Note that this is *not* the same as a rotate-left; the
+RHS of a wrapping shift-left is restricted to the range
+of the type, rather than the bits shifted out of the LHS
+being returned to the other end. The primitive integer
+types all implement a [`rotate_left`](#method.rotate_left) function,
+which may be what you want instead.
+
+# Examples
+
+Basic usage:
+
+```
+", $Feature, "assert_eq!(1", stringify!($SelfT), ".wrapping_shl(7), 128);
+assert_eq!(1", stringify!($SelfT), ".wrapping_shl(128), 1);", $EndFeature, "
+```"),
+ #[stable(feature = "num_wrapping", since = "1.2.0")]
+ #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn wrapping_shl(self, rhs: u32) -> Self {
+ // SAFETY: the masking by the bitsize of the type ensures that we do not shift
+ // out of bounds
+ unsafe {
+ intrinsics::unchecked_shl(self, (rhs & ($BITS - 1)) as $SelfT)
+ }
+ }
+ }
+
+ doc_comment! {
+ concat!("Panic-free bitwise shift-right; yields `self >> mask(rhs)`,
+where `mask` removes any high-order bits of `rhs` that
+would cause the shift to exceed the bitwidth of the type.
+
+Note that this is *not* the same as a rotate-right; the
+RHS of a wrapping shift-right is restricted to the range
+of the type, rather than the bits shifted out of the LHS
+being returned to the other end. The primitive integer
+types all implement a [`rotate_right`](#method.rotate_right) function,
+which may be what you want instead.
+
+# Examples
+
+Basic usage:
+
+```
+", $Feature, "assert_eq!(128", stringify!($SelfT), ".wrapping_shr(7), 1);
+assert_eq!(128", stringify!($SelfT), ".wrapping_shr(128), 128);", $EndFeature, "
+```"),
+ #[stable(feature = "num_wrapping", since = "1.2.0")]
+ #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn wrapping_shr(self, rhs: u32) -> Self {
+ // SAFETY: the masking by the bitsize of the type ensures that we do not shift
+ // out of bounds
+ unsafe {
+ intrinsics::unchecked_shr(self, (rhs & ($BITS - 1)) as $SelfT)
+ }
+ }
+ }
+
+ doc_comment! {
+ concat!("Wrapping (modular) exponentiation. Computes `self.pow(exp)`,
+wrapping around at the boundary of the type.
+
+# Examples
+
+Basic usage:
+
+```
+", $Feature, "assert_eq!(3", stringify!($SelfT), ".wrapping_pow(5), 243);
+assert_eq!(3u8.wrapping_pow(6), 217);", $EndFeature, "
+```"),
+ #[stable(feature = "no_panic_pow", since = "1.34.0")]
+ #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn wrapping_pow(self, mut exp: u32) -> Self {
+ if exp == 0 {
+ return 1;
+ }
+ let mut base = self;
+ let mut acc: Self = 1;
+
+ while exp > 1 {
+ if (exp & 1) == 1 {
+ acc = acc.wrapping_mul(base);
+ }
+ exp /= 2;
+ base = base.wrapping_mul(base);
+ }
+
+ // since exp!=0, finally the exp must be 1.
+ // Deal with the final bit of the exponent separately, since
+ // squaring the base afterwards is not necessary and may cause a
+ // needless overflow.
+ acc.wrapping_mul(base)
+ }
+ }
+
+ doc_comment! {
+ concat!("Calculates `self` + `rhs`
+
+Returns a tuple of the addition along with a boolean indicating
+whether an arithmetic overflow would occur. If an overflow would
+have occurred then the wrapped value is returned.
+
+# Examples
+
+Basic usage
+
+```
+", $Feature, "
+assert_eq!(5", stringify!($SelfT), ".overflowing_add(2), (7, false));
+assert_eq!(", stringify!($SelfT), "::MAX.overflowing_add(1), (0, true));", $EndFeature, "
+```"),
+ #[stable(feature = "wrapping", since = "1.7.0")]
+ #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn overflowing_add(self, rhs: Self) -> (Self, bool) {
+ let (a, b) = intrinsics::add_with_overflow(self as $ActualT, rhs as $ActualT);
+ (a as Self, b)
+ }
+ }
+
+ doc_comment! {
+ concat!("Calculates `self` - `rhs`
+
+Returns a tuple of the subtraction along with a boolean indicating
+whether an arithmetic overflow would occur. If an overflow would
+have occurred then the wrapped value is returned.
+
+# Examples
+
+Basic usage
+
+```
+", $Feature, "
+assert_eq!(5", stringify!($SelfT), ".overflowing_sub(2), (3, false));
+assert_eq!(0", stringify!($SelfT), ".overflowing_sub(1), (", stringify!($SelfT), "::MAX, true));",
+$EndFeature, "
+```"),
+ #[stable(feature = "wrapping", since = "1.7.0")]
+ #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn overflowing_sub(self, rhs: Self) -> (Self, bool) {
+ let (a, b) = intrinsics::sub_with_overflow(self as $ActualT, rhs as $ActualT);
+ (a as Self, b)
+ }
+ }
+
+ /// Calculates the multiplication of `self` and `rhs`.
+ ///
+ /// Returns a tuple of the multiplication along with a boolean
+ /// indicating whether an arithmetic overflow would occur. If an
+ /// overflow would have occurred then the wrapped value is returned.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// Please note that this example is shared between integer types.
+ /// Which explains why `u32` is used here.
+ ///
+ /// ```
+ /// assert_eq!(5u32.overflowing_mul(2), (10, false));
+ /// assert_eq!(1_000_000_000u32.overflowing_mul(10), (1410065408, true));
+ /// ```
+ #[stable(feature = "wrapping", since = "1.7.0")]
+ #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn overflowing_mul(self, rhs: Self) -> (Self, bool) {
+ let (a, b) = intrinsics::mul_with_overflow(self as $ActualT, rhs as $ActualT);
+ (a as Self, b)
+ }
+
+ doc_comment! {
+ concat!("Calculates the divisor when `self` is divided by `rhs`.
+
+Returns a tuple of the divisor along with a boolean indicating
+whether an arithmetic overflow would occur. Note that for unsigned
+integers overflow never occurs, so the second value is always
+`false`.
+
+# Panics
+
+This function will panic if `rhs` is 0.
+
+# Examples
+
+Basic usage
+
+```
+", $Feature, "assert_eq!(5", stringify!($SelfT), ".overflowing_div(2), (2, false));", $EndFeature, "
+```"),
+ #[inline]
+ #[stable(feature = "wrapping", since = "1.7.0")]
+ #[rustc_const_unstable(feature = "const_overflowing_int_methods", issue = "53718")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ pub const fn overflowing_div(self, rhs: Self) -> (Self, bool) {
+ (self / rhs, false)
+ }
+ }
+
+ doc_comment! {
+ concat!("Calculates the quotient of Euclidean division `self.div_euclid(rhs)`.
+
+Returns a tuple of the divisor along with a boolean indicating
+whether an arithmetic overflow would occur. Note that for unsigned
+integers overflow never occurs, so the second value is always
+`false`.
+Since, for the positive integers, all common
+definitions of division are equal, this
+is exactly equal to `self.overflowing_div(rhs)`.
+
+# Panics
+
+This function will panic if `rhs` is 0.
+
+# Examples
+
+Basic usage
+
+```
+assert_eq!(5", stringify!($SelfT), ".overflowing_div_euclid(2), (2, false));
+```"),
+ #[inline]
+ #[stable(feature = "euclidean_division", since = "1.38.0")]
+ #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ pub const fn overflowing_div_euclid(self, rhs: Self) -> (Self, bool) {
+ (self / rhs, false)
+ }
+ }
+
+ doc_comment! {
+ concat!("Calculates the remainder when `self` is divided by `rhs`.
+
+Returns a tuple of the remainder after dividing along with a boolean
+indicating whether an arithmetic overflow would occur. Note that for
+unsigned integers overflow never occurs, so the second value is
+always `false`.
+
+# Panics
+
+This function will panic if `rhs` is 0.
+
+# Examples
+
+Basic usage
+
+```
+", $Feature, "assert_eq!(5", stringify!($SelfT), ".overflowing_rem(2), (1, false));", $EndFeature, "
+```"),
+ #[inline]
+ #[stable(feature = "wrapping", since = "1.7.0")]
+ #[rustc_const_unstable(feature = "const_overflowing_int_methods", issue = "53718")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ pub const fn overflowing_rem(self, rhs: Self) -> (Self, bool) {
+ (self % rhs, false)
+ }
+ }
+
+ doc_comment! {
+ concat!("Calculates the remainder `self.rem_euclid(rhs)` as if by Euclidean division.
+
+Returns a tuple of the modulo after dividing along with a boolean
+indicating whether an arithmetic overflow would occur. Note that for
+unsigned integers overflow never occurs, so the second value is
+always `false`.
+Since, for the positive integers, all common
+definitions of division are equal, this operation
+is exactly equal to `self.overflowing_rem(rhs)`.
+
+# Panics
+
+This function will panic if `rhs` is 0.
+
+# Examples
+
+Basic usage
+
+```
+assert_eq!(5", stringify!($SelfT), ".overflowing_rem_euclid(2), (1, false));
+```"),
+ #[inline]
+ #[stable(feature = "euclidean_division", since = "1.38.0")]
+ #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ pub const fn overflowing_rem_euclid(self, rhs: Self) -> (Self, bool) {
+ (self % rhs, false)
+ }
+ }
+
+ doc_comment! {
+ concat!("Negates self in an overflowing fashion.
+
+Returns `!self + 1` using wrapping operations to return the value
+that represents the negation of this unsigned value. Note that for
+positive unsigned values overflow always occurs, but negating 0 does
+not overflow.
+
+# Examples
+
+Basic usage
+
+```
+", $Feature, "assert_eq!(0", stringify!($SelfT), ".overflowing_neg(), (0, false));
+assert_eq!(2", stringify!($SelfT), ".overflowing_neg(), (-2i32 as ", stringify!($SelfT),
+", true));", $EndFeature, "
+```"),
+ #[inline]
+ #[stable(feature = "wrapping", since = "1.7.0")]
+ #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")]
+ pub const fn overflowing_neg(self) -> (Self, bool) {
+ ((!self).wrapping_add(1), self != 0)
+ }
+ }
+
+ doc_comment! {
+ concat!("Shifts self left by `rhs` bits.
+
+Returns a tuple of the shifted version of self along with a boolean
+indicating whether the shift value was larger than or equal to the
+number of bits. If the shift value is too large, then value is
+masked (N-1) where N is the number of bits, and this value is then
+used to perform the shift.
+
+# Examples
+
+Basic usage
+
+```
+", $Feature, "assert_eq!(0x1", stringify!($SelfT), ".overflowing_shl(4), (0x10, false));
+assert_eq!(0x1", stringify!($SelfT), ".overflowing_shl(132), (0x10, true));", $EndFeature, "
+```"),
+ #[stable(feature = "wrapping", since = "1.7.0")]
+ #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn overflowing_shl(self, rhs: u32) -> (Self, bool) {
+ (self.wrapping_shl(rhs), (rhs > ($BITS - 1)))
+ }
+ }
+
+ doc_comment! {
+ concat!("Shifts self right by `rhs` bits.
+
+Returns a tuple of the shifted version of self along with a boolean
+indicating whether the shift value was larger than or equal to the
+number of bits. If the shift value is too large, then value is
+masked (N-1) where N is the number of bits, and this value is then
+used to perform the shift.
+
+# Examples
+
+Basic usage
+
+```
+", $Feature, "assert_eq!(0x10", stringify!($SelfT), ".overflowing_shr(4), (0x1, false));
+assert_eq!(0x10", stringify!($SelfT), ".overflowing_shr(132), (0x1, true));", $EndFeature, "
+```"),
+ #[stable(feature = "wrapping", since = "1.7.0")]
+ #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn overflowing_shr(self, rhs: u32) -> (Self, bool) {
+ (self.wrapping_shr(rhs), (rhs > ($BITS - 1)))
+ }
+ }
+
+ doc_comment! {
+ concat!("Raises self to the power of `exp`, using exponentiation by squaring.
+
+Returns a tuple of the exponentiation along with a bool indicating
+whether an overflow happened.
+
+# Examples
+
+Basic usage:
+
+```
+", $Feature, "assert_eq!(3", stringify!($SelfT), ".overflowing_pow(5), (243, false));
+assert_eq!(3u8.overflowing_pow(6), (217, true));", $EndFeature, "
+```"),
+ #[stable(feature = "no_panic_pow", since = "1.34.0")]
+ #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn overflowing_pow(self, mut exp: u32) -> (Self, bool) {
+ if exp == 0{
+ return (1,false);
+ }
+ let mut base = self;
+ let mut acc: Self = 1;
+ let mut overflown = false;
+ // Scratch space for storing results of overflowing_mul.
+ let mut r;
+
+ while exp > 1 {
+ if (exp & 1) == 1 {
+ r = acc.overflowing_mul(base);
+ acc = r.0;
+ overflown |= r.1;
+ }
+ exp /= 2;
+ r = base.overflowing_mul(base);
+ base = r.0;
+ overflown |= r.1;
+ }
+
+ // since exp!=0, finally the exp must be 1.
+ // Deal with the final bit of the exponent separately, since
+ // squaring the base afterwards is not necessary and may cause a
+ // needless overflow.
+ r = acc.overflowing_mul(base);
+ r.1 |= overflown;
+
+ r
+ }
+ }
+
+ doc_comment! {
+ concat!("Raises self to the power of `exp`, using exponentiation by squaring.
+
+# Examples
+
+Basic usage:
+
+```
+", $Feature, "assert_eq!(2", stringify!($SelfT), ".pow(5), 32);", $EndFeature, "
+```"),
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ #[rustc_inherit_overflow_checks]
+ pub const fn pow(self, mut exp: u32) -> Self {
+ if exp == 0 {
+ return 1;
+ }
+ let mut base = self;
+ let mut acc = 1;
+
+ while exp > 1 {
+ if (exp & 1) == 1 {
+ acc = acc * base;
+ }
+ exp /= 2;
+ base = base * base;
+ }
+
+ // since exp!=0, finally the exp must be 1.
+ // Deal with the final bit of the exponent separately, since
+ // squaring the base afterwards is not necessary and may cause a
+ // needless overflow.
+ acc * base
+ }
+ }
+
+ doc_comment! {
+ concat!("Performs Euclidean division.
+
+Since, for the positive integers, all common
+definitions of division are equal, this
+is exactly equal to `self / rhs`.
+
+# Panics
+
+This function will panic if `rhs` is 0.
+
+# Examples
+
+Basic usage:
+
+```
+assert_eq!(7", stringify!($SelfT), ".div_euclid(4), 1); // or any other integer type
+```"),
+ #[stable(feature = "euclidean_division", since = "1.38.0")]
+ #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ #[rustc_inherit_overflow_checks]
+ pub const fn div_euclid(self, rhs: Self) -> Self {
+ self / rhs
+ }
+ }
+
+
+ doc_comment! {
+ concat!("Calculates the least remainder of `self (mod rhs)`.
+
+Since, for the positive integers, all common
+definitions of division are equal, this
+is exactly equal to `self % rhs`.
+
+# Panics
+
+This function will panic if `rhs` is 0.
+
+# Examples
+
+Basic usage:
+
+```
+assert_eq!(7", stringify!($SelfT), ".rem_euclid(4), 3); // or any other integer type
+```"),
+ #[stable(feature = "euclidean_division", since = "1.38.0")]
+ #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ #[rustc_inherit_overflow_checks]
+ pub const fn rem_euclid(self, rhs: Self) -> Self {
+ self % rhs
+ }
+ }
+
+ doc_comment! {
+ concat!("Returns `true` if and only if `self == 2^k` for some `k`.
+
+# Examples
+
+Basic usage:
+
+```
+", $Feature, "assert!(16", stringify!($SelfT), ".is_power_of_two());
+assert!(!10", stringify!($SelfT), ".is_power_of_two());", $EndFeature, "
+```"),
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_stable(feature = "const_is_power_of_two", since = "1.32.0")]
+ #[inline]
+ pub const fn is_power_of_two(self) -> bool {
+ self.count_ones() == 1
+ }
+ }
+
+ // Returns one less than next power of two.
+ // (For 8u8 next power of two is 8u8 and for 6u8 it is 8u8)
+ //
+ // 8u8.one_less_than_next_power_of_two() == 7
+ // 6u8.one_less_than_next_power_of_two() == 7
+ //
+ // This method cannot overflow, as in the `next_power_of_two`
+ // overflow cases it instead ends up returning the maximum value
+ // of the type, and can return 0 for 0.
+ #[inline]
+ #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")]
+ const fn one_less_than_next_power_of_two(self) -> Self {
+ if self <= 1 { return 0; }
+
+ let p = self - 1;
+ // SAFETY: Because `p > 0`, it cannot consist entirely of leading zeros.
+ // That means the shift is always in-bounds, and some processors
+ // (such as intel pre-haswell) have more efficient ctlz
+ // intrinsics when the argument is non-zero.
+ let z = unsafe { intrinsics::ctlz_nonzero(p) };
+ <$SelfT>::MAX >> z
+ }
+
+ doc_comment! {
+ concat!("Returns the smallest power of two greater than or equal to `self`.
+
+When return value overflows (i.e., `self > (1 << (N-1))` for type
+`uN`), it panics in debug mode and return value is wrapped to 0 in
+release mode (the only situation in which method can return 0).
+
+# Examples
+
+Basic usage:
+
+```
+", $Feature, "assert_eq!(2", stringify!($SelfT), ".next_power_of_two(), 2);
+assert_eq!(3", stringify!($SelfT), ".next_power_of_two(), 4);", $EndFeature, "
+```"),
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")]
+ #[inline]
+ #[rustc_inherit_overflow_checks]
+ pub const fn next_power_of_two(self) -> Self {
+ self.one_less_than_next_power_of_two() + 1
+ }
+ }
+
+ doc_comment! {
+ concat!("Returns the smallest power of two greater than or equal to `n`. If
+the next power of two is greater than the type's maximum value,
+`None` is returned, otherwise the power of two is wrapped in `Some`.
+
+# Examples
+
+Basic usage:
+
+```
+", $Feature, "assert_eq!(2", stringify!($SelfT),
+".checked_next_power_of_two(), Some(2));
+assert_eq!(3", stringify!($SelfT), ".checked_next_power_of_two(), Some(4));
+assert_eq!(", stringify!($SelfT), "::MAX.checked_next_power_of_two(), None);",
+$EndFeature, "
+```"),
+ #[inline]
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")]
+ pub const fn checked_next_power_of_two(self) -> Option<Self> {
+ self.one_less_than_next_power_of_two().checked_add(1)
+ }
+ }
+
+ doc_comment! {
+ concat!("Returns the smallest power of two greater than or equal to `n`. If
+the next power of two is greater than the type's maximum value,
+the return value is wrapped to `0`.
+
+# Examples
+
+Basic usage:
+
+```
+#![feature(wrapping_next_power_of_two)]
+", $Feature, "
+assert_eq!(2", stringify!($SelfT), ".wrapping_next_power_of_two(), 2);
+assert_eq!(3", stringify!($SelfT), ".wrapping_next_power_of_two(), 4);
+assert_eq!(", stringify!($SelfT), "::MAX.wrapping_next_power_of_two(), 0);",
+$EndFeature, "
+```"),
+ #[unstable(feature = "wrapping_next_power_of_two", issue = "32463",
+ reason = "needs decision on wrapping behaviour")]
+ #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")]
+ pub const fn wrapping_next_power_of_two(self) -> Self {
+ self.one_less_than_next_power_of_two().wrapping_add(1)
+ }
+ }
+
+ doc_comment! {
+ concat!("Return the memory representation of this integer as a byte array in
+big-endian (network) byte order.
+",
+$to_xe_bytes_doc,
+"
+# Examples
+
+```
+let bytes = ", $swap_op, stringify!($SelfT), ".to_be_bytes();
+assert_eq!(bytes, ", $be_bytes, ");
+```"),
+ #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
+ #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")]
+ #[inline]
+ pub const fn to_be_bytes(self) -> [u8; mem::size_of::<Self>()] {
+ self.to_be().to_ne_bytes()
+ }
+ }
+
+ doc_comment! {
+ concat!("Return the memory representation of this integer as a byte array in
+little-endian byte order.
+",
+$to_xe_bytes_doc,
+"
+# Examples
+
+```
+let bytes = ", $swap_op, stringify!($SelfT), ".to_le_bytes();
+assert_eq!(bytes, ", $le_bytes, ");
+```"),
+ #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
+ #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")]
+ #[inline]
+ pub const fn to_le_bytes(self) -> [u8; mem::size_of::<Self>()] {
+ self.to_le().to_ne_bytes()
+ }
+ }
+
+ doc_comment! {
+ concat!("
+Return the memory representation of this integer as a byte array in
+native byte order.
+
+As the target platform's native endianness is used, portable code
+should use [`to_be_bytes`] or [`to_le_bytes`], as appropriate,
+instead.
+",
+$to_xe_bytes_doc,
+"
+[`to_be_bytes`]: #method.to_be_bytes
+[`to_le_bytes`]: #method.to_le_bytes
+
+# Examples
+
+```
+let bytes = ", $swap_op, stringify!($SelfT), ".to_ne_bytes();
+assert_eq!(
+ bytes,
+ if cfg!(target_endian = \"big\") {
+ ", $be_bytes, "
+ } else {
+ ", $le_bytes, "
+ }
+);
+```"),
+ #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
+ #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")]
+ // SAFETY: const sound because integers are plain old datatypes so we can always
+ // transmute them to arrays of bytes
+ #[allow_internal_unstable(const_fn_transmute)]
+ #[inline]
+ pub const fn to_ne_bytes(self) -> [u8; mem::size_of::<Self>()] {
+ // SAFETY: integers are plain old datatypes so we can always transmute them to
+ // arrays of bytes
+ unsafe { mem::transmute(self) }
+ }
+ }
+
+ doc_comment! {
+ concat!("Create a native endian integer value from its representation
+as a byte array in big endian.
+",
+$from_xe_bytes_doc,
+"
+# Examples
+
+```
+let value = ", stringify!($SelfT), "::from_be_bytes(", $be_bytes, ");
+assert_eq!(value, ", $swap_op, ");
+```
+
+When starting from a slice rather than an array, fallible conversion APIs can be used:
+
+```
+use std::convert::TryInto;
+
+fn read_be_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " {
+ let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">());
+ *input = rest;
+ ", stringify!($SelfT), "::from_be_bytes(int_bytes.try_into().unwrap())
+}
+```"),
+ #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
+ #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")]
+ #[inline]
+ pub const fn from_be_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
+ Self::from_be(Self::from_ne_bytes(bytes))
+ }
+ }
+
+ doc_comment! {
+ concat!("
+Create a native endian integer value from its representation
+as a byte array in little endian.
+",
+$from_xe_bytes_doc,
+"
+# Examples
+
+```
+let value = ", stringify!($SelfT), "::from_le_bytes(", $le_bytes, ");
+assert_eq!(value, ", $swap_op, ");
+```
+
+When starting from a slice rather than an array, fallible conversion APIs can be used:
+
+```
+use std::convert::TryInto;
+
+fn read_le_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " {
+ let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">());
+ *input = rest;
+ ", stringify!($SelfT), "::from_le_bytes(int_bytes.try_into().unwrap())
+}
+```"),
+ #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
+ #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")]
+ #[inline]
+ pub const fn from_le_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
+ Self::from_le(Self::from_ne_bytes(bytes))
+ }
+ }
+
+ doc_comment! {
+ concat!("Create a native endian integer value from its memory representation
+as a byte array in native endianness.
+
+As the target platform's native endianness is used, portable code
+likely wants to use [`from_be_bytes`] or [`from_le_bytes`], as
+appropriate instead.
+
+[`from_be_bytes`]: #method.from_be_bytes
+[`from_le_bytes`]: #method.from_le_bytes
+",
+$from_xe_bytes_doc,
+"
+# Examples
+
+```
+let value = ", stringify!($SelfT), "::from_ne_bytes(if cfg!(target_endian = \"big\") {
+ ", $be_bytes, "
+} else {
+ ", $le_bytes, "
+});
+assert_eq!(value, ", $swap_op, ");
+```
+
+When starting from a slice rather than an array, fallible conversion APIs can be used:
+
+```
+use std::convert::TryInto;
+
+fn read_ne_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " {
+ let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">());
+ *input = rest;
+ ", stringify!($SelfT), "::from_ne_bytes(int_bytes.try_into().unwrap())
+}
+```"),
+ #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
+ #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")]
+ // SAFETY: const sound because integers are plain old datatypes so we can always
+ // transmute to them
+ #[allow_internal_unstable(const_fn_transmute)]
+ #[inline]
+ pub const fn from_ne_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
+ // SAFETY: integers are plain old datatypes so we can always transmute to them
+ unsafe { mem::transmute(bytes) }
+ }
+ }
+
+ doc_comment! {
+ concat!("**This method is soft-deprecated.**
+
+Although using it won’t cause compilation warning,
+new code should use [`", stringify!($SelfT), "::MIN", "`](#associatedconstant.MIN) instead.
+
+Returns the smallest value that can be represented by this integer type."),
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_promotable]
+ #[inline(always)]
+ #[rustc_const_stable(feature = "const_max_value", since = "1.32.0")]
+ pub const fn min_value() -> Self { Self::MIN }
+ }
+
+ doc_comment! {
+ concat!("**This method is soft-deprecated.**
+
+Although using it won’t cause compilation warning,
+new code should use [`", stringify!($SelfT), "::MAX", "`](#associatedconstant.MAX) instead.
+
+Returns the largest value that can be represented by this integer type."),
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_promotable]
+ #[inline(always)]
+ #[rustc_const_stable(feature = "const_max_value", since = "1.32.0")]
+ pub const fn max_value() -> Self { Self::MAX }
+ }
+ }
+}
+++ /dev/null
-//! The pointer-sized unsigned integer type.
-//!
-//! *[See also the `usize` primitive type](../../std/primitive.usize.html).*
-//!
-//! Although using these constants won’t cause compilation warnings,
-//! new code should use the associated constants directly on the primitive type.
-
-#![stable(feature = "rust1", since = "1.0.0")]
-
-int_module! { usize }
-use super::Wrapping;
+//! Definitions of `Wrapping<T>`.
+
+use crate::fmt;
+use crate::ops::{Add, AddAssign, BitAnd, BitAndAssign, BitOr, BitOrAssign};
+use crate::ops::{BitXor, BitXorAssign, Div, DivAssign};
+use crate::ops::{Mul, MulAssign, Neg, Not, Rem, RemAssign};
+use crate::ops::{Shl, ShlAssign, Shr, ShrAssign, Sub, SubAssign};
+
+/// Provides intentionally-wrapped arithmetic on `T`.
+///
+/// Operations like `+` on `u32` values are intended to never overflow,
+/// and in some debug configurations overflow is detected and results
+/// in a panic. While most arithmetic falls into this category, some
+/// code explicitly expects and relies upon modular arithmetic (e.g.,
+/// hashing).
+///
+/// Wrapping arithmetic can be achieved either through methods like
+/// `wrapping_add`, or through the `Wrapping<T>` type, which says that
+/// all standard arithmetic operations on the underlying value are
+/// intended to have wrapping semantics.
+///
+/// The underlying value can be retrieved through the `.0` index of the
+/// `Wrapping` tuple.
+///
+/// # Examples
+///
+/// ```
+/// use std::num::Wrapping;
+///
+/// let zero = Wrapping(0u32);
+/// let one = Wrapping(1u32);
+///
+/// assert_eq!(u32::MAX, (zero - one).0);
+/// ```
+#[stable(feature = "rust1", since = "1.0.0")]
+#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Default, Hash)]
+#[repr(transparent)]
+pub struct Wrapping<T>(#[stable(feature = "rust1", since = "1.0.0")] pub T);
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: fmt::Debug> fmt::Debug for Wrapping<T> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ self.0.fmt(f)
+ }
+}
+
+#[stable(feature = "wrapping_display", since = "1.10.0")]
+impl<T: fmt::Display> fmt::Display for Wrapping<T> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ self.0.fmt(f)
+ }
+}
+
+#[stable(feature = "wrapping_fmt", since = "1.11.0")]
+impl<T: fmt::Binary> fmt::Binary for Wrapping<T> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ self.0.fmt(f)
+ }
+}
-use crate::ops::*;
+#[stable(feature = "wrapping_fmt", since = "1.11.0")]
+impl<T: fmt::Octal> fmt::Octal for Wrapping<T> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ self.0.fmt(f)
+ }
+}
+
+#[stable(feature = "wrapping_fmt", since = "1.11.0")]
+impl<T: fmt::LowerHex> fmt::LowerHex for Wrapping<T> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ self.0.fmt(f)
+ }
+}
+
+#[stable(feature = "wrapping_fmt", since = "1.11.0")]
+impl<T: fmt::UpperHex> fmt::UpperHex for Wrapping<T> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ self.0.fmt(f)
+ }
+}
#[allow(unused_macros)]
macro_rules! sh_impl_signed {
/// The iterator yields one value if the [`Option`] is a [`Some`], otherwise none.
///
/// This `struct` is created by the [`Option::into_iter`] function.
-///
-/// [`Option::into_iter`]: enum.Option.html#method.into_iter
#[derive(Clone, Debug)]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct IntoIter<A> {
use crate::fmt;
use crate::intrinsics::{assume, exact_div, unchecked_sub};
use crate::iter::{FusedIterator, TrustedLen, TrustedRandomAccess};
-use crate::marker::{self, Send, Sized, Sync};
+use crate::marker::{PhantomData, Send, Sized, Sync};
use crate::mem;
use crate::ptr::NonNull;
/// [slices]: ../../std/primitive.slice.html
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Iter<'a, T: 'a> {
- pub(super) ptr: NonNull<T>,
- pub(super) end: *const T, // If T is a ZST, this is actually ptr+len. This encoding is picked so that
+ ptr: NonNull<T>,
+ end: *const T, // If T is a ZST, this is actually ptr+len. This encoding is picked so that
// ptr == end is a quick test for the Iterator being empty, that works
// for both ZST and non-ZST.
- pub(super) _marker: marker::PhantomData<&'a T>,
+ _marker: PhantomData<&'a T>,
}
#[stable(feature = "core_impl_debug", since = "1.9.0")]
unsafe impl<T: Sync> Send for Iter<'_, T> {}
impl<'a, T> Iter<'a, T> {
+ #[inline]
+ pub(super) fn new(slice: &'a [T]) -> Self {
+ let ptr = slice.as_ptr();
+ // SAFETY: Similar to `IterMut::new`.
+ unsafe {
+ assume(!ptr.is_null());
+
+ let end = if mem::size_of::<T>() == 0 {
+ (ptr as *const u8).wrapping_add(slice.len()) as *const T
+ } else {
+ ptr.add(slice.len())
+ };
+
+ Self { ptr: NonNull::new_unchecked(ptr as *mut T), end, _marker: PhantomData }
+ }
+ }
+
/// Views the underlying data as a subslice of the original data.
///
/// This has the same lifetime as the original slice, and so the
/// [slices]: ../../std/primitive.slice.html
#[stable(feature = "rust1", since = "1.0.0")]
pub struct IterMut<'a, T: 'a> {
- pub(super) ptr: NonNull<T>,
- pub(super) end: *mut T, // If T is a ZST, this is actually ptr+len. This encoding is picked so that
+ ptr: NonNull<T>,
+ end: *mut T, // If T is a ZST, this is actually ptr+len. This encoding is picked so that
// ptr == end is a quick test for the Iterator being empty, that works
// for both ZST and non-ZST.
- pub(super) _marker: marker::PhantomData<&'a mut T>,
+ _marker: PhantomData<&'a mut T>,
}
#[stable(feature = "core_impl_debug", since = "1.9.0")]
unsafe impl<T: Send> Send for IterMut<'_, T> {}
impl<'a, T> IterMut<'a, T> {
+ #[inline]
+ pub(super) fn new(slice: &'a mut [T]) -> Self {
+ let ptr = slice.as_mut_ptr();
+ // SAFETY: There are several things here:
+ //
+ // `ptr` has been obtained by `slice.as_ptr()` where `slice` is a valid
+ // reference thus it is non-NUL and safe to use and pass to
+ // `NonNull::new_unchecked` .
+ //
+ // Adding `slice.len()` to the starting pointer gives a pointer
+ // at the end of `slice`. `end` will never be dereferenced, only checked
+ // for direct pointer equality with `ptr` to check if the iterator is
+ // done.
+ //
+ // In the case of a ZST, the end pointer is just the start pointer plus
+ // the length, to also allows for the fast `ptr == end` check.
+ //
+ // See the `next_unchecked!` and `is_empty!` macros as well as the
+ // `post_inc_start` method for more informations.
+ unsafe {
+ assume(!ptr.is_null());
+
+ let end = if mem::size_of::<T>() == 0 {
+ (ptr as *mut u8).wrapping_add(slice.len()) as *mut T
+ } else {
+ ptr.add(slice.len())
+ };
+
+ Self { ptr: NonNull::new_unchecked(ptr), end, _marker: PhantomData }
+ }
+ }
+
/// Views the underlying data as a subslice of the original data.
///
/// To avoid creating `&mut` references that alias, this is forced
where
P: FnMut(&T) -> bool,
{
- pub(super) v: &'a [T],
- pub(super) pred: P,
- pub(super) finished: bool,
+ v: &'a [T],
+ pred: P,
+ finished: bool,
+}
+
+impl<'a, T: 'a, P: FnMut(&T) -> bool> Split<'a, T, P> {
+ #[inline]
+ pub(super) fn new(slice: &'a [T], pred: P) -> Self {
+ Self { v: slice, pred, finished: false }
+ }
}
#[stable(feature = "core_impl_debug", since = "1.9.0")]
where
P: FnMut(&T) -> bool,
{
- pub(super) v: &'a [T],
- pub(super) pred: P,
- pub(super) finished: bool,
+ v: &'a [T],
+ pred: P,
+ finished: bool,
+}
+
+impl<'a, T: 'a, P: FnMut(&T) -> bool> SplitInclusive<'a, T, P> {
+ #[inline]
+ pub(super) fn new(slice: &'a [T], pred: P) -> Self {
+ Self { v: slice, pred, finished: false }
+ }
}
#[unstable(feature = "split_inclusive", issue = "72360")]
where
P: FnMut(&T) -> bool,
{
- pub(super) v: &'a mut [T],
- pub(super) pred: P,
- pub(super) finished: bool,
+ v: &'a mut [T],
+ pred: P,
+ finished: bool,
+}
+
+impl<'a, T: 'a, P: FnMut(&T) -> bool> SplitMut<'a, T, P> {
+ #[inline]
+ pub(super) fn new(slice: &'a mut [T], pred: P) -> Self {
+ Self { v: slice, pred, finished: false }
+ }
}
#[stable(feature = "core_impl_debug", since = "1.9.0")]
where
P: FnMut(&T) -> bool,
{
- pub(super) v: &'a mut [T],
- pub(super) pred: P,
- pub(super) finished: bool,
+ v: &'a mut [T],
+ pred: P,
+ finished: bool,
+}
+
+impl<'a, T: 'a, P: FnMut(&T) -> bool> SplitInclusiveMut<'a, T, P> {
+ #[inline]
+ pub(super) fn new(slice: &'a mut [T], pred: P) -> Self {
+ Self { v: slice, pred, finished: false }
+ }
}
#[unstable(feature = "split_inclusive", issue = "72360")]
where
P: FnMut(&T) -> bool,
{
- pub(super) inner: Split<'a, T, P>,
+ inner: Split<'a, T, P>,
+}
+
+impl<'a, T: 'a, P: FnMut(&T) -> bool> RSplit<'a, T, P> {
+ #[inline]
+ pub(super) fn new(slice: &'a [T], pred: P) -> Self {
+ Self { inner: Split::new(slice, pred) }
+ }
}
#[stable(feature = "slice_rsplit", since = "1.27.0")]
where
P: FnMut(&T) -> bool,
{
- pub(super) inner: SplitMut<'a, T, P>,
+ inner: SplitMut<'a, T, P>,
+}
+
+impl<'a, T: 'a, P: FnMut(&T) -> bool> RSplitMut<'a, T, P> {
+ #[inline]
+ pub(super) fn new(slice: &'a mut [T], pred: P) -> Self {
+ Self { inner: SplitMut::new(slice, pred) }
+ }
}
#[stable(feature = "slice_rsplit", since = "1.27.0")]
/// match a predicate function, splitting at most a fixed number of
/// times.
#[derive(Debug)]
-pub(super) struct GenericSplitN<I> {
- pub(super) iter: I,
- pub(super) count: usize,
+struct GenericSplitN<I> {
+ iter: I,
+ count: usize,
}
impl<T, I: SplitIter<Item = T>> Iterator for GenericSplitN<I> {
where
P: FnMut(&T) -> bool,
{
- pub(super) inner: GenericSplitN<Split<'a, T, P>>,
+ inner: GenericSplitN<Split<'a, T, P>>,
+}
+
+impl<'a, T: 'a, P: FnMut(&T) -> bool> SplitN<'a, T, P> {
+ #[inline]
+ pub(super) fn new(s: Split<'a, T, P>, n: usize) -> Self {
+ Self { inner: GenericSplitN { iter: s, count: n } }
+ }
}
#[stable(feature = "core_impl_debug", since = "1.9.0")]
where
P: FnMut(&T) -> bool,
{
- pub(super) inner: GenericSplitN<RSplit<'a, T, P>>,
+ inner: GenericSplitN<RSplit<'a, T, P>>,
+}
+
+impl<'a, T: 'a, P: FnMut(&T) -> bool> RSplitN<'a, T, P> {
+ #[inline]
+ pub(super) fn new(s: RSplit<'a, T, P>, n: usize) -> Self {
+ Self { inner: GenericSplitN { iter: s, count: n } }
+ }
}
#[stable(feature = "core_impl_debug", since = "1.9.0")]
where
P: FnMut(&T) -> bool,
{
- pub(super) inner: GenericSplitN<SplitMut<'a, T, P>>,
+ inner: GenericSplitN<SplitMut<'a, T, P>>,
+}
+
+impl<'a, T: 'a, P: FnMut(&T) -> bool> SplitNMut<'a, T, P> {
+ #[inline]
+ pub(super) fn new(s: SplitMut<'a, T, P>, n: usize) -> Self {
+ Self { inner: GenericSplitN { iter: s, count: n } }
+ }
}
#[stable(feature = "core_impl_debug", since = "1.9.0")]
where
P: FnMut(&T) -> bool,
{
- pub(super) inner: GenericSplitN<RSplitMut<'a, T, P>>,
+ inner: GenericSplitN<RSplitMut<'a, T, P>>,
+}
+
+impl<'a, T: 'a, P: FnMut(&T) -> bool> RSplitNMut<'a, T, P> {
+ #[inline]
+ pub(super) fn new(s: RSplitMut<'a, T, P>, n: usize) -> Self {
+ Self { inner: GenericSplitN { iter: s, count: n } }
+ }
}
#[stable(feature = "core_impl_debug", since = "1.9.0")]
#[derive(Debug)]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Windows<'a, T: 'a> {
- pub(super) v: &'a [T],
- pub(super) size: usize,
+ v: &'a [T],
+ size: usize,
+}
+
+impl<'a, T: 'a> Windows<'a, T> {
+ #[inline]
+ pub(super) fn new(slice: &'a [T], size: usize) -> Self {
+ Self { v: slice, size }
+ }
}
// FIXME(#26925) Remove in favor of `#[derive(Clone)]`
#[derive(Debug)]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Chunks<'a, T: 'a> {
- pub(super) v: &'a [T],
- pub(super) chunk_size: usize,
+ v: &'a [T],
+ chunk_size: usize,
+}
+
+impl<'a, T: 'a> Chunks<'a, T> {
+ #[inline]
+ pub(super) fn new(slice: &'a [T], size: usize) -> Self {
+ Self { v: slice, chunk_size: size }
+ }
}
// FIXME(#26925) Remove in favor of `#[derive(Clone)]`
#[derive(Debug)]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct ChunksMut<'a, T: 'a> {
- pub(super) v: &'a mut [T],
- pub(super) chunk_size: usize,
+ v: &'a mut [T],
+ chunk_size: usize,
+}
+
+impl<'a, T: 'a> ChunksMut<'a, T> {
+ #[inline]
+ pub(super) fn new(slice: &'a mut [T], size: usize) -> Self {
+ Self { v: slice, chunk_size: size }
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
#[derive(Debug)]
#[stable(feature = "chunks_exact", since = "1.31.0")]
pub struct ChunksExact<'a, T: 'a> {
- pub(super) v: &'a [T],
- pub(super) rem: &'a [T],
- pub(super) chunk_size: usize,
+ v: &'a [T],
+ rem: &'a [T],
+ chunk_size: usize,
}
impl<'a, T> ChunksExact<'a, T> {
+ #[inline]
+ pub(super) fn new(slice: &'a [T], chunk_size: usize) -> Self {
+ let rem = slice.len() % chunk_size;
+ let fst_len = slice.len() - rem;
+ // SAFETY: 0 <= fst_len <= slice.len() by construction above
+ let (fst, snd) = unsafe { slice.split_at_unchecked(fst_len) };
+ Self { v: fst, rem: snd, chunk_size }
+ }
+
/// Returns the remainder of the original slice that is not going to be
/// returned by the iterator. The returned slice has at most `chunk_size-1`
/// elements.
#[derive(Debug)]
#[stable(feature = "chunks_exact", since = "1.31.0")]
pub struct ChunksExactMut<'a, T: 'a> {
- pub(super) v: &'a mut [T],
- pub(super) rem: &'a mut [T],
- pub(super) chunk_size: usize,
+ v: &'a mut [T],
+ rem: &'a mut [T],
+ chunk_size: usize,
}
impl<'a, T> ChunksExactMut<'a, T> {
+ #[inline]
+ pub(super) fn new(slice: &'a mut [T], chunk_size: usize) -> Self {
+ let rem = slice.len() % chunk_size;
+ let fst_len = slice.len() - rem;
+ // SAFETY: 0 <= fst_len <= slice.len() by construction above
+ let (fst, snd) = unsafe { slice.split_at_mut_unchecked(fst_len) };
+ Self { v: fst, rem: snd, chunk_size }
+ }
+
/// Returns the remainder of the original slice that is not going to be
/// returned by the iterator. The returned slice has at most `chunk_size-1`
/// elements.
#[derive(Debug, Clone, Copy)]
#[unstable(feature = "array_windows", issue = "75027")]
pub struct ArrayWindows<'a, T: 'a, const N: usize> {
- pub(crate) slice_head: *const T,
- pub(crate) num: usize,
- pub(crate) marker: marker::PhantomData<&'a [T; N]>,
+ slice_head: *const T,
+ num: usize,
+ marker: PhantomData<&'a [T; N]>,
+}
+
+impl<'a, T: 'a, const N: usize> ArrayWindows<'a, T, N> {
+ #[inline]
+ pub(super) fn new(slice: &'a [T]) -> Self {
+ let num_windows = slice.len().saturating_sub(N - 1);
+ Self { slice_head: slice.as_ptr(), num: num_windows, marker: PhantomData }
+ }
}
#[unstable(feature = "array_windows", issue = "75027")]
#[derive(Debug)]
#[unstable(feature = "array_chunks", issue = "74985")]
pub struct ArrayChunks<'a, T: 'a, const N: usize> {
- pub(super) iter: Iter<'a, [T; N]>,
- pub(super) rem: &'a [T],
+ iter: Iter<'a, [T; N]>,
+ rem: &'a [T],
}
impl<'a, T, const N: usize> ArrayChunks<'a, T, N> {
+ #[inline]
+ pub(super) fn new(slice: &'a [T]) -> Self {
+ let len = slice.len() / N;
+ let (fst, snd) = slice.split_at(len * N);
+ // SAFETY: We cast a slice of `len * N` elements into
+ // a slice of `len` many `N` elements chunks.
+ let array_slice: &[[T; N]] = unsafe { from_raw_parts(fst.as_ptr().cast(), len) };
+
+ Self { iter: array_slice.iter(), rem: snd }
+ }
+
/// Returns the remainder of the original slice that is not going to be
/// returned by the iterator. The returned slice has at most `N-1`
/// elements.
#[derive(Debug)]
#[unstable(feature = "array_chunks", issue = "74985")]
pub struct ArrayChunksMut<'a, T: 'a, const N: usize> {
- pub(super) iter: IterMut<'a, [T; N]>,
- pub(super) rem: &'a mut [T],
+ iter: IterMut<'a, [T; N]>,
+ rem: &'a mut [T],
}
impl<'a, T, const N: usize> ArrayChunksMut<'a, T, N> {
+ #[inline]
+ pub(super) fn new(slice: &'a mut [T]) -> Self {
+ let len = slice.len() / N;
+ let (fst, snd) = slice.split_at_mut(len * N);
+ // SAFETY: We cast a slice of `len * N` elements into
+ // a slice of `len` many `N` elements chunks.
+ unsafe {
+ let array_slice: &mut [[T; N]] = from_raw_parts_mut(fst.as_mut_ptr().cast(), len);
+ Self { iter: array_slice.iter_mut(), rem: snd }
+ }
+ }
+
/// Returns the remainder of the original slice that is not going to be
/// returned by the iterator. The returned slice has at most `N-1`
/// elements.
#[derive(Debug)]
#[stable(feature = "rchunks", since = "1.31.0")]
pub struct RChunks<'a, T: 'a> {
- pub(super) v: &'a [T],
- pub(super) chunk_size: usize,
+ v: &'a [T],
+ chunk_size: usize,
+}
+
+impl<'a, T: 'a> RChunks<'a, T> {
+ #[inline]
+ pub(super) fn new(slice: &'a [T], size: usize) -> Self {
+ Self { v: slice, chunk_size: size }
+ }
}
// FIXME(#26925) Remove in favor of `#[derive(Clone)]`
#[derive(Debug)]
#[stable(feature = "rchunks", since = "1.31.0")]
pub struct RChunksMut<'a, T: 'a> {
- pub(super) v: &'a mut [T],
- pub(super) chunk_size: usize,
+ v: &'a mut [T],
+ chunk_size: usize,
+}
+
+impl<'a, T: 'a> RChunksMut<'a, T> {
+ #[inline]
+ pub(super) fn new(slice: &'a mut [T], size: usize) -> Self {
+ Self { v: slice, chunk_size: size }
+ }
}
#[stable(feature = "rchunks", since = "1.31.0")]
#[derive(Debug)]
#[stable(feature = "rchunks", since = "1.31.0")]
pub struct RChunksExact<'a, T: 'a> {
- pub(super) v: &'a [T],
- pub(super) rem: &'a [T],
- pub(super) chunk_size: usize,
+ v: &'a [T],
+ rem: &'a [T],
+ chunk_size: usize,
}
impl<'a, T> RChunksExact<'a, T> {
+ #[inline]
+ pub(super) fn new(slice: &'a [T], chunk_size: usize) -> Self {
+ let rem = slice.len() % chunk_size;
+ // SAFETY: 0 <= rem <= slice.len() by construction above
+ let (fst, snd) = unsafe { slice.split_at_unchecked(rem) };
+ Self { v: snd, rem: fst, chunk_size }
+ }
+
/// Returns the remainder of the original slice that is not going to be
/// returned by the iterator. The returned slice has at most `chunk_size-1`
/// elements.
#[derive(Debug)]
#[stable(feature = "rchunks", since = "1.31.0")]
pub struct RChunksExactMut<'a, T: 'a> {
- pub(super) v: &'a mut [T],
- pub(super) rem: &'a mut [T],
- pub(super) chunk_size: usize,
+ v: &'a mut [T],
+ rem: &'a mut [T],
+ chunk_size: usize,
}
impl<'a, T> RChunksExactMut<'a, T> {
+ #[inline]
+ pub(super) fn new(slice: &'a mut [T], chunk_size: usize) -> Self {
+ let rem = slice.len() % chunk_size;
+ // SAFETY: 0 <= rem <= slice.len() by construction above
+ let (fst, snd) = unsafe { slice.split_at_mut_unchecked(rem) };
+ Self { v: snd, rem: fst, chunk_size }
+ }
+
/// Returns the remainder of the original slice that is not going to be
/// returned by the iterator. The returned slice has at most `chunk_size-1`
/// elements.
#![stable(feature = "rust1", since = "1.0.0")]
use crate::cmp::Ordering::{self, Equal, Greater, Less};
-use crate::intrinsics::assume;
-use crate::marker::{self, Copy};
+use crate::marker::Copy;
use crate::mem;
use crate::ops::{FnMut, Range, RangeBounds};
use crate::option::Option;
use crate::option::Option::{None, Some};
-use crate::ptr::{self, NonNull};
+use crate::ptr;
use crate::result::Result;
use crate::result::Result::{Err, Ok};
mod rotate;
mod sort;
-use iter::GenericSplitN;
-
#[stable(feature = "rust1", since = "1.0.0")]
pub use iter::{Chunks, ChunksMut, Windows};
#[stable(feature = "rust1", since = "1.0.0")]
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn iter(&self) -> Iter<'_, T> {
- let ptr = self.as_ptr();
- // SAFETY: There are several things here:
- //
- // `ptr` has been obtained by `self.as_ptr()` where `self` is a valid
- // reference thus it is non-NUL and safe to use and pass to
- // `NonNull::new_unchecked` .
- //
- // Adding `self.len()` to the starting pointer gives a pointer
- // at the end of `self`. `end` will never be dereferenced, only checked
- // for direct pointer equality with `ptr` to check if the iterator is
- // done.
- //
- // In the case of a ZST, the end pointer is just the start pointer plus
- // the length, to also allows for the fast `ptr == end` check.
- //
- // See the `next_unchecked!` and `is_empty!` macros as well as the
- // `post_inc_start` method for more informations.
- unsafe {
- assume(!ptr.is_null());
-
- let end = if mem::size_of::<T>() == 0 {
- (ptr as *const u8).wrapping_add(self.len()) as *const T
- } else {
- ptr.add(self.len())
- };
-
- Iter { ptr: NonNull::new_unchecked(ptr as *mut T), end, _marker: marker::PhantomData }
- }
+ Iter::new(self)
}
/// Returns an iterator that allows modifying each value.
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn iter_mut(&mut self) -> IterMut<'_, T> {
- let ptr = self.as_mut_ptr();
- // SAFETY: There are several things here:
- //
- // `ptr` has been obtained by `self.as_ptr()` where `self` is a valid
- // reference thus it is non-NUL and safe to use and pass to
- // `NonNull::new_unchecked` .
- //
- // Adding `self.len()` to the starting pointer gives a pointer
- // at the end of `self`. `end` will never be dereferenced, only checked
- // for direct pointer equality with `ptr` to check if the iterator is
- // done.
- //
- // In the case of a ZST, the end pointer is just the start pointer plus
- // the length, to also allows for the fast `ptr == end` check.
- //
- // See the `next_unchecked!` and `is_empty!` macros as well as the
- // `post_inc_start` method for more informations.
- unsafe {
- assume(!ptr.is_null());
-
- let end = if mem::size_of::<T>() == 0 {
- (ptr as *mut u8).wrapping_add(self.len()) as *mut T
- } else {
- ptr.add(self.len())
- };
-
- IterMut { ptr: NonNull::new_unchecked(ptr), end, _marker: marker::PhantomData }
- }
+ IterMut::new(self)
}
/// Returns an iterator over all contiguous windows of length
#[inline]
pub fn windows(&self, size: usize) -> Windows<'_, T> {
assert_ne!(size, 0);
- Windows { v: self, size }
+ Windows::new(self, size)
}
/// Returns an iterator over `chunk_size` elements of the slice at a time, starting at the
#[inline]
pub fn chunks(&self, chunk_size: usize) -> Chunks<'_, T> {
assert_ne!(chunk_size, 0);
- Chunks { v: self, chunk_size }
+ Chunks::new(self, chunk_size)
}
/// Returns an iterator over `chunk_size` elements of the slice at a time, starting at the
#[inline]
pub fn chunks_mut(&mut self, chunk_size: usize) -> ChunksMut<'_, T> {
assert_ne!(chunk_size, 0);
- ChunksMut { v: self, chunk_size }
+ ChunksMut::new(self, chunk_size)
}
/// Returns an iterator over `chunk_size` elements of the slice at a time, starting at the
#[inline]
pub fn chunks_exact(&self, chunk_size: usize) -> ChunksExact<'_, T> {
assert_ne!(chunk_size, 0);
- let rem = self.len() % chunk_size;
- let fst_len = self.len() - rem;
- // SAFETY: 0 <= fst_len <= self.len() by construction above
- let (fst, snd) = unsafe { self.split_at_unchecked(fst_len) };
- ChunksExact { v: fst, rem: snd, chunk_size }
+ ChunksExact::new(self, chunk_size)
}
/// Returns an iterator over `chunk_size` elements of the slice at a time, starting at the
#[inline]
pub fn chunks_exact_mut(&mut self, chunk_size: usize) -> ChunksExactMut<'_, T> {
assert_ne!(chunk_size, 0);
- let rem = self.len() % chunk_size;
- let fst_len = self.len() - rem;
- // SAFETY: 0 <= fst_len <= self.len() by construction above
- let (fst, snd) = unsafe { self.split_at_mut_unchecked(fst_len) };
- ChunksExactMut { v: fst, rem: snd, chunk_size }
+ ChunksExactMut::new(self, chunk_size)
}
/// Returns an iterator over `N` elements of the slice at a time, starting at the
#[inline]
pub fn array_chunks<const N: usize>(&self) -> ArrayChunks<'_, T, N> {
assert_ne!(N, 0);
- let len = self.len() / N;
- let (fst, snd) = self.split_at(len * N);
- // SAFETY: We cast a slice of `len * N` elements into
- // a slice of `len` many `N` elements chunks.
- let array_slice: &[[T; N]] = unsafe { from_raw_parts(fst.as_ptr().cast(), len) };
- ArrayChunks { iter: array_slice.iter(), rem: snd }
+ ArrayChunks::new(self)
}
/// Returns an iterator over `N` elements of the slice at a time, starting at the
#[inline]
pub fn array_chunks_mut<const N: usize>(&mut self) -> ArrayChunksMut<'_, T, N> {
assert_ne!(N, 0);
- let len = self.len() / N;
- let (fst, snd) = self.split_at_mut(len * N);
- // SAFETY: We cast a slice of `len * N` elements into
- // a slice of `len` many `N` elements chunks.
- unsafe {
- let array_slice: &mut [[T; N]] = from_raw_parts_mut(fst.as_mut_ptr().cast(), len);
- ArrayChunksMut { iter: array_slice.iter_mut(), rem: snd }
- }
+ ArrayChunksMut::new(self)
}
/// Returns an iterator over overlapping windows of `N` elements of a slice,
///
/// This is the const generic equivalent of [`windows`].
///
- /// If `N` is smaller than the size of the array, it will return no windows.
+ /// If `N` is greater than the size of the slice, it will return no windows.
///
/// # Panics
///
#[inline]
pub fn array_windows<const N: usize>(&self) -> ArrayWindows<'_, T, N> {
assert_ne!(N, 0);
-
- let num_windows = self.len().saturating_sub(N - 1);
- ArrayWindows { slice_head: self.as_ptr(), num: num_windows, marker: marker::PhantomData }
+ ArrayWindows::new(self)
}
/// Returns an iterator over `chunk_size` elements of the slice at a time, starting at the end
#[inline]
pub fn rchunks(&self, chunk_size: usize) -> RChunks<'_, T> {
assert!(chunk_size != 0);
- RChunks { v: self, chunk_size }
+ RChunks::new(self, chunk_size)
}
/// Returns an iterator over `chunk_size` elements of the slice at a time, starting at the end
#[inline]
pub fn rchunks_mut(&mut self, chunk_size: usize) -> RChunksMut<'_, T> {
assert!(chunk_size != 0);
- RChunksMut { v: self, chunk_size }
+ RChunksMut::new(self, chunk_size)
}
/// Returns an iterator over `chunk_size` elements of the slice at a time, starting at the
#[inline]
pub fn rchunks_exact(&self, chunk_size: usize) -> RChunksExact<'_, T> {
assert!(chunk_size != 0);
- let rem = self.len() % chunk_size;
- // SAFETY: 0 <= rem <= self.len() by construction above
- let (fst, snd) = unsafe { self.split_at_unchecked(rem) };
- RChunksExact { v: snd, rem: fst, chunk_size }
+ RChunksExact::new(self, chunk_size)
}
/// Returns an iterator over `chunk_size` elements of the slice at a time, starting at the end
#[inline]
pub fn rchunks_exact_mut(&mut self, chunk_size: usize) -> RChunksExactMut<'_, T> {
assert!(chunk_size != 0);
- let rem = self.len() % chunk_size;
- // SAFETY: 0 <= rem <= self.len() by construction above
- let (fst, snd) = unsafe { self.split_at_mut_unchecked(rem) };
- RChunksExactMut { v: snd, rem: fst, chunk_size }
+ RChunksExactMut::new(self, chunk_size)
}
/// Divides one slice into two at an index.
where
F: FnMut(&T) -> bool,
{
- Split { v: self, pred, finished: false }
+ Split::new(self, pred)
}
/// Returns an iterator over mutable subslices separated by elements that
where
F: FnMut(&T) -> bool,
{
- SplitMut { v: self, pred, finished: false }
+ SplitMut::new(self, pred)
}
/// Returns an iterator over subslices separated by elements that match
where
F: FnMut(&T) -> bool,
{
- SplitInclusive { v: self, pred, finished: false }
+ SplitInclusive::new(self, pred)
}
/// Returns an iterator over mutable subslices separated by elements that
where
F: FnMut(&T) -> bool,
{
- SplitInclusiveMut { v: self, pred, finished: false }
+ SplitInclusiveMut::new(self, pred)
}
/// Returns an iterator over subslices separated by elements that match
where
F: FnMut(&T) -> bool,
{
- RSplit { inner: self.split(pred) }
+ RSplit::new(self, pred)
}
/// Returns an iterator over mutable subslices separated by elements that
where
F: FnMut(&T) -> bool,
{
- RSplitMut { inner: self.split_mut(pred) }
+ RSplitMut::new(self, pred)
}
/// Returns an iterator over subslices separated by elements that match
where
F: FnMut(&T) -> bool,
{
- SplitN { inner: GenericSplitN { iter: self.split(pred), count: n } }
+ SplitN::new(self.split(pred), n)
}
/// Returns an iterator over subslices separated by elements that match
where
F: FnMut(&T) -> bool,
{
- SplitNMut { inner: GenericSplitN { iter: self.split_mut(pred), count: n } }
+ SplitNMut::new(self.split_mut(pred), n)
}
/// Returns an iterator over subslices separated by elements that match
where
F: FnMut(&T) -> bool,
{
- RSplitN { inner: GenericSplitN { iter: self.rsplit(pred), count: n } }
+ RSplitN::new(self.rsplit(pred), n)
}
/// Returns an iterator over subslices separated by elements that match
where
F: FnMut(&T) -> bool,
{
- RSplitNMut { inner: GenericSplitN { iter: self.rsplit_mut(pred), count: n } }
+ RSplitNMut::new(self.rsplit_mut(pred), n)
}
/// Returns `true` if the slice contains an element with the given value.
random
};
let mut gen_usize = || {
- if mem::size_of::<usize>() <= 4 {
+ if usize::BITS <= 32 {
gen_u32() as usize
} else {
(((gen_u32() as u64) << 32) | (gen_u32() as u64)) as usize
///
/// `limit` is the number of allowed imbalanced partitions before switching to `heapsort`. If zero,
/// this function will immediately switch to heapsort.
-fn recurse<'a, T, F>(mut v: &'a mut [T], is_less: &mut F, mut pred: Option<&'a T>, mut limit: usize)
+fn recurse<'a, T, F>(mut v: &'a mut [T], is_less: &mut F, mut pred: Option<&'a T>, mut limit: u32)
where
F: FnMut(&T, &T) -> bool,
{
}
// Limit the number of imbalanced partitions to `floor(log2(len)) + 1`.
- let limit = mem::size_of::<usize>() * 8 - v.len().leading_zeros() as usize;
+ let limit = usize::BITS - v.len().leading_zeros();
recurse(v, &mut is_less, None, limit);
}
//!
//! For more details, see the [`std::str`] module.
//!
-//! [`std::str`]: self
+//! [`std::str`]: ../../std/str/index.html
#![stable(feature = "rust1", since = "1.0.0")]
/// when the string is ill-formatted return an error specific to the
/// inside [`Err`]. The error type is specific to implementation of the trait.
///
- /// [`Ok`]: ../../std/result/enum.Result.html#variant.Ok
- /// [`Err`]: ../../std/result/enum.Result.html#variant.Err
- ///
/// # Examples
///
/// Basic usage with [`i32`][ithirtytwo], a type that implements `FromStr`:
///
/// If you are sure that the byte slice is valid UTF-8, and you don't want to
/// incur the overhead of the validity check, there is an unsafe version of
-/// this function, [`from_utf8_unchecked`][fromutf8u], which has the same
+/// this function, [`from_utf8_unchecked`], which has the same
/// behavior but skips the check.
///
-/// [fromutf8u]: fn.from_utf8_unchecked.html
-///
/// If you need a `String` instead of a `&str`, consider
/// [`String::from_utf8`][string].
///
/// assert!(str::from_utf8(&sparkle_heart).is_err());
/// ```
///
-/// See the docs for [`Utf8Error`][error] for more details on the kinds of
+/// See the docs for [`Utf8Error`] for more details on the kinds of
/// errors that can be returned.
///
-/// [error]: struct.Utf8Error.html
-///
/// A "stack allocated string":
///
/// ```
///
/// assert!(str::from_utf8_mut(&mut invalid).is_err());
/// ```
-/// See the docs for [`Utf8Error`][error] for more details on the kinds of
+/// See the docs for [`Utf8Error`] for more details on the kinds of
/// errors that can be returned.
-///
-/// [error]: struct.Utf8Error.html
#[stable(feature = "str_mut_extras", since = "1.20.0")]
pub fn from_utf8_mut(v: &mut [u8]) -> Result<&mut str, Utf8Error> {
run_utf8_validation(v)?;
/// Converts a slice of bytes to a string slice without checking
/// that the string contains valid UTF-8.
///
-/// See the safe version, [`from_utf8`][fromutf8], for more information.
-///
-/// [fromutf8]: fn.from_utf8.html
+/// See the safe version, [`from_utf8`], for more information.
///
/// # Safety
///
//! assert_eq!(s.find(|c: char| c.is_ascii_punctuation()), Some(35));
//! ```
//!
-//! [pattern-impls]: trait.Pattern.html#implementors
+//! [pattern-impls]: Pattern#implementors
#![unstable(
feature = "pattern",
///
/// [vtable]: https://en.wikipedia.org/wiki/Virtual_method_table
///
-/// It consists of a data pointer and a [virtual function pointer table (vtable)][vtable] that
-/// customizes the behavior of the `RawWaker`.
-///
-/// [`Waker`]: struct.Waker.html
+/// It consists of a data pointer and a [virtual function pointer table (vtable)][vtable]
+/// that customizes the behavior of the `RawWaker`.
#[derive(PartialEq, Debug)]
#[stable(feature = "futures_api", since = "1.36.0")]
pub struct RawWaker {
/// The pointer passed to all functions inside the vtable is the `data` pointer
/// from the enclosing [`RawWaker`] object.
///
-/// The functions inside this struct are only intended be called on the `data`
+/// The functions inside this struct are only intended to be called on the `data`
/// pointer of a properly constructed [`RawWaker`] object from inside the
/// [`RawWaker`] implementation. Calling one of the contained functions using
/// any other `data` pointer will cause undefined behavior.
-///
-/// [`RawWaker`]: struct.RawWaker.html
#[stable(feature = "futures_api", since = "1.36.0")]
#[derive(PartialEq, Copy, Clone, Debug)]
pub struct RawWakerVTable {
/// required for this additional instance of a [`RawWaker`] and associated
/// task. Calling `wake` on the resulting [`RawWaker`] should result in a wakeup
/// of the same task that would have been awoken by the original [`RawWaker`].
- ///
- /// [`Waker`]: struct.Waker.html
- /// [`RawWaker`]: struct.RawWaker.html
clone: unsafe fn(*const ()) -> RawWaker,
/// This function will be called when `wake` is called on the [`Waker`].
/// The implementation of this function must make sure to release any
/// resources that are associated with this instance of a [`RawWaker`] and
/// associated task.
- ///
- /// [`Waker`]: struct.Waker.html
- /// [`RawWaker`]: struct.RawWaker.html
wake: unsafe fn(*const ()),
/// This function will be called when `wake_by_ref` is called on the [`Waker`].
///
/// This function is similar to `wake`, but must not consume the provided data
/// pointer.
- ///
- /// [`Waker`]: struct.Waker.html
- /// [`RawWaker`]: struct.RawWaker.html
wake_by_ref: unsafe fn(*const ()),
/// This function gets called when a [`RawWaker`] gets dropped.
/// The implementation of this function must make sure to release any
/// resources that are associated with this instance of a [`RawWaker`] and
/// associated task.
- ///
- /// [`RawWaker`]: struct.RawWaker.html
drop: unsafe fn(*const ()),
}
/// The implementation of this function must make sure to release any
/// resources that are associated with this instance of a [`RawWaker`] and
/// associated task.
- ///
- /// [`Waker`]: struct.Waker.html
- /// [`RawWaker`]: struct.RawWaker.html
#[rustc_promotable]
#[stable(feature = "futures_api", since = "1.36.0")]
// `rustc_allow_const_fn_ptr` is a hack that should not be used anywhere else
/// executor-specific wakeup behavior.
///
/// Implements [`Clone`], [`Send`], and [`Sync`].
-///
-/// [`RawWaker`]: struct.RawWaker.html
#[repr(transparent)]
#[stable(feature = "futures_api", since = "1.36.0")]
pub struct Waker {
/// The behavior of the returned `Waker` is undefined if the contract defined
/// in [`RawWaker`]'s and [`RawWakerVTable`]'s documentation is not upheld.
/// Therefore this method is unsafe.
- ///
- /// [`RawWaker`]: struct.RawWaker.html
- /// [`RawWakerVTable`]: struct.RawWakerVTable.html
#[inline]
#[stable(feature = "futures_api", since = "1.36.0")]
pub unsafe fn from_raw(waker: RawWaker) -> Waker {
}
let mut it = Test(0);
- let root = usize::MAX >> (::std::mem::size_of::<usize>() * 8 / 2);
+ let root = usize::MAX >> (usize::BITS / 2);
let n = root + 20;
(&mut it).step_by(n).nth(n);
assert_eq!(it.0, n as Bigger * n as Bigger);
#![feature(partition_point)]
#![feature(once_cell)]
#![feature(unsafe_block_in_unsafe_fn)]
+#![feature(int_bits_const)]
#![deny(unsafe_op_in_unsafe_fn)]
extern crate test;
($T:ident, $T_i:ident) => {
#[cfg(test)]
mod tests {
- use core::mem;
use core::ops::{BitAnd, BitOr, BitXor, Not, Shl, Shr};
use core::$T_i::*;
#[test]
fn test_count_zeros() {
- let bits = mem::size_of::<$T>() * 8;
- assert_eq!(A.count_zeros(), bits as u32 - 3);
- assert_eq!(B.count_zeros(), bits as u32 - 2);
- assert_eq!(C.count_zeros(), bits as u32 - 5);
+ assert_eq!(A.count_zeros(), $T::BITS - 3);
+ assert_eq!(B.count_zeros(), $T::BITS - 2);
+ assert_eq!(C.count_zeros(), $T::BITS - 5);
}
#[test]
fn test_leading_trailing_ones() {
- let bits = (mem::size_of::<$T>() * 8) as u32;
-
let a: $T = 0b0101_1111;
assert_eq!(a.trailing_ones(), 5);
- assert_eq!((!a).leading_ones(), bits - 7);
+ assert_eq!((!a).leading_ones(), $T::BITS - 7);
assert_eq!(a.reverse_bits().leading_ones(), 5);
- assert_eq!(_1.leading_ones(), bits);
- assert_eq!(_1.trailing_ones(), bits);
+ assert_eq!(_1.leading_ones(), $T::BITS);
+ assert_eq!(_1.trailing_ones(), $T::BITS);
assert_eq!((_1 << 1).trailing_ones(), 0);
assert_eq!(MAX.leading_ones(), 0);
- assert_eq!((_1 << 1).leading_ones(), bits - 1);
- assert_eq!(MAX.trailing_ones(), bits - 1);
+ assert_eq!((_1 << 1).leading_ones(), $T::BITS - 1);
+ assert_eq!(MAX.trailing_ones(), $T::BITS - 1);
assert_eq!(_0.leading_ones(), 0);
assert_eq!(_0.trailing_ones(), 0);
mod tests {
use core::ops::{BitAnd, BitOr, BitXor, Not, Shl, Shr};
use core::$T_i::*;
- use std::mem;
use std::str::FromStr;
use crate::num;
#[test]
fn test_count_zeros() {
- let bits = mem::size_of::<$T>() * 8;
- assert!(A.count_zeros() == bits as u32 - 3);
- assert!(B.count_zeros() == bits as u32 - 2);
- assert!(C.count_zeros() == bits as u32 - 5);
+ assert!(A.count_zeros() == $T::BITS - 3);
+ assert!(B.count_zeros() == $T::BITS - 2);
+ assert!(C.count_zeros() == $T::BITS - 5);
}
#[test]
fn test_leading_trailing_ones() {
- let bits = (mem::size_of::<$T>() * 8) as u32;
-
let a: $T = 0b0101_1111;
assert_eq!(a.trailing_ones(), 5);
- assert_eq!((!a).leading_ones(), bits - 7);
+ assert_eq!((!a).leading_ones(), $T::BITS - 7);
assert_eq!(a.reverse_bits().leading_ones(), 5);
- assert_eq!(_1.leading_ones(), bits);
- assert_eq!(_1.trailing_ones(), bits);
+ assert_eq!(_1.leading_ones(), $T::BITS);
+ assert_eq!(_1.trailing_ones(), $T::BITS);
assert_eq!((_1 << 1).trailing_ones(), 0);
assert_eq!((_1 >> 1).leading_ones(), 0);
- assert_eq!((_1 << 1).leading_ones(), bits - 1);
- assert_eq!((_1 >> 1).trailing_ones(), bits - 1);
+ assert_eq!((_1 << 1).leading_ones(), $T::BITS - 1);
+ assert_eq!((_1 >> 1).trailing_ones(), $T::BITS - 1);
assert_eq!(_0.leading_ones(), 0);
assert_eq!(_0.trailing_ones(), 0);
#![panic_runtime]
#![allow(unused_features)]
#![feature(core_intrinsics)]
-#![feature(libc)]
#![feature(nll)]
#![feature(panic_runtime)]
#![feature(staged_api)]
}
__rust_abort();
}
- } else if #[cfg(windows)] {
+ } else if #[cfg(all(windows, not(miri)))] {
// On Windows, use the processor-specific __fastfail mechanism. In Windows 8
// and later, this will terminate the process immediately without running any
// in-process exception handlers. In earlier versions of Windows, this
}
pub unsafe fn read_sleb128(&mut self) -> i64 {
- let mut shift: usize = 0;
+ let mut shift: u32 = 0;
let mut result: u64 = 0;
let mut byte: u8;
loop {
}
}
// sign-extend
- if shift < 8 * mem::size_of::<u64>() && (byte & 0x40) != 0 {
+ if shift < u64::BITS && (byte & 0x40) != 0 {
result |= (!0 as u64) << shift;
}
result as i64
#[cfg(target_arch = "hexagon")]
const UNWIND_DATA_REG: (i32, i32) = (0, 1); // R0, R1
-#[cfg(target_arch = "riscv64")]
+#[cfg(any(target_arch = "riscv64", target_arch = "riscv32"))]
const UNWIND_DATA_REG: (i32, i32) = (10, 11); // x10, x11
// The following code is based on GCC's C and C++ personality routines. For reference, see:
issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/"
)]
#![feature(core_intrinsics)]
+#![feature(int_bits_const)]
#![feature(lang_items)]
-#![feature(libc)]
#![feature(nll)]
#![feature(panic_unwind)]
#![feature(staged_api)]
/// This `enum` is constructed through the [`raw_entry_mut`] method on [`HashMap`],
/// then calling one of the methods of that [`RawEntryBuilderMut`].
///
-/// [`Entry`]: enum.Entry.html
/// [`raw_entry_mut`]: HashMap::raw_entry_mut
-/// [`RawEntryBuilderMut`]: struct.RawEntryBuilderMut.html
#[unstable(feature = "hash_raw_entry", issue = "56167")]
pub enum RawEntryMut<'a, K: 'a, V: 'a, S: 'a> {
/// An occupied entry.
/// A view into an occupied entry in a `HashMap`.
/// It is part of the [`Entry`] enum.
-///
-/// [`Entry`]: enum.Entry.html
#[stable(feature = "rust1", since = "1.0.0")]
pub struct OccupiedEntry<'a, K: 'a, V: 'a> {
base: base::RustcOccupiedEntry<'a, K, V>,
/// A view into a vacant entry in a `HashMap`.
/// It is part of the [`Entry`] enum.
-///
-/// [`Entry`]: enum.Entry.html
#[stable(feature = "rust1", since = "1.0.0")]
pub struct VacantEntry<'a, K: 'a, V: 'a> {
base: base::RustcVacantEntry<'a, K, V>,
/// See its documentation for more.
///
/// [`iter`]: HashSet::iter
+///
+/// # Examples
+///
+/// ```
+/// use std::collections::HashSet;
+///
+/// let a: HashSet<u32> = vec![1, 2, 3].into_iter().collect();
+///
+/// let mut iter = a.iter();
+/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Iter<'a, K: 'a> {
base: base::Iter<'a, K>,
/// (provided by the `IntoIterator` trait). See its documentation for more.
///
/// [`into_iter`]: IntoIterator::into_iter
+///
+/// # Examples
+///
+/// ```
+/// use std::collections::HashSet;
+///
+/// let a: HashSet<u32> = vec![1, 2, 3].into_iter().collect();
+///
+/// let mut iter = a.into_iter();
+/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub struct IntoIter<K> {
base: base::IntoIter<K>,
/// See its documentation for more.
///
/// [`drain`]: HashSet::drain
+///
+/// # Examples
+///
+/// ```
+/// use std::collections::HashSet;
+///
+/// let mut a: HashSet<u32> = vec![1, 2, 3].into_iter().collect();
+///
+/// let mut drain = a.drain();
+/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Drain<'a, K: 'a> {
base: base::Drain<'a, K>,
/// This `struct` is created by the [`drain_filter`] method on [`HashSet`].
///
/// [`drain_filter`]: HashSet::drain_filter
+///
+/// # Examples
+///
+/// ```
+/// #![feature(hash_drain_filter)]
+///
+/// use std::collections::HashSet;
+///
+/// let mut a: HashSet<u32> = vec![1, 2, 3].into_iter().collect();
+///
+/// let mut drain_filtered = a.drain_filter(|v| v % 2 == 0);
+/// ```
#[unstable(feature = "hash_drain_filter", issue = "59618")]
pub struct DrainFilter<'a, K, F>
where
/// See its documentation for more.
///
/// [`intersection`]: HashSet::intersection
+///
+/// # Examples
+///
+/// ```
+/// use std::collections::HashSet;
+///
+/// let a: HashSet<u32> = vec![1, 2, 3].into_iter().collect();
+/// let b: HashSet<_> = [4, 2, 3, 4].iter().cloned().collect();
+///
+/// let mut intersection = a.intersection(&b);
+/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Intersection<'a, T: 'a, S: 'a> {
// iterator of the first set
/// See its documentation for more.
///
/// [`difference`]: HashSet::difference
+///
+/// # Examples
+///
+/// ```
+/// use std::collections::HashSet;
+///
+/// let a: HashSet<u32> = vec![1, 2, 3].into_iter().collect();
+/// let b: HashSet<_> = [4, 2, 3, 4].iter().cloned().collect();
+///
+/// let mut difference = a.difference(&b);
+/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Difference<'a, T: 'a, S: 'a> {
// iterator of the first set
/// [`HashSet`]. See its documentation for more.
///
/// [`symmetric_difference`]: HashSet::symmetric_difference
+///
+/// # Examples
+///
+/// ```
+/// use std::collections::HashSet;
+///
+/// let a: HashSet<u32> = vec![1, 2, 3].into_iter().collect();
+/// let b: HashSet<_> = [4, 2, 3, 4].iter().cloned().collect();
+///
+/// let mut intersection = a.symmetric_difference(&b);
+/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub struct SymmetricDifference<'a, T: 'a, S: 'a> {
iter: Chain<Difference<'a, T, S>, Difference<'a, T, S>>,
/// See its documentation for more.
///
/// [`union`]: HashSet::union
+///
+/// # Examples
+///
+/// ```
+/// use std::collections::HashSet;
+///
+/// let a: HashSet<u32> = vec![1, 2, 3].into_iter().collect();
+/// let b: HashSet<_> = [4, 2, 3, 4].iter().cloned().collect();
+///
+/// let mut union_iter = a.union(&b);
+/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Union<'a, T: 'a, S: 'a> {
iter: Chain<Iter<'a, T>, Difference<'a, T, S>>,
#![feature(atomic_mut_ptr)]
#![feature(box_syntax)]
#![feature(c_variadic)]
-#![feature(can_vector)]
#![feature(cfg_accessible)]
#![feature(cfg_target_has_atomic)]
#![feature(cfg_target_thread_local)]
#![feature(gen_future)]
#![feature(generator_trait)]
#![feature(global_asm)]
-#![feature(hash_raw_entry)]
#![feature(hashmap_internals)]
#![feature(int_error_internals)]
#![feature(int_error_matching)]
#![feature(integer_atomics)]
#![feature(into_future)]
#![feature(lang_items)]
-#![feature(libc)]
#![feature(link_args)]
#![feature(linkage)]
#![feature(llvm_asm)]
target_arch = "mips64",
target_arch = "s390x",
target_arch = "sparc64",
- target_arch = "riscv64"
+ target_arch = "riscv64",
+ target_arch = "riscv32"
))]
mod arch {
pub use libc::{blkcnt_t, blksize_t, ino_t, nlink_t, off_t, stat, time_t};
target_arch = "powerpc",
target_arch = "powerpc64",
target_arch = "s390x",
- target_arch = "riscv64"
+ target_arch = "riscv64",
+ target_arch = "riscv32"
)
),
all(target_os = "android", any(target_arch = "aarch64", target_arch = "arm")),
target_arch = "powerpc",
target_arch = "powerpc64",
target_arch = "s390x",
- target_arch = "riscv64"
+ target_arch = "riscv64",
+ target_arch = "riscv32"
)
),
all(target_os = "android", any(target_arch = "aarch64", target_arch = "arm")),
//! [`push`]: PathBuf::push
#![stable(feature = "rust1", since = "1.0.0")]
+#![deny(unsafe_op_in_unsafe_fn)]
#[cfg(test)]
mod tests;
unsafe { &*(s as *const OsStr as *const [u8]) }
}
unsafe fn u8_slice_as_os_str(s: &[u8]) -> &OsStr {
- &*(s as *const [u8] as *const OsStr)
+ // SAFETY: see the comment of `os_str_as_u8_slice`
+ unsafe { &*(s as *const [u8] as *const OsStr) }
}
// Detect scheme on Redox
// basic workhorse for splitting stem and extension
fn split_file_at_dot(file: &OsStr) -> (Option<&OsStr>, Option<&OsStr>) {
- unsafe {
- if os_str_as_u8_slice(file) == b".." {
- return (Some(file), None);
- }
-
- // The unsafety here stems from converting between &OsStr and &[u8]
- // and back. This is safe to do because (1) we only look at ASCII
- // contents of the encoding and (2) new &OsStr values are produced
- // only from ASCII-bounded slices of existing &OsStr values.
+ if os_str_as_u8_slice(file) == b".." {
+ return (Some(file), None);
+ }
- let mut iter = os_str_as_u8_slice(file).rsplitn(2, |b| *b == b'.');
- let after = iter.next();
- let before = iter.next();
- if before == Some(b"") {
- (Some(file), None)
- } else {
- (before.map(|s| u8_slice_as_os_str(s)), after.map(|s| u8_slice_as_os_str(s)))
- }
+ // The unsafety here stems from converting between &OsStr and &[u8]
+ // and back. This is safe to do because (1) we only look at ASCII
+ // contents of the encoding and (2) new &OsStr values are produced
+ // only from ASCII-bounded slices of existing &OsStr values.
+ let mut iter = os_str_as_u8_slice(file).rsplitn(2, |b| *b == b'.');
+ let after = iter.next();
+ let before = iter.next();
+ if before == Some(b"") {
+ (Some(file), None)
+ } else {
+ unsafe { (before.map(|s| u8_slice_as_os_str(s)), after.map(|s| u8_slice_as_os_str(s))) }
}
}
// The following (private!) function allows construction of a path from a u8
// slice, which is only safe when it is known to follow the OsStr encoding.
unsafe fn from_u8_slice(s: &[u8]) -> &Path {
- Path::new(u8_slice_as_os_str(s))
+ unsafe { Path::new(u8_slice_as_os_str(s)) }
}
// The following (private!) function reveals the byte encoding used for OsStr.
fn as_u8_slice(&self) -> &[u8] {
target_arch = "powerpc64",
target_arch = "asmjs",
target_arch = "wasm32",
- target_arch = "hexagon"
+ target_arch = "hexagon",
+ target_arch = "riscv32"
)))]
pub const MIN_ALIGN: usize = 8;
#[cfg(all(any(
#[cfg(target_arch = "sparc64")]
pub const unwinder_private_data_size: usize = 2;
-#[cfg(target_arch = "riscv64")]
+#[cfg(any(target_arch = "riscv64", target_arch = "riscv32"))]
pub const unwinder_private_data_size: usize = 2;
#[cfg(target_os = "emscripten")]
use crate::Build;
-// The version number
-pub const CFG_RELEASE_NUM: &str = "1.48.0";
-
pub struct GitInfo {
inner: Option<Info>,
}
| Subcommand::Build { .. }
| Subcommand::Bench { .. }
| Subcommand::Dist { .. }
- | Subcommand::Install { .. } => assert_eq!(config.stage, 2),
+ | Subcommand::Install { .. } => {
+ assert_eq!(
+ config.stage, 2,
+ "x.py should be run with `--stage 2` on CI, but was run with `--stage {}`",
+ config.stage,
+ );
+ }
Subcommand::Clean { .. }
| Subcommand::Check { .. }
| Subcommand::Clippy { .. }
use crate::builder::{Builder, RunConfig, ShouldRun, Step};
use crate::cache::{Interned, INTERNER};
-use crate::channel;
use crate::compile;
use crate::config::TargetSelection;
use crate::tool::{self, Tool};
&page_dst,
&[
("<INSERT DATE HERE>", &month_year),
- ("<INSERT VERSION HERE>", channel::CFG_RELEASE_NUM),
+ ("<INSERT VERSION HERE>", &builder.version),
],
);
}
let stamp = compile::librustc_stamp(builder, compiler_to_use, target);
copy_target_libs(builder, target, &image, &stamp);
+ // Copy compiler sources.
+ let dst_src = image.join("lib/rustlib/rustc-src/rust");
+ t!(fs::create_dir_all(&dst_src));
+
+ let src_files = ["Cargo.lock"];
+ // This is the reduced set of paths which will become the rustc-dev component
+ // (essentially the compiler crates and all of their path dependencies).
+ copy_src_dirs(builder, &builder.src, &["compiler"], &[], &dst_src);
+ for file in src_files.iter() {
+ builder.copy(&builder.src.join(file), &dst_src.join(file));
+ }
+
let mut cmd = rust_installer(builder);
cmd.arg("generate")
.arg("--product-name=Rust")
}
fn add_env(builder: &Builder<'_>, cmd: &mut Command, target: TargetSelection) {
- let mut parts = channel::CFG_RELEASE_NUM.split('.');
+ let mut parts = builder.version.split('.');
cmd.env("CFG_RELEASE_INFO", builder.rust_version())
- .env("CFG_RELEASE_NUM", channel::CFG_RELEASE_NUM)
+ .env("CFG_RELEASE_NUM", &builder.version)
.env("CFG_RELEASE", builder.rust_release())
.env("CFG_VER_MAJOR", parts.next().unwrap())
.env("CFG_VER_MINOR", parts.next().unwrap())
.arg("-Z")
.arg("unstable-options")
.arg("--resource-suffix")
- .arg(crate::channel::CFG_RELEASE_NUM)
+ .arg(&builder.version)
.arg("--index-page")
.arg(&builder.src.join("src/doc/index.md"));
let mut index = tool::ErrorIndex::command(builder, self.compiler);
index.arg("html");
index.arg(out.join("error-index.html"));
- index.arg(crate::channel::CFG_RELEASE_NUM);
+ index.arg(&builder.version);
builder.run(&mut index);
}
impl Flags {
pub fn parse(args: &[String]) -> Flags {
- let mut extra_help = String::new();
let mut subcommand_help = String::from(
"\
Usage: x.py <subcommand> [options] [<paths>...]
"VALUE",
);
- // fn usage()
- let usage =
- |exit_code: i32, opts: &Options, subcommand_help: &str, extra_help: &str| -> ! {
- println!("{}", opts.usage(subcommand_help));
- if !extra_help.is_empty() {
- println!("{}", extra_help);
- }
- process::exit(exit_code);
- };
-
// We can't use getopt to parse the options until we have completed specifying which
// options are valid, but under the current implementation, some options are conditional on
// the subcommand. Therefore we must manually identify the subcommand first, so that we can
_ => {}
};
+ // fn usage()
+ let usage = |exit_code: i32, opts: &Options, verbose: bool, subcommand_help: &str| -> ! {
+ let mut extra_help = String::new();
+
+ // All subcommands except `clean` can have an optional "Available paths" section
+ if verbose {
+ let config = Config::parse(&["build".to_string()]);
+ let build = Build::new(config);
+
+ let maybe_rules_help = Builder::get_help(&build, subcommand.as_str());
+ extra_help.push_str(maybe_rules_help.unwrap_or_default().as_str());
+ } else if !(subcommand.as_str() == "clean" || subcommand.as_str() == "fmt") {
+ extra_help.push_str(
+ format!("Run `./x.py {} -h -v` to see a list of available paths.", subcommand)
+ .as_str(),
+ );
+ }
+
+ println!("{}", opts.usage(subcommand_help));
+ if !extra_help.is_empty() {
+ println!("{}", extra_help);
+ }
+ process::exit(exit_code);
+ };
+
// Done specifying what options are possible, so do the getopts parsing
let matches = opts.parse(&args[..]).unwrap_or_else(|e| {
// Invalid argument/option format
println!("\n{}\n", e);
- usage(1, &opts, &subcommand_help, &extra_help);
+ usage(1, &opts, false, &subcommand_help);
});
+
// Extra sanity check to make sure we didn't hit this crazy corner case:
//
// ./x.py --frobulate clean build
let paths = matches.free[1..].iter().map(|p| p.into()).collect::<Vec<PathBuf>>();
let cfg_file = env::var_os("BOOTSTRAP_CONFIG").map(PathBuf::from);
-
- // All subcommands except `clean` can have an optional "Available paths" section
- if matches.opt_present("verbose") {
- let config = Config::parse(&["build".to_string()]);
- let build = Build::new(config);
-
- let maybe_rules_help = Builder::get_help(&build, subcommand.as_str());
- extra_help.push_str(maybe_rules_help.unwrap_or_default().as_str());
- } else if !(subcommand.as_str() == "clean" || subcommand.as_str() == "fmt") {
- extra_help.push_str(
- format!("Run `./x.py {} -h -v` to see a list of available paths.", subcommand)
- .as_str(),
- );
- }
+ let verbose = matches.opt_present("verbose");
// User passed in -h/--help?
if matches.opt_present("help") {
- usage(0, &opts, &subcommand_help, &extra_help);
+ usage(0, &opts, verbose, &subcommand_help);
}
let cmd = match subcommand.as_str() {
"clean" => {
if !paths.is_empty() {
println!("\nclean does not take a path argument\n");
- usage(1, &opts, &subcommand_help, &extra_help);
+ usage(1, &opts, verbose, &subcommand_help);
}
Subcommand::Clean { all: matches.opt_present("all") }
"run" | "r" => {
if paths.is_empty() {
println!("\nrun requires at least a path!\n");
- usage(1, &opts, &subcommand_help, &extra_help);
+ usage(1, &opts, verbose, &subcommand_help);
}
Subcommand::Run { paths }
}
_ => {
- usage(1, &opts, &subcommand_help, &extra_help);
+ usage(1, &opts, verbose, &subcommand_help);
}
};
/// User-specified configuration from `config.toml`.
config: Config,
+ // Version information
+ version: String,
+
// Properties derived from the above configuration
src: PathBuf,
out: PathBuf,
.unwrap()
.to_path_buf();
+ let version = std::fs::read_to_string(src.join("src").join("version"))
+ .expect("failed to read src/version");
+ let version = version.trim();
+
let mut build = Build {
initial_rustc: config.initial_rustc.clone(),
initial_cargo: config.initial_cargo.clone(),
targets: config.targets.clone(),
config,
+ version: version.to_string(),
src,
out,
.next()
.unwrap()
.trim();
- let my_version = channel::CFG_RELEASE_NUM;
- if local_release.split('.').take(2).eq(my_version.split('.').take(2)) {
+ if local_release.split('.').take(2).eq(version.split('.').take(2)) {
build.verbose(&format!("auto-detected local-rebuild {}", local_release));
build.local_rebuild = true;
}
match which {
GitRepo::Rustc => {
- let sha = self.rust_sha().unwrap_or(channel::CFG_RELEASE_NUM);
+ let sha = self.rust_sha().unwrap_or(&self.version);
Some(format!("/rustc/{}", sha))
}
GitRepo::Llvm => Some(String::from("/rustc/llvm")),
/// Returns the value of `release` above for Rust itself.
fn rust_release(&self) -> String {
- self.release(channel::CFG_RELEASE_NUM)
+ self.release(&self.version)
}
/// Returns the "package version" for a component given the `num` release
/// Returns the value of `package_vers` above for Rust itself.
fn rust_package_vers(&self) -> String {
- self.package_vers(channel::CFG_RELEASE_NUM)
+ self.package_vers(&self.version)
}
/// Returns the value of `package_vers` above for Cargo
}
fn llvm_tools_package_vers(&self) -> String {
- self.package_vers(channel::CFG_RELEASE_NUM)
+ self.package_vers(&self.version)
}
fn llvm_tools_vers(&self) -> String {
/// Note that this is a descriptive string which includes the commit date,
/// sha, version, etc.
fn rust_version(&self) -> String {
- self.rust_info.version(self, channel::CFG_RELEASE_NUM)
+ self.rust_info.version(self, &self.version)
}
/// Returns the full commit hash.
use build_helper::{output, t};
use crate::builder::{Builder, RunConfig, ShouldRun, Step};
-use crate::channel;
use crate::config::TargetSelection;
use crate::util::{self, exe};
use crate::GitRepo;
// release number on the dev channel.
cfg.define("LLVM_VERSION_SUFFIX", "-rust-dev");
} else {
- let suffix = format!("-rust-{}-{}", channel::CFG_RELEASE_NUM, builder.config.channel);
+ let suffix = format!("-rust-{}-{}", builder.version, builder.config.channel);
cfg.define("LLVM_VERSION_SUFFIX", suffix);
}
.arg("--crate-name")
.arg("std")
.arg("--resource-suffix")
- .arg(crate::channel::CFG_RELEASE_NUM)
+ .arg(&builder.version)
.arg("--doc-folder")
.arg(builder.doc_out(self.target))
.arg("--test-folder")
use build_helper::t;
use crate::builder::{Builder, Cargo as CargoCommand, RunConfig, ShouldRun, Step};
-use crate::channel;
use crate::channel::GitInfo;
use crate::compile;
use crate::config::TargetSelection;
cargo.env("CFG_RELEASE", builder.rust_release());
cargo.env("CFG_RELEASE_CHANNEL", &builder.config.channel);
cargo.env("CFG_VERSION", builder.rust_version());
- cargo.env("CFG_RELEASE_NUM", channel::CFG_RELEASE_NUM);
+ cargo.env("CFG_RELEASE_NUM", &builder.version);
let info = GitInfo::new(builder.config.ignore_git, &dir);
if let Some(sha) = info.sha() {
dist-x86_64-apple:
SCRIPT: ./x.py dist
- INITIAL_RUST_CONFIGURE_ARGS: --host=x86_64-apple-darwin --target=aarch64-apple-ios,x86_64-apple-ios --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false
+ INITIAL_RUST_CONFIGURE_ARGS: --host=x86_64-apple-darwin --target=x86_64-apple-darwin,aarch64-apple-ios,x86_64-apple-ios --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false
RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
MACOSX_DEPLOYMENT_TARGET: 10.7
NO_LLVM_ASSERTIONS: 1
- name: dist-x86_64-apple
env:
SCRIPT: ./x.py dist
- RUST_CONFIGURE_ARGS: --host=x86_64-apple-darwin --target=aarch64-apple-ios,x86_64-apple-ios --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false
- RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
- MACOSX_DEPLOYMENT_TARGET: 10.7
- NO_LLVM_ASSERTIONS: 1
- NO_DEBUG_ASSERTIONS: 1
- DIST_REQUIRE_ALL_TOOLS: 1
- <<: *job-macos-xl
-
- - name: dist-x86_64-apple-alt
- env:
- SCRIPT: ./x.py dist
- RUST_CONFIGURE_ARGS: --enable-extended --enable-profiler --set rust.jemalloc --set llvm.ninja=false
- RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
- MACOSX_DEPLOYMENT_TARGET: 10.7
- NO_LLVM_ASSERTIONS: 1
- NO_DEBUG_ASSERTIONS: 1
- <<: *job-macos-xl
-
- - name: x86_64-apple
- env:
- SCRIPT: ./x.py --stage 2 test
- RUST_CONFIGURE_ARGS: --build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false
- RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
- MACOSX_DEPLOYMENT_TARGET: 10.8
- MACOSX_STD_DEPLOYMENT_TARGET: 10.7
- NO_LLVM_ASSERTIONS: 1
- NO_DEBUG_ASSERTIONS: 1
- <<: *job-macos-xl
-
- ####################
- # macOS Builders #
- ####################
-
- - name: dist-x86_64-apple
- env:
- SCRIPT: ./x.py dist
- RUST_CONFIGURE_ARGS: --host=x86_64-apple-darwin --target=aarch64-apple-ios,x86_64-apple-ios --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false
+ RUST_CONFIGURE_ARGS: --host=x86_64-apple-darwin --target=x86_64-apple-darwin,aarch64-apple-ios,x86_64-apple-ios --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false
RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
MACOSX_DEPLOYMENT_TARGET: 10.7
NO_LLVM_ASSERTIONS: 1
RUST_CONFIGURE_ARGS: >-
--build=i686-pc-windows-msvc
--host=i686-pc-windows-msvc
- --target=i586-pc-windows-msvc
+ --target=i686-pc-windows-msvc,i586-pc-windows-msvc
--enable-full-tools
--enable-profiler
SCRIPT: python x.py dist
attrs: Attrs<'_>,
other_attrs: Option<Attrs<'_>>,
) -> clean::Attributes {
- let mut merged_attrs: Vec<ast::Attribute> = Vec::with_capacity(attrs.len());
- // If we have additional attributes (from a re-export),
+ // NOTE: If we have additional attributes (from a re-export),
// always insert them first. This ensure that re-export
// doc comments show up before the original doc comments
// when we render them.
- if let Some(a) = other_attrs {
- merged_attrs.extend(a.iter().cloned());
- }
- merged_attrs.extend(attrs.to_vec());
+ let merged_attrs = if let Some(inner) = other_attrs {
+ let mut both = inner.to_vec();
+ both.extend_from_slice(attrs);
+ both
+ } else {
+ attrs.to_vec()
+ };
merged_attrs.clean(cx)
}
// This checks the constants from {low,high}_align_const, they share the same
// constant, but the alignment differs, so the higher one should be used
-// CHECK: [[LOW_HIGH:@[0-9]+]] = {{.*}} getelementptr inbounds (<{ [8 x i8] }>, <{ [8 x i8] }>* @alloc20, i32 0, i32 0, i32 0), {{.*}}
+// CHECK: [[LOW_HIGH:@alloc[0-9]+]] = {{.*}}, align 4
#[derive(Copy, Clone)]
// repr(i16) is required for the {low,high}_align_const test
#[no_mangle]
pub fn low_align_const() -> E<i16, [i16; 3]> {
// Check that low_align_const and high_align_const use the same constant
- // CHECK: load %"E<i16, [i16; 3]>"*, %"E<i16, [i16; 3]>"** bitcast (<{ i8*, [0 x i8] }>* [[LOW_HIGH]] to %"E<i16, [i16; 3]>"**),
+ // CHECK: memcpy.p0i8.p0i8.i{{(32|64)}}(i8* align 2 %1, i8* align 2 getelementptr inbounds (<{ [8 x i8] }>, <{ [8 x i8] }>* [[LOW_HIGH]], i32 0, i32 0, i32 0), i{{(32|64)}} 8, i1 false)
*&E::A(0)
}
#[no_mangle]
pub fn high_align_const() -> E<i16, i32> {
// Check that low_align_const and high_align_const use the same constant
- // CHECK: load %"E<i16, i32>"*, %"E<i16, i32>"** bitcast (<{ i8*, [0 x i8] }>* [[LOW_HIGH]] to %"E<i16, i32>"**),
+ // CHECK: memcpy.p0i8.p0i8.i{{(32|64)}}(i8* align 4 %1, i8* align 4 getelementptr inbounds (<{ [8 x i8] }>, <{ [8 x i8] }>* [[LOW_HIGH]], i32 0, i32 0, i32 0), i{{(32|64)}} 8, i1 false)
*&E::A(0)
}
struct Foo {
bytes: [u8; unsafe { intrinsics::size_of::<Foo>() }],
- //~^ ERROR cycle detected when const-evaluating + checking
+ //~^ ERROR cycle detected when simplifying constant for the type system
x: usize,
}
type Arr = [u8; 8];
#[cfg(cfail)]
type Arr = [u8; Self::C];
- //[cfail]~^ ERROR cycle detected when const-evaluating
+ //[cfail]~^ ERROR cycle detected when simplifying constant
}
fn main() {}
}
alloc0 (static: FOO, size: 8, align: 4) {
- ╾─alloc17─╼ 03 00 00 00 │ ╾──╼....
+ ╾─alloc14─╼ 03 00 00 00 │ ╾──╼....
}
-alloc17 (size: 48, align: 4) {
+alloc14 (size: 48, align: 4) {
0x00 │ 00 00 00 00 __ __ __ __ ╾─alloc4──╼ 00 00 00 00 │ ....░░░░╾──╼....
- 0x10 │ 00 00 00 00 __ __ __ __ ╾─alloc8──╼ 02 00 00 00 │ ....░░░░╾──╼....
- 0x20 │ 01 00 00 00 2a 00 00 00 ╾─alloc13─╼ 03 00 00 00 │ ....*...╾──╼....
+ 0x10 │ 00 00 00 00 __ __ __ __ ╾─alloc7──╼ 02 00 00 00 │ ....░░░░╾──╼....
+ 0x20 │ 01 00 00 00 2a 00 00 00 ╾─alloc11─╼ 03 00 00 00 │ ....*...╾──╼....
}
alloc4 (size: 0, align: 4) {}
-alloc8 (size: 16, align: 4) {
- ╾─alloc7──╼ 03 00 00 00 ╾─alloc9──╼ 03 00 00 00 │ ╾──╼....╾──╼....
+alloc7 (size: 16, align: 4) {
+ ╾─alloc6──╼ 03 00 00 00 ╾─alloc8──╼ 03 00 00 00 │ ╾──╼....╾──╼....
}
-alloc7 (size: 3, align: 1) {
+alloc6 (size: 3, align: 1) {
66 6f 6f │ foo
}
-alloc9 (size: 3, align: 1) {
+alloc8 (size: 3, align: 1) {
62 61 72 │ bar
}
-alloc13 (size: 24, align: 4) {
- 0x00 │ ╾─alloc12─╼ 03 00 00 00 ╾─alloc14─╼ 03 00 00 00 │ ╾──╼....╾──╼....
- 0x10 │ ╾─alloc15─╼ 04 00 00 00 │ ╾──╼....
+alloc11 (size: 24, align: 4) {
+ 0x00 │ ╾─alloc10─╼ 03 00 00 00 ╾─alloc12─╼ 03 00 00 00 │ ╾──╼....╾──╼....
+ 0x10 │ ╾─alloc13─╼ 04 00 00 00 │ ╾──╼....
}
-alloc12 (size: 3, align: 1) {
+alloc10 (size: 3, align: 1) {
6d 65 68 │ meh
}
-alloc14 (size: 3, align: 1) {
+alloc12 (size: 3, align: 1) {
6d 6f 70 │ mop
}
-alloc15 (size: 4, align: 1) {
+alloc13 (size: 4, align: 1) {
6d c3 b6 70 │ m..p
}
}
alloc0 (static: FOO, size: 16, align: 8) {
- ╾───────alloc17───────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........
+ ╾───────alloc14───────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........
}
-alloc17 (size: 72, align: 8) {
+alloc14 (size: 72, align: 8) {
0x00 │ 00 00 00 00 __ __ __ __ ╾───────alloc4────────╼ │ ....░░░░╾──────╼
0x10 │ 00 00 00 00 00 00 00 00 00 00 00 00 __ __ __ __ │ ............░░░░
- 0x20 │ ╾───────alloc8────────╼ 02 00 00 00 00 00 00 00 │ ╾──────╼........
- 0x30 │ 01 00 00 00 2a 00 00 00 ╾───────alloc13───────╼ │ ....*...╾──────╼
+ 0x20 │ ╾───────alloc7────────╼ 02 00 00 00 00 00 00 00 │ ╾──────╼........
+ 0x30 │ 01 00 00 00 2a 00 00 00 ╾───────alloc11───────╼ │ ....*...╾──────╼
0x40 │ 03 00 00 00 00 00 00 00 │ ........
}
alloc4 (size: 0, align: 8) {}
-alloc8 (size: 32, align: 8) {
- 0x00 │ ╾───────alloc7────────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........
- 0x10 │ ╾───────alloc9────────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........
+alloc7 (size: 32, align: 8) {
+ 0x00 │ ╾───────alloc6────────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........
+ 0x10 │ ╾───────alloc8────────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........
}
-alloc7 (size: 3, align: 1) {
+alloc6 (size: 3, align: 1) {
66 6f 6f │ foo
}
-alloc9 (size: 3, align: 1) {
+alloc8 (size: 3, align: 1) {
62 61 72 │ bar
}
-alloc13 (size: 48, align: 8) {
- 0x00 │ ╾───────alloc12───────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........
- 0x10 │ ╾───────alloc14───────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........
- 0x20 │ ╾───────alloc15───────╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........
+alloc11 (size: 48, align: 8) {
+ 0x00 │ ╾───────alloc10───────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........
+ 0x10 │ ╾───────alloc12───────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........
+ 0x20 │ ╾───────alloc13───────╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........
}
-alloc12 (size: 3, align: 1) {
+alloc10 (size: 3, align: 1) {
6d 65 68 │ meh
}
-alloc14 (size: 3, align: 1) {
+alloc12 (size: 3, align: 1) {
6d 6f 70 │ mop
}
-alloc15 (size: 4, align: 1) {
+alloc13 (size: 4, align: 1) {
6d c3 b6 70 │ m..p
}
}
alloc0 (static: FOO, size: 8, align: 4) {
- ╾─alloc23─╼ 03 00 00 00 │ ╾──╼....
+ ╾─alloc20─╼ 03 00 00 00 │ ╾──╼....
}
-alloc23 (size: 48, align: 4) {
+alloc20 (size: 48, align: 4) {
0x00 │ 00 00 00 00 __ __ __ __ ╾─alloc8──╼ 00 00 00 00 │ ....░░░░╾──╼....
- 0x10 │ 00 00 00 00 __ __ __ __ ╾─alloc13─╼ 02 00 00 00 │ ....░░░░╾──╼....
- 0x20 │ 01 00 00 00 2a 00 00 00 ╾─alloc21─╼ 03 00 00 00 │ ....*...╾──╼....
+ 0x10 │ 00 00 00 00 __ __ __ __ ╾─alloc12─╼ 02 00 00 00 │ ....░░░░╾──╼....
+ 0x20 │ 01 00 00 00 2a 00 00 00 ╾─alloc19─╼ 03 00 00 00 │ ....*...╾──╼....
}
alloc8 (size: 0, align: 4) {}
-alloc13 (size: 8, align: 4) {
- ╾─alloc11─╼ ╾─alloc12─╼ │ ╾──╼╾──╼
+alloc12 (size: 8, align: 4) {
+ ╾─alloc10─╼ ╾─alloc11─╼ │ ╾──╼╾──╼
}
-alloc11 (size: 1, align: 1) {
+alloc10 (size: 1, align: 1) {
05 │ .
}
-alloc12 (size: 1, align: 1) {
+alloc11 (size: 1, align: 1) {
06 │ .
}
-alloc21 (size: 12, align: 4) {
- ╾─a17+0x3─╼ ╾─alloc18─╼ ╾─a20+0x2─╼ │ ╾──╼╾──╼╾──╼
+alloc19 (size: 12, align: 4) {
+ ╾─a15+0x3─╼ ╾─alloc16─╼ ╾─a18+0x2─╼ │ ╾──╼╾──╼╾──╼
}
-alloc17 (size: 4, align: 1) {
+alloc15 (size: 4, align: 1) {
2a 45 15 6f │ *E.o
}
-alloc18 (size: 1, align: 1) {
+alloc16 (size: 1, align: 1) {
2a │ *
}
-alloc20 (size: 4, align: 1) {
+alloc18 (size: 4, align: 1) {
2a 45 15 6f │ *E.o
}
}
alloc0 (static: FOO, size: 16, align: 8) {
- ╾───────alloc23───────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........
+ ╾───────alloc20───────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........
}
-alloc23 (size: 72, align: 8) {
+alloc20 (size: 72, align: 8) {
0x00 │ 00 00 00 00 __ __ __ __ ╾───────alloc8────────╼ │ ....░░░░╾──────╼
0x10 │ 00 00 00 00 00 00 00 00 00 00 00 00 __ __ __ __ │ ............░░░░
- 0x20 │ ╾───────alloc13───────╼ 02 00 00 00 00 00 00 00 │ ╾──────╼........
- 0x30 │ 01 00 00 00 2a 00 00 00 ╾───────alloc21───────╼ │ ....*...╾──────╼
+ 0x20 │ ╾───────alloc12───────╼ 02 00 00 00 00 00 00 00 │ ╾──────╼........
+ 0x30 │ 01 00 00 00 2a 00 00 00 ╾───────alloc19───────╼ │ ....*...╾──────╼
0x40 │ 03 00 00 00 00 00 00 00 │ ........
}
alloc8 (size: 0, align: 8) {}
-alloc13 (size: 16, align: 8) {
- ╾───────alloc11───────╼ ╾───────alloc12───────╼ │ ╾──────╼╾──────╼
+alloc12 (size: 16, align: 8) {
+ ╾───────alloc10───────╼ ╾───────alloc11───────╼ │ ╾──────╼╾──────╼
}
-alloc11 (size: 1, align: 1) {
+alloc10 (size: 1, align: 1) {
05 │ .
}
-alloc12 (size: 1, align: 1) {
+alloc11 (size: 1, align: 1) {
06 │ .
}
-alloc21 (size: 24, align: 8) {
- 0x00 │ ╾─────alloc17+0x3─────╼ ╾───────alloc18───────╼ │ ╾──────╼╾──────╼
- 0x10 │ ╾─────alloc20+0x2─────╼ │ ╾──────╼
+alloc19 (size: 24, align: 8) {
+ 0x00 │ ╾─────alloc15+0x3─────╼ ╾───────alloc16───────╼ │ ╾──────╼╾──────╼
+ 0x10 │ ╾─────alloc18+0x2─────╼ │ ╾──────╼
}
-alloc17 (size: 4, align: 1) {
+alloc15 (size: 4, align: 1) {
2a 45 15 6f │ *E.o
}
-alloc18 (size: 1, align: 1) {
+alloc16 (size: 1, align: 1) {
2a │ *
}
-alloc20 (size: 4, align: 1) {
+alloc18 (size: 4, align: 1) {
2a 45 15 6f │ *E.o
}
}
alloc0 (static: FOO, size: 4, align: 4) {
- ╾─alloc9──╼ │ ╾──╼
+ ╾─alloc3──╼ │ ╾──╼
}
-alloc9 (size: 168, align: 1) {
+alloc3 (size: 168, align: 1) {
0x00 │ ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab │ ................
0x10 │ ab ab ab ab ab ab ab ab ab ab ab ab ╾─alloc4──╼ │ ............╾──╼
0x20 │ 01 ef cd ab 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
}
alloc0 (static: FOO, size: 8, align: 8) {
- ╾───────alloc9────────╼ │ ╾──────╼
+ ╾───────alloc3────────╼ │ ╾──────╼
}
-alloc9 (size: 180, align: 1) {
+alloc3 (size: 180, align: 1) {
0x00 │ ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab │ ................
0x10 │ ab ab ab ab ab ab ab ab ab ab ab ab ╾──alloc4── │ ............╾───
0x20 │ ──────────╼ 01 ef cd ab 00 00 00 00 00 00 00 00 │ ───╼............
let mut _0: u32; // return place in scope 0 at $DIR/copy_propagation.rs:3:20: 3:23
let _2: u32; // in scope 0 at $DIR/copy_propagation.rs:4:9: 4:10
scope 1 {
-- debug y => _2; // in scope 1 at $DIR/copy_propagation.rs:4:9: 4:10
-+ debug y => _1; // in scope 1 at $DIR/copy_propagation.rs:4:9: 4:10
+ debug y => _0; // in scope 1 at $DIR/copy_propagation.rs:4:9: 4:10
}
bb0: {
-- StorageLive(_2); // scope 0 at $DIR/copy_propagation.rs:4:9: 4:10
-- _2 = _1; // scope 0 at $DIR/copy_propagation.rs:4:13: 4:14
-- _0 = _2; // scope 1 at $DIR/copy_propagation.rs:5:5: 5:6
-- StorageDead(_2); // scope 0 at $DIR/copy_propagation.rs:6:1: 6:2
-+ nop; // scope 0 at $DIR/copy_propagation.rs:4:9: 4:10
-+ nop; // scope 0 at $DIR/copy_propagation.rs:4:13: 4:14
-+ _0 = _1; // scope 1 at $DIR/copy_propagation.rs:5:5: 5:6
-+ nop; // scope 0 at $DIR/copy_propagation.rs:6:1: 6:2
+ nop; // scope 0 at $DIR/copy_propagation.rs:4:9: 4:10
+ _0 = _1; // scope 0 at $DIR/copy_propagation.rs:4:13: 4:14
+ nop; // scope 1 at $DIR/copy_propagation.rs:5:5: 5:6
+ nop; // scope 0 at $DIR/copy_propagation.rs:6:1: 6:2
return; // scope 0 at $DIR/copy_propagation.rs:6:2: 6:2
}
}
let mut _0: i32; // return place in scope 0 at $DIR/copy_propagation_arg.rs:27:27: 27:30
let _2: i32; // in scope 0 at $DIR/copy_propagation_arg.rs:28:9: 28:10
scope 1 {
- debug y => _2; // in scope 1 at $DIR/copy_propagation_arg.rs:28:9: 28:10
+ debug y => _0; // in scope 1 at $DIR/copy_propagation_arg.rs:28:9: 28:10
}
bb0: {
- StorageLive(_2); // scope 0 at $DIR/copy_propagation_arg.rs:28:9: 28:10
- _2 = _1; // scope 0 at $DIR/copy_propagation_arg.rs:28:13: 28:14
+ nop; // scope 0 at $DIR/copy_propagation_arg.rs:28:9: 28:10
+ _0 = _1; // scope 0 at $DIR/copy_propagation_arg.rs:28:13: 28:14
_1 = const 123_i32; // scope 1 at $DIR/copy_propagation_arg.rs:29:5: 29:12
- _0 = _2; // scope 1 at $DIR/copy_propagation_arg.rs:30:5: 30:6
- StorageDead(_2); // scope 0 at $DIR/copy_propagation_arg.rs:31:1: 31:2
+ nop; // scope 1 at $DIR/copy_propagation_arg.rs:30:5: 30:6
+ nop; // scope 0 at $DIR/copy_propagation_arg.rs:31:1: 31:2
return; // scope 0 at $DIR/copy_propagation_arg.rs:31:2: 31:2
}
}
let mut _2: i32; // in scope 0 at $DIR/copy_propagation_arg.rs:23:9: 23:10
bb0: {
- StorageLive(_2); // scope 0 at $DIR/copy_propagation_arg.rs:23:9: 23:10
- _2 = _1; // scope 0 at $DIR/copy_propagation_arg.rs:23:9: 23:10
- _1 = move _2; // scope 0 at $DIR/copy_propagation_arg.rs:23:5: 23:10
- StorageDead(_2); // scope 0 at $DIR/copy_propagation_arg.rs:23:9: 23:10
+ nop; // scope 0 at $DIR/copy_propagation_arg.rs:23:9: 23:10
+ nop; // scope 0 at $DIR/copy_propagation_arg.rs:23:9: 23:10
+ nop; // scope 0 at $DIR/copy_propagation_arg.rs:23:5: 23:10
+ nop; // scope 0 at $DIR/copy_propagation_arg.rs:23:9: 23:10
_0 = const (); // scope 0 at $DIR/copy_propagation_arg.rs:21:20: 24:2
return; // scope 0 at $DIR/copy_propagation_arg.rs:24:2: 24:2
}
let mut _3: u8; // in scope 0 at $DIR/copy_propagation_arg.rs:11:15: 11:16
bb0: {
- StorageLive(_2); // scope 0 at $DIR/copy_propagation_arg.rs:11:9: 11:17
+ nop; // scope 0 at $DIR/copy_propagation_arg.rs:11:9: 11:17
StorageLive(_3); // scope 0 at $DIR/copy_propagation_arg.rs:11:15: 11:16
_3 = _1; // scope 0 at $DIR/copy_propagation_arg.rs:11:15: 11:16
- _2 = dummy(move _3) -> bb1; // scope 0 at $DIR/copy_propagation_arg.rs:11:9: 11:17
+ _1 = dummy(move _3) -> bb1; // scope 0 at $DIR/copy_propagation_arg.rs:11:9: 11:17
// mir::Constant
// + span: $DIR/copy_propagation_arg.rs:11:9: 11:14
// + literal: Const { ty: fn(u8) -> u8 {dummy}, val: Value(Scalar(<ZST>)) }
bb1: {
StorageDead(_3); // scope 0 at $DIR/copy_propagation_arg.rs:11:16: 11:17
- _1 = move _2; // scope 0 at $DIR/copy_propagation_arg.rs:11:5: 11:17
- StorageDead(_2); // scope 0 at $DIR/copy_propagation_arg.rs:11:16: 11:17
+ nop; // scope 0 at $DIR/copy_propagation_arg.rs:11:5: 11:17
+ nop; // scope 0 at $DIR/copy_propagation_arg.rs:11:16: 11:17
_0 = const (); // scope 0 at $DIR/copy_propagation_arg.rs:9:19: 12:2
return; // scope 0 at $DIR/copy_propagation_arg.rs:12:2: 12:2
}
--- /dev/null
+- // MIR for `main` before DestinationPropagation
++ // MIR for `main` after DestinationPropagation
+
+ fn main() -> () {
+ let mut _0: (); // return place in scope 0 at $DIR/branch.rs:12:11: 12:11
+ let _1: i32; // in scope 0 at $DIR/branch.rs:13:9: 13:10
+ let mut _3: bool; // in scope 0 at $DIR/branch.rs:15:16: 15:22
+ let _4: i32; // in scope 0 at $DIR/branch.rs:18:9: 18:14
+ scope 1 {
+- debug x => _1; // in scope 1 at $DIR/branch.rs:13:9: 13:10
++ debug x => _2; // in scope 1 at $DIR/branch.rs:13:9: 13:10
+ let _2: i32; // in scope 1 at $DIR/branch.rs:15:9: 15:10
+ scope 2 {
+ debug y => _2; // in scope 2 at $DIR/branch.rs:15:9: 15:10
+ }
+ }
+
+ bb0: {
+- StorageLive(_1); // scope 0 at $DIR/branch.rs:13:9: 13:10
+- _1 = val() -> bb1; // scope 0 at $DIR/branch.rs:13:13: 13:18
++ nop; // scope 0 at $DIR/branch.rs:13:9: 13:10
++ _2 = val() -> bb1; // scope 0 at $DIR/branch.rs:13:13: 13:18
+ // mir::Constant
+ // + span: $DIR/branch.rs:13:13: 13:16
+ // + literal: Const { ty: fn() -> i32 {val}, val: Value(Scalar(<ZST>)) }
+ }
+
+ bb1: {
+- StorageLive(_2); // scope 1 at $DIR/branch.rs:15:9: 15:10
++ nop; // scope 1 at $DIR/branch.rs:15:9: 15:10
+ StorageLive(_3); // scope 1 at $DIR/branch.rs:15:16: 15:22
+ _3 = cond() -> bb2; // scope 1 at $DIR/branch.rs:15:16: 15:22
+ // mir::Constant
+ // + span: $DIR/branch.rs:15:16: 15:20
+ // + literal: Const { ty: fn() -> bool {cond}, val: Value(Scalar(<ZST>)) }
+ }
+
+ bb2: {
+ switchInt(_3) -> [false: bb3, otherwise: bb4]; // scope 1 at $DIR/branch.rs:15:13: 20:6
+ }
+
+ bb3: {
+ StorageLive(_4); // scope 1 at $DIR/branch.rs:18:9: 18:14
+ _4 = val() -> bb5; // scope 1 at $DIR/branch.rs:18:9: 18:14
+ // mir::Constant
+ // + span: $DIR/branch.rs:18:9: 18:12
+ // + literal: Const { ty: fn() -> i32 {val}, val: Value(Scalar(<ZST>)) }
+ }
+
+ bb4: {
+- _2 = _1; // scope 1 at $DIR/branch.rs:16:9: 16:10
++ nop; // scope 1 at $DIR/branch.rs:16:9: 16:10
+ goto -> bb6; // scope 1 at $DIR/branch.rs:15:13: 20:6
+ }
+
+ bb5: {
+ StorageDead(_4); // scope 1 at $DIR/branch.rs:18:14: 18:15
+- _2 = _1; // scope 1 at $DIR/branch.rs:19:9: 19:10
++ nop; // scope 1 at $DIR/branch.rs:19:9: 19:10
+ goto -> bb6; // scope 1 at $DIR/branch.rs:15:13: 20:6
+ }
+
+ bb6: {
+ StorageDead(_3); // scope 1 at $DIR/branch.rs:20:6: 20:7
+ _0 = const (); // scope 0 at $DIR/branch.rs:12:11: 21:2
+- StorageDead(_2); // scope 1 at $DIR/branch.rs:21:1: 21:2
+- StorageDead(_1); // scope 0 at $DIR/branch.rs:21:1: 21:2
++ nop; // scope 1 at $DIR/branch.rs:21:1: 21:2
++ nop; // scope 0 at $DIR/branch.rs:21:1: 21:2
+ return; // scope 0 at $DIR/branch.rs:21:2: 21:2
+ }
+ }
+
--- /dev/null
+//! Tests that assignment in both branches of an `if` are eliminated.
+
+fn val() -> i32 {
+ 1
+}
+
+fn cond() -> bool {
+ true
+}
+
+// EMIT_MIR branch.main.DestinationPropagation.diff
+fn main() {
+ let x = val();
+
+ let y = if cond() {
+ x
+ } else {
+ val();
+ x
+ };
+}
--- /dev/null
+- // MIR for `main` before DestinationPropagation
++ // MIR for `main` after DestinationPropagation
+
+ fn main() -> () {
+ let mut _0: (); // return place in scope 0 at $DIR/cycle.rs:8:11: 8:11
+ let mut _1: i32; // in scope 0 at $DIR/cycle.rs:9:9: 9:14
+ let mut _4: i32; // in scope 0 at $DIR/cycle.rs:12:9: 12:10
+ let _5: (); // in scope 0 at $DIR/cycle.rs:14:5: 14:12
+ let mut _6: i32; // in scope 0 at $DIR/cycle.rs:14:10: 14:11
+ scope 1 {
+- debug x => _1; // in scope 1 at $DIR/cycle.rs:9:9: 9:14
++ debug x => _4; // in scope 1 at $DIR/cycle.rs:9:9: 9:14
+ let _2: i32; // in scope 1 at $DIR/cycle.rs:10:9: 10:10
+ scope 2 {
+- debug y => _2; // in scope 2 at $DIR/cycle.rs:10:9: 10:10
++ debug y => _4; // in scope 2 at $DIR/cycle.rs:10:9: 10:10
+ let _3: i32; // in scope 2 at $DIR/cycle.rs:11:9: 11:10
+ scope 3 {
+- debug z => _3; // in scope 3 at $DIR/cycle.rs:11:9: 11:10
++ debug z => _4; // in scope 3 at $DIR/cycle.rs:11:9: 11:10
+ scope 4 {
+ debug _x => _6; // in scope 4 at $SRC_DIR/core/src/mem/mod.rs:LL:COL
+ }
+ }
+ }
+ }
+
+ bb0: {
+- StorageLive(_1); // scope 0 at $DIR/cycle.rs:9:9: 9:14
+- _1 = val() -> bb1; // scope 0 at $DIR/cycle.rs:9:17: 9:22
++ nop; // scope 0 at $DIR/cycle.rs:9:9: 9:14
++ _4 = val() -> bb1; // scope 0 at $DIR/cycle.rs:9:17: 9:22
+ // mir::Constant
+ // + span: $DIR/cycle.rs:9:17: 9:20
+ // + literal: Const { ty: fn() -> i32 {val}, val: Value(Scalar(<ZST>)) }
+ }
+
+ bb1: {
+- StorageLive(_2); // scope 1 at $DIR/cycle.rs:10:9: 10:10
+- _2 = _1; // scope 1 at $DIR/cycle.rs:10:13: 10:14
+- StorageLive(_3); // scope 2 at $DIR/cycle.rs:11:9: 11:10
+- _3 = _2; // scope 2 at $DIR/cycle.rs:11:13: 11:14
+- StorageLive(_4); // scope 3 at $DIR/cycle.rs:12:9: 12:10
+- _4 = _3; // scope 3 at $DIR/cycle.rs:12:9: 12:10
+- _1 = move _4; // scope 3 at $DIR/cycle.rs:12:5: 12:10
+- StorageDead(_4); // scope 3 at $DIR/cycle.rs:12:9: 12:10
++ nop; // scope 1 at $DIR/cycle.rs:10:9: 10:10
++ nop; // scope 1 at $DIR/cycle.rs:10:13: 10:14
++ nop; // scope 2 at $DIR/cycle.rs:11:9: 11:10
++ nop; // scope 2 at $DIR/cycle.rs:11:13: 11:14
++ nop; // scope 3 at $DIR/cycle.rs:12:9: 12:10
++ nop; // scope 3 at $DIR/cycle.rs:12:9: 12:10
++ nop; // scope 3 at $DIR/cycle.rs:12:5: 12:10
++ nop; // scope 3 at $DIR/cycle.rs:12:9: 12:10
+ StorageLive(_5); // scope 3 at $DIR/cycle.rs:14:5: 14:12
+ StorageLive(_6); // scope 3 at $DIR/cycle.rs:14:10: 14:11
+- _6 = _1; // scope 3 at $DIR/cycle.rs:14:10: 14:11
++ _6 = _4; // scope 3 at $DIR/cycle.rs:14:10: 14:11
+ _5 = const (); // scope 4 at $SRC_DIR/core/src/mem/mod.rs:LL:COL
+ drop(_6) -> bb2; // scope 4 at $SRC_DIR/core/src/mem/mod.rs:LL:COL
+ }
+
+ bb2: {
+ StorageDead(_6); // scope 3 at $DIR/cycle.rs:14:11: 14:12
+ StorageDead(_5); // scope 3 at $DIR/cycle.rs:14:12: 14:13
+ _0 = const (); // scope 0 at $DIR/cycle.rs:8:11: 15:2
+- StorageDead(_3); // scope 2 at $DIR/cycle.rs:15:1: 15:2
+- StorageDead(_2); // scope 1 at $DIR/cycle.rs:15:1: 15:2
+- StorageDead(_1); // scope 0 at $DIR/cycle.rs:15:1: 15:2
++ nop; // scope 2 at $DIR/cycle.rs:15:1: 15:2
++ nop; // scope 1 at $DIR/cycle.rs:15:1: 15:2
++ nop; // scope 0 at $DIR/cycle.rs:15:1: 15:2
+ return; // scope 0 at $DIR/cycle.rs:15:2: 15:2
+ }
+ }
+
--- /dev/null
+//! Tests that cyclic assignments don't hang DestinationPropagation, and result in reasonable code.
+
+fn val() -> i32 {
+ 1
+}
+
+// EMIT_MIR cycle.main.DestinationPropagation.diff
+fn main() {
+ let mut x = val();
+ let y = x;
+ let z = y;
+ x = z;
+
+ drop(x);
+}
--- /dev/null
+- // MIR for `nrvo` before DestinationPropagation
++ // MIR for `nrvo` after DestinationPropagation
+
+ fn nrvo(_1: for<'r> fn(&'r mut [u8; 1024])) -> [u8; 1024] {
+ debug init => _1; // in scope 0 at $DIR/simple.rs:4:9: 4:13
+ let mut _0: [u8; 1024]; // return place in scope 0 at $DIR/simple.rs:4:39: 4:49
+ let mut _2: [u8; 1024]; // in scope 0 at $DIR/simple.rs:5:9: 5:16
+ let _3: (); // in scope 0 at $DIR/simple.rs:6:5: 6:19
+ let mut _4: for<'r> fn(&'r mut [u8; 1024]); // in scope 0 at $DIR/simple.rs:6:5: 6:9
+ let mut _5: &mut [u8; 1024]; // in scope 0 at $DIR/simple.rs:6:10: 6:18
+ let mut _6: &mut [u8; 1024]; // in scope 0 at $DIR/simple.rs:6:10: 6:18
+ scope 1 {
+- debug buf => _2; // in scope 1 at $DIR/simple.rs:5:9: 5:16
++ debug buf => _0; // in scope 1 at $DIR/simple.rs:5:9: 5:16
+ }
+
+ bb0: {
+- StorageLive(_2); // scope 0 at $DIR/simple.rs:5:9: 5:16
+- _2 = [const 0_u8; 1024]; // scope 0 at $DIR/simple.rs:5:19: 5:28
++ nop; // scope 0 at $DIR/simple.rs:5:9: 5:16
++ _0 = [const 0_u8; 1024]; // scope 0 at $DIR/simple.rs:5:19: 5:28
+ StorageLive(_3); // scope 1 at $DIR/simple.rs:6:5: 6:19
+ StorageLive(_4); // scope 1 at $DIR/simple.rs:6:5: 6:9
+ _4 = _1; // scope 1 at $DIR/simple.rs:6:5: 6:9
+ StorageLive(_5); // scope 1 at $DIR/simple.rs:6:10: 6:18
+ StorageLive(_6); // scope 1 at $DIR/simple.rs:6:10: 6:18
+- _6 = &mut _2; // scope 1 at $DIR/simple.rs:6:10: 6:18
++ _6 = &mut _0; // scope 1 at $DIR/simple.rs:6:10: 6:18
+ _5 = &mut (*_6); // scope 1 at $DIR/simple.rs:6:10: 6:18
+ _3 = move _4(move _5) -> bb1; // scope 1 at $DIR/simple.rs:6:5: 6:19
+ }
+
+ bb1: {
+ StorageDead(_5); // scope 1 at $DIR/simple.rs:6:18: 6:19
+ StorageDead(_4); // scope 1 at $DIR/simple.rs:6:18: 6:19
+ StorageDead(_6); // scope 1 at $DIR/simple.rs:6:19: 6:20
+ StorageDead(_3); // scope 1 at $DIR/simple.rs:6:19: 6:20
+- _0 = _2; // scope 1 at $DIR/simple.rs:7:5: 7:8
+- StorageDead(_2); // scope 0 at $DIR/simple.rs:8:1: 8:2
++ nop; // scope 1 at $DIR/simple.rs:7:5: 7:8
++ nop; // scope 0 at $DIR/simple.rs:8:1: 8:2
+ return; // scope 0 at $DIR/simple.rs:8:2: 8:2
+ }
+ }
+
--- /dev/null
+//! Copy of `nrvo-simple.rs`, to ensure that full dest-prop handles it too.
+
+// EMIT_MIR simple.nrvo.DestinationPropagation.diff
+fn nrvo(init: fn(&mut [u8; 1024])) -> [u8; 1024] {
+ let mut buf = [0; 1024];
+ init(&mut buf);
+ buf
+}
+
+fn main() {
+ let _ = nrvo(|buf| {
+ buf[4] = 4;
+ });
+}
--- /dev/null
+- // MIR for `main` before DestinationPropagation
++ // MIR for `main` after DestinationPropagation
+
+ fn main() -> () {
+ let mut _0: (); // return place in scope 0 at $DIR/union.rs:8:11: 8:11
+ let _1: main::Un; // in scope 0 at $DIR/union.rs:13:9: 13:11
+ let mut _2: u32; // in scope 0 at $DIR/union.rs:13:23: 13:28
+ let _3: (); // in scope 0 at $DIR/union.rs:15:5: 15:27
+ let mut _4: u32; // in scope 0 at $DIR/union.rs:15:10: 15:26
+ scope 1 {
+ debug un => _1; // in scope 1 at $DIR/union.rs:13:9: 13:11
+ scope 2 {
+ }
+ scope 3 {
+ debug _x => _4; // in scope 3 at $SRC_DIR/core/src/mem/mod.rs:LL:COL
+ }
+ }
+
+ bb0: {
+ StorageLive(_1); // scope 0 at $DIR/union.rs:13:9: 13:11
+ StorageLive(_2); // scope 0 at $DIR/union.rs:13:23: 13:28
+ _2 = val() -> bb1; // scope 0 at $DIR/union.rs:13:23: 13:28
+ // mir::Constant
+ // + span: $DIR/union.rs:13:23: 13:26
+ // + literal: Const { ty: fn() -> u32 {val}, val: Value(Scalar(<ZST>)) }
+ }
+
+ bb1: {
+ (_1.0: u32) = move _2; // scope 0 at $DIR/union.rs:13:14: 13:30
+ StorageDead(_2); // scope 0 at $DIR/union.rs:13:29: 13:30
+ StorageLive(_3); // scope 1 at $DIR/union.rs:15:5: 15:27
+ StorageLive(_4); // scope 1 at $DIR/union.rs:15:10: 15:26
+ _4 = (_1.0: u32); // scope 2 at $DIR/union.rs:15:19: 15:24
+ _3 = const (); // scope 3 at $SRC_DIR/core/src/mem/mod.rs:LL:COL
+ drop(_4) -> bb2; // scope 3 at $SRC_DIR/core/src/mem/mod.rs:LL:COL
+ }
+
+ bb2: {
+ StorageDead(_4); // scope 1 at $DIR/union.rs:15:26: 15:27
+ StorageDead(_3); // scope 1 at $DIR/union.rs:15:27: 15:28
+ _0 = const (); // scope 0 at $DIR/union.rs:8:11: 16:2
+ StorageDead(_1); // scope 0 at $DIR/union.rs:16:1: 16:2
+ return; // scope 0 at $DIR/union.rs:16:2: 16:2
+ }
+ }
+
--- /dev/null
+//! Tests that projections through unions cancel `DestinationPropagation`.
+
+fn val() -> u32 {
+ 1
+}
+
+// EMIT_MIR union.main.DestinationPropagation.diff
+fn main() {
+ union Un {
+ us: u32,
+ }
+
+ let un = Un { us: val() };
+
+ drop(unsafe { un.us });
+}
// MIR for `std::ops::Fn::call` before AddMovesForPackedDrops
-fn std::ops::Fn::call(_1: *const fn(), _2: Args) -> <Self as FnOnce<Args>>::Output {
- let mut _0: <Self as std::ops::FnOnce<Args>>::Output; // return place in scope 0 at $SRC_DIR/core/src/ops/function.rs:LL:COL
+fn std::ops::Fn::call(_1: *const fn(), _2: ()) -> <fn() as FnOnce<()>>::Output {
+ let mut _0: <fn() as std::ops::FnOnce<()>>::Output; // return place in scope 0 at $SRC_DIR/core/src/ops/function.rs:LL:COL
bb0: {
_0 = move (*_1)() -> bb1; // scope 0 at $SRC_DIR/core/src/ops/function.rs:LL:COL
let mut _6: &[closure@foo<T>::{{closure}}#0 q:&i32, t:&T]; // in scope 0 at $DIR/inline-closure-captures.rs:12:5: 12:6
let mut _7: (i32,); // in scope 0 at $DIR/inline-closure-captures.rs:12:5: 12:9
let mut _8: i32; // in scope 0 at $DIR/inline-closure-captures.rs:12:7: 12:8
- let mut _11: i32; // in scope 0 at $DIR/inline-closure-captures.rs:12:5: 12:9
+ let mut _10: i32; // in scope 0 at $DIR/inline-closure-captures.rs:12:5: 12:9
scope 1 {
debug x => _3; // in scope 1 at $DIR/inline-closure-captures.rs:11:9: 11:10
scope 2 {
- debug _q => _11; // in scope 2 at $DIR/inline-closure-captures.rs:11:14: 11:16
+ debug _q => _10; // in scope 2 at $DIR/inline-closure-captures.rs:11:14: 11:16
debug q => (*((*_6).0: &i32)); // in scope 2 at $DIR/inline-closure-captures.rs:10:23: 10:24
debug t => (*((*_6).1: &T)); // in scope 2 at $DIR/inline-closure-captures.rs:10:17: 10:18
- let mut _9: i32; // in scope 2 at $DIR/inline-closure-captures.rs:12:5: 12:9
- let mut _10: T; // in scope 2 at $DIR/inline-closure-captures.rs:12:5: 12:9
+ let mut _9: T; // in scope 2 at $DIR/inline-closure-captures.rs:12:5: 12:9
}
}
StorageLive(_8); // scope 1 at $DIR/inline-closure-captures.rs:12:7: 12:8
_8 = _2; // scope 1 at $DIR/inline-closure-captures.rs:12:7: 12:8
(_7.0: i32) = move _8; // scope 1 at $DIR/inline-closure-captures.rs:12:5: 12:9
- StorageLive(_11); // scope 1 at $DIR/inline-closure-captures.rs:12:5: 12:9
- _11 = move (_7.0: i32); // scope 1 at $DIR/inline-closure-captures.rs:12:5: 12:9
- StorageLive(_9); // scope 2 at $DIR/inline-closure-captures.rs:11:19: 11:20
- _9 = (*((*_6).0: &i32)); // scope 2 at $DIR/inline-closure-captures.rs:11:19: 11:20
- StorageLive(_10); // scope 2 at $DIR/inline-closure-captures.rs:11:22: 11:23
- _10 = (*((*_6).1: &T)); // scope 2 at $DIR/inline-closure-captures.rs:11:22: 11:23
- (_0.0: i32) = move _9; // scope 2 at $DIR/inline-closure-captures.rs:11:18: 11:24
- (_0.1: T) = move _10; // scope 2 at $DIR/inline-closure-captures.rs:11:18: 11:24
- StorageDead(_10); // scope 2 at $DIR/inline-closure-captures.rs:11:23: 11:24
+ StorageLive(_10); // scope 1 at $DIR/inline-closure-captures.rs:12:5: 12:9
+ _10 = move (_7.0: i32); // scope 1 at $DIR/inline-closure-captures.rs:12:5: 12:9
+ (_0.0: i32) = (*((*_6).0: &i32)); // scope 2 at $DIR/inline-closure-captures.rs:11:19: 11:20
+ StorageLive(_9); // scope 2 at $DIR/inline-closure-captures.rs:11:22: 11:23
+ _9 = (*((*_6).1: &T)); // scope 2 at $DIR/inline-closure-captures.rs:11:22: 11:23
+ (_0.1: T) = move _9; // scope 2 at $DIR/inline-closure-captures.rs:11:18: 11:24
StorageDead(_9); // scope 2 at $DIR/inline-closure-captures.rs:11:23: 11:24
- StorageDead(_11); // scope 1 at $DIR/inline-closure-captures.rs:12:5: 12:9
+ StorageDead(_10); // scope 1 at $DIR/inline-closure-captures.rs:12:5: 12:9
StorageDead(_8); // scope 1 at $DIR/inline-closure-captures.rs:12:8: 12:9
StorageDead(_7); // scope 1 at $DIR/inline-closure-captures.rs:12:8: 12:9
StorageDead(_6); // scope 1 at $DIR/inline-closure-captures.rs:12:8: 12:9
fn main() -> () {
let mut _0: (); // return place in scope 0 at $DIR/issue-73223.rs:1:11: 1:11
- let mut _1: std::option::Option<i32>; // in scope 0 at $DIR/issue-73223.rs:2:23: 2:30
- let _2: i32; // in scope 0 at $DIR/issue-73223.rs:3:14: 3:15
- let mut _4: i32; // in scope 0 at $DIR/issue-73223.rs:7:22: 7:27
- let mut _5: (&i32, &i32); // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _6: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _9: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _10: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _11: i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let _12: &std::fmt::Arguments; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
- let _13: std::fmt::Arguments; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
- let mut _14: &[&str]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _15: &[std::fmt::ArgumentV1]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
- let _16: &[std::fmt::ArgumentV1; 2]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
- let _17: [std::fmt::ArgumentV1; 2]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
- let mut _18: (&&i32, &&i32); // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
- let mut _19: &&i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let _20: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _21: &&i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _24: std::fmt::ArgumentV1; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
- let mut _25: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _26: std::fmt::ArgumentV1; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
- let mut _27: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let _1: i32; // in scope 0 at $DIR/issue-73223.rs:2:9: 2:14
+ let mut _2: std::option::Option<i32>; // in scope 0 at $DIR/issue-73223.rs:2:23: 2:30
+ let mut _4: (&i32, &i32); // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _5: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _6: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _7: i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _8: &std::fmt::Arguments; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
+ let _9: std::fmt::Arguments; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
+ let mut _10: &[std::fmt::ArgumentV1; 2]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
+ let _11: [std::fmt::ArgumentV1; 2]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
+ let mut _12: (&&i32, &&i32); // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
+ let _13: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _14: &&i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let _15: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _16: std::fmt::ArgumentV1; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
+ let mut _17: std::fmt::ArgumentV1; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
scope 1 {
- debug split => _2; // in scope 1 at $DIR/issue-73223.rs:2:9: 2:14
+ debug split => _1; // in scope 1 at $DIR/issue-73223.rs:2:9: 2:14
let _3: std::option::Option<i32>; // in scope 1 at $DIR/issue-73223.rs:7:9: 7:14
scope 3 {
debug _prev => _3; // in scope 3 at $DIR/issue-73223.rs:7:9: 7:14
- let _7: &i32; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let _8: &i32; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
scope 4 {
- debug left_val => _7; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- debug right_val => _8; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let _22: &&i32; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let _23: &&i32; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ debug left_val => _13; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ debug right_val => _15; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
scope 5 {
- debug arg0 => _22; // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ debug arg0 => _20; // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
debug arg1 => _23; // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
scope 6 {
- debug x => _22; // in scope 6 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
- debug f => _25; // in scope 6 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
- let mut _28: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 6 at $SRC_DIR/std/src/macros.rs:LL:COL
- let mut _29: &core::fmt::Opaque; // in scope 6 at $SRC_DIR/std/src/macros.rs:LL:COL
+ debug x => _20; // in scope 6 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+ debug f => _19; // in scope 6 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+ let mut _18: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 6 at $SRC_DIR/std/src/macros.rs:LL:COL
+ let mut _19: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 6 at $SRC_DIR/std/src/macros.rs:LL:COL
+ let mut _20: &&i32; // in scope 6 at $SRC_DIR/std/src/macros.rs:LL:COL
}
scope 8 {
debug x => _23; // in scope 8 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
- debug f => _27; // in scope 8 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
- let mut _30: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 8 at $SRC_DIR/std/src/macros.rs:LL:COL
- let mut _31: &core::fmt::Opaque; // in scope 8 at $SRC_DIR/std/src/macros.rs:LL:COL
+ debug f => _22; // in scope 8 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+ let mut _21: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 8 at $SRC_DIR/std/src/macros.rs:LL:COL
+ let mut _22: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 8 at $SRC_DIR/std/src/macros.rs:LL:COL
+ let mut _23: &&i32; // in scope 8 at $SRC_DIR/std/src/macros.rs:LL:COL
}
}
scope 10 {
- debug pieces => _14; // in scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
- debug args => _15; // in scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
- let mut _32: std::option::Option<&[std::fmt::rt::v1::Argument]>; // in scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL
+ debug pieces => (_9.0: &[&str]); // in scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+ debug args => _25; // in scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+ let mut _24: std::option::Option<&[std::fmt::rt::v1::Argument]>; // in scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL
+ let mut _25: &[std::fmt::ArgumentV1]; // in scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL
}
}
}
}
scope 2 {
- debug v => _2; // in scope 2 at $DIR/issue-73223.rs:3:14: 3:15
+ debug v => _1; // in scope 2 at $DIR/issue-73223.rs:3:14: 3:15
}
scope 7 {
}
}
bb0: {
- StorageLive(_1); // scope 0 at $DIR/issue-73223.rs:2:23: 2:30
- ((_1 as Some).0: i32) = const 1_i32; // scope 0 at $DIR/issue-73223.rs:2:23: 2:30
- discriminant(_1) = 1; // scope 0 at $DIR/issue-73223.rs:2:23: 2:30
- _2 = ((_1 as Some).0: i32); // scope 0 at $DIR/issue-73223.rs:3:14: 3:15
- StorageDead(_1); // scope 0 at $DIR/issue-73223.rs:5:6: 5:7
- StorageLive(_3); // scope 1 at $DIR/issue-73223.rs:7:9: 7:14
- StorageLive(_4); // scope 1 at $DIR/issue-73223.rs:7:22: 7:27
- _4 = _2; // scope 1 at $DIR/issue-73223.rs:7:22: 7:27
- ((_3 as Some).0: i32) = move _4; // scope 1 at $DIR/issue-73223.rs:7:17: 7:28
+ StorageLive(_2); // scope 0 at $DIR/issue-73223.rs:2:23: 2:30
+ ((_2 as Some).0: i32) = const 1_i32; // scope 0 at $DIR/issue-73223.rs:2:23: 2:30
+ discriminant(_2) = 1; // scope 0 at $DIR/issue-73223.rs:2:23: 2:30
+ _1 = ((_2 as Some).0: i32); // scope 0 at $DIR/issue-73223.rs:3:14: 3:15
+ StorageDead(_2); // scope 0 at $DIR/issue-73223.rs:5:6: 5:7
+ ((_3 as Some).0: i32) = _1; // scope 1 at $DIR/issue-73223.rs:7:22: 7:27
discriminant(_3) = 1; // scope 1 at $DIR/issue-73223.rs:7:17: 7:28
- StorageDead(_4); // scope 1 at $DIR/issue-73223.rs:7:27: 7:28
- StorageLive(_5); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_6); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _6 = &_2; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- (_5.0: &i32) = move _6; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- (_5.1: &i32) = const main::promoted[1]; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ (_4.0: &i32) = &_1; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ (_4.1: &i32) = const main::promoted[1]; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
// ty::Const
// + ty: &i32
// + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main[0]), const_param_did: None }, [], Some(promoted[1]))
// mir::Constant
// + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
// + literal: Const { ty: &i32, val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main[0]), const_param_did: None }, [], Some(promoted[1])) }
- StorageDead(_6); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_7); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _7 = (_5.0: &i32); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _8 = (_5.1: &i32); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_9); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_10); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_11); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _11 = (*_7); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _10 = Eq(move _11, const 1_i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageDead(_11); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _9 = Not(move _10); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageDead(_10); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- switchInt(_9) -> [false: bb1, otherwise: bb2]; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _13 = (_4.0: &i32); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _15 = (_4.1: &i32); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_5); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_6); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_7); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _7 = (*_13); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _6 = Eq(move _7, const 1_i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_7); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _5 = Not(move _6); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_6); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ switchInt(_5) -> [false: bb1, otherwise: bb2]; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
}
bb1: {
- StorageDead(_9); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageDead(_7); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageDead(_5); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_5); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
_0 = const (); // scope 0 at $DIR/issue-73223.rs:1:11: 9:2
- StorageDead(_3); // scope 1 at $DIR/issue-73223.rs:9:1: 9:2
return; // scope 0 at $DIR/issue-73223.rs:9:2: 9:2
}
bb2: {
- StorageLive(_13); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
- _14 = const main::promoted[0] as &[&str] (Pointer(Unsize)); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ (_9.0: &[&str]) = const main::promoted[0] as &[&str] (Pointer(Unsize)); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
// ty::Const
// + ty: &[&str; 3]
// + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main[0]), const_param_did: None }, [], Some(promoted[0]))
// mir::Constant
// + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
// + literal: Const { ty: &[&str; 3], val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main[0]), const_param_did: None }, [], Some(promoted[0])) }
- StorageLive(_17); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageLive(_18); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageLive(_19); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_20); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _20 = _7; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _19 = &_20; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_21); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _21 = &_8; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- (_18.0: &&i32) = move _19; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
- (_18.1: &&i32) = move _21; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageDead(_21); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageDead(_19); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
- _22 = (_18.0: &&i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _23 = (_18.1: &&i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_24); // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL
- _25 = <&i32 as Debug>::fmt as for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_11); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+ (_12.0: &&i32) = &_13; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_14); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _14 = &_15; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ (_12.1: &&i32) = move _14; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+ StorageDead(_14); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+ _20 = (_12.0: &&i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _23 = (_12.1: &&i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _19 = <&i32 as Debug>::fmt as for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
// mir::Constant
// + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
// + literal: Const { ty: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {<&i32 as std::fmt::Debug>::fmt}, val: Value(Scalar(<ZST>)) }
- StorageLive(_28); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
- _28 = transmute::<for<'r, 's, 't0> fn(&'r &i32, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _25) -> bb3; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+ StorageLive(_18); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+ _18 = transmute::<for<'r, 's, 't0> fn(&'r &i32, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _19) -> bb3; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
// mir::Constant
// + span: $SRC_DIR/core/src/fmt/mod.rs:LL:COL
// + literal: Const { ty: unsafe extern "rust-intrinsic" fn(for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) -> for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {std::intrinsics::transmute::<for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>}, val: Value(Scalar(<ZST>)) }
}
bb3: {
- StorageLive(_29); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
- _29 = transmute::<&&i32, &core::fmt::Opaque>(move _22) -> bb4; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+ (_16.0: &core::fmt::Opaque) = transmute::<&&i32, &core::fmt::Opaque>(move _20) -> bb4; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
// mir::Constant
// + span: $SRC_DIR/core/src/fmt/mod.rs:LL:COL
// + literal: Const { ty: unsafe extern "rust-intrinsic" fn(&&i32) -> &core::fmt::Opaque {std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>}, val: Value(Scalar(<ZST>)) }
}
bb4: {
- (_24.0: &core::fmt::Opaque) = move _29; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
- (_24.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _28; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
- StorageDead(_29); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
- StorageDead(_28); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
- StorageLive(_26); // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL
- _27 = <&i32 as Debug>::fmt as for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ (_16.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _18; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+ StorageDead(_18); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+ _22 = <&i32 as Debug>::fmt as for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
// mir::Constant
// + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
// + literal: Const { ty: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {<&i32 as std::fmt::Debug>::fmt}, val: Value(Scalar(<ZST>)) }
- StorageLive(_30); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
- _30 = transmute::<for<'r, 's, 't0> fn(&'r &i32, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _27) -> bb5; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+ StorageLive(_21); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+ _21 = transmute::<for<'r, 's, 't0> fn(&'r &i32, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _22) -> bb5; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
// mir::Constant
// + span: $SRC_DIR/core/src/fmt/mod.rs:LL:COL
// + literal: Const { ty: unsafe extern "rust-intrinsic" fn(for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) -> for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {std::intrinsics::transmute::<for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>}, val: Value(Scalar(<ZST>)) }
}
bb5: {
- StorageLive(_31); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
- _31 = transmute::<&&i32, &core::fmt::Opaque>(move _23) -> bb6; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+ (_17.0: &core::fmt::Opaque) = transmute::<&&i32, &core::fmt::Opaque>(move _23) -> bb6; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
// mir::Constant
// + span: $SRC_DIR/core/src/fmt/mod.rs:LL:COL
// + literal: Const { ty: unsafe extern "rust-intrinsic" fn(&&i32) -> &core::fmt::Opaque {std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>}, val: Value(Scalar(<ZST>)) }
}
bb6: {
- (_26.0: &core::fmt::Opaque) = move _31; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
- (_26.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _30; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
- StorageDead(_31); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
- StorageDead(_30); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
- _17 = [move _24, move _26]; // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageDead(_26); // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageDead(_24); // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL
- _16 = &_17; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
- _15 = move _16 as &[std::fmt::ArgumentV1] (Pointer(Unsize)); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageLive(_32); // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
- discriminant(_32) = 0; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
- (_13.0: &[&str]) = move _14; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
- (_13.1: std::option::Option<&[std::fmt::rt::v1::Argument]>) = move _32; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
- (_13.2: &[std::fmt::ArgumentV1]) = move _15; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
- StorageDead(_32); // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
- _12 = &_13; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
- begin_panic_fmt(move _12); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+ (_17.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _21; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+ StorageDead(_21); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+ _11 = [move _16, move _17]; // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL
+ _10 = &_11; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+ _25 = move _10 as &[std::fmt::ArgumentV1] (Pointer(Unsize)); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+ StorageLive(_24); // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+ discriminant(_24) = 0; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+ (_9.1: std::option::Option<&[std::fmt::rt::v1::Argument]>) = move _24; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+ (_9.2: &[std::fmt::ArgumentV1]) = move _25; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+ StorageDead(_24); // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+ _8 = &_9; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+ begin_panic_fmt(move _8); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
// mir::Constant
// + span: $SRC_DIR/std/src/macros.rs:LL:COL
// + literal: Const { ty: for<'r, 's> fn(&'r std::fmt::Arguments<'s>) -> ! {std::rt::begin_panic_fmt}, val: Value(Scalar(<ZST>)) }
fn main() -> () {
let mut _0: (); // return place in scope 0 at $DIR/issue-73223.rs:1:11: 1:11
- let mut _1: std::option::Option<i32>; // in scope 0 at $DIR/issue-73223.rs:2:23: 2:30
- let _2: i32; // in scope 0 at $DIR/issue-73223.rs:3:14: 3:15
- let mut _4: i32; // in scope 0 at $DIR/issue-73223.rs:7:22: 7:27
- let mut _5: (&i32, &i32); // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _6: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _9: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _10: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _11: i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let _12: &std::fmt::Arguments; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
- let _13: std::fmt::Arguments; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
- let mut _14: &[&str]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _15: &[std::fmt::ArgumentV1]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
- let _16: &[std::fmt::ArgumentV1; 2]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
- let _17: [std::fmt::ArgumentV1; 2]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
- let mut _18: (&&i32, &&i32); // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
- let mut _19: &&i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let _20: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _21: &&i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _24: std::fmt::ArgumentV1; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
- let mut _25: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _26: std::fmt::ArgumentV1; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
- let mut _27: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let _1: i32; // in scope 0 at $DIR/issue-73223.rs:2:9: 2:14
+ let mut _2: std::option::Option<i32>; // in scope 0 at $DIR/issue-73223.rs:2:23: 2:30
+ let mut _4: (&i32, &i32); // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _5: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _6: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _7: i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _8: &std::fmt::Arguments; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
+ let _9: std::fmt::Arguments; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
+ let mut _10: &[std::fmt::ArgumentV1; 2]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
+ let _11: [std::fmt::ArgumentV1; 2]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
+ let mut _12: (&&i32, &&i32); // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
+ let _13: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _14: &&i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let _15: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _16: std::fmt::ArgumentV1; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
+ let mut _17: std::fmt::ArgumentV1; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
scope 1 {
- debug split => _2; // in scope 1 at $DIR/issue-73223.rs:2:9: 2:14
+ debug split => _1; // in scope 1 at $DIR/issue-73223.rs:2:9: 2:14
let _3: std::option::Option<i32>; // in scope 1 at $DIR/issue-73223.rs:7:9: 7:14
scope 3 {
debug _prev => _3; // in scope 3 at $DIR/issue-73223.rs:7:9: 7:14
- let _7: &i32; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let _8: &i32; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
scope 4 {
- debug left_val => _7; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- debug right_val => _8; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let _22: &&i32; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let _23: &&i32; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ debug left_val => _13; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ debug right_val => _15; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
scope 5 {
- debug arg0 => _22; // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ debug arg0 => _20; // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
debug arg1 => _23; // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
scope 6 {
- debug x => _22; // in scope 6 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
- debug f => _25; // in scope 6 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
- let mut _28: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 6 at $SRC_DIR/std/src/macros.rs:LL:COL
- let mut _29: &core::fmt::Opaque; // in scope 6 at $SRC_DIR/std/src/macros.rs:LL:COL
+ debug x => _20; // in scope 6 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+ debug f => _19; // in scope 6 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+ let mut _18: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 6 at $SRC_DIR/std/src/macros.rs:LL:COL
+ let mut _19: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 6 at $SRC_DIR/std/src/macros.rs:LL:COL
+ let mut _20: &&i32; // in scope 6 at $SRC_DIR/std/src/macros.rs:LL:COL
}
scope 8 {
debug x => _23; // in scope 8 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
- debug f => _27; // in scope 8 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
- let mut _30: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 8 at $SRC_DIR/std/src/macros.rs:LL:COL
- let mut _31: &core::fmt::Opaque; // in scope 8 at $SRC_DIR/std/src/macros.rs:LL:COL
+ debug f => _22; // in scope 8 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+ let mut _21: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 8 at $SRC_DIR/std/src/macros.rs:LL:COL
+ let mut _22: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 8 at $SRC_DIR/std/src/macros.rs:LL:COL
+ let mut _23: &&i32; // in scope 8 at $SRC_DIR/std/src/macros.rs:LL:COL
}
}
scope 10 {
- debug pieces => _14; // in scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
- debug args => _15; // in scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
- let mut _32: std::option::Option<&[std::fmt::rt::v1::Argument]>; // in scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL
+ debug pieces => (_9.0: &[&str]); // in scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+ debug args => _25; // in scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+ let mut _24: std::option::Option<&[std::fmt::rt::v1::Argument]>; // in scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL
+ let mut _25: &[std::fmt::ArgumentV1]; // in scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL
}
}
}
}
scope 2 {
- debug v => _2; // in scope 2 at $DIR/issue-73223.rs:3:14: 3:15
+ debug v => _1; // in scope 2 at $DIR/issue-73223.rs:3:14: 3:15
}
scope 7 {
}
}
bb0: {
- StorageLive(_1); // scope 0 at $DIR/issue-73223.rs:2:23: 2:30
- ((_1 as Some).0: i32) = const 1_i32; // scope 0 at $DIR/issue-73223.rs:2:23: 2:30
- discriminant(_1) = 1; // scope 0 at $DIR/issue-73223.rs:2:23: 2:30
- _2 = ((_1 as Some).0: i32); // scope 0 at $DIR/issue-73223.rs:3:14: 3:15
- StorageDead(_1); // scope 0 at $DIR/issue-73223.rs:5:6: 5:7
- StorageLive(_3); // scope 1 at $DIR/issue-73223.rs:7:9: 7:14
- StorageLive(_4); // scope 1 at $DIR/issue-73223.rs:7:22: 7:27
- _4 = _2; // scope 1 at $DIR/issue-73223.rs:7:22: 7:27
- ((_3 as Some).0: i32) = move _4; // scope 1 at $DIR/issue-73223.rs:7:17: 7:28
+ StorageLive(_2); // scope 0 at $DIR/issue-73223.rs:2:23: 2:30
+ ((_2 as Some).0: i32) = const 1_i32; // scope 0 at $DIR/issue-73223.rs:2:23: 2:30
+ discriminant(_2) = 1; // scope 0 at $DIR/issue-73223.rs:2:23: 2:30
+ _1 = ((_2 as Some).0: i32); // scope 0 at $DIR/issue-73223.rs:3:14: 3:15
+ StorageDead(_2); // scope 0 at $DIR/issue-73223.rs:5:6: 5:7
+ ((_3 as Some).0: i32) = _1; // scope 1 at $DIR/issue-73223.rs:7:22: 7:27
discriminant(_3) = 1; // scope 1 at $DIR/issue-73223.rs:7:17: 7:28
- StorageDead(_4); // scope 1 at $DIR/issue-73223.rs:7:27: 7:28
- StorageLive(_5); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_6); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _6 = &_2; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- (_5.0: &i32) = move _6; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- (_5.1: &i32) = const main::promoted[1]; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ (_4.0: &i32) = &_1; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ (_4.1: &i32) = const main::promoted[1]; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
// ty::Const
// + ty: &i32
// + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main[0]), const_param_did: None }, [], Some(promoted[1]))
// mir::Constant
// + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
// + literal: Const { ty: &i32, val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main[0]), const_param_did: None }, [], Some(promoted[1])) }
- StorageDead(_6); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_7); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _7 = (_5.0: &i32); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _8 = (_5.1: &i32); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_9); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_10); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_11); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _11 = (*_7); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _10 = Eq(move _11, const 1_i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageDead(_11); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _9 = Not(move _10); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageDead(_10); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- switchInt(_9) -> [false: bb1, otherwise: bb2]; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _13 = (_4.0: &i32); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _15 = (_4.1: &i32); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_5); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_6); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_7); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _7 = (*_13); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _6 = Eq(move _7, const 1_i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_7); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _5 = Not(move _6); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_6); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ switchInt(_5) -> [false: bb1, otherwise: bb2]; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
}
bb1: {
- StorageDead(_9); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageDead(_7); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageDead(_5); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_5); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
_0 = const (); // scope 0 at $DIR/issue-73223.rs:1:11: 9:2
- StorageDead(_3); // scope 1 at $DIR/issue-73223.rs:9:1: 9:2
return; // scope 0 at $DIR/issue-73223.rs:9:2: 9:2
}
bb2: {
- StorageLive(_13); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
- _14 = const main::promoted[0] as &[&str] (Pointer(Unsize)); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ (_9.0: &[&str]) = const main::promoted[0] as &[&str] (Pointer(Unsize)); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
// ty::Const
// + ty: &[&str; 3]
// + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main[0]), const_param_did: None }, [], Some(promoted[0]))
// mir::Constant
// + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
// + literal: Const { ty: &[&str; 3], val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main[0]), const_param_did: None }, [], Some(promoted[0])) }
- StorageLive(_17); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageLive(_18); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageLive(_19); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_20); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _20 = _7; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _19 = &_20; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_21); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _21 = &_8; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- (_18.0: &&i32) = move _19; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
- (_18.1: &&i32) = move _21; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageDead(_21); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageDead(_19); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
- _22 = (_18.0: &&i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _23 = (_18.1: &&i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_24); // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL
- _25 = <&i32 as Debug>::fmt as for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_11); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+ (_12.0: &&i32) = &_13; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_14); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _14 = &_15; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ (_12.1: &&i32) = move _14; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+ StorageDead(_14); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+ _20 = (_12.0: &&i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _23 = (_12.1: &&i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _19 = <&i32 as Debug>::fmt as for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
// mir::Constant
// + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
// + literal: Const { ty: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {<&i32 as std::fmt::Debug>::fmt}, val: Value(Scalar(<ZST>)) }
- StorageLive(_28); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
- _28 = transmute::<for<'r, 's, 't0> fn(&'r &i32, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _25) -> bb3; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+ StorageLive(_18); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+ _18 = transmute::<for<'r, 's, 't0> fn(&'r &i32, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _19) -> bb3; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
// mir::Constant
// + span: $SRC_DIR/core/src/fmt/mod.rs:LL:COL
// + literal: Const { ty: unsafe extern "rust-intrinsic" fn(for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) -> for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {std::intrinsics::transmute::<for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>}, val: Value(Scalar(<ZST>)) }
}
bb3: {
- StorageLive(_29); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
- _29 = transmute::<&&i32, &core::fmt::Opaque>(move _22) -> bb4; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+ (_16.0: &core::fmt::Opaque) = transmute::<&&i32, &core::fmt::Opaque>(move _20) -> bb4; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
// mir::Constant
// + span: $SRC_DIR/core/src/fmt/mod.rs:LL:COL
// + literal: Const { ty: unsafe extern "rust-intrinsic" fn(&&i32) -> &core::fmt::Opaque {std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>}, val: Value(Scalar(<ZST>)) }
}
bb4: {
- (_24.0: &core::fmt::Opaque) = move _29; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
- (_24.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _28; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
- StorageDead(_29); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
- StorageDead(_28); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
- StorageLive(_26); // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL
- _27 = <&i32 as Debug>::fmt as for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ (_16.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _18; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+ StorageDead(_18); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+ _22 = <&i32 as Debug>::fmt as for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
// mir::Constant
// + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
// + literal: Const { ty: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {<&i32 as std::fmt::Debug>::fmt}, val: Value(Scalar(<ZST>)) }
- StorageLive(_30); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
- _30 = transmute::<for<'r, 's, 't0> fn(&'r &i32, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _27) -> bb5; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+ StorageLive(_21); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+ _21 = transmute::<for<'r, 's, 't0> fn(&'r &i32, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _22) -> bb5; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
// mir::Constant
// + span: $SRC_DIR/core/src/fmt/mod.rs:LL:COL
// + literal: Const { ty: unsafe extern "rust-intrinsic" fn(for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) -> for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {std::intrinsics::transmute::<for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>}, val: Value(Scalar(<ZST>)) }
}
bb5: {
- StorageLive(_31); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
- _31 = transmute::<&&i32, &core::fmt::Opaque>(move _23) -> bb6; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+ (_17.0: &core::fmt::Opaque) = transmute::<&&i32, &core::fmt::Opaque>(move _23) -> bb6; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
// mir::Constant
// + span: $SRC_DIR/core/src/fmt/mod.rs:LL:COL
// + literal: Const { ty: unsafe extern "rust-intrinsic" fn(&&i32) -> &core::fmt::Opaque {std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>}, val: Value(Scalar(<ZST>)) }
}
bb6: {
- (_26.0: &core::fmt::Opaque) = move _31; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
- (_26.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _30; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
- StorageDead(_31); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
- StorageDead(_30); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
- _17 = [move _24, move _26]; // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageDead(_26); // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageDead(_24); // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL
- _16 = &_17; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
- _15 = move _16 as &[std::fmt::ArgumentV1] (Pointer(Unsize)); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageLive(_32); // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
- discriminant(_32) = 0; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
- (_13.0: &[&str]) = move _14; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
- (_13.1: std::option::Option<&[std::fmt::rt::v1::Argument]>) = move _32; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
- (_13.2: &[std::fmt::ArgumentV1]) = move _15; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
- StorageDead(_32); // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
- _12 = &_13; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
- begin_panic_fmt(move _12); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+ (_17.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _21; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+ StorageDead(_21); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+ _11 = [move _16, move _17]; // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL
+ _10 = &_11; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+ _25 = move _10 as &[std::fmt::ArgumentV1] (Pointer(Unsize)); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+ StorageLive(_24); // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+ discriminant(_24) = 0; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+ (_9.1: std::option::Option<&[std::fmt::rt::v1::Argument]>) = move _24; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+ (_9.2: &[std::fmt::ArgumentV1]) = move _25; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+ StorageDead(_24); // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+ _8 = &_9; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+ begin_panic_fmt(move _8); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
// mir::Constant
// + span: $SRC_DIR/std/src/macros.rs:LL:COL
// + literal: Const { ty: for<'r, 's> fn(&'r std::fmt::Arguments<'s>) -> ! {std::rt::begin_panic_fmt}, val: Value(Scalar(<ZST>)) }
--- /dev/null
+// EMIT_MIR issue_75439.foo.MatchBranchSimplification.diff
+
+#![feature(const_fn_transmute)]
+#![feature(or_patterns)]
+
+use std::mem::transmute;
+
+pub fn foo(bytes: [u8; 16]) -> Option<[u8; 4]> {
+ // big endian `u32`s
+ let dwords: [u32; 4] = unsafe { transmute(bytes) };
+ const FF: u32 = 0x0000_ffff_u32.to_be();
+ if let [0, 0, 0 | FF, ip] = dwords {
+ Some(unsafe { transmute(ip) })
+ } else {
+ None
+ }
+}
+
+fn main() {
+ let _ = foo([0; 16]);
+}
--- /dev/null
+- // MIR for `foo` before MatchBranchSimplification
++ // MIR for `foo` after MatchBranchSimplification
+
+ fn foo(_1: [u8; 16]) -> Option<[u8; 4]> {
+ debug bytes => _1; // in scope 0 at $DIR/issue-75439.rs:8:12: 8:17
+ let mut _0: std::option::Option<[u8; 4]>; // return place in scope 0 at $DIR/issue-75439.rs:8:32: 8:47
+ let _2: [u32; 4]; // in scope 0 at $DIR/issue-75439.rs:10:9: 10:15
+ let mut _3: [u8; 16]; // in scope 0 at $DIR/issue-75439.rs:10:47: 10:52
+ let mut _5: [u8; 4]; // in scope 0 at $DIR/issue-75439.rs:13:14: 13:38
+ let mut _6: u32; // in scope 0 at $DIR/issue-75439.rs:13:33: 13:35
+ scope 1 {
+ debug dwords => _2; // in scope 1 at $DIR/issue-75439.rs:10:9: 10:15
+ let _4: u32; // in scope 1 at $DIR/issue-75439.rs:12:27: 12:29
+ scope 3 {
+ debug ip => _4; // in scope 3 at $DIR/issue-75439.rs:12:27: 12:29
+ scope 4 {
+ }
+ }
+ }
+ scope 2 {
+ }
+
+ bb0: {
+ StorageLive(_2); // scope 0 at $DIR/issue-75439.rs:10:9: 10:15
+ StorageLive(_3); // scope 2 at $DIR/issue-75439.rs:10:47: 10:52
+ _3 = _1; // scope 2 at $DIR/issue-75439.rs:10:47: 10:52
+ _2 = transmute::<[u8; 16], [u32; 4]>(move _3) -> bb1; // scope 2 at $DIR/issue-75439.rs:10:37: 10:53
+ // mir::Constant
+ // + span: $DIR/issue-75439.rs:10:37: 10:46
+ // + literal: Const { ty: unsafe extern "rust-intrinsic" fn([u8; 16]) -> [u32; 4] {std::intrinsics::transmute::<[u8; 16], [u32; 4]>}, val: Value(Scalar(<ZST>)) }
+ }
+
+ bb1: {
+ StorageDead(_3); // scope 2 at $DIR/issue-75439.rs:10:52: 10:53
+ switchInt(_2[0 of 4]) -> [0_u32: bb2, otherwise: bb4]; // scope 1 at $DIR/issue-75439.rs:12:13: 12:14
+ }
+
+ bb2: {
+ switchInt(_2[1 of 4]) -> [0_u32: bb3, otherwise: bb4]; // scope 1 at $DIR/issue-75439.rs:12:16: 12:17
+ }
+
+ bb3: {
+ switchInt(_2[2 of 4]) -> [0_u32: bb6, 4294901760_u32: bb7, otherwise: bb4]; // scope 1 at $DIR/issue-75439.rs:12:19: 12:20
+ }
+
+ bb4: {
+ discriminant(_0) = 0; // scope 1 at $DIR/issue-75439.rs:15:9: 15:13
+ goto -> bb9; // scope 1 at $DIR/issue-75439.rs:12:5: 16:6
+ }
+
+ bb5: {
+ StorageLive(_5); // scope 3 at $DIR/issue-75439.rs:13:14: 13:38
+ StorageLive(_6); // scope 4 at $DIR/issue-75439.rs:13:33: 13:35
+ _6 = _4; // scope 4 at $DIR/issue-75439.rs:13:33: 13:35
+ _5 = transmute::<u32, [u8; 4]>(move _6) -> bb8; // scope 4 at $DIR/issue-75439.rs:13:23: 13:36
+ // mir::Constant
+ // + span: $DIR/issue-75439.rs:13:23: 13:32
+ // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(u32) -> [u8; 4] {std::intrinsics::transmute::<u32, [u8; 4]>}, val: Value(Scalar(<ZST>)) }
+ }
+
+ bb6: {
+ StorageLive(_4); // scope 1 at $DIR/issue-75439.rs:12:27: 12:29
+ _4 = _2[3 of 4]; // scope 1 at $DIR/issue-75439.rs:12:27: 12:29
+ goto -> bb5; // scope 1 at $DIR/issue-75439.rs:12:5: 16:6
+ }
+
+ bb7: {
+ StorageLive(_4); // scope 1 at $DIR/issue-75439.rs:12:27: 12:29
+ _4 = _2[3 of 4]; // scope 1 at $DIR/issue-75439.rs:12:27: 12:29
+ goto -> bb5; // scope 1 at $DIR/issue-75439.rs:12:5: 16:6
+ }
+
+ bb8: {
+ StorageDead(_6); // scope 4 at $DIR/issue-75439.rs:13:35: 13:36
+ ((_0 as Some).0: [u8; 4]) = move _5; // scope 3 at $DIR/issue-75439.rs:13:9: 13:39
+ discriminant(_0) = 1; // scope 3 at $DIR/issue-75439.rs:13:9: 13:39
+ StorageDead(_5); // scope 3 at $DIR/issue-75439.rs:13:38: 13:39
+ StorageDead(_4); // scope 1 at $DIR/issue-75439.rs:14:5: 14:6
+ goto -> bb9; // scope 1 at $DIR/issue-75439.rs:12:5: 16:6
+ }
+
+ bb9: {
+ StorageDead(_2); // scope 0 at $DIR/issue-75439.rs:17:1: 17:2
+ return; // scope 0 at $DIR/issue-75439.rs:17:2: 17:2
+ }
+ }
+
+// compile-flags: -Zmir-opt-level=1
+
// EMIT_MIR nrvo_simple.nrvo.RenameReturnPlace.diff
fn nrvo(init: fn(&mut [u8; 1024])) -> [u8; 1024] {
let mut buf = [0; 1024];
+ // MIR for `nrvo` after RenameReturnPlace
fn nrvo(_1: for<'r> fn(&'r mut [u8; 1024])) -> [u8; 1024] {
- debug init => _1; // in scope 0 at $DIR/nrvo-simple.rs:2:9: 2:13
-- let mut _0: [u8; 1024]; // return place in scope 0 at $DIR/nrvo-simple.rs:2:39: 2:49
-+ let mut _0: [u8; 1024]; // return place in scope 0 at $DIR/nrvo-simple.rs:3:9: 3:16
- let mut _2: [u8; 1024]; // in scope 0 at $DIR/nrvo-simple.rs:3:9: 3:16
- let _3: (); // in scope 0 at $DIR/nrvo-simple.rs:4:5: 4:19
- let mut _4: for<'r> fn(&'r mut [u8; 1024]); // in scope 0 at $DIR/nrvo-simple.rs:4:5: 4:9
- let mut _5: &mut [u8; 1024]; // in scope 0 at $DIR/nrvo-simple.rs:4:10: 4:18
- let mut _6: &mut [u8; 1024]; // in scope 0 at $DIR/nrvo-simple.rs:4:10: 4:18
+ debug init => _1; // in scope 0 at $DIR/nrvo-simple.rs:4:9: 4:13
+- let mut _0: [u8; 1024]; // return place in scope 0 at $DIR/nrvo-simple.rs:4:39: 4:49
++ let mut _0: [u8; 1024]; // return place in scope 0 at $DIR/nrvo-simple.rs:5:9: 5:16
+ let mut _2: [u8; 1024]; // in scope 0 at $DIR/nrvo-simple.rs:5:9: 5:16
+ let _3: (); // in scope 0 at $DIR/nrvo-simple.rs:6:5: 6:19
+ let mut _4: for<'r> fn(&'r mut [u8; 1024]); // in scope 0 at $DIR/nrvo-simple.rs:6:5: 6:9
+ let mut _5: &mut [u8; 1024]; // in scope 0 at $DIR/nrvo-simple.rs:6:10: 6:18
+ let mut _6: &mut [u8; 1024]; // in scope 0 at $DIR/nrvo-simple.rs:6:10: 6:18
scope 1 {
-- debug buf => _2; // in scope 1 at $DIR/nrvo-simple.rs:3:9: 3:16
-+ debug buf => _0; // in scope 1 at $DIR/nrvo-simple.rs:3:9: 3:16
+- debug buf => _2; // in scope 1 at $DIR/nrvo-simple.rs:5:9: 5:16
++ debug buf => _0; // in scope 1 at $DIR/nrvo-simple.rs:5:9: 5:16
}
bb0: {
-- StorageLive(_2); // scope 0 at $DIR/nrvo-simple.rs:3:9: 3:16
-- _2 = [const 0_u8; 1024]; // scope 0 at $DIR/nrvo-simple.rs:3:19: 3:28
-+ _0 = [const 0_u8; 1024]; // scope 0 at $DIR/nrvo-simple.rs:3:19: 3:28
- StorageLive(_3); // scope 1 at $DIR/nrvo-simple.rs:4:5: 4:19
- StorageLive(_5); // scope 1 at $DIR/nrvo-simple.rs:4:10: 4:18
- StorageLive(_6); // scope 1 at $DIR/nrvo-simple.rs:4:10: 4:18
-- _6 = &mut _2; // scope 1 at $DIR/nrvo-simple.rs:4:10: 4:18
-+ _6 = &mut _0; // scope 1 at $DIR/nrvo-simple.rs:4:10: 4:18
- _5 = &mut (*_6); // scope 1 at $DIR/nrvo-simple.rs:4:10: 4:18
- _3 = move _1(move _5) -> bb1; // scope 1 at $DIR/nrvo-simple.rs:4:5: 4:19
+- StorageLive(_2); // scope 0 at $DIR/nrvo-simple.rs:5:9: 5:16
+- _2 = [const 0_u8; 1024]; // scope 0 at $DIR/nrvo-simple.rs:5:19: 5:28
++ _0 = [const 0_u8; 1024]; // scope 0 at $DIR/nrvo-simple.rs:5:19: 5:28
+ StorageLive(_3); // scope 1 at $DIR/nrvo-simple.rs:6:5: 6:19
+ StorageLive(_4); // scope 1 at $DIR/nrvo-simple.rs:6:5: 6:9
+ _4 = _1; // scope 1 at $DIR/nrvo-simple.rs:6:5: 6:9
+ StorageLive(_5); // scope 1 at $DIR/nrvo-simple.rs:6:10: 6:18
+ StorageLive(_6); // scope 1 at $DIR/nrvo-simple.rs:6:10: 6:18
+- _6 = &mut _2; // scope 1 at $DIR/nrvo-simple.rs:6:10: 6:18
++ _6 = &mut _0; // scope 1 at $DIR/nrvo-simple.rs:6:10: 6:18
+ _5 = &mut (*_6); // scope 1 at $DIR/nrvo-simple.rs:6:10: 6:18
+ _3 = move _4(move _5) -> bb1; // scope 1 at $DIR/nrvo-simple.rs:6:5: 6:19
}
bb1: {
- StorageDead(_5); // scope 1 at $DIR/nrvo-simple.rs:4:18: 4:19
- StorageDead(_6); // scope 1 at $DIR/nrvo-simple.rs:4:19: 4:20
- StorageDead(_3); // scope 1 at $DIR/nrvo-simple.rs:4:19: 4:20
-- _0 = _2; // scope 1 at $DIR/nrvo-simple.rs:5:5: 5:8
-- StorageDead(_2); // scope 0 at $DIR/nrvo-simple.rs:6:1: 6:2
- return; // scope 0 at $DIR/nrvo-simple.rs:6:2: 6:2
+ StorageDead(_5); // scope 1 at $DIR/nrvo-simple.rs:6:18: 6:19
+ StorageDead(_4); // scope 1 at $DIR/nrvo-simple.rs:6:18: 6:19
+ StorageDead(_6); // scope 1 at $DIR/nrvo-simple.rs:6:19: 6:20
+ StorageDead(_3); // scope 1 at $DIR/nrvo-simple.rs:6:19: 6:20
+- _0 = _2; // scope 1 at $DIR/nrvo-simple.rs:7:5: 7:8
+- StorageDead(_2); // scope 0 at $DIR/nrvo-simple.rs:8:1: 8:2
+ return; // scope 0 at $DIR/nrvo-simple.rs:8:2: 8:2
}
}
--- /dev/null
+- // MIR for `try_identity` before DestinationPropagation
++ // MIR for `try_identity` after DestinationPropagation
+
+ fn try_identity(_1: std::result::Result<u32, i32>) -> std::result::Result<u32, i32> {
+ debug x => _1; // in scope 0 at $DIR/simplify_try.rs:6:17: 6:18
+ let mut _0: std::result::Result<u32, i32>; // return place in scope 0 at $DIR/simplify_try.rs:6:41: 6:57
+ let _2: u32; // in scope 0 at $DIR/simplify_try.rs:7:9: 7:10
+ let mut _3: std::result::Result<u32, i32>; // in scope 0 at $DIR/simplify_try.rs:7:13: 7:15
+ let mut _4: std::result::Result<u32, i32>; // in scope 0 at $DIR/simplify_try.rs:7:13: 7:14
+ let mut _5: isize; // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15
+ let _6: i32; // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15
+ let mut _7: !; // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15
+ let mut _8: i32; // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15
+ let mut _9: i32; // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15
+ let _10: u32; // in scope 0 at $DIR/simplify_try.rs:7:13: 7:15
+ let mut _11: u32; // in scope 0 at $DIR/simplify_try.rs:8:8: 8:9
+ scope 1 {
+ debug y => _2; // in scope 1 at $DIR/simplify_try.rs:7:9: 7:10
+ }
+ scope 2 {
+ debug err => _6; // in scope 2 at $DIR/simplify_try.rs:7:14: 7:15
+ scope 3 {
+ scope 7 {
+ debug t => _9; // in scope 7 at $SRC_DIR/libcore/convert/mod.rs:LL:COL
+ }
+ scope 8 {
+ debug v => _8; // in scope 8 at $SRC_DIR/libcore/result.rs:LL:COL
+ let mut _12: i32; // in scope 8 at $DIR/simplify_try.rs:7:14: 7:15
+ }
+ }
+ }
+ scope 4 {
+ debug val => _10; // in scope 4 at $DIR/simplify_try.rs:7:13: 7:15
+ scope 5 {
+ }
+ }
+ scope 6 {
+- debug self => _4; // in scope 6 at $SRC_DIR/libcore/result.rs:LL:COL
++ debug self => _0; // in scope 6 at $SRC_DIR/libcore/result.rs:LL:COL
+ }
+
+ bb0: {
+ StorageLive(_2); // scope 0 at $DIR/simplify_try.rs:7:9: 7:10
+- StorageLive(_3); // scope 0 at $DIR/simplify_try.rs:7:13: 7:15
+- StorageLive(_4); // scope 0 at $DIR/simplify_try.rs:7:13: 7:14
+- _4 = _1; // scope 0 at $DIR/simplify_try.rs:7:13: 7:14
+- _3 = move _4; // scope 6 at $SRC_DIR/libcore/result.rs:LL:COL
+- StorageDead(_4); // scope 0 at $DIR/simplify_try.rs:7:14: 7:15
+- _5 = discriminant(_3); // scope 0 at $DIR/simplify_try.rs:7:14: 7:15
++ nop; // scope 0 at $DIR/simplify_try.rs:7:13: 7:15
++ nop; // scope 0 at $DIR/simplify_try.rs:7:13: 7:14
++ _0 = _1; // scope 0 at $DIR/simplify_try.rs:7:13: 7:14
++ nop; // scope 6 at $SRC_DIR/libcore/result.rs:LL:COL
++ nop; // scope 0 at $DIR/simplify_try.rs:7:14: 7:15
++ _5 = discriminant(_0); // scope 0 at $DIR/simplify_try.rs:7:14: 7:15
+ goto -> bb1; // scope 0 at $DIR/simplify_try.rs:7:14: 7:15
+ }
+
+ bb1: {
+- _0 = move _3; // scope 1 at $DIR/simplify_try.rs:8:5: 8:10
+- StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:7:15: 7:16
++ nop; // scope 1 at $DIR/simplify_try.rs:8:5: 8:10
++ nop; // scope 0 at $DIR/simplify_try.rs:7:15: 7:16
+ StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:9:1: 9:2
+ goto -> bb2; // scope 0 at $DIR/simplify_try.rs:9:2: 9:2
+ }
+
+ bb2: {
+ return; // scope 0 at $DIR/simplify_try.rs:9:2: 9:2
+ }
+ }
+
// EMIT_MIR simplify_try.try_identity.SimplifyArmIdentity.diff
// EMIT_MIR simplify_try.try_identity.SimplifyBranchSame.after.mir
// EMIT_MIR simplify_try.try_identity.SimplifyLocals.after.mir
+// EMIT_MIR simplify_try.try_identity.DestinationPropagation.diff
fn try_identity(x: Result<u32, i32>) -> Result<u32, i32> {
let y = x?;
--- /dev/null
+- // MIR for `try_identity` before DestinationPropagation
++ // MIR for `try_identity` after DestinationPropagation
+
+ fn try_identity(_1: std::result::Result<u32, i32>) -> std::result::Result<u32, i32> {
+ debug x => _1; // in scope 0 at $DIR/simplify_try.rs:6:17: 6:18
+ let mut _0: std::result::Result<u32, i32>; // return place in scope 0 at $DIR/simplify_try.rs:6:41: 6:57
+ let _2: u32; // in scope 0 at $DIR/simplify_try.rs:7:9: 7:10
+ let mut _3: std::result::Result<u32, i32>; // in scope 0 at $DIR/simplify_try.rs:7:13: 7:15
+ let mut _4: std::result::Result<u32, i32>; // in scope 0 at $DIR/simplify_try.rs:7:13: 7:14
+ let mut _5: isize; // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15
+ let _6: i32; // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15
+ let mut _7: !; // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15
+ let mut _8: i32; // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15
+ let mut _9: i32; // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15
+ let _10: u32; // in scope 0 at $DIR/simplify_try.rs:7:13: 7:15
+ let mut _11: u32; // in scope 0 at $DIR/simplify_try.rs:8:8: 8:9
+ scope 1 {
+ debug y => ((_0 as Ok).0: u32); // in scope 1 at $DIR/simplify_try.rs:7:9: 7:10
+ }
+ scope 2 {
+ debug err => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify_try.rs:7:14: 7:15
+ scope 3 {
+ scope 7 {
+ debug t => ((_0 as Err).0: i32); // in scope 7 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
+ }
+ scope 8 {
+ debug v => ((_0 as Err).0: i32); // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
+ let mut _12: i32; // in scope 8 at $DIR/simplify_try.rs:7:14: 7:15
+ }
+ }
+ }
+ scope 4 {
+ debug val => ((_0 as Ok).0: u32); // in scope 4 at $DIR/simplify_try.rs:7:13: 7:15
+ scope 5 {
+ }
+ }
+ scope 6 {
+- debug self => _4; // in scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
++ debug self => _0; // in scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
+ }
+
+ bb0: {
+ StorageLive(_2); // scope 0 at $DIR/simplify_try.rs:7:9: 7:10
+- StorageLive(_3); // scope 0 at $DIR/simplify_try.rs:7:13: 7:15
+- StorageLive(_4); // scope 0 at $DIR/simplify_try.rs:7:13: 7:14
+- _4 = _1; // scope 0 at $DIR/simplify_try.rs:7:13: 7:14
+- _3 = move _4; // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
+- StorageDead(_4); // scope 0 at $DIR/simplify_try.rs:7:14: 7:15
+- _5 = discriminant(_3); // scope 0 at $DIR/simplify_try.rs:7:14: 7:15
++ nop; // scope 0 at $DIR/simplify_try.rs:7:13: 7:15
++ nop; // scope 0 at $DIR/simplify_try.rs:7:13: 7:14
++ _0 = _1; // scope 0 at $DIR/simplify_try.rs:7:13: 7:14
++ nop; // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
++ nop; // scope 0 at $DIR/simplify_try.rs:7:14: 7:15
++ _5 = discriminant(_0); // scope 0 at $DIR/simplify_try.rs:7:14: 7:15
+ goto -> bb1; // scope 0 at $DIR/simplify_try.rs:7:14: 7:15
+ }
+
+ bb1: {
+- _0 = move _3; // scope 1 at $DIR/simplify_try.rs:8:5: 8:10
+- StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:7:15: 7:16
++ nop; // scope 1 at $DIR/simplify_try.rs:8:5: 8:10
++ nop; // scope 0 at $DIR/simplify_try.rs:7:15: 7:16
+ StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:9:1: 9:2
+ goto -> bb2; // scope 0 at $DIR/simplify_try.rs:9:2: 9:2
+ }
+
+ bb2: {
+ return; // scope 0 at $DIR/simplify_try.rs:9:2: 9:2
+ }
+ }
+
+ // MIR for `try_identity` after SimplifyArmIdentity
fn try_identity(_1: std::result::Result<u32, i32>) -> std::result::Result<u32, i32> {
- debug x => _1; // in scope 0 at $DIR/simplify_try.rs:5:17: 5:18
- let mut _0: std::result::Result<u32, i32>; // return place in scope 0 at $DIR/simplify_try.rs:5:41: 5:57
- let _2: u32; // in scope 0 at $DIR/simplify_try.rs:6:9: 6:10
- let mut _3: std::result::Result<u32, i32>; // in scope 0 at $DIR/simplify_try.rs:6:13: 6:15
- let mut _4: std::result::Result<u32, i32>; // in scope 0 at $DIR/simplify_try.rs:6:13: 6:14
- let mut _5: isize; // in scope 0 at $DIR/simplify_try.rs:6:14: 6:15
- let _6: i32; // in scope 0 at $DIR/simplify_try.rs:6:14: 6:15
- let mut _7: !; // in scope 0 at $DIR/simplify_try.rs:6:14: 6:15
- let mut _8: i32; // in scope 0 at $DIR/simplify_try.rs:6:14: 6:15
- let mut _9: i32; // in scope 0 at $DIR/simplify_try.rs:6:14: 6:15
- let _10: u32; // in scope 0 at $DIR/simplify_try.rs:6:13: 6:15
- let mut _11: u32; // in scope 0 at $DIR/simplify_try.rs:7:8: 7:9
+ debug x => _1; // in scope 0 at $DIR/simplify_try.rs:6:17: 6:18
+ let mut _0: std::result::Result<u32, i32>; // return place in scope 0 at $DIR/simplify_try.rs:6:41: 6:57
+ let _2: u32; // in scope 0 at $DIR/simplify_try.rs:7:9: 7:10
+ let mut _3: std::result::Result<u32, i32>; // in scope 0 at $DIR/simplify_try.rs:7:13: 7:15
+ let mut _4: std::result::Result<u32, i32>; // in scope 0 at $DIR/simplify_try.rs:7:13: 7:14
+ let mut _5: isize; // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15
+ let _6: i32; // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15
+ let mut _7: !; // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15
+ let mut _8: i32; // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15
+ let mut _9: i32; // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15
+ let _10: u32; // in scope 0 at $DIR/simplify_try.rs:7:13: 7:15
+ let mut _11: u32; // in scope 0 at $DIR/simplify_try.rs:8:8: 8:9
scope 1 {
-- debug y => _2; // in scope 1 at $DIR/simplify_try.rs:6:9: 6:10
-+ debug y => ((_0 as Ok).0: u32); // in scope 1 at $DIR/simplify_try.rs:6:9: 6:10
+- debug y => _2; // in scope 1 at $DIR/simplify_try.rs:7:9: 7:10
++ debug y => ((_0 as Ok).0: u32); // in scope 1 at $DIR/simplify_try.rs:7:9: 7:10
}
scope 2 {
-- debug err => _6; // in scope 2 at $DIR/simplify_try.rs:6:14: 6:15
-+ debug err => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify_try.rs:6:14: 6:15
+- debug err => _6; // in scope 2 at $DIR/simplify_try.rs:7:14: 7:15
++ debug err => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify_try.rs:7:14: 7:15
scope 3 {
scope 7 {
- debug t => _9; // in scope 7 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
scope 8 {
- debug v => _8; // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
+ debug v => ((_0 as Err).0: i32); // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
- let mut _12: i32; // in scope 8 at $DIR/simplify_try.rs:6:14: 6:15
+ let mut _12: i32; // in scope 8 at $DIR/simplify_try.rs:7:14: 7:15
}
}
}
scope 4 {
-- debug val => _10; // in scope 4 at $DIR/simplify_try.rs:6:13: 6:15
-+ debug val => ((_0 as Ok).0: u32); // in scope 4 at $DIR/simplify_try.rs:6:13: 6:15
+- debug val => _10; // in scope 4 at $DIR/simplify_try.rs:7:13: 7:15
++ debug val => ((_0 as Ok).0: u32); // in scope 4 at $DIR/simplify_try.rs:7:13: 7:15
scope 5 {
}
}
}
bb0: {
- StorageLive(_2); // scope 0 at $DIR/simplify_try.rs:6:9: 6:10
- StorageLive(_3); // scope 0 at $DIR/simplify_try.rs:6:13: 6:15
- StorageLive(_4); // scope 0 at $DIR/simplify_try.rs:6:13: 6:14
- _4 = _1; // scope 0 at $DIR/simplify_try.rs:6:13: 6:14
+ StorageLive(_2); // scope 0 at $DIR/simplify_try.rs:7:9: 7:10
+ StorageLive(_3); // scope 0 at $DIR/simplify_try.rs:7:13: 7:15
+ StorageLive(_4); // scope 0 at $DIR/simplify_try.rs:7:13: 7:14
+ _4 = _1; // scope 0 at $DIR/simplify_try.rs:7:13: 7:14
_3 = move _4; // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
- StorageDead(_4); // scope 0 at $DIR/simplify_try.rs:6:14: 6:15
- _5 = discriminant(_3); // scope 0 at $DIR/simplify_try.rs:6:14: 6:15
- switchInt(move _5) -> [0_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify_try.rs:6:14: 6:15
+ StorageDead(_4); // scope 0 at $DIR/simplify_try.rs:7:14: 7:15
+ _5 = discriminant(_3); // scope 0 at $DIR/simplify_try.rs:7:14: 7:15
+ switchInt(move _5) -> [0_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify_try.rs:7:14: 7:15
}
bb1: {
-- StorageLive(_10); // scope 0 at $DIR/simplify_try.rs:6:13: 6:15
-- _10 = ((_3 as Ok).0: u32); // scope 0 at $DIR/simplify_try.rs:6:13: 6:15
-- _2 = _10; // scope 5 at $DIR/simplify_try.rs:6:13: 6:15
-- StorageDead(_10); // scope 0 at $DIR/simplify_try.rs:6:14: 6:15
-+ _0 = move _3; // scope 1 at $DIR/simplify_try.rs:7:5: 7:10
- StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:6:15: 6:16
-- StorageLive(_11); // scope 1 at $DIR/simplify_try.rs:7:8: 7:9
-- _11 = _2; // scope 1 at $DIR/simplify_try.rs:7:8: 7:9
-- ((_0 as Ok).0: u32) = move _11; // scope 1 at $DIR/simplify_try.rs:7:5: 7:10
-- discriminant(_0) = 0; // scope 1 at $DIR/simplify_try.rs:7:5: 7:10
-- StorageDead(_11); // scope 1 at $DIR/simplify_try.rs:7:9: 7:10
- StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:8:1: 8:2
- goto -> bb3; // scope 0 at $DIR/simplify_try.rs:8:2: 8:2
+- StorageLive(_10); // scope 0 at $DIR/simplify_try.rs:7:13: 7:15
+- _10 = ((_3 as Ok).0: u32); // scope 0 at $DIR/simplify_try.rs:7:13: 7:15
+- _2 = _10; // scope 5 at $DIR/simplify_try.rs:7:13: 7:15
+- StorageDead(_10); // scope 0 at $DIR/simplify_try.rs:7:14: 7:15
++ _0 = move _3; // scope 1 at $DIR/simplify_try.rs:8:5: 8:10
+ StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:7:15: 7:16
+- StorageLive(_11); // scope 1 at $DIR/simplify_try.rs:8:8: 8:9
+- _11 = _2; // scope 1 at $DIR/simplify_try.rs:8:8: 8:9
+- ((_0 as Ok).0: u32) = move _11; // scope 1 at $DIR/simplify_try.rs:8:5: 8:10
+- discriminant(_0) = 0; // scope 1 at $DIR/simplify_try.rs:8:5: 8:10
+- StorageDead(_11); // scope 1 at $DIR/simplify_try.rs:8:9: 8:10
+ StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:9:1: 9:2
+ goto -> bb3; // scope 0 at $DIR/simplify_try.rs:9:2: 9:2
}
bb2: {
-- StorageLive(_6); // scope 0 at $DIR/simplify_try.rs:6:14: 6:15
-- _6 = ((_3 as Err).0: i32); // scope 0 at $DIR/simplify_try.rs:6:14: 6:15
-- StorageLive(_8); // scope 3 at $DIR/simplify_try.rs:6:14: 6:15
-- StorageLive(_9); // scope 3 at $DIR/simplify_try.rs:6:14: 6:15
-- _9 = _6; // scope 3 at $DIR/simplify_try.rs:6:14: 6:15
+- StorageLive(_6); // scope 0 at $DIR/simplify_try.rs:7:14: 7:15
+- _6 = ((_3 as Err).0: i32); // scope 0 at $DIR/simplify_try.rs:7:14: 7:15
+- StorageLive(_8); // scope 3 at $DIR/simplify_try.rs:7:14: 7:15
+- StorageLive(_9); // scope 3 at $DIR/simplify_try.rs:7:14: 7:15
+- _9 = _6; // scope 3 at $DIR/simplify_try.rs:7:14: 7:15
- _8 = move _9; // scope 7 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
-- StorageDead(_9); // scope 3 at $DIR/simplify_try.rs:6:14: 6:15
+- StorageDead(_9); // scope 3 at $DIR/simplify_try.rs:7:14: 7:15
- StorageLive(_12); // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
- _12 = move _8; // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
- ((_0 as Err).0: i32) = move _12; // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
- discriminant(_0) = 1; // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
- StorageDead(_12); // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
-- StorageDead(_8); // scope 3 at $DIR/simplify_try.rs:6:14: 6:15
-- StorageDead(_6); // scope 0 at $DIR/simplify_try.rs:6:14: 6:15
+- StorageDead(_8); // scope 3 at $DIR/simplify_try.rs:7:14: 7:15
+- StorageDead(_6); // scope 0 at $DIR/simplify_try.rs:7:14: 7:15
+ _0 = move _3; // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
- StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:6:15: 6:16
- StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:8:1: 8:2
- goto -> bb3; // scope 0 at $DIR/simplify_try.rs:6:14: 6:15
+ StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:7:15: 7:16
+ StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:9:1: 9:2
+ goto -> bb3; // scope 0 at $DIR/simplify_try.rs:7:14: 7:15
}
bb3: {
- return; // scope 0 at $DIR/simplify_try.rs:8:2: 8:2
+ return; // scope 0 at $DIR/simplify_try.rs:9:2: 9:2
}
}
// MIR for `try_identity` after SimplifyBranchSame
fn try_identity(_1: std::result::Result<u32, i32>) -> std::result::Result<u32, i32> {
- debug x => _1; // in scope 0 at $DIR/simplify_try.rs:5:17: 5:18
- let mut _0: std::result::Result<u32, i32>; // return place in scope 0 at $DIR/simplify_try.rs:5:41: 5:57
- let _2: u32; // in scope 0 at $DIR/simplify_try.rs:6:9: 6:10
- let mut _3: std::result::Result<u32, i32>; // in scope 0 at $DIR/simplify_try.rs:6:13: 6:15
- let mut _4: std::result::Result<u32, i32>; // in scope 0 at $DIR/simplify_try.rs:6:13: 6:14
- let mut _5: isize; // in scope 0 at $DIR/simplify_try.rs:6:14: 6:15
- let _6: i32; // in scope 0 at $DIR/simplify_try.rs:6:14: 6:15
- let mut _7: !; // in scope 0 at $DIR/simplify_try.rs:6:14: 6:15
- let mut _8: i32; // in scope 0 at $DIR/simplify_try.rs:6:14: 6:15
- let mut _9: i32; // in scope 0 at $DIR/simplify_try.rs:6:14: 6:15
- let _10: u32; // in scope 0 at $DIR/simplify_try.rs:6:13: 6:15
- let mut _11: u32; // in scope 0 at $DIR/simplify_try.rs:7:8: 7:9
+ debug x => _1; // in scope 0 at $DIR/simplify_try.rs:6:17: 6:18
+ let mut _0: std::result::Result<u32, i32>; // return place in scope 0 at $DIR/simplify_try.rs:6:41: 6:57
+ let _2: u32; // in scope 0 at $DIR/simplify_try.rs:7:9: 7:10
+ let mut _3: std::result::Result<u32, i32>; // in scope 0 at $DIR/simplify_try.rs:7:13: 7:15
+ let mut _4: std::result::Result<u32, i32>; // in scope 0 at $DIR/simplify_try.rs:7:13: 7:14
+ let mut _5: isize; // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15
+ let _6: i32; // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15
+ let mut _7: !; // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15
+ let mut _8: i32; // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15
+ let mut _9: i32; // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15
+ let _10: u32; // in scope 0 at $DIR/simplify_try.rs:7:13: 7:15
+ let mut _11: u32; // in scope 0 at $DIR/simplify_try.rs:8:8: 8:9
scope 1 {
- debug y => ((_0 as Ok).0: u32); // in scope 1 at $DIR/simplify_try.rs:6:9: 6:10
+ debug y => ((_0 as Ok).0: u32); // in scope 1 at $DIR/simplify_try.rs:7:9: 7:10
}
scope 2 {
- debug err => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify_try.rs:6:14: 6:15
+ debug err => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify_try.rs:7:14: 7:15
scope 3 {
scope 7 {
debug t => ((_0 as Err).0: i32); // in scope 7 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
}
scope 8 {
debug v => ((_0 as Err).0: i32); // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
- let mut _12: i32; // in scope 8 at $DIR/simplify_try.rs:6:14: 6:15
+ let mut _12: i32; // in scope 8 at $DIR/simplify_try.rs:7:14: 7:15
}
}
}
scope 4 {
- debug val => ((_0 as Ok).0: u32); // in scope 4 at $DIR/simplify_try.rs:6:13: 6:15
+ debug val => ((_0 as Ok).0: u32); // in scope 4 at $DIR/simplify_try.rs:7:13: 7:15
scope 5 {
}
}
}
bb0: {
- StorageLive(_2); // scope 0 at $DIR/simplify_try.rs:6:9: 6:10
- StorageLive(_3); // scope 0 at $DIR/simplify_try.rs:6:13: 6:15
- StorageLive(_4); // scope 0 at $DIR/simplify_try.rs:6:13: 6:14
- _4 = _1; // scope 0 at $DIR/simplify_try.rs:6:13: 6:14
+ StorageLive(_2); // scope 0 at $DIR/simplify_try.rs:7:9: 7:10
+ StorageLive(_3); // scope 0 at $DIR/simplify_try.rs:7:13: 7:15
+ StorageLive(_4); // scope 0 at $DIR/simplify_try.rs:7:13: 7:14
+ _4 = _1; // scope 0 at $DIR/simplify_try.rs:7:13: 7:14
_3 = move _4; // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
- StorageDead(_4); // scope 0 at $DIR/simplify_try.rs:6:14: 6:15
- _5 = discriminant(_3); // scope 0 at $DIR/simplify_try.rs:6:14: 6:15
- goto -> bb1; // scope 0 at $DIR/simplify_try.rs:6:14: 6:15
+ StorageDead(_4); // scope 0 at $DIR/simplify_try.rs:7:14: 7:15
+ _5 = discriminant(_3); // scope 0 at $DIR/simplify_try.rs:7:14: 7:15
+ goto -> bb1; // scope 0 at $DIR/simplify_try.rs:7:14: 7:15
}
bb1: {
- _0 = move _3; // scope 1 at $DIR/simplify_try.rs:7:5: 7:10
- StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:6:15: 6:16
- StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:8:1: 8:2
- goto -> bb2; // scope 0 at $DIR/simplify_try.rs:8:2: 8:2
+ _0 = move _3; // scope 1 at $DIR/simplify_try.rs:8:5: 8:10
+ StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:7:15: 7:16
+ StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:9:1: 9:2
+ goto -> bb2; // scope 0 at $DIR/simplify_try.rs:9:2: 9:2
}
bb2: {
- return; // scope 0 at $DIR/simplify_try.rs:8:2: 8:2
+ return; // scope 0 at $DIR/simplify_try.rs:9:2: 9:2
}
}
// MIR for `try_identity` after SimplifyLocals
fn try_identity(_1: std::result::Result<u32, i32>) -> std::result::Result<u32, i32> {
- debug x => _1; // in scope 0 at $DIR/simplify_try.rs:5:17: 5:18
- let mut _0: std::result::Result<u32, i32>; // return place in scope 0 at $DIR/simplify_try.rs:5:41: 5:57
+ debug x => _1; // in scope 0 at $DIR/simplify_try.rs:6:17: 6:18
+ let mut _0: std::result::Result<u32, i32>; // return place in scope 0 at $DIR/simplify_try.rs:6:41: 6:57
scope 1 {
- debug y => ((_0 as Ok).0: u32); // in scope 1 at $DIR/simplify_try.rs:6:9: 6:10
+ debug y => ((_0 as Ok).0: u32); // in scope 1 at $DIR/simplify_try.rs:7:9: 7:10
}
scope 2 {
- debug err => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify_try.rs:6:14: 6:15
+ debug err => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify_try.rs:7:14: 7:15
scope 3 {
scope 7 {
debug t => ((_0 as Err).0: i32); // in scope 7 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
}
}
scope 4 {
- debug val => ((_0 as Ok).0: u32); // in scope 4 at $DIR/simplify_try.rs:6:13: 6:15
+ debug val => ((_0 as Ok).0: u32); // in scope 4 at $DIR/simplify_try.rs:7:13: 7:15
scope 5 {
}
}
scope 6 {
- debug self => _1; // in scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
+ debug self => _0; // in scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
}
bb0: {
- _0 = move _1; // scope 1 at $DIR/simplify_try.rs:7:5: 7:10
- return; // scope 0 at $DIR/simplify_try.rs:8:2: 8:2
+ _0 = _1; // scope 0 at $DIR/simplify_try.rs:7:13: 7:14
+ return; // scope 0 at $DIR/simplify_try.rs:9:2: 9:2
}
}
error[E0391]: cycle detected when normalizing `<() as Tr>::A`
|
-note: ...which requires const-evaluating + checking `Tr::A`...
+note: ...which requires simplifying constant for the type system `Tr::A`...
--> $DIR/defaults-cyclic-fail.rs:6:5
|
LL | const A: u8 = Self::B;
| ^^^^^^^^^^^^^^^^^^^^^^
-note: ...which requires const-evaluating + checking `Tr::A`...
+note: ...which requires simplifying constant for the type system `Tr::A`...
--> $DIR/defaults-cyclic-fail.rs:6:5
|
LL | const A: u8 = Self::B;
| ^^^^^^^^^^^^^^^^^^^^^^
-note: ...which requires const-evaluating `Tr::A`...
+note: ...which requires const-evaluating + checking `Tr::A`...
--> $DIR/defaults-cyclic-fail.rs:6:5
|
LL | const A: u8 = Self::B;
| ^^^^^^^^^^^^^^^^^^^^^^
= note: ...which requires normalizing `<() as Tr>::B`...
-note: ...which requires const-evaluating + checking `Tr::B`...
+note: ...which requires simplifying constant for the type system `Tr::B`...
--> $DIR/defaults-cyclic-fail.rs:8:5
|
LL | const B: u8 = Self::A;
| ^^^^^^^^^^^^^^^^^^^^^^
-note: ...which requires const-evaluating + checking `Tr::B`...
+note: ...which requires simplifying constant for the type system `Tr::B`...
--> $DIR/defaults-cyclic-fail.rs:8:5
|
LL | const B: u8 = Self::A;
| ^^^^^^^^^^^^^^^^^^^^^^
-note: ...which requires const-evaluating `Tr::B`...
+note: ...which requires const-evaluating + checking `Tr::B`...
--> $DIR/defaults-cyclic-fail.rs:8:5
|
LL | const B: u8 = Self::A;
| ^^^^^^^^^^^^^^^^^^^^^^
= note: ...which again requires normalizing `<() as Tr>::A`, completing the cycle
-note: cycle used when const-evaluating `main::promoted[2]`
+note: cycle used when const-evaluating + checking `main::promoted[2]`
--> $DIR/defaults-cyclic-fail.rs:14:1
|
LL | fn main() {
-error[E0391]: cycle detected when const-evaluating + checking `IMPL_REF_BAR`
+error[E0391]: cycle detected when simplifying constant for the type system `IMPL_REF_BAR`
--> $DIR/issue-24949-assoc-const-static-recursion-impl.rs:7:1
|
LL | const IMPL_REF_BAR: u32 = GlobalImplRef::BAR;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
-note: ...which requires const-evaluating + checking `IMPL_REF_BAR`...
+note: ...which requires simplifying constant for the type system `IMPL_REF_BAR`...
--> $DIR/issue-24949-assoc-const-static-recursion-impl.rs:7:1
|
LL | const IMPL_REF_BAR: u32 = GlobalImplRef::BAR;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-note: ...which requires const-evaluating `IMPL_REF_BAR`...
+note: ...which requires const-evaluating + checking `IMPL_REF_BAR`...
--> $DIR/issue-24949-assoc-const-static-recursion-impl.rs:7:1
|
LL | const IMPL_REF_BAR: u32 = GlobalImplRef::BAR;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: ...which requires normalizing `<impl at $DIR/issue-24949-assoc-const-static-recursion-impl.rs:11:1: 13:2>::BAR`...
-note: ...which requires const-evaluating + checking `<impl at $DIR/issue-24949-assoc-const-static-recursion-impl.rs:11:1: 13:2>::BAR`...
+note: ...which requires simplifying constant for the type system `<impl at $DIR/issue-24949-assoc-const-static-recursion-impl.rs:11:1: 13:2>::BAR`...
--> $DIR/issue-24949-assoc-const-static-recursion-impl.rs:12:5
|
LL | const BAR: u32 = IMPL_REF_BAR;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-note: ...which requires const-evaluating + checking `<impl at $DIR/issue-24949-assoc-const-static-recursion-impl.rs:11:1: 13:2>::BAR`...
+note: ...which requires simplifying constant for the type system `<impl at $DIR/issue-24949-assoc-const-static-recursion-impl.rs:11:1: 13:2>::BAR`...
--> $DIR/issue-24949-assoc-const-static-recursion-impl.rs:12:5
|
LL | const BAR: u32 = IMPL_REF_BAR;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-note: ...which requires const-evaluating `<impl at $DIR/issue-24949-assoc-const-static-recursion-impl.rs:11:1: 13:2>::BAR`...
+note: ...which requires const-evaluating + checking `<impl at $DIR/issue-24949-assoc-const-static-recursion-impl.rs:11:1: 13:2>::BAR`...
--> $DIR/issue-24949-assoc-const-static-recursion-impl.rs:12:5
|
LL | const BAR: u32 = IMPL_REF_BAR;
LL | const BAR: u32 = IMPL_REF_BAR;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: ...which requires normalizing `IMPL_REF_BAR`...
- = note: ...which again requires const-evaluating + checking `IMPL_REF_BAR`, completing the cycle
+ = note: ...which again requires simplifying constant for the type system `IMPL_REF_BAR`, completing the cycle
= note: cycle used when running analysis passes on this crate
error: aborting due to previous error
-error[E0391]: cycle detected when const-evaluating + checking `DEFAULT_REF_BAR`
+error[E0391]: cycle detected when simplifying constant for the type system `DEFAULT_REF_BAR`
--> $DIR/issue-24949-assoc-const-static-recursion-trait-default.rs:11:1
|
LL | const DEFAULT_REF_BAR: u32 = <GlobalDefaultRef>::BAR;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
-note: ...which requires const-evaluating + checking `DEFAULT_REF_BAR`...
+note: ...which requires simplifying constant for the type system `DEFAULT_REF_BAR`...
--> $DIR/issue-24949-assoc-const-static-recursion-trait-default.rs:11:1
|
LL | const DEFAULT_REF_BAR: u32 = <GlobalDefaultRef>::BAR;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-note: ...which requires const-evaluating `DEFAULT_REF_BAR`...
+note: ...which requires const-evaluating + checking `DEFAULT_REF_BAR`...
--> $DIR/issue-24949-assoc-const-static-recursion-trait-default.rs:11:1
|
LL | const DEFAULT_REF_BAR: u32 = <GlobalDefaultRef>::BAR;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: ...which requires normalizing `<GlobalDefaultRef as FooDefault>::BAR`...
-note: ...which requires const-evaluating + checking `FooDefault::BAR`...
+note: ...which requires simplifying constant for the type system `FooDefault::BAR`...
--> $DIR/issue-24949-assoc-const-static-recursion-trait-default.rs:8:5
|
LL | const BAR: u32 = DEFAULT_REF_BAR;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-note: ...which requires const-evaluating + checking `FooDefault::BAR`...
+note: ...which requires simplifying constant for the type system `FooDefault::BAR`...
--> $DIR/issue-24949-assoc-const-static-recursion-trait-default.rs:8:5
|
LL | const BAR: u32 = DEFAULT_REF_BAR;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-note: ...which requires const-evaluating `FooDefault::BAR`...
+note: ...which requires const-evaluating + checking `FooDefault::BAR`...
--> $DIR/issue-24949-assoc-const-static-recursion-trait-default.rs:8:5
|
LL | const BAR: u32 = DEFAULT_REF_BAR;
LL | const BAR: u32 = DEFAULT_REF_BAR;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: ...which requires normalizing `DEFAULT_REF_BAR`...
- = note: ...which again requires const-evaluating + checking `DEFAULT_REF_BAR`, completing the cycle
+ = note: ...which again requires simplifying constant for the type system `DEFAULT_REF_BAR`, completing the cycle
= note: cycle used when running analysis passes on this crate
error: aborting due to previous error
-error[E0391]: cycle detected when const-evaluating + checking `TRAIT_REF_BAR`
+error[E0391]: cycle detected when simplifying constant for the type system `TRAIT_REF_BAR`
--> $DIR/issue-24949-assoc-const-static-recursion-trait.rs:7:1
|
LL | const TRAIT_REF_BAR: u32 = <GlobalTraitRef>::BAR;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
-note: ...which requires const-evaluating + checking `TRAIT_REF_BAR`...
+note: ...which requires simplifying constant for the type system `TRAIT_REF_BAR`...
--> $DIR/issue-24949-assoc-const-static-recursion-trait.rs:7:1
|
LL | const TRAIT_REF_BAR: u32 = <GlobalTraitRef>::BAR;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-note: ...which requires const-evaluating `TRAIT_REF_BAR`...
+note: ...which requires const-evaluating + checking `TRAIT_REF_BAR`...
--> $DIR/issue-24949-assoc-const-static-recursion-trait.rs:7:1
|
LL | const TRAIT_REF_BAR: u32 = <GlobalTraitRef>::BAR;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: ...which requires normalizing `<GlobalTraitRef as Foo>::BAR`...
-note: ...which requires const-evaluating + checking `<impl at $DIR/issue-24949-assoc-const-static-recursion-trait.rs:11:1: 13:2>::BAR`...
+note: ...which requires simplifying constant for the type system `<impl at $DIR/issue-24949-assoc-const-static-recursion-trait.rs:11:1: 13:2>::BAR`...
--> $DIR/issue-24949-assoc-const-static-recursion-trait.rs:12:5
|
LL | const BAR: u32 = TRAIT_REF_BAR;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-note: ...which requires const-evaluating + checking `<impl at $DIR/issue-24949-assoc-const-static-recursion-trait.rs:11:1: 13:2>::BAR`...
+note: ...which requires simplifying constant for the type system `<impl at $DIR/issue-24949-assoc-const-static-recursion-trait.rs:11:1: 13:2>::BAR`...
--> $DIR/issue-24949-assoc-const-static-recursion-trait.rs:12:5
|
LL | const BAR: u32 = TRAIT_REF_BAR;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-note: ...which requires const-evaluating `<impl at $DIR/issue-24949-assoc-const-static-recursion-trait.rs:11:1: 13:2>::BAR`...
+note: ...which requires const-evaluating + checking `<impl at $DIR/issue-24949-assoc-const-static-recursion-trait.rs:11:1: 13:2>::BAR`...
--> $DIR/issue-24949-assoc-const-static-recursion-trait.rs:12:5
|
LL | const BAR: u32 = TRAIT_REF_BAR;
LL | const BAR: u32 = TRAIT_REF_BAR;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: ...which requires normalizing `TRAIT_REF_BAR`...
- = note: ...which again requires const-evaluating + checking `TRAIT_REF_BAR`, completing the cycle
+ = note: ...which again requires simplifying constant for the type system `TRAIT_REF_BAR`, completing the cycle
= note: cycle used when running analysis passes on this crate
error: aborting due to previous error
--- /dev/null
+// build-pass
+
+// Closures include captured types twice in a type tree.
+//
+// Wrapping one closure with another leads to doubling
+// the amount of types in the type tree.
+//
+// This test ensures that rust can handle
+// deeply nested type trees with a lot
+// of duplicated subtrees.
+
+fn dup(f: impl Fn(i32) -> i32) -> impl Fn(i32) -> i32 {
+ move |a| f(a * 2)
+}
+
+fn main() {
+ let f = |a| a;
+
+ let f = dup(f);
+ let f = dup(f);
+ let f = dup(f);
+ let f = dup(f);
+ let f = dup(f);
+
+ let f = dup(f);
+ let f = dup(f);
+ let f = dup(f);
+ let f = dup(f);
+ let f = dup(f);
+
+ let f = dup(f);
+ let f = dup(f);
+ let f = dup(f);
+ let f = dup(f);
+ let f = dup(f);
+
+ let f = dup(f);
+ let f = dup(f);
+ let f = dup(f);
+ let f = dup(f);
+ let f = dup(f);
+
+ // Compiler dies around here if it tries
+ // to walk the tree exhaustively.
+
+ let f = dup(f);
+ let f = dup(f);
+ let f = dup(f);
+ let f = dup(f);
+ let f = dup(f);
+
+ let f = dup(f);
+ let f = dup(f);
+ let f = dup(f);
+ let f = dup(f);
+ let f = dup(f);
+
+ println!("Type size was at least {}", f(1));
+}
--- /dev/null
+#![feature(const_generics, const_evaluatable_checked)]
+#![allow(incomplete_features)]
+
+pub fn test1<T>() -> [u8; std::mem::size_of::<T>() - 1]
+where
+ [u8; std::mem::size_of::<T>() - 1]: Sized,
+{
+ [0; std::mem::size_of::<T>() - 1]
+}
--- /dev/null
+// aux-build:const_evaluatable_lib.rs
+// run-pass
+#![feature(const_generics, const_evaluatable_checked)]
+#![allow(incomplete_features)]
+extern crate const_evaluatable_lib;
+
+fn user<T>() where [u8; std::mem::size_of::<T>() - 1]: Sized {
+ assert_eq!(const_evaluatable_lib::test1::<T>(), [0; std::mem::size_of::<T>() - 1]);
+}
+
+fn main() {
+ assert_eq!(const_evaluatable_lib::test1::<u32>(), [0; 3]);
+ user::<u32>();
+ user::<u64>();
+}
--- /dev/null
+// aux-build:const_evaluatable_lib.rs
+#![feature(const_generics, const_evaluatable_checked)]
+#![allow(incomplete_features)]
+extern crate const_evaluatable_lib;
+
+fn user<T>() {
+ let _ = const_evaluatable_lib::test1::<T>();
+ //~^ ERROR constant expression depends
+ //~| ERROR constant expression depends
+ //~| ERROR constant expression depends
+}
+
+fn main() {}
--- /dev/null
+error: constant expression depends on a generic parameter
+ --> $DIR/cross_crate_predicate.rs:7:13
+ |
+LL | let _ = const_evaluatable_lib::test1::<T>();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ ::: $DIR/auxiliary/const_evaluatable_lib.rs:6:41
+ |
+LL | [u8; std::mem::size_of::<T>() - 1]: Sized,
+ | ----- required by this bound in `test1`
+ |
+ = note: this may fail depending on what value the parameter takes
+
+error: constant expression depends on a generic parameter
+ --> $DIR/cross_crate_predicate.rs:7:13
+ |
+LL | let _ = const_evaluatable_lib::test1::<T>();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ ::: $DIR/auxiliary/const_evaluatable_lib.rs:6:41
+ |
+LL | [u8; std::mem::size_of::<T>() - 1]: Sized,
+ | ----- required by this bound in `test1::{{constant}}#1`
+ |
+ = note: this may fail depending on what value the parameter takes
+
+error: constant expression depends on a generic parameter
+ --> $DIR/cross_crate_predicate.rs:7:13
+ |
+LL | let _ = const_evaluatable_lib::test1::<T>();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: this may fail depending on what value the parameter takes
+
+error: aborting due to 3 previous errors
+
--- /dev/null
+// run-pass
+#![feature(const_generics, const_evaluatable_checked)]
+#![allow(incomplete_features)]
+
+const fn test_me<T>(a: usize, b: usize) -> usize {
+ if a < b {
+ std::mem::size_of::<T>()
+ } else {
+ std::usize::MAX
+ }
+}
+
+fn test_simple<T>() -> [u8; std::mem::size_of::<T>()]
+where
+ [u8; std::mem::size_of::<T>()]: Sized,
+{
+ [0; std::mem::size_of::<T>()]
+}
+
+fn test_with_args<T, const N: usize>() -> [u8; test_me::<T>(N, N + 1) + N]
+where
+ [u8; test_me::<T>(N, N + 1) + N]: Sized,
+{
+ [0; test_me::<T>(N, N + 1) + N]
+}
+
+fn main() {
+ assert_eq!([0; 8], test_simple::<u64>());
+ assert_eq!([0; 12], test_with_args::<u64, 4>());
+}
--- /dev/null
+// run-pass
+#![feature(const_generics, const_evaluatable_checked)]
+#![allow(incomplete_features)]
+
+struct Foo<const B: bool>;
+
+fn test<const N: usize>() -> Foo<{ N > 10 }> where Foo<{ N > 10 }>: Sized {
+ Foo
+}
+
+fn main() {
+ let _: Foo<true> = test::<12>();
+ let _: Foo<false> = test::<9>();
+}
--- /dev/null
+#![feature(const_generics, const_evaluatable_checked)]
+#![allow(incomplete_features)]
+
+// We do not yet want to support let-bindings in abstract consts,
+// so this test should keep failing for now.
+fn test<const N: usize>() -> [u8; { let x = N; N + 1 }] where [u8; { let x = N; N + 1 }]: Default {
+ //~^ ERROR constant expression depends
+ //~| ERROR constant expression depends
+ Default::default()
+}
+
+fn main() {
+ let x = test::<31>();
+ assert_eq!(x, [0; 32]);
+}
--- /dev/null
+error: constant expression depends on a generic parameter
+ --> $DIR/let-bindings.rs:6:91
+ |
+LL | fn test<const N: usize>() -> [u8; { let x = N; N + 1 }] where [u8; { let x = N; N + 1 }]: Default {
+ | ^^^^^^^ required by this bound in `test::{{constant}}#0`
+ |
+ = note: this may fail depending on what value the parameter takes
+
+error: constant expression depends on a generic parameter
+ --> $DIR/let-bindings.rs:6:30
+ |
+LL | fn test<const N: usize>() -> [u8; { let x = N; N + 1 }] where [u8; { let x = N; N + 1 }]: Default {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: this may fail depending on what value the parameter takes
+
+error: aborting due to 2 previous errors
+
error: generic parameters must not be used inside of non trivial constant values
- --> $DIR/simple.rs:8:33
+ --> $DIR/simple.rs:8:53
|
-LL | type Arr<const N: usize> = [u8; N - 1];
- | ^ non-trivial anonymous constants must not depend on the parameter `N`
+LL | fn test<const N: usize>() -> [u8; N - 1] where [u8; N - 1]: Default {
+ | ^ non-trivial anonymous constants must not depend on the parameter `N`
|
= help: it is currently only allowed to use either `N` or `{ N }` as generic constants
-error: aborting due to previous error
+error: generic parameters must not be used inside of non trivial constant values
+ --> $DIR/simple.rs:8:35
+ |
+LL | fn test<const N: usize>() -> [u8; N - 1] where [u8; N - 1]: Default {
+ | ^ non-trivial anonymous constants must not depend on the parameter `N`
+ |
+ = help: it is currently only allowed to use either `N` or `{ N }` as generic constants
+
+error: aborting due to 2 previous errors
#![feature(const_evaluatable_checked)]
#![allow(incomplete_features)]
-type Arr<const N: usize> = [u8; N - 1];
-//[min]~^ ERROR generic parameters must not be used inside of non trivial constant values
-
-fn test<const N: usize>() -> Arr<N> where Arr<N>: Default {
+fn test<const N: usize>() -> [u8; N - 1] where [u8; N - 1]: Default {
+ //[min]~^ ERROR generic parameters
+ //[min]~| ERROR generic parameters
Default::default()
}
--- /dev/null
+// run-pass
+#![feature(const_generics, const_evaluatable_checked)]
+#![allow(incomplete_features)]
+
+struct Foo<const B: bool>;
+
+fn test<const N: usize>() -> Foo<{ !(N > 10) }> where Foo<{ !(N > 10) }>: Sized {
+ Foo
+}
+
+fn main() {
+ let _: Foo<false> = test::<12>();
+ let _: Foo<true> = test::<9>();
+}
// run-pass
// Test a ZST enum whose dicriminant is ~0i128. This caused an ICE when casting to a i32.
+#![feature(test)]
+use std::hint::black_box;
#[derive(Copy, Clone)]
enum Nums {
const NEG_ONE_I64: i64 = Nums::NegOne as i64;
const NEG_ONE_I128: i128 = Nums::NegOne as i128;
-#[inline(never)]
-fn identity<T>(t: T) -> T { t }
-
fn test_as_arg(n: Nums) {
assert_eq!(-1i8, n as i8);
assert_eq!(-1i16, n as i16);
assert_eq!(-1i64, kind as i64);
assert_eq!(-1i128, kind as i128);
- assert_eq!(-1i8, identity(kind) as i8);
- assert_eq!(-1i16, identity(kind) as i16);
- assert_eq!(-1i32, identity(kind) as i32);
- assert_eq!(-1i64, identity(kind) as i64);
- assert_eq!(-1i128, identity(kind) as i128);
+ assert_eq!(-1i8, black_box(kind) as i8);
+ assert_eq!(-1i16, black_box(kind) as i16);
+ assert_eq!(-1i32, black_box(kind) as i32);
+ assert_eq!(-1i64, black_box(kind) as i64);
+ assert_eq!(-1i128, black_box(kind) as i128);
test_as_arg(Nums::NegOne);
= note: `#[deny(const_err)]` on by default
query stack during panic:
-#0 [const_eval_raw] const-evaluating `main::promoted[1]`
-#1 [const_eval_validated] const-evaluating + checking `main::promoted[1]`
-#2 [const_eval_validated] const-evaluating + checking `main::promoted[1]`
+#0 [eval_to_allocation_raw] const-evaluating + checking `main::promoted[1]`
+#1 [eval_to_const_value_raw] simplifying constant for the type system `main::promoted[1]`
+#2 [eval_to_const_value_raw] simplifying constant for the type system `main::promoted[1]`
#3 [normalize_generic_arg_after_erasing_regions] normalizing `main::promoted[1]`
#4 [optimized_mir] optimizing MIR for `main`
#5 [collect_and_partition_mono_items] collect_and_partition_mono_items
--> $DIR/const-pointer-values-in-various-types.rs:37:5
|
LL | const I32_REF_U64_UNION: u64 = unsafe { Nonsense { int_32_ref: &3 }.uint_64 };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc22, but expected initialized plain (non-pointer) bytes
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc18, but expected initialized plain (non-pointer) bytes
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
--> $DIR/const-pointer-values-in-various-types.rs:52:5
|
LL | const I32_REF_I64_UNION: i64 = unsafe { Nonsense { int_32_ref: &3 }.int_64 };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc47, but expected initialized plain (non-pointer) bytes
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc38, but expected initialized plain (non-pointer) bytes
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
--> $DIR/const-pointer-values-in-various-types.rs:61:5
|
LL | const I32_REF_F64_UNION: f64 = unsafe { Nonsense { int_32_ref: &3 }.float_64 };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc62, but expected initialized plain (non-pointer) bytes
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc50, but expected initialized plain (non-pointer) bytes
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
--> $DIR/const-pointer-values-in-various-types.rs:79:5
|
LL | const STR_U64_UNION: u64 = unsafe { Nonsense { stringy: "3" }.uint_64 };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc86, but expected initialized plain (non-pointer) bytes
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc71, but expected initialized plain (non-pointer) bytes
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
--> $DIR/const-pointer-values-in-various-types.rs:94:5
|
LL | const STR_I64_UNION: i64 = unsafe { Nonsense { stringy: "3" }.int_64 };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc101, but expected initialized plain (non-pointer) bytes
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc86, but expected initialized plain (non-pointer) bytes
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
--> $DIR/const-pointer-values-in-various-types.rs:103:5
|
LL | const STR_F64_UNION: f64 = unsafe { Nonsense { stringy: "3" }.float_64 };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc110, but expected initialized plain (non-pointer) bytes
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc95, but expected initialized plain (non-pointer) bytes
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+// check-pass
+
+// This test exhibits undefined behavior, but it is very expensive and complex to check for such
+// UB in constants.
+// Thus, we do not detect it if you create references to statics in ways that are UB.
+
enum Foo {
A = 5,
B = 42,
u8: &'static u8,
}
static BAR: u8 = 5;
-static FOO: (&Foo, &Bar) = unsafe {( //~ undefined behavior
- Union { u8: &BAR }.foo,
- Union { u8: &BAR }.bar,
-)};
-static FOO2: (&Foo, &Bar) = unsafe {(std::mem::transmute(&BAR), std::mem::transmute(&BAR))};
-//~^ undefined behavior
+static FOO: (&Foo, &Bar) = unsafe {
+ (
+ // undefined behavior
+ Union { u8: &BAR }.foo,
+ Union { u8: &BAR }.bar,
+ )
+};
+static FOO2: (&Foo, &Bar) = unsafe { (std::mem::transmute(&BAR), std::mem::transmute(&BAR)) };
+//^ undefined behavior
fn main() {}
+++ /dev/null
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/double_check2.rs:16:1
- |
-LL | / static FOO: (&Foo, &Bar) = unsafe {(
-LL | | Union { u8: &BAR }.foo,
-LL | | Union { u8: &BAR }.bar,
-LL | | )};
- | |___^ type validation failed: encountered 0x05 at .1.<deref>.<enum-tag>, but expected a valid enum tag
- |
- = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/double_check2.rs:20:1
- |
-LL | static FOO2: (&Foo, &Bar) = unsafe {(std::mem::transmute(&BAR), std::mem::transmute(&BAR))};
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x05 at .1.<deref>.<enum-tag>, but expected a valid enum tag
- |
- = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0080`.
--> $DIR/ub-enum.rs:30:1
|
LL | const BAD_ENUM_WRAPPED: Wrap<Enum> = unsafe { mem::transmute(&1) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc13 at .0.<enum-tag>, but expected initialized plain (non-pointer) bytes
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc12 at .0.<enum-tag>, but expected initialized plain (non-pointer) bytes
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
--> $DIR/ub-enum.rs:44:1
|
LL | const BAD_ENUM2_PTR: Enum2 = unsafe { mem::transmute(&0) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc20 at .<enum-tag>, but expected initialized plain (non-pointer) bytes
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc18 at .<enum-tag>, but expected initialized plain (non-pointer) bytes
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
--> $DIR/ub-enum.rs:47:1
|
LL | const BAD_ENUM2_WRAPPED: Wrap<Enum2> = unsafe { mem::transmute(&0) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc25 at .0.<enum-tag>, but expected initialized plain (non-pointer) bytes
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc22 at .0.<enum-tag>, but expected initialized plain (non-pointer) bytes
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
--> $DIR/ub-enum.rs:60:1
|
LL | const BAD_ENUM2_OPTION_PTR: Option<Enum2> = unsafe { mem::transmute(&0) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc32 at .<enum-tag>, but expected initialized plain (non-pointer) bytes
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc28 at .<enum-tag>, but expected initialized plain (non-pointer) bytes
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
LL | | let ptr: &[u8; 256] = mem::transmute(&0u8); // &0 gets promoted so it does not dangle
LL | | // Use address-of-element for pointer arithmetic. This could wrap around to NULL!
LL | | let out_of_bounds_ptr = &ptr[255];
- | | ^^^^^^^^^ memory access failed: pointer must be in-bounds at offset 256, but is outside bounds of alloc11 which has size 1
+ | | ^^^^^^^^^ memory access failed: pointer must be in-bounds at offset 256, but is outside bounds of alloc10 which has size 1
LL | | mem::transmute(out_of_bounds_ptr)
LL | | } };
| |____-
--> $DIR/ub-ref.rs:23:1
|
LL | const REF_AS_USIZE: usize = unsafe { mem::transmute(&0) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc16, but expected initialized plain (non-pointer) bytes
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc14, but expected initialized plain (non-pointer) bytes
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-error[E0391]: cycle detected when const-evaluating + checking `Foo::bytes::{{constant}}#0`
+error[E0391]: cycle detected when simplifying constant for the type system `Foo::bytes::{{constant}}#0`
--> $DIR/const-size_of-cycle.rs:4:17
|
LL | bytes: [u8; std::mem::size_of::<Foo>()]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
-note: ...which requires const-evaluating + checking `Foo::bytes::{{constant}}#0`...
+note: ...which requires simplifying constant for the type system `Foo::bytes::{{constant}}#0`...
--> $DIR/const-size_of-cycle.rs:4:17
|
LL | bytes: [u8; std::mem::size_of::<Foo>()]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
-note: ...which requires const-evaluating `Foo::bytes::{{constant}}#0`...
+note: ...which requires const-evaluating + checking `Foo::bytes::{{constant}}#0`...
--> $DIR/const-size_of-cycle.rs:4:17
|
LL | bytes: [u8; std::mem::size_of::<Foo>()]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
-note: ...which requires const-evaluating `std::mem::size_of`...
+note: ...which requires const-evaluating + checking `std::mem::size_of`...
--> $SRC_DIR/core/src/mem/mod.rs:LL:COL
|
LL | pub const fn size_of<T>() -> usize {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-note: ...which requires const-evaluating + checking `std::intrinsics::size_of`...
+note: ...which requires simplifying constant for the type system `std::intrinsics::size_of`...
--> $SRC_DIR/core/src/intrinsics.rs:LL:COL
|
LL | pub fn size_of<T>() -> usize;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: ...which requires computing layout of `Foo`...
= note: ...which requires normalizing `[u8; _]`...
- = note: ...which again requires const-evaluating + checking `Foo::bytes::{{constant}}#0`, completing the cycle
+ = note: ...which again requires simplifying constant for the type system `Foo::bytes::{{constant}}#0`, completing the cycle
note: cycle used when checking that `Foo` is well-formed
--> $DIR/const-size_of-cycle.rs:3:1
|
// run-pass
#![feature(const_discriminant)]
+#![feature(test)]
#![allow(dead_code)]
use std::mem::{discriminant, Discriminant};
-
-// `discriminant(const_expr)` may get const-propagated.
-// As we want to check that const-eval is equal to ordinary exection,
-// we wrap `const_expr` with a function which is not const to prevent this.
-#[inline(never)]
-fn identity<T>(x: T) -> T { x }
+use std::hint::black_box;
enum Test {
A(u8),
fn main() {
assert_eq!(TEST_A, TEST_A_OTHER);
- assert_eq!(TEST_A, discriminant(identity(&Test::A(17))));
- assert_eq!(TEST_B, discriminant(identity(&Test::B)));
+ assert_eq!(TEST_A, discriminant(black_box(&Test::A(17))));
+ assert_eq!(TEST_B, discriminant(black_box(&Test::B)));
assert_ne!(TEST_A, TEST_B);
- assert_ne!(TEST_B, discriminant(identity(&Test::C { a: 42, b: 7 })));
+ assert_ne!(TEST_B, discriminant(black_box(&Test::C { a: 42, b: 7 })));
- assert_eq!(TEST_V, discriminant(identity(&SingleVariant::V)));
+ assert_eq!(TEST_V, discriminant(black_box(&SingleVariant::V)));
}
+++ /dev/null
-// ignore-tidy-linelength
-// We do not promote mutable references.
-static mut TEST1: Option<&mut [i32]> = Some(&mut [1, 2, 3]); //~ ERROR temporary value dropped while borrowed
-
-static mut TEST2: &'static mut [i32] = {
- let x = &mut [1,2,3]; //~ ERROR temporary value dropped while borrowed
- x
-};
-
-fn main() {}
+++ /dev/null
-error[E0716]: temporary value dropped while borrowed
- --> $DIR/promote-no-mut.rs:3:50
- |
-LL | static mut TEST1: Option<&mut [i32]> = Some(&mut [1, 2, 3]);
- | ----------^^^^^^^^^-
- | | | |
- | | | temporary value is freed at the end of this statement
- | | creates a temporary which is freed while still in use
- | using this value as a static requires that borrow lasts for `'static`
-
-error[E0716]: temporary value dropped while borrowed
- --> $DIR/promote-no-mut.rs:6:18
- |
-LL | let x = &mut [1,2,3];
- | ^^^^^^^ creates a temporary which is freed while still in use
-LL | x
- | - using this value as a static requires that borrow lasts for `'static`
-LL | };
- | - temporary value is freed at the end of this statement
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0716`.
--- /dev/null
+// ignore-tidy-linelength
+// Test various things that we do not want to promote.
+#![allow(unconditional_panic, const_err)]
+#![feature(const_fn, const_fn_union)]
+
+// We do not promote mutable references.
+static mut TEST1: Option<&mut [i32]> = Some(&mut [1, 2, 3]); //~ ERROR temporary value dropped while borrowed
+
+static mut TEST2: &'static mut [i32] = {
+ let x = &mut [1,2,3]; //~ ERROR temporary value dropped while borrowed
+ x
+};
+
+// We do not promote fn calls in `fn`, including `const fn`.
+pub const fn promote_cal(b: bool) -> i32 {
+ const fn foo() { [()][42] }
+
+ if b {
+ let _x: &'static () = &foo(); //~ ERROR temporary value dropped while borrowed
+ }
+ 13
+}
+
+// We do not promote union field accesses in `fn.
+union U { x: i32, y: i32 }
+pub const fn promote_union() {
+ let _x: &'static i32 = &unsafe { U { x: 0 }.x }; //~ ERROR temporary value dropped while borrowed
+}
+
+fn main() {}
--- /dev/null
+error[E0716]: temporary value dropped while borrowed
+ --> $DIR/promote-not.rs:7:50
+ |
+LL | static mut TEST1: Option<&mut [i32]> = Some(&mut [1, 2, 3]);
+ | ----------^^^^^^^^^-
+ | | | |
+ | | | temporary value is freed at the end of this statement
+ | | creates a temporary which is freed while still in use
+ | using this value as a static requires that borrow lasts for `'static`
+
+error[E0716]: temporary value dropped while borrowed
+ --> $DIR/promote-not.rs:10:18
+ |
+LL | let x = &mut [1,2,3];
+ | ^^^^^^^ creates a temporary which is freed while still in use
+LL | x
+ | - using this value as a static requires that borrow lasts for `'static`
+LL | };
+ | - temporary value is freed at the end of this statement
+
+error[E0716]: temporary value dropped while borrowed
+ --> $DIR/promote-not.rs:19:32
+ |
+LL | let _x: &'static () = &foo();
+ | ----------- ^^^^^ creates a temporary which is freed while still in use
+ | |
+ | type annotation requires that borrow lasts for `'static`
+LL | }
+ | - temporary value is freed at the end of this statement
+
+error[E0716]: temporary value dropped while borrowed
+ --> $DIR/promote-not.rs:27:29
+ |
+LL | let _x: &'static i32 = &unsafe { U { x: 0 }.x };
+ | ------------ ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+ | |
+ | type annotation requires that borrow lasts for `'static`
+LL | }
+ | - temporary value is freed at the end of this statement
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0716`.
-// run-pass
+// check-pass
// compile-flags: -O
-error[E0391]: cycle detected when const-evaluating `FOO`
+error[E0391]: cycle detected when const-evaluating + checking `FOO`
--> $DIR/recursive-zst-static.rs:10:1
|
LL | static FOO: () = FOO;
| ^^^^^^^^^^^^^^^^^^^^^
|
-note: ...which requires const-evaluating `FOO`...
- --> $DIR/recursive-zst-static.rs:10:1
- |
-LL | static FOO: () = FOO;
- | ^^^^^^^^^^^^^^^^^^^^^
- = note: ...which again requires const-evaluating `FOO`, completing the cycle
-note: cycle used when const-evaluating + checking `FOO`
+note: ...which requires const-evaluating + checking `FOO`...
--> $DIR/recursive-zst-static.rs:10:1
|
LL | static FOO: () = FOO;
| ^^^^^^^^^^^^^^^^^^^^^
+ = note: ...which again requires const-evaluating + checking `FOO`, completing the cycle
+ = note: cycle used when running analysis passes on this crate
error: aborting due to previous error
// can depend on this fact and will thus do unsound things when it is violated.
// See https://github.com/rust-lang/rust/issues/71078 for more details.
-static FOO: () = FOO; //~ cycle detected when const-evaluating `FOO`
+static FOO: () = FOO; //~ cycle detected when const-evaluating + checking `FOO`
fn main() {
FOO
-error[E0391]: cycle detected when const-evaluating `FOO`
+error[E0391]: cycle detected when const-evaluating + checking `FOO`
--> $DIR/recursive-zst-static.rs:10:1
|
LL | static FOO: () = FOO;
| ^^^^^^^^^^^^^^^^^^^^^
|
-note: ...which requires const-evaluating `FOO`...
- --> $DIR/recursive-zst-static.rs:10:1
- |
-LL | static FOO: () = FOO;
- | ^^^^^^^^^^^^^^^^^^^^^
- = note: ...which again requires const-evaluating `FOO`, completing the cycle
-note: cycle used when const-evaluating + checking `FOO`
+note: ...which requires const-evaluating + checking `FOO`...
--> $DIR/recursive-zst-static.rs:10:1
|
LL | static FOO: () = FOO;
| ^^^^^^^^^^^^^^^^^^^^^
+ = note: ...which again requires const-evaluating + checking `FOO`, completing the cycle
+ = note: cycle used when running analysis passes on this crate
error: aborting due to previous error
--- /dev/null
+// run-pass
+
+// compile-flags: -Zmir-opt-level=2
+
+trait IterExt: Iterator {
+ fn fold_ex<B, F>(mut self, init: B, mut f: F) -> B
+ where
+ Self: Sized,
+ F: FnMut(B, Self::Item) -> B,
+ {
+ let mut accum = init;
+ while let Some(x) = self.next() {
+ accum = f(accum, x);
+ }
+ accum
+ }
+}
+
+impl<T: Iterator> IterExt for T {}
+
+fn main() {
+ let test = &["\n"];
+ test.iter().fold_ex(String::new(), |_, b| b.to_string());
+}
-error: reached the recursion limit while instantiating `function::<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<usize>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
+error: reached the recursion limit while instantiating `function::<Option<Option<Option<...>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
--> $DIR/infinite-instantiation.rs:21:9
|
LL | function(counter - 1, t.to_option());
//https://github.com/rust-lang/rust/issues/31364
-const fn a() -> usize { b() } //~ ERROR cycle detected when const-evaluating `a` [E0391]
-const fn b() -> usize { a() }
+const fn a() -> usize {
+ //~^ ERROR cycle detected when const-evaluating + checking `a` [E0391]
+ b()
+}
+const fn b() -> usize {
+ a()
+}
const ARR: [i32; a()] = [5; 6];
-fn main(){}
+fn main() {}
-error[E0391]: cycle detected when const-evaluating `a`
+error[E0391]: cycle detected when const-evaluating + checking `a`
--> $DIR/infinite-recursion-const-fn.rs:3:1
|
-LL | const fn a() -> usize { b() }
+LL | const fn a() -> usize {
| ^^^^^^^^^^^^^^^^^^^^^
|
-note: ...which requires const-evaluating `b`...
- --> $DIR/infinite-recursion-const-fn.rs:4:1
+note: ...which requires const-evaluating + checking `b`...
+ --> $DIR/infinite-recursion-const-fn.rs:7:1
|
-LL | const fn b() -> usize { a() }
+LL | const fn b() -> usize {
| ^^^^^^^^^^^^^^^^^^^^^
- = note: ...which again requires const-evaluating `a`, completing the cycle
-note: cycle used when const-evaluating `ARR::{{constant}}#0`
- --> $DIR/infinite-recursion-const-fn.rs:5:18
+ = note: ...which again requires const-evaluating + checking `a`, completing the cycle
+note: cycle used when const-evaluating + checking `ARR::{{constant}}#0`
+ --> $DIR/infinite-recursion-const-fn.rs:10:18
|
LL | const ARR: [i32; a()] = [5; 6];
| ^^^
error[E0391]: cycle detected when normalizing `FOO`
|
-note: ...which requires const-evaluating + checking `FOO`...
+note: ...which requires simplifying constant for the type system `FOO`...
--> $DIR/issue-17252.rs:1:1
|
LL | const FOO: usize = FOO;
| ^^^^^^^^^^^^^^^^^^^^^^^
-note: ...which requires const-evaluating + checking `FOO`...
+note: ...which requires simplifying constant for the type system `FOO`...
--> $DIR/issue-17252.rs:1:1
|
LL | const FOO: usize = FOO;
| ^^^^^^^^^^^^^^^^^^^^^^^
-note: ...which requires const-evaluating `FOO`...
+note: ...which requires const-evaluating + checking `FOO`...
--> $DIR/issue-17252.rs:1:1
|
LL | const FOO: usize = FOO;
| ^^^^^^^^^^^^^^^^^^^^^^^
= note: ...which again requires normalizing `FOO`, completing the cycle
-note: cycle used when const-evaluating `main::{{constant}}#0`
+note: cycle used when const-evaluating + checking `main::{{constant}}#0`
--> $DIR/issue-17252.rs:4:18
|
LL | let _x: [u8; FOO]; // caused stack overflow prior to fix
impl D {
pub fn matches<F: Fn()>(&self, f: &F) {
- //~^ ERROR reached the type-length limit while instantiating `D::matches::<[closure
let &D(ref a) = self;
a.matches(f)
+ //~^ ERROR reached the recursion limit while instantiating `A::matches::<[closure
}
}
-error: reached the type-length limit while instantiating `D::matches::$CLOSURE`
- --> $DIR/issue-22638.rs:53:5
+error: reached the recursion limit while instantiating `A::matches::$CLOSURE`
+ --> $DIR/issue-22638.rs:55:9
+ |
+LL | a.matches(f)
+ | ^^^^^^^^^^^^
+ |
+note: `A::matches` defined here
+ --> $DIR/issue-22638.rs:14:5
|
LL | pub fn matches<F: Fn()>(&self, f: &F) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: consider adding a `#![type_length_limit="30408681"]` attribute to your crate
error: aborting due to previous error
-error[E0391]: cycle detected when const-evaluating + checking `X::A::{{constant}}#0`
+error[E0391]: cycle detected when simplifying constant for the type system `X::A::{{constant}}#0`
--> $DIR/issue-23302-1.rs:4:9
|
LL | A = X::A as isize,
| ^^^^^^^^^^^^^
|
-note: ...which requires const-evaluating + checking `X::A::{{constant}}#0`...
+note: ...which requires simplifying constant for the type system `X::A::{{constant}}#0`...
--> $DIR/issue-23302-1.rs:4:9
|
LL | A = X::A as isize,
| ^^^^^^^^^^^^^
-note: ...which requires const-evaluating `X::A::{{constant}}#0`...
+note: ...which requires const-evaluating + checking `X::A::{{constant}}#0`...
--> $DIR/issue-23302-1.rs:4:9
|
LL | A = X::A as isize,
| ^^^^^^^^^^^^^
= note: ...which requires normalizing `X::A as isize`...
- = note: ...which again requires const-evaluating + checking `X::A::{{constant}}#0`, completing the cycle
+ = note: ...which again requires simplifying constant for the type system `X::A::{{constant}}#0`, completing the cycle
note: cycle used when collecting item types in top-level module
--> $DIR/issue-23302-1.rs:3:1
|
-error[E0391]: cycle detected when const-evaluating + checking `Y::A::{{constant}}#0`
+error[E0391]: cycle detected when simplifying constant for the type system `Y::A::{{constant}}#0`
--> $DIR/issue-23302-2.rs:4:9
|
LL | A = Y::B as isize,
| ^^^^^^^^^^^^^
|
-note: ...which requires const-evaluating + checking `Y::A::{{constant}}#0`...
+note: ...which requires simplifying constant for the type system `Y::A::{{constant}}#0`...
--> $DIR/issue-23302-2.rs:4:9
|
LL | A = Y::B as isize,
| ^^^^^^^^^^^^^
-note: ...which requires const-evaluating `Y::A::{{constant}}#0`...
+note: ...which requires const-evaluating + checking `Y::A::{{constant}}#0`...
--> $DIR/issue-23302-2.rs:4:9
|
LL | A = Y::B as isize,
| ^^^^^^^^^^^^^
= note: ...which requires normalizing `Y::B as isize`...
- = note: ...which again requires const-evaluating + checking `Y::A::{{constant}}#0`, completing the cycle
+ = note: ...which again requires simplifying constant for the type system `Y::A::{{constant}}#0`, completing the cycle
note: cycle used when collecting item types in top-level module
--> $DIR/issue-23302-2.rs:3:1
|
-error[E0391]: cycle detected when const-evaluating + checking `A`
+error[E0391]: cycle detected when simplifying constant for the type system `A`
--> $DIR/issue-23302-3.rs:1:1
|
LL | const A: i32 = B;
| ^^^^^^^^^^^^^^^^^
|
-note: ...which requires const-evaluating + checking `A`...
+note: ...which requires simplifying constant for the type system `A`...
--> $DIR/issue-23302-3.rs:1:1
|
LL | const A: i32 = B;
| ^^^^^^^^^^^^^^^^^
-note: ...which requires const-evaluating `A`...
+note: ...which requires const-evaluating + checking `A`...
--> $DIR/issue-23302-3.rs:1:1
|
LL | const A: i32 = B;
| ^^^^^^^^^^^^^^^^^
= note: ...which requires normalizing `B`...
-note: ...which requires const-evaluating + checking `B`...
+note: ...which requires simplifying constant for the type system `B`...
--> $DIR/issue-23302-3.rs:3:1
|
LL | const B: i32 = A;
| ^^^^^^^^^^^^^^^^^
-note: ...which requires const-evaluating + checking `B`...
+note: ...which requires simplifying constant for the type system `B`...
--> $DIR/issue-23302-3.rs:3:1
|
LL | const B: i32 = A;
| ^^^^^^^^^^^^^^^^^
-note: ...which requires const-evaluating `B`...
+note: ...which requires const-evaluating + checking `B`...
--> $DIR/issue-23302-3.rs:3:1
|
LL | const B: i32 = A;
| ^^^^^^^^^^^^^^^^^
= note: ...which requires normalizing `A`...
- = note: ...which again requires const-evaluating + checking `A`, completing the cycle
+ = note: ...which again requires simplifying constant for the type system `A`, completing the cycle
= note: cycle used when running analysis passes on this crate
error: aborting due to previous error
-error[E0391]: cycle detected when const-evaluating + checking `Foo::B::{{constant}}#0`
+error[E0391]: cycle detected when simplifying constant for the type system `Foo::B::{{constant}}#0`
--> $DIR/issue-36163.rs:4:9
|
LL | B = A,
| ^
|
-note: ...which requires const-evaluating + checking `Foo::B::{{constant}}#0`...
+note: ...which requires simplifying constant for the type system `Foo::B::{{constant}}#0`...
--> $DIR/issue-36163.rs:4:9
|
LL | B = A,
| ^
-note: ...which requires const-evaluating `Foo::B::{{constant}}#0`...
+note: ...which requires const-evaluating + checking `Foo::B::{{constant}}#0`...
--> $DIR/issue-36163.rs:4:9
|
LL | B = A,
| ^
= note: ...which requires normalizing `A`...
-note: ...which requires const-evaluating + checking `A`...
+note: ...which requires simplifying constant for the type system `A`...
--> $DIR/issue-36163.rs:1:1
|
LL | const A: isize = Foo::B as isize;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-note: ...which requires const-evaluating + checking `A`...
+note: ...which requires simplifying constant for the type system `A`...
--> $DIR/issue-36163.rs:1:1
|
LL | const A: isize = Foo::B as isize;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-note: ...which requires const-evaluating `A`...
+note: ...which requires const-evaluating + checking `A`...
--> $DIR/issue-36163.rs:1:1
|
LL | const A: isize = Foo::B as isize;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: ...which requires normalizing `A`...
- = note: ...which again requires const-evaluating + checking `Foo::B::{{constant}}#0`, completing the cycle
+ = note: ...which again requires simplifying constant for the type system `Foo::B::{{constant}}#0`, completing the cycle
note: cycle used when collecting item types in top-level module
--> $DIR/issue-36163.rs:1:1
|
impl<T> Foo for T {
#[allow(unconditional_recursion)]
- fn recurse(&self) { //~ ERROR reached the type-length limit
- (self, self).recurse();
+ fn recurse(&self) {
+ (self, self).recurse(); //~ ERROR reached the recursion limit
}
}
-error: reached the type-length limit while instantiating `<(&(&(&(&(&(&(&(&(&(&(&(&(&(&(&(...))))))))))))))) as Foo>::recurse`
+error: reached the recursion limit while instantiating `<(&(&(&(&(&(&(&(&(&(&(&(&(&(&(&(.....), ...), ...) as Foo>::recurse`
+ --> $DIR/issue-37311.rs:16:9
+ |
+LL | (self, self).recurse();
+ | ^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: `<T as Foo>::recurse` defined here
--> $DIR/issue-37311.rs:15:5
|
LL | fn recurse(&self) {
| ^^^^^^^^^^^^^^^^^
- |
- = note: consider adding a `#![type_length_limit="2097149"]` attribute to your crate
error: aborting due to previous error
-error: reached the recursion limit while instantiating `rec::<&mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut Empty>`
+error: reached the recursion limit while instantiating `rec::<&mut &mut &mut &mut &mut &... &mut &mut &mut &mut &mut Empty>`
--> $DIR/issue-67552.rs:27:9
|
LL | rec(identity(&mut it))
#![allow(non_snake_case)]
use std::ops::RangeInclusive;
+
const RANGE: RangeInclusive<i32> = 0..=255;
+const RANGE2: RangeInclusive<i32> = panic!();
+
fn main() {
let n: i32 = 1;
match n {
RANGE => {}
//~^ ERROR mismatched types
+ RANGE2 => {}
+ //~^ ERROR mismatched types
_ => {}
}
}
error[E0308]: mismatched types
- --> $DIR/issue-76191.rs:10:9
+ --> $DIR/issue-76191.rs:13:9
|
LL | const RANGE: RangeInclusive<i32> = 0..=255;
| ------------------------------------------- constant defined here
|
= note: expected type `i32`
found struct `RangeInclusive<i32>`
+help: you may want to move the range into the match block
+ |
+LL | 0..=255 => {}
+ | ^^^^^^^
+
+error[E0308]: mismatched types
+ --> $DIR/issue-76191.rs:15:9
+ |
+LL | const RANGE2: RangeInclusive<i32> = panic!();
+ | --------------------------------------------- constant defined here
+...
+LL | match n {
+ | - this expression has type `i32`
+...
+LL | RANGE2 => {}
+ | ^^^^^^
+ | |
+ | expected `i32`, found struct `RangeInclusive`
+ | `RANGE2` is interpreted as a constant, not a new binding
+ |
+ = note: expected type `i32`
+ found struct `RangeInclusive<i32>`
= note: constants only support matching by type, if you meant to match against a range of values, consider using a range pattern like `min ..= max` in the match block
-error: aborting due to previous error
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0308`.
= note: `#[warn(unconditional_recursion)]` on by default
= help: a `loop` may express intention better if this is on purpose
-error: reached the recursion limit while instantiating `generic::<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<Option<i32>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
+error: reached the recursion limit while instantiating `generic::<Option<Option<Option<O...>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
--> $DIR/issue-8727.rs:7:5
|
LL | generic::<Option<T>>();
-error: reached the recursion limit while instantiating `drop_in_place::<S<fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(u32))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))>> - shim(Some(S<fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(u32))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))>))`
+error: reached the recursion limit while instantiating `drop_in_place::<S<fn(fn(fn(fn(fn...)))))))))))))))))))))))))))))>))`
--> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
|
LL | / pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
-error: reached the recursion limit while instantiating `test::<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Nil>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
+error: reached the recursion limit while instantiating `test::<Cons<Cons<Cons<Cons<Cons<...>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
--> $DIR/recursion.rs:17:11
|
LL | _ => {test (n-1, i+1, Cons {head:2*i+1, tail:first}, Cons{head:i*i, tail:second})}
pub static FOO: u32 = FOO;
-//~^ ERROR cycle detected when const-evaluating `FOO`
+//~^ ERROR cycle detected when const-evaluating + checking `FOO`
fn main() {}
-error[E0391]: cycle detected when const-evaluating `FOO`
+error[E0391]: cycle detected when const-evaluating + checking `FOO`
--> $DIR/recursive-static-definition.rs:1:1
|
LL | pub static FOO: u32 = FOO;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
-note: ...which requires const-evaluating `FOO`...
- --> $DIR/recursive-static-definition.rs:1:1
- |
-LL | pub static FOO: u32 = FOO;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^
- = note: ...which again requires const-evaluating `FOO`, completing the cycle
-note: cycle used when const-evaluating + checking `FOO`
+note: ...which requires const-evaluating + checking `FOO`...
--> $DIR/recursive-static-definition.rs:1:1
|
LL | pub static FOO: u32 = FOO;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ = note: ...which again requires const-evaluating + checking `FOO`, completing the cycle
+ = note: cycle used when running analysis passes on this crate
error: aborting due to previous error
-// check-pass
+// run-pass
// Use of global static variables in literal values should be allowed for
// promotion.
#[repr(u8)]
enum Alpha {
V1 = 41,
- V2 = Self::V1 as u8 + 1, // OK; See #50072.
- V3 = Self::V1 {} as u8 + 2, //~ ERROR cycle detected when const-evaluating
+ V2 = Self::V1 as u8 + 1, // OK; See #50072.
+ V3 = Self::V1 {} as u8 + 2, //~ ERROR cycle detected when simplifying constant
}
fn main() {}
-error[E0391]: cycle detected when const-evaluating + checking `Alpha::V3::{{constant}}#0`
+error[E0391]: cycle detected when simplifying constant for the type system `Alpha::V3::{{constant}}#0`
--> $DIR/self-in-enum-definition.rs:5:10
|
LL | V3 = Self::V1 {} as u8 + 2,
| ^^^^^^^^
|
-note: ...which requires const-evaluating + checking `Alpha::V3::{{constant}}#0`...
+note: ...which requires simplifying constant for the type system `Alpha::V3::{{constant}}#0`...
--> $DIR/self-in-enum-definition.rs:5:10
|
LL | V3 = Self::V1 {} as u8 + 2,
| ^^^^^^^^
-note: ...which requires const-evaluating `Alpha::V3::{{constant}}#0`...
+note: ...which requires const-evaluating + checking `Alpha::V3::{{constant}}#0`...
--> $DIR/self-in-enum-definition.rs:5:10
|
LL | V3 = Self::V1 {} as u8 + 2,
| ^^^^^^^^
= note: ...which requires computing layout of `Alpha`...
- = note: ...which again requires const-evaluating + checking `Alpha::V3::{{constant}}#0`, completing the cycle
+ = note: ...which again requires simplifying constant for the type system `Alpha::V3::{{constant}}#0`, completing the cycle
note: cycle used when collecting item types in top-level module
--> $DIR/self-in-enum-definition.rs:1:1
|
LL | / #[repr(u8)]
LL | | enum Alpha {
LL | | V1 = 41,
-LL | | V2 = Self::V1 as u8 + 1, // OK; See #50072.
+LL | | V2 = Self::V1 as u8 + 1, // OK; See #50072.
... |
LL | |
LL | | fn main() {}
// Test that the type length limit can be changed.
#![allow(dead_code)]
-#![type_length_limit="256"]
+#![type_length_limit="4"]
macro_rules! link {
($id:ident, $t:ty) => {
-error: reached the type-length limit while instantiating `std::mem::drop::<Option<((((((G,... G), (G, G, G), (G, G, G))))))>>`
+error: reached the type-length limit while instantiating `std::mem::drop::<Option<((((...,....., ...), ..., ...), ..., ...)>>`
--> $SRC_DIR/core/src/mem/mod.rs:LL:COL
|
LL | pub fn drop<T>(_x: T) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
- = note: consider adding a `#![type_length_limit="1094"]` attribute to your crate
+ = note: consider adding a `#![type_length_limit="8"]` attribute to your crate
error: aborting due to previous error
LL | pub static mut B: () = unsafe { A = 1; };
| ^^^^^ modifying a static's initial value from another static's initializer
-error[E0391]: cycle detected when const-evaluating `C`
+error[E0391]: cycle detected when const-evaluating + checking `C`
--> $DIR/write-to-static-mut-in-static.rs:5:1
|
LL | pub static mut C: u32 = unsafe { C = 1; 0 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
-note: ...which requires const-evaluating `C`...
- --> $DIR/write-to-static-mut-in-static.rs:5:1
- |
-LL | pub static mut C: u32 = unsafe { C = 1; 0 };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- = note: ...which again requires const-evaluating `C`, completing the cycle
-note: cycle used when const-evaluating + checking `C`
+note: ...which requires const-evaluating + checking `C`...
--> $DIR/write-to-static-mut-in-static.rs:5:1
|
LL | pub static mut C: u32 = unsafe { C = 1; 0 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ = note: ...which again requires const-evaluating + checking `C`, completing the cycle
+ = note: cycle used when running analysis passes on this crate
error: aborting due to 2 previous errors
"riscv32i-unknown-none-elf",
"riscv32imc-unknown-none-elf",
"riscv32imac-unknown-none-elf",
+ "riscv32gc-unknown-linux-gnu",
"riscv64imac-unknown-none-elf",
"riscv64gc-unknown-none-elf",
"riscv64gc-unknown-linux-gnu",