]> git.lizzy.rs Git - rust.git/commitdiff
Rollup merge of #76891 - lcnr:less-ref, r=ecstatic-morse
authorRalf Jung <post@ralfj.de>
Sun, 20 Sep 2020 13:52:03 +0000 (15:52 +0200)
committerGitHub <noreply@github.com>
Sun, 20 Sep 2020 13:52:03 +0000 (15:52 +0200)
don't take `TyCtxt` by reference

small cleanup

303 files changed:
.github/workflows/ci.yml
Cargo.lock
README.md
compiler/rustc_arena/src/lib.rs
compiler/rustc_arena/src/tests.rs
compiler/rustc_ast/src/ast.rs
compiler/rustc_ast/src/lib.rs
compiler/rustc_ast_lowering/src/item.rs
compiler/rustc_ast_passes/src/ast_validation.rs
compiler/rustc_attr/src/builtin.rs
compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
compiler/rustc_codegen_llvm/src/consts.rs
compiler/rustc_codegen_llvm/src/intrinsic.rs
compiler/rustc_codegen_ssa/src/lib.rs
compiler/rustc_codegen_ssa/src/mir/block.rs
compiler/rustc_codegen_ssa/src/mir/intrinsic.rs [new file with mode: 0644]
compiler/rustc_codegen_ssa/src/mir/mod.rs
compiler/rustc_codegen_ssa/src/traits/backend.rs
compiler/rustc_data_structures/src/lib.rs
compiler/rustc_data_structures/src/sorted_map.rs
compiler/rustc_data_structures/src/tagged_ptr/copy.rs
compiler/rustc_driver/src/args.rs
compiler/rustc_errors/src/snippet.rs
compiler/rustc_expand/src/lib.rs
compiler/rustc_infer/Cargo.toml
compiler/rustc_infer/src/infer/combine.rs
compiler/rustc_infer/src/infer/mod.rs
compiler/rustc_infer/src/infer/outlives/verify.rs
compiler/rustc_infer/src/lib.rs
compiler/rustc_interface/src/tests.rs
compiler/rustc_interface/src/util.rs
compiler/rustc_lint/src/builtin.rs
compiler/rustc_lint/src/lib.rs
compiler/rustc_lint/src/nonstandard_style.rs
compiler/rustc_lint/src/types.rs
compiler/rustc_llvm/Cargo.toml
compiler/rustc_metadata/src/rmeta/decoder.rs
compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
compiler/rustc_metadata/src/rmeta/encoder.rs
compiler/rustc_metadata/src/rmeta/mod.rs
compiler/rustc_middle/Cargo.toml
compiler/rustc_middle/src/lib.rs
compiler/rustc_middle/src/middle/cstore.rs
compiler/rustc_middle/src/mir/abstract_const.rs [new file with mode: 0644]
compiler/rustc_middle/src/mir/interpret/error.rs
compiler/rustc_middle/src/mir/interpret/mod.rs
compiler/rustc_middle/src/mir/interpret/queries.rs
compiler/rustc_middle/src/mir/interpret/value.rs
compiler/rustc_middle/src/mir/mod.rs
compiler/rustc_middle/src/query/mod.rs
compiler/rustc_middle/src/ty/codec.rs
compiler/rustc_middle/src/ty/context.rs
compiler/rustc_middle/src/ty/instance.rs
compiler/rustc_middle/src/ty/mod.rs
compiler/rustc_middle/src/ty/outlives.rs
compiler/rustc_middle/src/ty/print/mod.rs
compiler/rustc_middle/src/ty/print/pretty.rs
compiler/rustc_middle/src/ty/query/keys.rs
compiler/rustc_middle/src/ty/query/mod.rs
compiler/rustc_middle/src/ty/query/on_disk_cache.rs
compiler/rustc_middle/src/ty/relate.rs
compiler/rustc_middle/src/ty/sty.rs
compiler/rustc_middle/src/ty/walk.rs
compiler/rustc_mir/src/borrow_check/diagnostics/move_errors.rs
compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs
compiler/rustc_mir/src/borrow_check/diagnostics/outlives_suggestion.rs
compiler/rustc_mir/src/const_eval/eval_queries.rs
compiler/rustc_mir/src/const_eval/machine.rs
compiler/rustc_mir/src/dataflow/framework/graphviz.rs
compiler/rustc_mir/src/dataflow/impls/mod.rs
compiler/rustc_mir/src/dataflow/move_paths/builder.rs
compiler/rustc_mir/src/interpret/eval_context.rs
compiler/rustc_mir/src/interpret/intrinsics.rs
compiler/rustc_mir/src/interpret/memory.rs
compiler/rustc_mir/src/interpret/operand.rs
compiler/rustc_mir/src/interpret/place.rs
compiler/rustc_mir/src/interpret/validity.rs
compiler/rustc_mir/src/lib.rs
compiler/rustc_mir/src/monomorphize/collector.rs
compiler/rustc_mir/src/monomorphize/partitioning/mod.rs
compiler/rustc_mir/src/shim.rs
compiler/rustc_mir/src/transform/dest_prop.rs [new file with mode: 0644]
compiler/rustc_mir/src/transform/mod.rs
compiler/rustc_mir/src/transform/nrvo.rs
compiler/rustc_mir/src/transform/promote_consts.rs
compiler/rustc_mir/src/transform/simplify.rs
compiler/rustc_mir/src/util/pretty.rs
compiler/rustc_mir_build/src/build/block.rs
compiler/rustc_mir_build/src/build/matches/mod.rs
compiler/rustc_mir_build/src/build/matches/util.rs
compiler/rustc_mir_build/src/lib.rs
compiler/rustc_mir_build/src/thir/pattern/_match.rs
compiler/rustc_parse/src/lib.rs
compiler/rustc_parse_format/src/lib.rs
compiler/rustc_privacy/src/lib.rs
compiler/rustc_resolve/src/build_reduced_graph.rs
compiler/rustc_resolve/src/late.rs
compiler/rustc_resolve/src/late/diagnostics.rs
compiler/rustc_session/src/config.rs
compiler/rustc_session/src/search_paths.rs
compiler/rustc_session/src/session.rs
compiler/rustc_span/src/lib.rs
compiler/rustc_trait_selection/src/lib.rs
compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
compiler/rustc_trait_selection/src/traits/fulfill.rs
compiler/rustc_trait_selection/src/traits/mod.rs
compiler/rustc_trait_selection/src/traits/select/mod.rs
compiler/rustc_traits/src/lib.rs
compiler/rustc_ty/src/lib.rs
compiler/rustc_typeck/src/check/demand.rs
compiler/rustc_typeck/src/check/expr.rs
compiler/rustc_typeck/src/check/mod.rs
compiler/rustc_typeck/src/check/op.rs
compiler/rustc_typeck/src/check/pat.rs
compiler/rustc_typeck/src/collect.rs
library/alloc/benches/vec.rs
library/alloc/src/collections/binary_heap.rs
library/alloc/src/collections/btree/borrow.rs
library/alloc/src/collections/btree/map.rs
library/alloc/src/collections/btree/map/tests.rs
library/alloc/src/collections/btree/node.rs
library/alloc/src/collections/linked_list.rs
library/alloc/src/collections/vec_deque.rs
library/alloc/src/collections/vec_deque/drain.rs
library/alloc/src/lib.rs
library/alloc/src/raw_vec.rs
library/alloc/src/string.rs
library/alloc/src/vec.rs
library/alloc/tests/lib.rs
library/alloc/tests/string.rs
library/alloc/tests/vec.rs
library/core/src/ascii.rs
library/core/src/fmt/mod.rs
library/core/src/future/pending.rs
library/core/src/future/poll_fn.rs
library/core/src/future/ready.rs
library/core/src/hint.rs
library/core/src/lib.rs
library/core/src/num/bignum.rs
library/core/src/num/error.rs [new file with mode: 0644]
library/core/src/num/i128.rs [deleted file]
library/core/src/num/i16.rs [deleted file]
library/core/src/num/i32.rs [deleted file]
library/core/src/num/i64.rs [deleted file]
library/core/src/num/i8.rs [deleted file]
library/core/src/num/int_macros.rs
library/core/src/num/isize.rs [deleted file]
library/core/src/num/mod.rs
library/core/src/num/nonzero.rs [new file with mode: 0644]
library/core/src/num/shells/i128.rs [new file with mode: 0644]
library/core/src/num/shells/i16.rs [new file with mode: 0644]
library/core/src/num/shells/i32.rs [new file with mode: 0644]
library/core/src/num/shells/i64.rs [new file with mode: 0644]
library/core/src/num/shells/i8.rs [new file with mode: 0644]
library/core/src/num/shells/int_macros.rs [new file with mode: 0644]
library/core/src/num/shells/isize.rs [new file with mode: 0644]
library/core/src/num/shells/u128.rs [new file with mode: 0644]
library/core/src/num/shells/u16.rs [new file with mode: 0644]
library/core/src/num/shells/u32.rs [new file with mode: 0644]
library/core/src/num/shells/u64.rs [new file with mode: 0644]
library/core/src/num/shells/u8.rs [new file with mode: 0644]
library/core/src/num/shells/usize.rs [new file with mode: 0644]
library/core/src/num/u128.rs [deleted file]
library/core/src/num/u16.rs [deleted file]
library/core/src/num/u32.rs [deleted file]
library/core/src/num/u64.rs [deleted file]
library/core/src/num/u8.rs [deleted file]
library/core/src/num/uint_macros.rs [new file with mode: 0644]
library/core/src/num/usize.rs [deleted file]
library/core/src/num/wrapping.rs
library/core/src/option.rs
library/core/src/slice/iter.rs
library/core/src/slice/mod.rs
library/core/src/slice/sort.rs
library/core/src/str/mod.rs
library/core/src/str/pattern.rs
library/core/src/task/wake.rs
library/core/tests/iter.rs
library/core/tests/lib.rs
library/core/tests/num/int_macros.rs
library/core/tests/num/uint_macros.rs
library/panic_abort/src/lib.rs
library/panic_unwind/src/dwarf/mod.rs
library/panic_unwind/src/gcc.rs
library/panic_unwind/src/lib.rs
library/std/src/collections/hash/map.rs
library/std/src/collections/hash/set.rs
library/std/src/lib.rs
library/std/src/os/linux/raw.rs
library/std/src/os/raw/mod.rs
library/std/src/path.rs
library/std/src/sys_common/alloc.rs
library/unwind/src/libunwind.rs
src/bootstrap/channel.rs
src/bootstrap/config.rs
src/bootstrap/dist.rs
src/bootstrap/doc.rs
src/bootstrap/flags.rs
src/bootstrap/lib.rs
src/bootstrap/native.rs
src/bootstrap/test.rs
src/bootstrap/tool.rs
src/ci/azure-pipelines/auto.yml
src/ci/github-actions/ci.yml
src/librustdoc/clean/inline.rs
src/test/codegen/consts.rs
src/test/compile-fail/issue-44415.rs
src/test/incremental/issue-54242.rs
src/test/mir-opt/const_allocation.main.ConstProp.after.32bit.mir
src/test/mir-opt/const_allocation.main.ConstProp.after.64bit.mir
src/test/mir-opt/const_allocation2.main.ConstProp.after.32bit.mir
src/test/mir-opt/const_allocation2.main.ConstProp.after.64bit.mir
src/test/mir-opt/const_allocation3.main.ConstProp.after.32bit.mir
src/test/mir-opt/const_allocation3.main.ConstProp.after.64bit.mir
src/test/mir-opt/copy_propagation.test.CopyPropagation.diff
src/test/mir-opt/copy_propagation_arg.arg_src.CopyPropagation.diff
src/test/mir-opt/copy_propagation_arg.baz.CopyPropagation.diff
src/test/mir-opt/copy_propagation_arg.foo.CopyPropagation.diff
src/test/mir-opt/dest-prop/branch.main.DestinationPropagation.diff [new file with mode: 0644]
src/test/mir-opt/dest-prop/branch.rs [new file with mode: 0644]
src/test/mir-opt/dest-prop/cycle.main.DestinationPropagation.diff [new file with mode: 0644]
src/test/mir-opt/dest-prop/cycle.rs [new file with mode: 0644]
src/test/mir-opt/dest-prop/simple.nrvo.DestinationPropagation.diff [new file with mode: 0644]
src/test/mir-opt/dest-prop/simple.rs [new file with mode: 0644]
src/test/mir-opt/dest-prop/union.main.DestinationPropagation.diff [new file with mode: 0644]
src/test/mir-opt/dest-prop/union.rs [new file with mode: 0644]
src/test/mir-opt/fn_ptr_shim.core.ops-function-Fn-call.AddMovesForPackedDrops.before.mir
src/test/mir-opt/inline/inline_closure_captures.foo.Inline.after.mir
src/test/mir-opt/issue_73223.main.PreCodegen.32bit.diff
src/test/mir-opt/issue_73223.main.PreCodegen.64bit.diff
src/test/mir-opt/issues/issue-75439.rs [new file with mode: 0644]
src/test/mir-opt/issues/issue_75439.foo.MatchBranchSimplification.diff [new file with mode: 0644]
src/test/mir-opt/nrvo-simple.rs
src/test/mir-opt/nrvo_simple.nrvo.RenameReturnPlace.diff
src/test/mir-opt/rustc.try_identity.DestinationPropagation.diff [new file with mode: 0644]
src/test/mir-opt/simplify_try.rs
src/test/mir-opt/simplify_try.try_identity.DestinationPropagation.diff [new file with mode: 0644]
src/test/mir-opt/simplify_try.try_identity.SimplifyArmIdentity.diff
src/test/mir-opt/simplify_try.try_identity.SimplifyBranchSame.after.mir
src/test/mir-opt/simplify_try.try_identity.SimplifyLocals.after.mir
src/test/ui/associated-const/defaults-cyclic-fail.stderr
src/test/ui/associated-consts/issue-24949-assoc-const-static-recursion-impl.stderr
src/test/ui/associated-consts/issue-24949-assoc-const-static-recursion-trait-default.stderr
src/test/ui/associated-consts/issue-24949-assoc-const-static-recursion-trait.stderr
src/test/ui/closures/issue-72408-nested-closures-exponential.rs [new file with mode: 0644]
src/test/ui/const-generics/const_evaluatable_checked/auxiliary/const_evaluatable_lib.rs [new file with mode: 0644]
src/test/ui/const-generics/const_evaluatable_checked/cross_crate.rs [new file with mode: 0644]
src/test/ui/const-generics/const_evaluatable_checked/cross_crate_predicate.rs [new file with mode: 0644]
src/test/ui/const-generics/const_evaluatable_checked/cross_crate_predicate.stderr [new file with mode: 0644]
src/test/ui/const-generics/const_evaluatable_checked/fn_call.rs [new file with mode: 0644]
src/test/ui/const-generics/const_evaluatable_checked/less_than.rs [new file with mode: 0644]
src/test/ui/const-generics/const_evaluatable_checked/let-bindings.rs [new file with mode: 0644]
src/test/ui/const-generics/const_evaluatable_checked/let-bindings.stderr [new file with mode: 0644]
src/test/ui/const-generics/const_evaluatable_checked/simple.min.stderr
src/test/ui/const-generics/const_evaluatable_checked/simple.rs
src/test/ui/const-generics/const_evaluatable_checked/unop.rs [new file with mode: 0644]
src/test/ui/consts/cast-discriminant-zst-enum.rs
src/test/ui/consts/const-eval/const-eval-query-stack.stderr
src/test/ui/consts/const-eval/const-pointer-values-in-various-types.stderr
src/test/ui/consts/const-eval/double_check2.rs
src/test/ui/consts/const-eval/double_check2.stderr [deleted file]
src/test/ui/consts/const-eval/ub-enum.stderr
src/test/ui/consts/const-eval/ub-nonnull.stderr
src/test/ui/consts/const-eval/ub-ref.stderr
src/test/ui/consts/const-size_of-cycle.stderr
src/test/ui/consts/const_discriminant.rs
src/test/ui/consts/promote-no-mut.rs [deleted file]
src/test/ui/consts/promote-no-mut.stderr [deleted file]
src/test/ui/consts/promote-not.rs [new file with mode: 0644]
src/test/ui/consts/promote-not.stderr [new file with mode: 0644]
src/test/ui/consts/promotion.rs
src/test/ui/consts/recursive-zst-static.default.stderr
src/test/ui/consts/recursive-zst-static.rs
src/test/ui/consts/recursive-zst-static.unleash.stderr
src/test/ui/dest-prop/skeptic-miscompile.rs [new file with mode: 0644]
src/test/ui/infinite/infinite-instantiation.stderr
src/test/ui/infinite/infinite-recursion-const-fn.rs
src/test/ui/infinite/infinite-recursion-const-fn.stderr
src/test/ui/issues/issue-17252.stderr
src/test/ui/issues/issue-22638.rs
src/test/ui/issues/issue-22638.stderr
src/test/ui/issues/issue-23302-1.stderr
src/test/ui/issues/issue-23302-2.stderr
src/test/ui/issues/issue-23302-3.stderr
src/test/ui/issues/issue-36163.stderr
src/test/ui/issues/issue-37311-type-length-limit/issue-37311.rs
src/test/ui/issues/issue-37311-type-length-limit/issue-37311.stderr
src/test/ui/issues/issue-67552.stderr
src/test/ui/issues/issue-76191.rs
src/test/ui/issues/issue-76191.stderr
src/test/ui/issues/issue-8727.stderr
src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.stderr
src/test/ui/recursion/recursion.stderr
src/test/ui/recursion/recursive-static-definition.rs
src/test/ui/recursion/recursive-static-definition.stderr
src/test/ui/statics/static-promotion.rs
src/test/ui/type-alias-enum-variants/self-in-enum-definition.rs
src/test/ui/type-alias-enum-variants/self-in-enum-definition.stderr
src/test/ui/type_length_limit.rs
src/test/ui/type_length_limit.stderr
src/test/ui/write-to-static-mut-in-static.stderr
src/tools/build-manifest/src/main.rs
src/version [new file with mode: 0644]

index 50ae8c313d6fcb152fb0e3f600296f23062050a2..490258f9c09bba70d7d168ea7a0f00b8ffa31079 100644 (file)
@@ -378,36 +378,7 @@ jobs:
           - 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
@@ -508,7 +479,7 @@ jobs:
             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
index d3f777bc663ddd250b9d13cf6f2ea5d0bbf33a0c..4ec750f7b4226940e9ff5f18a168db9c655a0c6a 100644 (file)
@@ -408,9 +408,9 @@ version = "0.1.0"
 
 [[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",
 ]
@@ -1657,9 +1657,9 @@ dependencies = [
 
 [[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",
@@ -3605,6 +3605,7 @@ dependencies = [
 name = "rustc_infer"
 version = "0.0.0"
 dependencies = [
+ "arrayvec",
  "rustc_ast",
  "rustc_data_structures",
  "rustc_errors",
@@ -3744,6 +3745,7 @@ dependencies = [
 name = "rustc_middle"
 version = "0.0.0"
 dependencies = [
+ "arrayvec",
  "bitflags",
  "chalk-ir",
  "measureme",
index cb5d71477d81026f6b71e6d4fc9a24aff3c4b00a..d445bbdf6e8423a7a41df536db568f44ad22a1c1 100644 (file)
--- a/README.md
+++ b/README.md
@@ -44,8 +44,8 @@ by running `./x.py --help` or reading the [rustc dev guide][rustcguidebuild].
 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
@@ -57,7 +57,7 @@ by running `./x.py --help` or reading the [rustc dev guide][rustcguidebuild].
     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
@@ -68,7 +68,7 @@ by running `./x.py --help` or reading the [rustc dev guide][rustcguidebuild].
 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
@@ -106,7 +106,7 @@ build.
 
    ```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,
@@ -114,7 +114,7 @@ build.
    # 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 \
@@ -127,7 +127,7 @@ build.
 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
@@ -145,7 +145,7 @@ With these dependencies installed, you can build the compiler in a `cmd.exe`
 shell with:
 
 ```sh
-python x.py build
+python x.py build
 ```
 
 Currently, building Rust only works with some known versions of Visual Studio. If
@@ -154,8 +154,8 @@ you may need to force rustbuild to use an older version. This can be done
 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
@@ -181,8 +181,8 @@ While it's not the recommended build system, this project also provides a
 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
@@ -194,7 +194,7 @@ 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
index 5e6a0340d12a0f35d12956b32dfc93595b5efe5b..6f9cccf58dd01fb165047ca8d8f5cadbd20f6a9f 100644 (file)
     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.
@@ -52,7 +47,7 @@ pub struct TypedArena<T> {
 
 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,
 }
@@ -60,7 +55,7 @@ struct TypedArenaChunk<T> {
 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.
@@ -69,30 +64,25 @@ unsafe fn destroy(&mut self, len: usize) {
         // 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())
             }
         }
     }
@@ -130,7 +120,7 @@ pub fn alloc(&self, object: T) -> &mut T {
 
         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);
@@ -226,10 +216,10 @@ fn grow(&self, additional: usize) {
                 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();
                 }
@@ -239,7 +229,7 @@ fn grow(&self, additional: usize) {
             // 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);
@@ -301,7 +291,7 @@ fn drop(&mut self) {
                     chunk.destroy(chunk.entries);
                 }
             }
-            // RawVec handles deallocation of `last_chunk` and `self.chunks`.
+            // Box handles deallocation of `last_chunk` and `self.chunks`.
         }
     }
 }
@@ -344,10 +334,10 @@ fn grow(&self, additional: usize) {
                 // 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();
                 }
@@ -357,7 +347,7 @@ fn grow(&self, additional: usize) {
             // 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);
index 8e63bdf545841b727ff59e1dd41eb1430750c9d4..e8a1f2db1a16b029b380b4f0004306f0ab43ac63 100644 (file)
@@ -121,6 +121,17 @@ pub fn bench_typed_arena_clear(b: &mut Bencher) {
     })
 }
 
+#[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> {
index dee3a16f9b133a6153f0c3ff4a088b3fa298444e..95abf552915063abeece8f75ca747e6cd5460a1c 100644 (file)
@@ -1931,7 +1931,7 @@ pub enum TyKind {
 
 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 {
@@ -2227,7 +2227,7 @@ pub enum Async {
 
 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.
@@ -2508,7 +2508,7 @@ pub enum VisibilityKind {
 
 impl VisibilityKind {
     pub fn is_pub(&self) -> bool {
-        if let VisibilityKind::Public = *self { true } else { false }
+        matches!(self, VisibilityKind::Public)
     }
 }
 
index b556c1a446b7b3c85416b333ee82aeb21750ed52..76b84d9da83348bad7abc43cc26ea8e7cef7e16c 100644 (file)
@@ -5,17 +5,13 @@
 //! 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]
index 6d41b7836b12114f7e1c4577fadb6fbdae24998b..617cacee0e7f1d580a2003e6b68931a632fc587b 100644 (file)
@@ -27,7 +27,7 @@ pub(super) struct ItemLowerer<'a, 'lowering, 'hir> {
 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;
     }
index 31c05325d1d258dcc32b4f78742b57ddd1246baf..232ee35c4f7df82d9d780346c21ed379ce03d70a 100644 (file)
@@ -868,10 +868,7 @@ fn visit_ty(&mut self, ty: &'a Ty) {
                     .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");
                 }
 
index b8929fe08891305eb65e8ffa828164311b298c3a..9951c25200129da648036609adeed89640a1a85a 100644 (file)
@@ -160,10 +160,10 @@ pub enum StabilityLevel {
 
 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 { .. })
     }
 }
 
index d235caec1031f580a2ec918ff7c6d7650e49a3f4..f4924997d1af960ababae9bed61987be0d4e89a5 100644 (file)
@@ -1529,7 +1529,7 @@ fn summarise_struct(&self, cx: &mut ExtCtxt<'_>, struct_def: &VariantData) -> St
             }
         }
 
-        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,
index 2b2bcd979999f42b1be559b714d30fed9ffc71a0..dc09790df02952dfe9342ad773dcdea24d7d54e0 100644 (file)
@@ -12,7 +12,7 @@
 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};
@@ -85,10 +85,7 @@ pub fn codegen_static_initializer(
     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))
 }
 
index 2208ceca00c83483e54628323b523b9b7355ef71..7f5b09eac4f9e0215e054bcfe42ca24abbb4702d 100644 (file)
@@ -7,15 +7,12 @@
 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};
@@ -71,8 +68,6 @@ fn get_simple_intrinsic(cx: &CodegenCx<'ll, '_>, name: Symbol) -> Option<&'ll Va
         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))
@@ -112,9 +107,6 @@ fn codegen_intrinsic_call(
                 &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)
@@ -137,8 +129,6 @@ fn codegen_intrinsic_call(
                 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)
@@ -169,123 +159,7 @@ fn codegen_intrinsic_call(
                     _ => 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();
@@ -343,20 +217,6 @@ fn codegen_intrinsic_call(
             | 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
@@ -396,84 +256,6 @@ fn codegen_intrinsic_call(
                             &[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();
@@ -513,75 +295,6 @@ fn codegen_intrinsic_call(
                     }
                 }
             }
-            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) {
@@ -589,174 +302,6 @@ fn codegen_intrinsic_call(
                     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),
         };
@@ -807,39 +352,6 @@ fn va_end(&mut self, va_list: &'ll Value) -> &'ll Value {
     }
 }
 
-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,
@@ -2205,37 +1717,12 @@ macro_rules! arith {
 // 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,
     }
 }
index 73e33369175874fe83d3d4b7e48849d9ec5be056..a87ce1446ba140f5a094478fa714df12a2d310e8 100644 (file)
@@ -8,8 +8,6 @@
 #![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).
index 4639ce4a5ab5bc2a696135e960c00d5442d57270..703a17b200a345abc2fc5758c6899dfa29b14d3c 100644 (file)
@@ -13,7 +13,7 @@
 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;
@@ -687,7 +687,8 @@ fn codegen_call_terminator(
                 })
                 .collect();
 
-            bx.codegen_intrinsic_call(
+            Self::codegen_intrinsic_call(
+                &mut bx,
                 *instance.as_ref().unwrap(),
                 &fn_abi,
                 &args,
@@ -867,24 +868,12 @@ fn codegen_asm_terminator(
                         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() {
diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
new file mode 100644 (file)
index 0000000..14f1ed5
--- /dev/null
@@ -0,0 +1,596 @@
+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,
+    }
+}
index c1e7cfd80ef101e2b8930a7af3412212ed50baeb..64d456fb7aa67b8dd6afb816e61d215eb31873a2 100644 (file)
@@ -486,6 +486,7 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
 pub mod constant;
 pub mod coverageinfo;
 pub mod debuginfo;
+mod intrinsic;
 pub mod operand;
 pub mod place;
 mod rvalue;
index 3522ea0115334bba1ca196a42f9398470f98d437..90520f77e3c04337111a9c01213531431a070d73 100644 (file)
@@ -15,6 +15,7 @@
 };
 use rustc_span::symbol::Symbol;
 use rustc_target::abi::LayoutOf;
+use rustc_target::spec::Target;
 
 pub use rustc_data_structures::sync::MetadataRef;
 
@@ -54,6 +55,12 @@ fn target_features(&self, _sess: &Session) -> Vec<Symbol> {
     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);
index 88c160e93b66a618eed378141e8314f18aaa7ee7..8dafcdf3bc6b7cc956d4762f577d68a49600096d 100644 (file)
@@ -8,12 +8,13 @@
 
 #![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)]
@@ -26,7 +27,7 @@
 #![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)]
 
index 856eb73e6297a79ac5cc48051fb241080baab0c9..4807380595db7267446061203cf4f7c26dbaee6e 100644 (file)
@@ -34,7 +34,7 @@ pub fn new() -> SortedMap<K, V> {
     /// 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 }
     }
@@ -159,7 +159,7 @@ pub fn insert_presorted(&mut self, mut elements: Vec<(K, V)>) {
             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);
 
index d39d146db318f230f11e8ff1ae909c14e2e47175..d63bcdb3c2b0425d4993010dccc6fb0aee679cab 100644 (file)
@@ -48,7 +48,7 @@ impl<P, T, const COMPARE_PACKED: bool> CopyTaggedPtr<P, T, COMPARE_PACKED>
     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
index 5686819c61b402441490e510ce66f40b5333f9a7..4f2febf04b135acf54afa8009bd74a46d42a1705 100644 (file)
@@ -4,8 +4,7 @@
 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 => {
index 160bf57779970a58ab0b6369a5736534c634c5e4..fae5b94b3a81edc650fd124051888f4b919e47c7 100644 (file)
@@ -118,17 +118,15 @@ pub struct Annotation {
 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 {
index 5436b1ef737f519ba7980bafaf62cbbf4ddb9ccc..47247294f5dc69ed5b90bc18d5695ad5d8f39fd1 100644 (file)
@@ -1,5 +1,4 @@
 #![feature(bool_to_option)]
-#![feature(cow_is_borrowed)]
 #![feature(crate_visibility_modifier)]
 #![feature(decl_macro)]
 #![feature(or_patterns)]
index 5dba4106c9423b5274c864286f42459f6ad003a5..a8c1a370cef821eeefab90a84eedd6c6dfd280fb 100644 (file)
@@ -21,4 +21,5 @@ rustc_serialize = { path = "../rustc_serialize" }
 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" }
index ae4612a89f277be695115423a79cf1014aa9faf0..5bd6c667fd7f63144416b354f4323c06711f7ee2 100644 (file)
@@ -31,6 +31,9 @@
 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>,
@@ -379,6 +439,7 @@ fn generalize(
             needs_wf: false,
             root_ty: ty,
             param_env: self.param_env,
+            cache: MiniMap::new(),
         };
 
         let ty = match generalize.relate(ty, ty) {
@@ -438,6 +499,8 @@ struct Generalizer<'cx, 'tcx> {
     root_ty: Ty<'tcx>,
 
     param_env: ty::ParamEnv<'tcx>,
+
+    cache: MiniMap<Ty<'tcx>, RelateResult<'tcx, Ty<'tcx>>>,
 }
 
 /// Result from a generalization operation. This includes
@@ -535,13 +598,16 @@ fn relate_with_variance<T: Relate<'tcx>>(
     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);
@@ -598,7 +664,10 @@ fn tys(&mut self, t: Ty<'tcx>, t2: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
                 Ok(t)
             }
             _ => relate::super_relate_tys(self, t, t),
-        }
+        };
+
+        self.cache.insert(t, result.clone());
+        return result;
     }
 
     fn regions(
index 685d2bac94ee37af716ce6b7606dec726b2482e5..2cbdc954e2007cc7c6ea28e5621efa83e60ff210 100644 (file)
@@ -21,7 +21,7 @@
 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};
@@ -1542,7 +1542,7 @@ pub fn const_eval_resolve(
         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);
 
index d6f1ca3cf95360bc1ccb8df8ddfe1c35a2ec527b..e06bfb5958086f9ddc414b9fdc7ba4dba4501e46 100644 (file)
@@ -3,6 +3,7 @@
 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`
@@ -31,16 +32,23 @@ pub fn new(
     /// 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),
@@ -50,9 +58,9 @@ fn type_bound(&self, ty: Ty<'tcx>) -> VerifyBound<'tcx> {
                 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.
@@ -66,7 +74,7 @@ fn type_bound(&self, ty: Ty<'tcx>) -> VerifyBound<'tcx> {
                     ),
                 }
             }
-            _ => self.recursive_bound(ty.into()),
+            _ => self.recursive_bound(ty.into(), visited),
         }
     }
 
@@ -137,7 +145,11 @@ pub fn projection_declared_bounds_from_trait(
         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 =
@@ -166,21 +178,25 @@ pub fn projection_bound(&self, projection_ty: ty::ProjectionTy<'tcx>) -> VerifyB
 
         // 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.
index e05041d88460e3cf40fbd010f42f295fd8a12ec6..504b66bae7329c26594cdb9f428a85a7319dc9e5 100644 (file)
@@ -13,7 +13,6 @@
 //! 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)]
@@ -23,7 +22,6 @@
 #![feature(never_type)]
 #![feature(or_patterns)]
 #![feature(in_band_lifetimes)]
-#![feature(crate_visibility_modifier)]
 #![recursion_limit = "512"] // For rustdoc
 
 #[macro_use]
index dc4fa807f7868b1c390bfa5c07d8156a1979f7b2..72e10bc4304d050d41b2cb68f5b247a5c0f4843e 100644 (file)
@@ -40,6 +40,7 @@ fn mk_session(matches: getopts::Matches) -> (Session, CfgSpecs) {
         DiagnosticOutput::Default,
         Default::default(),
         None,
+        None,
     );
     (sess, cfg)
 }
index f15eb413833ae0389cdab6a37291df953128d3ce..0eed6938c316923e106d31f67fb74d059ad4d836 100644 (file)
@@ -65,6 +65,10 @@ pub fn create_session(
     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,
@@ -72,9 +76,10 @@ pub fn create_session(
         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);
@@ -219,13 +224,13 @@ fn load_backend_from_dylib(path: &Path) -> fn() -> Box<dyn CodegenBackend> {
     }
 }
 
-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),
@@ -235,9 +240,7 @@ pub fn get_codegen_backend(sess: &Session) -> Box<dyn CodegenBackend> {
             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
index 5b5dbcf192ca16caf6fb17405e658de0df370372..32107d621dd6d050f089ea850ef5894aa90e5bca 100644 (file)
@@ -21,7 +21,8 @@
 //! `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};
@@ -1473,21 +1474,19 @@ fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
     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);
             }
             _ => {}
         }
@@ -1985,9 +1984,9 @@ fn collect_outlives_bound_spans<'tcx>(
             .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 }
                         }),
@@ -2079,9 +2078,10 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
             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;
                 }
@@ -2688,8 +2688,7 @@ fn structurally_same_type_impl<'tcx>(
                         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",
                                 )
index 0a14b16e274c83396f46c4778cf45bde1e930bb9..b48592c103ca2d71deb6e5baba9c6cfae43b0246 100644 (file)
@@ -27,6 +27,7 @@
 
 #![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)]
index 24467f811726abcce9dd5f7bb6c1d4ef69aa9eb3..b3125f55d4d6e4b4d054cc627236d0b61557023e 100644 (file)
@@ -70,9 +70,9 @@ fn is_camel_case(name: &str) -> bool {
     // 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 == '_'
         })
 }
 
index a202efa6edadd927f370bc1a6a90c40d8b439f37..ccbe9f80e25b73a3b086644c696727b2d76779b5 100644 (file)
@@ -639,6 +639,26 @@ enum FfiResult<'tcx> {
         .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;
@@ -654,7 +674,7 @@ enum FfiResult<'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;
                     }
@@ -675,7 +695,7 @@ fn get_nullable_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'t
         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,
@@ -816,7 +836,7 @@ fn check_variant_for_ffi(
         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");
index ee83689f0a4695d41de257fec03e8d60a66866cc..e29af0532891f8dee55c7c2b26790fa7904eb4ef 100644 (file)
@@ -13,4 +13,4 @@ libc = "0.2.73"
 
 [build-dependencies]
 build_helper = { path = "../../src/build_helper" }
-cc = "1.0.58"
+cc = "1.0.60"
index 43d76e9fdb4c308cbc256b69307e85599a400aee..a2e2cf1ca0219b947a8979ad2947be8363448c3b 100644 (file)
@@ -562,6 +562,12 @@ fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> Result<Span, String> {
     }
 }
 
+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)
@@ -1191,6 +1197,19 @@ fn get_optimized_mir(&self, tcx: TyCtxt<'tcx>, id: DefIndex) -> Body<'tcx> {
             .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
index 94abfac19c665cb426e4ccff96e3e8df40c95b98..d4f577a7d1b492127ed23e16dc25df2117ecebb8 100644 (file)
@@ -112,6 +112,7 @@ fn into_args(self) -> (DefId, DefId) {
     }
     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) }
index 1e313b7edfc272131a230d2c9e29f16c7a2bc041..eb091d86b82c6d3ddd84d01ce5e84358254c2b76 100644 (file)
@@ -321,6 +321,12 @@ fn encode_alloc_id(
     }
 }
 
+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)
@@ -1109,6 +1115,11 @@ fn encode_optimized_mir(&mut self, def_id: LocalDefId) {
             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);
+            }
         }
     }
 
index 1ba5962d119e807ac09a1e8e54efa802f02e95cd..ba540c944117d1e4ad4fc043d9fce171973a2f58 100644 (file)
@@ -284,6 +284,7 @@ fn encode(&self, buf: &mut Encoder) -> LazyTables<'tcx> {
     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
index a5a860a38b3e8f45d4d24f868ba37be82c911326..1d84ddad7f52dd0cdd39d2b1c496925f9375557d 100644 (file)
@@ -28,5 +28,6 @@ rustc_ast = { path = "../rustc_ast" }
 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" }
index a675aae5b17d421c81354f86429cfd73fb996cf2..74cb3c130b7f087962427b8ff25012589847765f 100644 (file)
@@ -23,6 +23,7 @@
 //! 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"]
 
index 1af1d58181760b65aef5ad23f5bc4239e6fc172d..f3d7c8506ab6ff3338ae7cebfb4b6859d4648f3b 100644 (file)
@@ -69,7 +69,7 @@ pub enum LibSource {
 
 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> {
diff --git a/compiler/rustc_middle/src/mir/abstract_const.rs b/compiler/rustc_middle/src/mir/abstract_const.rs
new file mode 100644 (file)
index 0000000..b85f1e6
--- /dev/null
@@ -0,0 +1,20 @@
+//! 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]),
+}
index 059925088ce1d52d66266574111bfe509ba3dccb..13333dc45de0c4bbac2b16ce930c590095ee5644 100644 (file)
@@ -1,4 +1,4 @@
-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};
@@ -27,8 +27,8 @@ pub enum ErrorHandled {
     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)
index 51642fceb1d93147f3347214fc8f444f87215a5d..20363625e42b644dc1820b503f2ba406dcf710d7 100644 (file)
@@ -118,12 +118,12 @@ macro_rules! throw_machine_stop {
 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};
 
index dcc1f8b1a4b3cd673a198eab02a69b8d12abd111..f366681bc75e9d1ab47d017c47e07632812350bc 100644 (file)
@@ -1,4 +1,4 @@
-use super::{ConstEvalResult, ErrorHandled, GlobalId};
+use super::{ErrorHandled, EvalToConstValueResult, GlobalId};
 
 use crate::mir;
 use crate::ty::subst::{InternalSubsts, SubstsRef};
@@ -10,7 +10,7 @@ impl<'tcx> TyCtxt<'tcx> {
     /// 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
@@ -38,7 +38,7 @@ pub fn const_eval_resolve(
         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 };
@@ -54,7 +54,7 @@ pub fn const_eval_instance(
         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)
     }
 
@@ -64,14 +64,14 @@ pub fn const_eval_global_id(
         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(&param_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)
         }
     }
 
@@ -94,7 +94,7 @@ fn eval_to_allocation(
         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())
     }
 }
index 7d6ff3eb5c1ccb25c7732403b2e7b7bfffe6025a..1f547d9dc3a43a44b2fe8837a90f9ab754192da4 100644 (file)
@@ -12,9 +12,9 @@
 
 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,
@@ -578,6 +578,9 @@ pub enum ScalarMaybeUninit<Tag = ()> {
     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 {
index 29daf7e9309aa36716a15ad9e430b5e5f3926580..8ff75bf392e69a8543813214255d13c9b8226005 100644 (file)
@@ -40,6 +40,7 @@
 use self::predecessors::{PredecessorCache, Predecessors};
 pub use self::query::*;
 
+pub mod abstract_const;
 pub mod coverage;
 pub mod interpret;
 pub mod mono;
@@ -1076,6 +1077,25 @@ pub struct VarDebugInfo<'tcx> {
 // 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{}",
@@ -1092,6 +1112,7 @@ pub fn start_location(self) -> Location {
 ///////////////////////////////////////////////////////////////////////////
 // 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.
@@ -2285,7 +2306,7 @@ fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
 /// 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)]
index 15e3110bc851e8976b41ffa27176c254f00f8f28..c0a606a586b6b5b549a458584b5f5512f88d3085 100644 (file)
@@ -244,6 +244,35 @@ fn describe_as_module(def_id: LocalDefId, tcx: TyCtxt<'_>) -> String {
             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>> {
@@ -678,32 +707,27 @@ fn describe_as_module(def_id: LocalDefId, tcx: TyCtxt<'_>) -> String {
     }
 
     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) {
index e2e5f08462f7231139c30befcf0201f0c146e559..8ea34f9161abcf563c06fc0ae8b5f9603ea14af8 100644 (file)
@@ -357,6 +357,26 @@ fn decode(decoder: &mut D) -> Result<&'tcx Self, D::Error> {
     }
 }
 
+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>>,
index 39bf5472b76f83c8c36bac57ea6526e7a32596aa..cd8f12a4f3576f5ce29cc909a2623cba258fce19 100644 (file)
@@ -2419,7 +2419,7 @@ pub fn intern_existential_predicates(
         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)
     }
 
index c8b6705b35f363b6f6fe36fba152e9c16e77aae8..a6b62097d5b18d8d3baf764192ef081b968c9da2 100644 (file)
@@ -62,10 +62,6 @@ pub enum InstanceDef<'tcx> {
     /// `<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`.
@@ -87,10 +83,6 @@ pub enum InstanceDef<'tcx> {
     /// 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.
@@ -99,10 +91,6 @@ pub enum InstanceDef<'tcx> {
     /// 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>),
 }
 
@@ -243,6 +231,27 @@ pub fn requires_caller_location(&self, tcx: TyCtxt<'_>) -> bool {
             _ => 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> {
@@ -440,30 +449,18 @@ pub fn fn_once_adapter_instance(
         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
index 8283deb3ecc24ffaae4b71cb526fb3a733721ce2..f23d666cfcfdd4f63c0aa2e138224385499f8639 100644 (file)
@@ -1999,7 +1999,7 @@ pub struct VariantDef {
     flags: VariantFlags,
 }
 
-impl<'tcx> VariantDef {
+impl VariantDef {
     /// Creates a new `VariantDef`.
     ///
     /// `variant_did` is the `DefId` that identifies the enum variant (if this `VariantDef`
@@ -2065,19 +2065,6 @@ pub fn is_field_list_non_exhaustive(&self) -> bool {
     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)]
index 783f116a87d385ecc7786c464ebc0c013da8443b..01649f44c8861f4b6403e9b75f274c13107e5ca4 100644 (file)
@@ -3,6 +3,7 @@
 // RFC for reference.
 
 use crate::ty::subst::{GenericArg, GenericArgKind};
+use crate::ty::walk::MiniSet;
 use crate::ty::{self, Ty, TyCtxt, TypeFoldable};
 use smallvec::SmallVec;
 
@@ -50,12 +51,18 @@ impl<'tcx> TyCtxt<'tcx> {
     /// 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
@@ -73,11 +80,11 @@ impl<'tcx> TyCtxt<'tcx> {
                 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);
                         }
                     }
                 }
@@ -85,19 +92,19 @@ impl<'tcx> TyCtxt<'tcx> {
 
             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
@@ -135,7 +142,8 @@ impl<'tcx> TyCtxt<'tcx> {
                     // 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()));
                 }
             }
@@ -177,7 +185,7 @@ impl<'tcx> TyCtxt<'tcx> {
                 // 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);
             }
         }
 }
@@ -186,11 +194,12 @@ fn compute_components_recursive(
     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.
@@ -199,7 +208,7 @@ fn compute_components_recursive(
                 }
             }
             GenericArgKind::Const(_) => {
-                compute_components_recursive(tcx, child, out);
+                compute_components_recursive(tcx, child, out, visited);
             }
         }
     }
index 709a4018d809c66b8544b75f40c2312412883f43..f315292dab546adb4b8214e518414972bfca226a 100644 (file)
@@ -4,6 +4,7 @@
 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;
@@ -263,21 +264,33 @@ fn default_print_impl_path(
 /// 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, _)
@@ -302,6 +315,9 @@ pub fn characteristic_def_id_of_type(ty: Ty<'_>) -> Option<DefId> {
         | 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;
index 4b2e9a16d4a07ec6398ea08f705dc49e53c7a4ab..f0bae48cc1221798ef8bea519e8c91117a03e936 100644 (file)
@@ -1264,6 +1264,7 @@ pub struct FmtPrinterData<'a, 'tcx, F> {
     used_region_names: FxHashSet<Symbol>,
     region_index: usize,
     binder_depth: usize,
+    printed_type_count: usize,
 
     pub region_highlight_mode: RegionHighlightMode,
 
@@ -1294,6 +1295,7 @@ pub fn new(tcx: TyCtxt<'tcx>, fmt: F, ns: Namespace) -> Self {
             used_region_names: Default::default(),
             region_index: 0,
             binder_depth: 0,
+            printed_type_count: 0,
             region_highlight_mode: RegionHighlightMode::default(),
             name_resolver: None,
         }))
@@ -1411,8 +1413,14 @@ fn print_region(self, region: ty::Region<'_>) -> Result<Self::Region, Self::Erro
         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(
index 3f7a20bba2b9add597b91cf99d5dfea170c82f3e..a005990264cf11176443819ad7e8446804e15cb8 100644 (file)
@@ -193,6 +193,22 @@ fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
     }
 }
 
+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;
 
index ee9b203b151804390860599744f6fafdd88d676c..d3a7412ef14e777c2d58da3879f38373a1b28c62 100644 (file)
@@ -14,7 +14,7 @@
 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::{
index dcfb8d314300f2ba971fd1718961cfbb652ddf7a..b0c48a860ebafd328e17f0cb141805e132b2e3bd 100644 (file)
@@ -760,6 +760,12 @@ fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> {
     }
 }
 
+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)
index 7d3634a75b0a7c9c41cddf26adaccf0493d0da41..c4df0bba726cb9d0929c355b7f0021e88061c0e0 100644 (file)
@@ -576,7 +576,20 @@ pub fn super_relate_consts<R: TypeRelation<'tcx>>(
             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),
index d4c8ba082751e89a13abeb1a95c9fc7e0ce6239e..724ec101b23b71a388f914dcdf9f7bdb0da1dd43 100644 (file)
@@ -2322,9 +2322,4 @@ pub fn is_trivially_sized(&self, tcx: TyCtxt<'tcx>) -> bool {
             }
         }
     }
-
-    /// 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)
-    }
 }
index 4f55517c6f4357d320acea7bb959d9555fd169b5..7afa6e6cc056d4f948e5dc0f8e4a9ca7a9fde3ba 100644 (file)
@@ -3,7 +3,50 @@
 
 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
@@ -41,11 +93,15 @@ impl<'tcx> Iterator for TypeWalker<'tcx> {
 
     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);
+            }
+        }
     }
 }
 
@@ -67,9 +123,17 @@ pub fn walk(self) -> TypeWalker<'tcx> {
     /// 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()
     }
 }
index e256fb55b124b70a2d3eec66140982b394056a05..629e9be9ddd45f57d9932f253d3f0fecf4902c51 100644 (file)
@@ -492,8 +492,8 @@ fn add_move_error_suggestions(&self, err: &mut DiagnosticBuilder<'a>, binds_to:
             {
                 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)
                         {
index 8b0121cf360e0f24130e9629f5c6ed5523e12d10..d4cdf02104ace23c088bfe61d14847c15bfaa43f 100644 (file)
@@ -631,9 +631,8 @@ fn suggest_ampmut<'tcx>(
                 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));
             }
         }
     }
index a775fa59c1b9dce220554c6197a3568f600462eb..7505e6e2dd11e224db3f97f0c0b91372335ac407 100644 (file)
@@ -115,9 +115,10 @@ fn compile_all_suggestions(
             //    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
index 72151df7230be2df821d4720625863bc59a671c6..a0ee7fdc072ef3c21209a476bbb5d3a845ae932a 100644 (file)
@@ -1,8 +1,8 @@
 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,
 };
 
@@ -104,6 +104,8 @@ pub(super) fn mk_eval_cx<'mir, 'tcx>(
     )
 }
 
+/// 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>,
@@ -182,63 +184,37 @@ pub(super) fn op_to_const<'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
@@ -261,13 +237,13 @@ pub fn const_eval_validated_provider<'tcx>(
         });
     }
 
-    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
@@ -279,7 +255,7 @@ pub fn const_eval_raw_provider<'tcx>(
     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
@@ -318,9 +294,8 @@ pub fn const_eval_raw_provider<'tcx>(
     );
 
     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 {
@@ -342,7 +317,7 @@ pub fn const_eval_raw_provider<'tcx>(
                     );
                 }
 
-                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()) {
@@ -356,12 +331,12 @@ pub fn const_eval_raw_provider<'tcx>(
                     // 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
@@ -370,31 +345,65 @@ pub fn const_eval_raw_provider<'tcx>(
                         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 })
+            }
+        }
+    }
 }
index 02e905505c0f5bbffce70e36081bd934e9dbd7a2..73ca7e0d471ca21dadabef1a32b06eec0c8415f4 100644 (file)
@@ -51,7 +51,7 @@ fn try_eval_const_fn_call(
 
         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)?;
 
index 94151fbd0903aa496cf6b7f6d0308482ad8cb524..5d4c4251961d20df3bdf7d1c71e31ef3eafae90f 100644 (file)
@@ -1,6 +1,7 @@
 //! A helpful diagram for debugging dataflow problems.
 
 use std::borrow::Cow;
+use std::lazy::SyncOnceCell;
 use std::{io, ops, str};
 
 use regex::Regex;
@@ -570,6 +571,13 @@ fn visit_terminator_after_primary_effect(
     }
 }
 
+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>,
@@ -578,7 +586,7 @@ fn diff_pretty<T, C>(new: T, old: T, ctxt: &C) -> String
         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 });
 
index c42d58678565658fd5396c4c7bed84c693d8075d..1769feaf7a5140c2abf61f6592a0796224303116 100644 (file)
@@ -204,7 +204,7 @@ fn move_data(&self) -> &MoveData<'tcx> {
 
 /// `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.
index b083044a9c6d9a4e6f955137b85def97de4270b3..5c3e3538401801993de42ebe832fdd8423fba66b 100644 (file)
@@ -4,7 +4,6 @@
 use rustc_middle::ty::{self, TyCtxt};
 use smallvec::{smallvec, SmallVec};
 
-use std::convert::TryInto;
 use std::mem;
 
 use super::abs_domain::Lift;
@@ -481,12 +480,7 @@ fn gather_move(&mut self, place: Place<'tcx>) {
             };
             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 {
index f2f6c893eda4e912647e0153ef6ca20548918e12..00d6ffb14eaf265928c9c52dbdcedf33c65cb291 100644 (file)
@@ -20,7 +20,7 @@
 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;
@@ -875,32 +875,7 @@ pub(super) fn deallocate_local(
         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>> {
@@ -914,14 +889,7 @@ pub fn const_eval_raw(
         } 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)
     }
 
index 47ca71d9642ba0f4851c719fa4c36e380af53eea..0664f25e409dcd3c8765233d1763a786a2fe13d7 100644 (file)
@@ -152,7 +152,10 @@ pub fn emulate_intrinsic(
                     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)?;
             }
 
index d4be2ce0568fd38c285f0b88077f20c0b3d416aa..86e242c67d520439172fba2032f913b4ef920fe5 100644 (file)
@@ -469,7 +469,7 @@ fn get_global_alloc(
                 // 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!
index 57245696e576e601320c36663f2f79582b2c0d1d..8c4bb19866e3f94f30f6c7a8173ab0eee47c2c01 100644 (file)
@@ -553,13 +553,7 @@ pub(super) fn eval_operands(
             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(..)
index 9e16063bd21af2a0ca6bd656d273404914e58e7f..72551b23370dd3f2124a32a08426b825110d4c07 100644 (file)
@@ -13,9 +13,9 @@
 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)]
@@ -551,7 +551,7 @@ pub(super) fn mplace_projection(
                 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 {
@@ -565,9 +565,7 @@ pub(super) fn mplace_projection(
                 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)?,
         })
     }
 
@@ -1122,7 +1120,7 @@ pub fn write_discriminant(
 
     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);
index ca62f0347ffacc6aef380e43e0f3c611d53ee80e..2b83e1c8134efe75508140c3e04fa7f4e4002c13 100644 (file)
@@ -425,26 +425,28 @@ fn check_safe_pointer(
                 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!
index 42717f273843aa4196ff0aaacd2cd18e901ecd22..a356ae1709deb64a2f74cfe8aad60f11ae8516b8 100644 (file)
@@ -6,6 +6,8 @@
 
 #![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]
@@ -52,8 +52,8 @@ pub fn provide(providers: &mut Providers) {
     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();
index 9ea103463d5ebd8b63656f2b0d7f9ad6f58cb105..4ef871b05f47f3375916fd58c7717ef789a30feb 100644 (file)
@@ -364,8 +364,10 @@ fn collect_items_rec<'tcx>(
 
             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) => {
@@ -418,6 +420,29 @@ fn record_accesses<'a, 'tcx: 'a>(
     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>,
@@ -440,7 +465,10 @@ fn check_recursion_limit<'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),
@@ -474,26 +502,9 @@ fn check_type_length_limit<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) {
     //
     // 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!(
index b60beca688068c8494e5e4211e92bcfd01543463..db6d3b2d912d693aa640358abe69eaf54720c1fa 100644 (file)
@@ -277,14 +277,8 @@ fn assert_symbols_are_distinct<'a, 'tcx, I>(tcx: TyCtxt<'tcx>, mono_items: I)
 
     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);
 
index bfe0b85b5b1e2abd292adc0067742a0282f872ad..7e4d189f0b73785bfe34fb18dabdd9ec7e5169f3 100644 (file)
@@ -33,7 +33,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<'
     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();
@@ -42,16 +42,8 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<'
                 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
@@ -59,7 +51,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<'
         // 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);
@@ -70,13 +62,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<'
                 .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),
@@ -641,29 +627,45 @@ fn tuple_like_shim<I>(&mut self, dest: Place<'tcx>, src: Place<'tcx>, tys: I)
     }
 }
 
-/// 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
diff --git a/compiler/rustc_mir/src/transform/dest_prop.rs b/compiler/rustc_mir/src/transform/dest_prop.rs
new file mode 100644 (file)
index 0000000..46cbced
--- /dev/null
@@ -0,0 +1,1057 @@
+//! 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);
+    }
+}
index 8025b7c02043d4b84b6cd226d3b88aee5715e702..fc9854ba499f839ab51a7b509e956977eb80e262 100644 (file)
@@ -24,6 +24,7 @@
 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;
@@ -329,7 +330,11 @@ fn mir_promoted(
     // 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();
@@ -463,6 +468,7 @@ fn run_optimization_passes<'tcx>(
         &simplify_comparison_integral::SimplifyComparisonIntegral,
         &simplify_try::SimplifyArmIdentity,
         &simplify_try::SimplifyBranchSame,
+        &dest_prop::DestinationPropagation,
         &copy_prop::CopyPropagation,
         &simplify_branches::SimplifyBranches::new("after-copy-prop"),
         &remove_noop_landing_pads::RemoveNoopLandingPads,
index 3673b6a4aa223c2e5e9c0b9dd139c3133aed904e..1ffb5a87c4762f2b00a77e483e7e51dc139950bd 100644 (file)
@@ -36,6 +36,12 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut mir::Body
             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 => {
index 1d2295a37dddf10bfadfef0740136e396b5c343a..01d518386fc4ec589534b87aa0427d4d8fff3eac 100644 (file)
@@ -92,7 +92,7 @@ pub enum TempState {
 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 { .. } )
     }
 }
 
@@ -297,6 +297,17 @@ fn deref(&self) -> &Self::Target {
 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) => {
@@ -363,12 +374,10 @@ fn validate_candidate(&self, candidate: Candidate) -> Result<(), Unpromotable> {
 
                             // 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 {
@@ -495,9 +504,10 @@ fn validate_place(&self, place: PlaceRef<'tcx>) -> Result<(), Unpromotable> {
         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
@@ -512,6 +522,9 @@ fn validate_place(&self, place: PlaceRef<'tcx>) -> Result<(), Unpromotable> {
                             }) = 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, * ].
@@ -524,13 +537,13 @@ fn validate_place(&self, place: PlaceRef<'tcx>) -> Result<(), Unpromotable> {
                                         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);
                         }
                     }
@@ -545,7 +558,7 @@ fn validate_place(&self, place: PlaceRef<'tcx>) -> Result<(), 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() {
@@ -573,6 +586,10 @@ fn validate_operand(&self, operand: &Operand<'tcx>) -> Result<(), Unpromotable>
                 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);
@@ -591,20 +608,20 @@ fn validate_operand(&self, operand: &Operand<'tcx>) -> Result<(), 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
@@ -616,13 +633,14 @@ fn validate_rvalue(&self, rvalue: &Rvalue<'tcx>) -> Result<(), Unpromotable> {
                             || 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.
             _ => {}
         }
 
@@ -644,8 +662,8 @@ fn validate_rvalue(&self, rvalue: &Rvalue<'tcx>) -> Result<(), Unpromotable> {
             }
 
             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() {
@@ -664,12 +682,10 @@ fn validate_rvalue(&self, rvalue: &Rvalue<'tcx>) -> Result<(), Unpromotable> {
 
                     // 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 {
@@ -734,7 +750,7 @@ fn validate_call(
     ) -> 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]`.
index d8995e92abfcc7dbd780569f41dfbfebc7a35221..3fc8e6d4b04b85e046422e29909ecea88ad60791 100644 (file)
@@ -281,8 +281,7 @@ fn simplify_branch(&mut self, terminator: &mut Terminator<'tcx>) -> bool {
 
     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))
         }
     }
 }
index 75567181b69164d9f4519eb2a9e4ee95adfff689..49c644a20bf8248dc427c155567461f45fd1b105 100644 (file)
@@ -631,14 +631,11 @@ fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> bool {
             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)",
index d1cbf209b06cebc4035cb783f8a3de4ccf29cfe3..beaf12b1db04255bb05e936216c0cb35a9fffd8e 100644 (file)
@@ -96,8 +96,7 @@ fn ast_block_stmts(
                     );
                 }
                 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.
index 3a525d10b08175cda5f8976e181f073ba7b64e78..6e9d5eedf051f231c732b2bfd0f8c3686093e90f 100644 (file)
@@ -1793,7 +1793,7 @@ fn bind_and_guard_matched_candidate<'pat>(
                     .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.
index d6e828c966a95de5b28eb875b8d1f50c4d067eb1..4ef88c25cadf3393663ba6a6b90b236a7d2b2857 100644 (file)
@@ -33,7 +33,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         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),
         };
index e55180ff4be526bef3c2950a5c87b5477bdb09d2..714041ad4e8741df90c20ee28640030f398058ba 100644 (file)
@@ -1,7 +1,7 @@
 //! 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)]
index ad94740c160669f157ceeb6d0af32c454e733108..eddd2882406ba38cb40a586cc9873fec8f62a102 100644 (file)
@@ -2299,19 +2299,19 @@ fn range_borders(r: IntRange<'_>) -> impl Iterator<Item = Border> {
                 // 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),
                 );
index 0becdf24c532be6ab438641ba27847f884004688..72a34b86ae20bbb0451f8e33ec97763b92b6cdd6 100644 (file)
@@ -3,7 +3,6 @@
 #![feature(bool_to_option)]
 #![feature(crate_visibility_modifier)]
 #![feature(bindings_after_at)]
-#![feature(try_blocks)]
 #![feature(or_patterns)]
 
 use rustc_ast as ast;
index e07b8b86aef8e45cb84879be4841a8b13f04bc2b..dde162681b77311f1f4923f13d3d04f55f6dda68 100644 (file)
@@ -11,8 +11,6 @@
 )]
 #![feature(nll)]
 #![feature(or_patterns)]
-#![feature(rustc_private)]
-#![feature(unicode_internals)]
 #![feature(bool_to_option)]
 
 pub use Alignment::*;
index 03cc718b8995d0fe82aed76fc147d3754e6b6665..c2de4cdbf0dd5c76e0d3f847178fddc0d3c16d48 100644 (file)
@@ -1,7 +1,6 @@
 #![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;
@@ -97,6 +96,15 @@ fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> bool {
                 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),
         }
     }
index 565313902a42ee1c89eea8c126573085947ef006..a48d002b2a35bb772c5e21202a91e743c334bb7d 100644 (file)
@@ -395,7 +395,7 @@ fn build_reduced_graph_for_use_tree(
         // 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())
index 6788df9be7820489bbcdb694f4c5debc6517ded9..2c01934b490dcc429f8a2b73c98ee59f01b5ada2 100644 (file)
@@ -1034,7 +1034,7 @@ fn with_generic_param_rib<'c, F>(&'c mut self, generics: &'c Generics, kind: Rib
             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)));
index 2cc87dc637566fafa9cec8a914790039f02b2b3e..ced272e474d1154f55576ad7b301316df9ef7caa 100644 (file)
@@ -1418,9 +1418,9 @@ impl<'tcx> LifetimeContext<'_, 'tcx> {
                         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)));
                         }
                     }
                 }
index 3f12596a236abe228b6e8fb2ddf77fa5ad11e22c..8d004675d7f4dd69aaa4196e4083fb80821e3150 100644 (file)
@@ -818,10 +818,11 @@ pub fn build_configuration(sess: &Session, mut user_cfg: CrateConfig) -> CrateCo
     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",
@@ -835,7 +836,7 @@ pub fn build_target_config(opts: &Options, error_format: ErrorOutputType) -> Con
         "32" => 32,
         "64" => 64,
         w => early_error(
-            error_format,
+            opts.error_format,
             &format!(
                 "target specification was invalid: \
              unrecognized target-pointer-width {}",
index e12364b7dac7cb355917994aa0855998076e3dec..83b737a73b1e84239a9d5ea1c33cb56e563aede7 100644 (file)
@@ -56,16 +56,16 @@ pub fn matches(&self, kind: PathKind) -> bool {
 
 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)
         };
index 974f4c31bb6a4eb448eb4aa4cdaa5605637ffef7..ff67d3cb107d9d7720b9e24a99cfdbfbf03eadbb 100644 (file)
@@ -1234,6 +1234,7 @@ pub fn build_session(
     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
@@ -1253,7 +1254,7 @@ pub fn build_session(
         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))
index e38cd516b91ac16edb12e91cd9791d6bda347f6a..a730c30378827e328ae8f5c5106e9e5da5f3d3ab 100644 (file)
@@ -5,15 +5,14 @@
 //! 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;
@@ -1158,7 +1157,12 @@ fn encode(&self, s: &mut S) -> Result<(), S::Error> {
                     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 {
@@ -1173,7 +1177,7 @@ fn encode(&self, s: &mut S) -> Result<(), S::Error> {
                     // 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 => {
index b5882df47294ee2a83542f9c423752f22a60a099..da1996b92a60b520f4fab62e38031a9f3bc266f9 100644 (file)
@@ -12,6 +12,7 @@
 
 #![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)]
index fdb87c085b54ef377ba7306c1d4e44a548812087..2642358dbc54c4a6b99b7f9ce6d47766bda88fea 100644 (file)
@@ -1,10 +1,25 @@
+//! 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>(
@@ -16,18 +31,23 @@ 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
             }
         }
     }
@@ -76,3 +96,337 @@ pub fn is_const_evaluatable<'cx, 'tcx>(
     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,
+    }
+}
index 1dd50d69a2195ce73e35bad9fd7ba4891d03a483..5b4314598deb5e43f7f3f6914895bd6b77df7d6d 100644 (file)
@@ -476,6 +476,25 @@ fn process_obligation(
 
                 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;
 
index b72e86a4cbde63064f747cdc2a6d40d503e759f6..79495ba7f9b30b662ebe2593747f63a1363a7681 100644 (file)
@@ -552,6 +552,21 @@ pub fn provide(providers: &mut ty::query::Providers) {
         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
     };
 }
index ac98d840e98af6756c8c02bfe096549a051ab681..5e2f7d81d000a871ccb9c55fb6f7d7fdcb337014 100644 (file)
@@ -450,153 +450,167 @@ fn evaluate_predicate_recursively<'o>(
             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>(
index 6fea4732dda3fd6a18c713f4621f16316de12a45..d0b05beb4e63c86ee9ea23d25931a4a5c715acfc 100644 (file)
@@ -4,7 +4,6 @@
 #![feature(crate_visibility_modifier)]
 #![feature(in_band_lifetimes)]
 #![feature(nll)]
-#![feature(or_patterns)]
 #![recursion_limit = "256"]
 
 #[macro_use]
index 6e9042d1ba7c84518aae084c1016f4b539e076c7..8dd6aa3c7fcc1da74fecf7dd8e88416f1227d66e 100644 (file)
@@ -5,7 +5,6 @@
 //! 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"]
 
index f6b768bb1222005233b3be4dc6853ea42ba64d33..c7ce5008c335405ba45d50e0c18ec5b4b53c2305 100644 (file)
@@ -370,7 +370,11 @@ fn replace_prefix<A, B, C>(&self, s: A, old: B, new: C) -> Option<String>
     {
         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
index d5563cdac02de090cdb78efc989e0dfc404e55c5..af800eab67a5e36386d0ddccc96a4e8a0ac8e03c 100644 (file)
@@ -439,9 +439,11 @@ fn check_named_place_expr(&self, oprnd: &'tcx hir::Expr<'tcx>) {
             // 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 })
index 9a9e57638d7589ad10c85c3c13f94709bcf5407a..e84cc3c9b8684646725f14d0f78a93051a34447a 100644 (file)
 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,
 };
@@ -2070,8 +2069,8 @@ fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: LocalDefId, span: S
     // `#[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 \
@@ -2079,7 +2078,6 @@ fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: LocalDefId, span: S
                 tcx.sess.span_err(span, msg);
             }
         }
-        Ok(_) => bug!("Matching on non-ByRef static"),
         Err(_) => {}
     }
 }
index 529b8525a4a8d8e2d68e4e48b43519c12c110648..66975f32a1f4ad6fe873ca268c264a21cbd15782 100644 (file)
@@ -589,10 +589,10 @@ fn check_str_addition(
                                 } 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)
                                 },
@@ -617,10 +617,10 @@ fn check_str_addition(
                     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)
                         };
index 54b0671fab5a7f1f9b927ce3b441dbb283a527b2..321472b8fe8d36332fbf7f29305c95d38e6e1704 100644 (file)
@@ -1,5 +1,6 @@
 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};
@@ -740,6 +741,40 @@ fn check_pat_path(
         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<'_>,
@@ -772,12 +807,12 @@ fn emit_bad_pat_path(
                         );
                     }
                     _ => {
-                        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 = &[
@@ -788,11 +823,13 @@ fn emit_bad_pat_path(
                             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());
index 9b8427a46955cc9ebf0192b16e8597ba4c9ae4a2..f5418c9e01e4928a0a6f1d86f398e4be369bfba3 100644 (file)
@@ -1693,25 +1693,27 @@ pub fn const_evaluatable_predicates_of<'tcx>(
 ) -> 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)
     })
 }
 
@@ -2341,8 +2343,8 @@ fn from_target_feature(
                         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");
                         }
index 5ba3e0e00572c052f509c3e155e42dd1ca63a48f..6703a99b15155683008ef24d88474ea40b00befe 100644 (file)
@@ -457,9 +457,7 @@ fn bench_clone_from_10_1000_0100(b: &mut Bencher) {
 }
 
 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) {
@@ -467,7 +465,8 @@ 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())
                 });
             }
@@ -476,24 +475,24 @@ fn $fname(b: &mut Bencher) {
 }
 
 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]
index 24d17fdd880ba8bc9585f93ce7c4e08dbaf7b59e..621c4ff6378c9e2f01dbe2fdc29114d154a08aff 100644 (file)
@@ -15,7 +15,6 @@
 //! [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>,
@@ -255,8 +254,7 @@ pub struct BinaryHeap<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>,
@@ -617,7 +615,7 @@ pub fn append(&mut self, other: &mut Self) {
 
         #[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
@@ -802,7 +800,7 @@ pub fn capacity(&self) -> usize {
     /// 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);
@@ -1057,11 +1055,10 @@ fn drop(&mut self) {
 
 /// 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>,
@@ -1122,11 +1119,10 @@ impl<T> FusedIterator for Iter<'_, 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> {
@@ -1227,11 +1223,10 @@ unsafe impl<T: Ord> TrustedLen for IntoIterSorted<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> {
@@ -1273,11 +1268,10 @@ impl<T> FusedIterator for Drain<'_, T> {}
 
 /// 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> {
index 5c95acfbe9c2095e052048b78d485a656c4c4c02..016f139a501a00da5749e941e4c1d47df2fdaccb 100644 (file)
@@ -16,6 +16,9 @@ pub struct DormantMutRef<'a, T> {
     _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
index aed898be08fb681305840287935fd4a88458f4fd..3e6a4e4ead6e88d96ac1192e65ee941446a00a45 100644 (file)
@@ -47,7 +47,6 @@
 /// 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;
@@ -453,8 +453,6 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 
 /// 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,
@@ -474,8 +472,6 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 
 /// 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>,
@@ -815,7 +811,7 @@ pub fn get_mut<Q: ?Sized>(&mut self, key: &Q) -> Option<&mut V>
     /// 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
     ///
@@ -2554,7 +2550,7 @@ pub fn get(&self) -> &V {
     /// 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
     ///
@@ -2584,7 +2580,7 @@ pub fn get_mut(&mut self) -> &mut V {
     ///
     /// If you need multiple references to the `OccupiedEntry`, see [`get_mut`].
     ///
-    /// [`get_mut`]: #method.get_mut
+    /// [`get_mut`]: OccupiedEntry::get_mut
     ///
     /// # Examples
     ///
index af5cf7d7d875c39a6ca46795383bb0298c6f58c9..d2cd6b8e5241ad7e2fbd7dc0ee469eb7bd7826aa 100644 (file)
@@ -1418,6 +1418,146 @@ fn vals<'a, 'new>(v: Values<'a, (), &'static str>) -> Values<'a, (), &'new str>
     }
 }
 
+#[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();
index 8776a5efbe4f5ad084f450efd848426beaf305fa..ae42701b36a530449c4b873a321b83361a611277 100644 (file)
@@ -12,7 +12,7 @@
 //     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,
 // }
@@ -50,9 +50,8 @@
 /// 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`.
@@ -80,7 +79,7 @@ unsafe fn new() -> Self {
             // 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,
         }
@@ -224,7 +223,7 @@ pub fn pop_internal_level(&mut self) {
             )
         };
         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>>());
@@ -309,7 +308,7 @@ impl<BorrowType, K, V, Type> NodeRef<BorrowType, K, V, Type> {
     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
@@ -365,16 +364,19 @@ pub fn ascend(
     ) -> 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> {
@@ -572,7 +574,7 @@ impl<'a, K: 'a, V: 'a> NodeRef<marker::Mut<'a>, K, V, marker::Leaf> {
     /// 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 {
@@ -617,7 +619,7 @@ pub fn push(&mut self, key: K, val: V, edge: Root<K, V>) {
         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 {
@@ -672,7 +674,7 @@ pub fn pop(&mut self) -> (K, V, Option<Root<K, V>>) {
                     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)
                 }
             };
@@ -704,7 +706,7 @@ pub fn pop_front(&mut self) -> (K, V, Option<Root<K, V>>) {
                     );
 
                     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();
@@ -956,7 +958,7 @@ impl<'a, K, V> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Internal>, marker::
     /// 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);
index 5390b57a1d98dddcd84ef1e2dfc0e7896c1ddd20..412c65681e684003ada71c0df9d8ee4f3f7a087a 100644 (file)
@@ -102,7 +102,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 /// 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> {
index 65cfe9a9b49965c3b1576952c64f977c312b0ca4..8e9acc42d9aba2775ef085b685041fa0b649a32d 100644 (file)
 /// 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> {
@@ -640,7 +640,7 @@ pub fn capacity(&self) -> usize {
     /// 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);
@@ -987,8 +987,10 @@ pub fn iter_mut(&mut self) -> IterMut<'_, T> {
     /// 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
     ///
@@ -1020,8 +1022,10 @@ pub fn as_slices(&self) -> (&[T], &[T]) {
     /// 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
     ///
@@ -2160,15 +2164,20 @@ pub fn resize_with(&mut self, new_len: usize, generator: impl FnMut() -> T) {
         }
     }
 
-    /// 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.
@@ -2495,8 +2504,7 @@ fn count(tail: usize, head: usize, size: usize) -> usize {
 /// 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],
@@ -2650,8 +2658,7 @@ impl<T> FusedIterator for Iter<'_, 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],
@@ -2756,8 +2763,7 @@ impl<T> FusedIterator for IterMut<'_, 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> {
index 1ae94de75adb7174f076a4cb61b10260089c142a..4ffb435d1e36670d3a2778eae55d94630cc454da 100644 (file)
@@ -9,8 +9,7 @@
 /// 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,
index 7881c101f9f60f496f1b6f62b525c7cb330a2a2b..5ae4b7cf36adc46bb108a78f8e90315af3b79dda 100644 (file)
@@ -74,6 +74,7 @@
 #![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)]
@@ -81,7 +82,6 @@
 #![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)]
index 05382d0b5594edfece3d193fb5d1698b8fdcdab0..62675665f037f39da3c680db2e7338f6fdc83071 100644 (file)
@@ -528,7 +528,7 @@ fn drop(&mut self) {
 
 #[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(())
index 2b0ce5ede56308b1a907def495bc12d5215b0d27..d3598ccfce81f341e319dc7ccb61489de0b7c8a8 100644 (file)
@@ -2440,7 +2440,7 @@ pub struct Drain<'a> {
 #[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()
     }
 }
 
@@ -2463,6 +2463,40 @@ fn drop(&mut self) {
     }
 }
 
+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;
index 9dbea0dc9e68b9296d8d2dbdaebdb48635cb07d4..8c0b6af54829b4cbfc1a224bbd51b94cfd03fc20 100644 (file)
@@ -55,6 +55,7 @@
 #![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};
@@ -2754,6 +2755,57 @@ fn from(s: &str) -> Vec<u8> {
     }
 }
 
+#[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
 ////////////////////////////////////////////////////////////////////////////////
index 03737e1ef1f4dcd4d8be3439edffbd365ea8741f..3ee0cfbe74759862a6da591141abb1b85a931808 100644 (file)
@@ -18,6 +18,7 @@
 #![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};
index 4e6043541226f77310e96628c9b23a7a5026354e..a6e41b21b618c8d841d510c73fcba95e24028993 100644 (file)
@@ -1,6 +1,5 @@
 use std::borrow::Cow;
 use std::collections::TryReserveError::*;
-use std::mem::size_of;
 use std::ops::Bound::*;
 
 pub trait IntoCow<'a, B: ?Sized>
@@ -605,7 +604,7 @@ fn test_try_reserve() {
     // 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
@@ -686,7 +685,7 @@ fn test_try_reserve_exact() {
     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();
index 368ca4c543219a50d0d8e8a601185eeea7d4c5da..a49ca7c256a75697ff19c6c7aad7738e730a7cfa 100644 (file)
@@ -1341,7 +1341,7 @@ fn test_try_reserve() {
     // 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
index e78dfd1ed4abfca43a6b2d1d304b78ff505790ca..a8a25f927163cd33a63ef4c1ba9194570febc65c 100644 (file)
@@ -6,8 +6,6 @@
 //!
 //! 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")]
 
@@ -20,8 +18,6 @@
 ///
 /// 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 {
index 48b7f2739eeb29b9ac47958bdb14d13bf3acf06d..8558cb5a5e8a32ebadc1f8c3becb89f78f73f3c5 100644 (file)
@@ -2086,7 +2086,7 @@ fn fmt(&self, f: &mut Formatter<'_>) -> Result {
             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);
index 4fec219ede2bce8e067c255a26f355f23b3ad2d6..ab162638a1cfe24d2fb257bd0fe8850883c7e3f2 100644 (file)
@@ -7,10 +7,8 @@
 /// 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> {
index 9ab3bfcea1c71b810c0d51ccbd44abf9d3d9bd3c..f302cda09e721166e2d6929402d46e621aa5db4c 100644 (file)
@@ -33,10 +33,8 @@ pub fn poll_fn<T, F>(f: F) -> PollFn<F>
 
 /// 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> {
index fcfd8779b0ad2e702688308b37d59db1f40f94ee..e98f5c570bf3cb70a5e5ce814acab0146817d917 100644 (file)
@@ -4,10 +4,8 @@
 
 /// 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"]
index 1192b9e164a1450efb5ec71bf4bf59798f5649dd..4eb47dd1378c56562b4de07e84f29d924fc6e99a 100644 (file)
@@ -108,9 +108,10 @@ pub fn spin_loop() {
 /// 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
index 3bddc3772e60050177bb6594967b42647e903d88..adcc7350e6e5511d9420280cb150d5d330e878b4 100644 (file)
@@ -66,9 +66,7 @@
 #![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"]
index 6f16b93d0488aa6278a24591f6a5c952e828f86d..6a1a1e1976160077f340cf17664a8a8f4434cf85 100644 (file)
@@ -20,7 +20,6 @@
 #![macro_use]
 
 use crate::intrinsics;
-use crate::mem;
 
 /// Arithmetic operations required by bignums.
 pub trait FullOps: Sized {
@@ -58,25 +57,22 @@ fn full_mul(self, other: $ty, carry: $ty) -> ($ty, $ty) {
                     // 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)
                 }
@@ -128,13 +124,11 @@ pub fn from_small(v: $ty) -> $name {
 
             /// 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 }
@@ -150,9 +144,7 @@ pub fn digits(&self) -> &[$ty] {
             /// 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
@@ -166,8 +158,6 @@ pub fn is_zero(&self) -> bool {
             /// 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();
@@ -180,7 +170,7 @@ pub fn bit_length(&self) -> usize {
                 }
                 // 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;
@@ -265,9 +255,7 @@ pub fn mul_small(&mut self, other: $ty) -> &mut $name {
 
             /// 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;
 
@@ -393,13 +381,11 @@ pub fn div_rem_small(&mut self, other: $ty) -> (&mut $name, $ty) {
             /// 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;
                 }
@@ -462,10 +448,8 @@ fn clone(&self) -> Self {
 
         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() {
diff --git a/library/core/src/num/error.rs b/library/core/src/num/error.rs
new file mode 100644 (file)
index 0000000..aab1715
--- /dev/null
@@ -0,0 +1,151 @@
+//! 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)
+    }
+}
diff --git a/library/core/src/num/i128.rs b/library/core/src/num/i128.rs
deleted file mode 100644 (file)
index 08cb795..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-//! 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")] }
diff --git a/library/core/src/num/i16.rs b/library/core/src/num/i16.rs
deleted file mode 100644 (file)
index 288eace..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-//! 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 }
diff --git a/library/core/src/num/i32.rs b/library/core/src/num/i32.rs
deleted file mode 100644 (file)
index 0e1a2ec..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-//! 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 }
diff --git a/library/core/src/num/i64.rs b/library/core/src/num/i64.rs
deleted file mode 100644 (file)
index 27f7092..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-//! 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 }
diff --git a/library/core/src/num/i8.rs b/library/core/src/num/i8.rs
deleted file mode 100644 (file)
index e84b421..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-//! 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 }
index ffd30b03f2109c677692713e06c203351aa89b09..369175fb6ab1eca8a6cb51e9016249a882e76e80 100644 (file)
-#![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
+            }
         }
-    )
+    }
 }
diff --git a/library/core/src/num/isize.rs b/library/core/src/num/isize.rs
deleted file mode 100644 (file)
index 0dcfa4a..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-//! 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 }
index 050c187e55576b5009becf286bd3c3576b780322..4f64e30ccf84a0d43552651631b271eab3d3ff4e 100644 (file)
-// 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"]
@@ -5115,6 +760,16 @@ pub enum FpCategory {
     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")]
@@ -5128,58 +783,6 @@ fn from_str(src: &str) -> Result<Self, ParseIntError> {
 }
 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]
@@ -5272,111 +875,3 @@ fn from_str_radix<T: FromStrRadixHelper>(src: &str, radix: u32) -> Result<T, Par
     }
     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;
diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs
new file mode 100644 (file)
index 0000000..382f799
--- /dev/null
@@ -0,0 +1,190 @@
+//! 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 }
diff --git a/library/core/src/num/shells/i128.rs b/library/core/src/num/shells/i128.rs
new file mode 100644 (file)
index 0000000..08cb795
--- /dev/null
@@ -0,0 +1,10 @@
+//! 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")] }
diff --git a/library/core/src/num/shells/i16.rs b/library/core/src/num/shells/i16.rs
new file mode 100644 (file)
index 0000000..288eace
--- /dev/null
@@ -0,0 +1,10 @@
+//! 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 }
diff --git a/library/core/src/num/shells/i32.rs b/library/core/src/num/shells/i32.rs
new file mode 100644 (file)
index 0000000..0e1a2ec
--- /dev/null
@@ -0,0 +1,10 @@
+//! 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 }
diff --git a/library/core/src/num/shells/i64.rs b/library/core/src/num/shells/i64.rs
new file mode 100644 (file)
index 0000000..27f7092
--- /dev/null
@@ -0,0 +1,10 @@
+//! 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 }
diff --git a/library/core/src/num/shells/i8.rs b/library/core/src/num/shells/i8.rs
new file mode 100644 (file)
index 0000000..e84b421
--- /dev/null
@@ -0,0 +1,10 @@
+//! 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 }
diff --git a/library/core/src/num/shells/int_macros.rs b/library/core/src/num/shells/int_macros.rs
new file mode 100644 (file)
index 0000000..ffd30b0
--- /dev/null
@@ -0,0 +1,49 @@
+#![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;
+        }
+    )
+}
diff --git a/library/core/src/num/shells/isize.rs b/library/core/src/num/shells/isize.rs
new file mode 100644 (file)
index 0000000..0dcfa4a
--- /dev/null
@@ -0,0 +1,10 @@
+//! 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 }
diff --git a/library/core/src/num/shells/u128.rs b/library/core/src/num/shells/u128.rs
new file mode 100644 (file)
index 0000000..dd45ff1
--- /dev/null
@@ -0,0 +1,9 @@
+//! 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")] }
diff --git a/library/core/src/num/shells/u16.rs b/library/core/src/num/shells/u16.rs
new file mode 100644 (file)
index 0000000..7380716
--- /dev/null
@@ -0,0 +1,10 @@
+//! 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 }
diff --git a/library/core/src/num/shells/u32.rs b/library/core/src/num/shells/u32.rs
new file mode 100644 (file)
index 0000000..9800c90
--- /dev/null
@@ -0,0 +1,10 @@
+//! 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 }
diff --git a/library/core/src/num/shells/u64.rs b/library/core/src/num/shells/u64.rs
new file mode 100644 (file)
index 0000000..fb686c3
--- /dev/null
@@ -0,0 +1,10 @@
+//! 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 }
diff --git a/library/core/src/num/shells/u8.rs b/library/core/src/num/shells/u8.rs
new file mode 100644 (file)
index 0000000..c03cbdd
--- /dev/null
@@ -0,0 +1,10 @@
+//! 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 }
diff --git a/library/core/src/num/shells/usize.rs b/library/core/src/num/shells/usize.rs
new file mode 100644 (file)
index 0000000..a893041
--- /dev/null
@@ -0,0 +1,10 @@
+//! 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 }
diff --git a/library/core/src/num/u128.rs b/library/core/src/num/u128.rs
deleted file mode 100644 (file)
index dd45ff1..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-//! 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")] }
diff --git a/library/core/src/num/u16.rs b/library/core/src/num/u16.rs
deleted file mode 100644 (file)
index 7380716..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-//! 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 }
diff --git a/library/core/src/num/u32.rs b/library/core/src/num/u32.rs
deleted file mode 100644 (file)
index 9800c90..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-//! 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 }
diff --git a/library/core/src/num/u64.rs b/library/core/src/num/u64.rs
deleted file mode 100644 (file)
index fb686c3..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-//! 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 }
diff --git a/library/core/src/num/u8.rs b/library/core/src/num/u8.rs
deleted file mode 100644 (file)
index c03cbdd..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-//! 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 }
diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs
new file mode 100644 (file)
index 0000000..234c309
--- /dev/null
@@ -0,0 +1,1955 @@
+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 }
+        }
+    }
+}
diff --git a/library/core/src/num/usize.rs b/library/core/src/num/usize.rs
deleted file mode 100644 (file)
index a893041..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-//! 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 }
index f6acb8f8b9a9273f3865281c2c47d7cc02f018f6..5324dfdeddde281ce17470651429f5f01f47f644 100644 (file)
@@ -1,6 +1,83 @@
-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 {
index dd7556758be7d17347b7fbc880f591d7f8298100..7e560d63fe23b40245b66e001b6e958825600d0d 100644 (file)
@@ -1502,8 +1502,6 @@ unsafe impl<A> TrustedLen for IterMut<'_, A> {}
 /// 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> {
index 84fa34c75e3a2ed3219d3daea51151bc34a946e0..546edef7f5753536c8cc9d38b055679453cd0c8e 100644 (file)
@@ -8,7 +8,7 @@
 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;
 
@@ -62,11 +62,11 @@ fn size_from_ptr<T>(_: *const T) -> usize {
 /// [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")]
@@ -82,6 +82,23 @@ unsafe impl<T: Sync> Sync for Iter<'_, T> {}
 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
@@ -164,11 +181,11 @@ fn as_ref(&self) -> &[T] {
 /// [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")]
@@ -184,6 +201,38 @@ unsafe impl<T: Sync> Sync for IterMut<'_, T> {}
 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
@@ -277,9 +326,16 @@ pub struct Split<'a, T: 'a, P>
 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")]
@@ -385,9 +441,16 @@ pub struct SplitInclusive<'a, T: 'a, P>
 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")]
@@ -483,9 +546,16 @@ pub struct SplitMut<'a, T: 'a, P>
 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")]
@@ -598,9 +668,16 @@ pub struct SplitInclusiveMut<'a, T: 'a, P>
 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")]
@@ -706,7 +783,14 @@ pub struct RSplit<'a, T: 'a, P>
 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")]
@@ -777,7 +861,14 @@ pub struct RSplitMut<'a, T: 'a, P>
 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")]
@@ -840,9 +931,9 @@ impl<T, P> FusedIterator for RSplitMut<'_, T, P> where P: FnMut(&T) -> bool {}
 /// 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> {
@@ -882,7 +973,14 @@ pub struct SplitN<'a, T: 'a, P>
 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")]
@@ -908,7 +1006,14 @@ pub struct RSplitN<'a, T: 'a, P>
 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")]
@@ -933,7 +1038,14 @@ pub struct SplitNMut<'a, T: 'a, P>
 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")]
@@ -959,7 +1071,14 @@ pub struct RSplitNMut<'a, T: 'a, P>
 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")]
@@ -986,8 +1105,15 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 #[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)]`
@@ -1118,8 +1244,15 @@ fn may_have_side_effect() -> bool {
 #[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)]`
@@ -1272,8 +1405,15 @@ fn may_have_side_effect() -> bool {
 #[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")]
@@ -1425,12 +1565,21 @@ fn may_have_side_effect() -> bool {
 #[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.
@@ -1565,12 +1714,21 @@ fn may_have_side_effect() -> bool {
 #[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.
@@ -1697,9 +1855,17 @@ fn may_have_side_effect() -> bool {
 #[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")]
@@ -1802,11 +1968,22 @@ fn is_empty(&self) -> bool {
 #[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.
@@ -1909,11 +2086,23 @@ fn may_have_side_effect() -> bool {
 #[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.
@@ -2006,8 +2195,15 @@ fn may_have_side_effect() -> bool {
 #[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)]`
@@ -2156,8 +2352,15 @@ fn may_have_side_effect() -> bool {
 #[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")]
@@ -2306,12 +2509,20 @@ fn may_have_side_effect() -> bool {
 #[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.
@@ -2451,12 +2662,20 @@ fn may_have_side_effect() -> bool {
 #[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.
index 8e9d1eb98a86b08130ea21fc972cf63d719c8f73..ff926c517bc7cac0150cc1144ddab141ce9a6b3c 100644 (file)
@@ -9,13 +9,12 @@
 #![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};
 
@@ -35,8 +34,6 @@
 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")]
@@ -681,34 +678,7 @@ pub fn reverse(&mut self) {
     #[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.
@@ -725,34 +695,7 @@ pub fn iter(&self) -> Iter<'_, T> {
     #[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
@@ -785,7 +728,7 @@ pub fn iter_mut(&mut self) -> IterMut<'_, T> {
     #[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
@@ -819,7 +762,7 @@ pub fn windows(&self, size: usize) -> Windows<'_, T> {
     #[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
@@ -857,7 +800,7 @@ pub fn chunks(&self, chunk_size: usize) -> Chunks<'_, T> {
     #[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
@@ -894,11 +837,7 @@ pub fn chunks_mut(&mut self, chunk_size: usize) -> ChunksMut<'_, T> {
     #[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
@@ -940,11 +879,7 @@ pub fn chunks_exact(&self, chunk_size: usize) -> ChunksExact<'_, T> {
     #[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
@@ -978,12 +913,7 @@ pub fn chunks_exact_mut(&mut self, chunk_size: usize) -> ChunksExactMut<'_, T> {
     #[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
@@ -1019,14 +949,7 @@ pub fn array_chunks<const N: usize>(&self) -> ArrayChunks<'_, T, N> {
     #[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,
@@ -1034,7 +957,7 @@ pub fn array_chunks_mut<const N: usize>(&mut self) -> ArrayChunksMut<'_, T, N> {
     ///
     /// 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
     ///
@@ -1058,9 +981,7 @@ pub fn array_chunks_mut<const N: usize>(&mut self) -> ArrayChunksMut<'_, T, N> {
     #[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
@@ -1094,7 +1015,7 @@ pub fn array_windows<const N: usize>(&self) -> ArrayWindows<'_, T, N> {
     #[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
@@ -1132,7 +1053,7 @@ pub fn rchunks(&self, chunk_size: usize) -> RChunks<'_, T> {
     #[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
@@ -1171,10 +1092,7 @@ pub fn rchunks_mut(&mut self, chunk_size: usize) -> RChunksMut<'_, T> {
     #[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
@@ -1217,10 +1135,7 @@ pub fn rchunks_exact(&self, chunk_size: usize) -> RChunksExact<'_, T> {
     #[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.
@@ -1439,7 +1354,7 @@ pub fn split<F>(&self, pred: F) -> Split<'_, T, F>
     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
@@ -1461,7 +1376,7 @@ pub fn split_mut<F>(&mut self, pred: F) -> SplitMut<'_, T, F>
     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
@@ -1499,7 +1414,7 @@ pub fn split_inclusive<F>(&self, pred: F) -> SplitInclusive<'_, T, F>
     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
@@ -1524,7 +1439,7 @@ pub fn split_inclusive_mut<F>(&mut self, pred: F) -> SplitInclusiveMut<'_, T, F>
     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
@@ -1560,7 +1475,7 @@ pub fn rsplit<F>(&self, pred: F) -> RSplit<'_, T, F>
     where
         F: FnMut(&T) -> bool,
     {
-        RSplit { inner: self.split(pred) }
+        RSplit::new(self, pred)
     }
 
     /// Returns an iterator over mutable subslices separated by elements that
@@ -1586,7 +1501,7 @@ pub fn rsplit_mut<F>(&mut self, pred: F) -> RSplitMut<'_, T, F>
     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
@@ -1614,7 +1529,7 @@ pub fn splitn<F>(&self, n: usize, pred: F) -> SplitN<'_, T, F>
     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
@@ -1640,7 +1555,7 @@ pub fn splitn_mut<F>(&mut self, n: usize, pred: F) -> SplitNMut<'_, T, F>
     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
@@ -1669,7 +1584,7 @@ pub fn rsplitn<F>(&self, n: usize, pred: F) -> RSplitN<'_, T, F>
     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
@@ -1696,7 +1611,7 @@ pub fn rsplitn_mut<F>(&mut self, n: usize, pred: F) -> RSplitNMut<'_, T, F>
     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.
index 8c14651bd826cd4881f545a8d16d9446bf234037..71d2c2c9b2f4c2f3be43c3f9754ceec87f56c8dc 100644 (file)
@@ -565,7 +565,7 @@ fn break_patterns<T>(v: &mut [T]) {
             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
@@ -667,7 +667,7 @@ fn choose_pivot<T, F>(v: &mut [T], is_less: &mut F) -> (usize, bool)
 ///
 /// `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,
 {
@@ -763,7 +763,7 @@ pub fn quicksort<T, F>(v: &mut [T], mut is_less: F)
     }
 
     // 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);
 }
index ab9afeb25e0cec7d0e6191ac65c33c0361173113..6dc14f9125fefc11425b27ce09338b4f92579e66 100644 (file)
@@ -4,7 +4,7 @@
 //!
 //! For more details, see the [`std::str`] module.
 //!
-//! [`std::str`]: self
+//! [`std::str`]: ../../std/str/index.html
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
@@ -84,9 +84,6 @@ pub trait FromStr: Sized {
     /// 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`:
@@ -269,11 +266,9 @@ pub fn error_len(&self) -> Option<usize> {
 ///
 /// 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].
 ///
@@ -318,11 +313,9 @@ pub fn error_len(&self) -> Option<usize> {
 /// 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":
 ///
 /// ```
@@ -371,10 +364,8 @@ pub fn from_utf8(v: &[u8]) -> Result<&str, Utf8Error> {
 ///
 /// 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)?;
@@ -385,9 +376,7 @@ pub fn from_utf8_mut(v: &mut [u8]) -> Result<&mut str, Utf8Error> {
 /// 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
 ///
index 1cc2de5b8756a8bdc8cc06e2fd26374aa1c45f90..508c522e71aa25b7f9d60e6c90186dff41b7270c 100644 (file)
@@ -28,7 +28,7 @@
 //! 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",
index 92057209d8bfdf848ce9f0354ae6ad2ac1372dac..668a028a3f1ea948c0f110ea4c53a70a3a5840bf 100644 (file)
@@ -8,10 +8,8 @@
 ///
 /// [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 {
@@ -52,12 +50,10 @@ pub const fn new(data: *const (), vtable: &'static RawWakerVTable) -> 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 {
@@ -68,9 +64,6 @@ 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`].
@@ -79,9 +72,6 @@ pub struct RawWakerVTable {
     /// 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`].
@@ -89,9 +79,6 @@ pub struct RawWakerVTable {
     ///
     /// 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.
@@ -99,8 +86,6 @@ pub struct RawWakerVTable {
     /// 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 ()),
 }
 
@@ -142,9 +127,6 @@ impl RawWakerVTable {
     /// 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
@@ -208,8 +190,6 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 /// 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 {
@@ -275,9 +255,6 @@ pub fn will_wake(&self, other: &Waker) -> bool {
     /// 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 {
index 00e3972c42f9d41fe0e14eb356615e2c851f5fca..0eb9af3f454e986adb2eb73e2161a447eab939f8 100644 (file)
@@ -474,7 +474,7 @@ fn nth(&mut self, n: usize) -> Option<Self::Item> {
     }
 
     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);
index a5b1b51e06c64ebea26e19a3d3b54a486d7579ac..4db391f3e567eb69c962c40b7c53264320c5057e 100644 (file)
@@ -52,6 +52,7 @@
 #![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;
index 58a585669122ca3b7859cf19b9bef7525354d705..27e6760e7cbb9175e667dc50941b4828dec8ec0f 100644 (file)
@@ -2,7 +2,6 @@ macro_rules! int_module {
     ($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::*;
 
@@ -82,30 +81,27 @@ fn test_count_ones() {
 
             #[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);
index b84a8a7d9f88ba3aee84214cc61ac21f764e9a56..952ec188dc1385f9911e4665c237db2935feb2f4 100644 (file)
@@ -4,7 +4,6 @@ macro_rules! uint_module {
         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;
@@ -47,30 +46,27 @@ fn test_count_ones() {
 
             #[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);
index 3b08a64b22d85f89a562cd23a893a815a2019bf8..9690996e6021e6c9dd9b0182b6c4d7f66f48d8cc 100644 (file)
@@ -12,7 +12,6 @@
 #![panic_runtime]
 #![allow(unused_features)]
 #![feature(core_intrinsics)]
-#![feature(libc)]
 #![feature(nll)]
 #![feature(panic_runtime)]
 #![feature(staged_api)]
@@ -47,7 +46,7 @@ unsafe fn abort() -> ! {
                 }
                 __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
index 649bbce52a364ccc6a329816c2a2ca462562cb0c..652fbe95a14d195f39281a727d056b5f78aede60 100644 (file)
@@ -53,7 +53,7 @@ pub unsafe fn read_uleb128(&mut self) -> u64 {
     }
 
     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 {
@@ -65,7 +65,7 @@ pub unsafe fn read_sleb128(&mut self) -> i64 {
             }
         }
         // 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
index 85a2a18947db211345d438824dac13e254f7b2fc..1cfd527b5841aed3339bcc2534ca0663586ed5cc 100644 (file)
@@ -120,7 +120,7 @@ fn rust_exception_class() -> uw::_Unwind_Exception_Class {
 #[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:
index 6f31e6dcae70d7b40f406b2c863034ffbd77a8a2..682289384c8e241eff20e35637a1e4a922de4350 100644 (file)
@@ -18,8 +18,8 @@
     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)]
index 1a3a493fbb8f68dcff12a948f828669847bf99fb..61d71d55d6593c3e267a6cbda4018114d2e09425 100644 (file)
@@ -1298,9 +1298,7 @@ pub struct RawEntryBuilderMut<'a, K: 'a, V: 'a, S: 'a> {
 /// 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.
@@ -1705,8 +1703,6 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 
 /// 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>,
@@ -1721,8 +1717,6 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 
 /// 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>,
index 72f4798b65d66d665f27c1bb9af67636e09bb6b0..a0c39852ad5d8b69180064d9eccea1326db4216f 100644 (file)
@@ -1173,6 +1173,16 @@ fn sub(self, rhs: &HashSet<T, S>) -> HashSet<T, S> {
 /// 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>,
@@ -1184,6 +1194,16 @@ pub struct Iter<'a, K: 'a> {
 /// (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>,
@@ -1195,6 +1215,16 @@ pub struct 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>,
@@ -1205,6 +1235,18 @@ pub struct Drain<'a, K: 'a> {
 /// 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
@@ -1219,6 +1261,17 @@ pub struct DrainFilter<'a, K, F>
 /// 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
@@ -1233,6 +1286,17 @@ pub struct Intersection<'a, T: 'a, S: 'a> {
 /// 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
@@ -1247,6 +1311,17 @@ pub struct Difference<'a, T: 'a, S: 'a> {
 /// [`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>>,
@@ -1258,6 +1333,17 @@ pub struct SymmetricDifference<'a, T: 'a, S: 'a> {
 /// 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>>,
index 5333d75ec1bc5ac17aff7d32ccebc43b08b49a6c..0b74af53ab19d33e5c5dae2158356f87746286e1 100644 (file)
 #![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)]
index a007fd2b6be04c4b879756b7c9f4b49f2ade3f32..4ff3a6e578984cc0bb36da0d4f6e7b3c36648200 100644 (file)
@@ -234,7 +234,8 @@ pub struct stat {
     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};
index 83e8853fe79230a74ab94410c29251b7f83d32c4..16272aa05712f7bab6a717e74ea078d24f9061b3 100644 (file)
@@ -22,7 +22,8 @@
             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")),
@@ -65,7 +66,8 @@
             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")),
index d71e89d0eee682f7d7ab15d61eef35840d80fa34..b83c1e9628dc646f482366862ebbc4a4ebe86f4e 100644 (file)
@@ -58,6 +58,7 @@
 //! [`push`]: PathBuf::push
 
 #![stable(feature = "rust1", since = "1.0.0")]
+#![deny(unsafe_op_in_unsafe_fn)]
 
 #[cfg(test)]
 mod tests;
@@ -294,7 +295,8 @@ fn os_str_as_u8_slice(s: &OsStr) -> &[u8] {
     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
@@ -314,24 +316,21 @@ fn has_physical_root(s: &[u8], prefix: Option<Prefix<'_>>) -> bool {
 
 // 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))) }
     }
 }
 
@@ -1702,7 +1701,7 @@ impl Path {
     // 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] {
index c669410078592ca952035430ff178486b494cb34..f22476be325603039fcecd71728d7569acd545dc 100644 (file)
@@ -14,7 +14,8 @@
     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(
index 0c57861f70a82ca7eadd7c62c754ce07525717c0..dcf4fcd4e5aabeb6105b66c2d10c6ab8b35ec8b9 100644 (file)
@@ -54,7 +54,7 @@ pub enum _Unwind_Reason_Code {
 #[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")]
index 2a461170b5cce8d9ef8d397fef38bfa938117d3a..2b82f6c30b27364aa4f56ab0d44ffa0aad9d0428 100644 (file)
@@ -12,9 +12,6 @@
 
 use crate::Build;
 
-// The version number
-pub const CFG_RELEASE_NUM: &str = "1.48.0";
-
 pub struct GitInfo {
     inner: Option<Info>,
 }
index 7e2cb7721865e512034a64f6fc6725a62639e391..6de4388495bafd29e9f5cc7c268d292d3d7c3fcd 100644 (file)
@@ -617,7 +617,13 @@ pub fn parse(args: &[String]) -> Config {
                 | 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 { .. }
index cf73e570fa56f7e432a2f78b13bc80b3e6390600..c1ee8fb6b7f8170f31cfee70ab28e0ef6e38437b 100644 (file)
@@ -18,7 +18,6 @@
 
 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};
@@ -569,7 +568,7 @@ fn prepare_image(builder: &Builder<'_>, compiler: Compiler, image: &Path) {
                     &page_dst,
                     &[
                         ("<INSERT DATE HERE>", &month_year),
-                        ("<INSERT VERSION HERE>", channel::CFG_RELEASE_NUM),
+                        ("<INSERT VERSION HERE>", &builder.version),
                     ],
                 );
             }
@@ -793,6 +792,18 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
         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")
@@ -2289,9 +2300,9 @@ fn filter(contents: &str, marker: &str) -> String {
 }
 
 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())
index f90e76a4f4ea68f8a8ee331a125bc9c5c0f56f3c..97f32b61fb9c9a29277b9a9086caa8cdee42ebda 100644 (file)
@@ -433,7 +433,7 @@ fn run(self, builder: &Builder<'_>) {
                 .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"));
 
@@ -659,7 +659,7 @@ fn run(self, builder: &Builder<'_>) {
         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);
     }
index ff8468574469eefaa7deadb3fe19d79bd4be3aae..842c84a3e5cd6dcd82220e36c49133be5da00db2 100644 (file)
@@ -98,7 +98,6 @@ fn default() -> Subcommand {
 
 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>...]
@@ -170,16 +169,6 @@ pub fn parse(args: &[String]) -> Flags {
             "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
@@ -263,12 +252,38 @@ pub fn parse(args: &[String]) -> Flags {
             _ => {}
         };
 
+        // 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
@@ -436,24 +451,11 @@ pub fn parse(args: &[String]) -> Flags {
         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() {
@@ -483,7 +485,7 @@ pub fn parse(args: &[String]) -> Flags {
             "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") }
@@ -494,12 +496,12 @@ pub fn parse(args: &[String]) -> Flags {
             "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);
             }
         };
 
index 91b85f5af1d4bd39e64a4b3cb2bb2355cc236bb5..3f7aeae0ed4951f79c598960341b0ffc65bb4e48 100644 (file)
@@ -218,6 +218,9 @@ pub struct Build {
     /// User-specified configuration from `config.toml`.
     config: Config,
 
+    // Version information
+    version: String,
+
     // Properties derived from the above configuration
     src: PathBuf,
     out: PathBuf,
@@ -380,6 +383,10 @@ pub fn new(config: Config) -> Build {
             .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(),
@@ -395,6 +402,7 @@ pub fn new(config: Config) -> Build {
             targets: config.targets.clone(),
 
             config,
+            version: version.to_string(),
             src,
             out,
 
@@ -433,8 +441,7 @@ pub fn new(config: Config) -> Build {
             .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;
         }
@@ -785,7 +792,7 @@ fn debuginfo_map_to(&self, which: GitRepo) -> Option<String> {
 
         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")),
@@ -1016,7 +1023,7 @@ fn beta_prerelease_version(&self) -> u32 {
 
     /// 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
@@ -1036,7 +1043,7 @@ fn package_vers(&self, num: &str) -> String {
 
     /// 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
@@ -1070,7 +1077,7 @@ fn rustfmt_package_vers(&self) -> String {
     }
 
     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 {
@@ -1087,7 +1094,7 @@ fn llvm_link_tools_dynamically(&self, target: TargetSelection) -> bool {
     /// 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.
index 3829d47da335f005f0d46f5711bc68bcfc00776e..9e4d6d0023dc947e469c6bf442b99aabc4a005b0 100644 (file)
@@ -19,7 +19,6 @@
 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;
@@ -296,7 +295,7 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
             // 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);
         }
 
index ba5f75c49ac7769e2de63b3686afc88ec98ee89e..dc28b8ece2452597ab3bb30f6822241cff66b4f4 100644 (file)
@@ -636,7 +636,7 @@ fn run(self, builder: &Builder<'_>) {
                 .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")
index 99e33e3b006fe89a2d2d02f41875ca10d0a31030..5d66632d92ceb49e85af55b6e1ddff0bc582f1e4 100644 (file)
@@ -7,7 +7,6 @@
 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;
@@ -255,7 +254,7 @@ pub fn prepare_tool_cargo(
     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() {
index 2dcb55bb9731baaffd2732ea5a7d560d3d7666ad..05177e517d03db2ddbe6c4218c0c1a76cc65a9ef 100644 (file)
@@ -46,7 +46,7 @@ jobs:
 
       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
index f8d3bc8e8e5881be92e5346c6a682cfe260db10e..ea7e65a116836f1b395d04ce006ccf71bc5a29b9 100644 (file)
@@ -439,43 +439,7 @@ jobs:
           - 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
@@ -624,7 +588,7 @@ jobs:
               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
index f8987c6beca33966aa0e3594d10d905f22d21412..a12181be67dd3cc4cdf1457bdc4413e55607c267 100644 (file)
@@ -306,15 +306,17 @@ fn merge_attrs(
     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)
 }
 
index 318f9b0eec3a98ea9da9e05641fbe8098b86cee3..fcb9002986a1c1ab4a833fa4b5a63702afb9c076 100644 (file)
@@ -14,7 +14,7 @@
 
 // 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
@@ -43,7 +43,7 @@ pub fn inline_enum_const() -> E<i8, i16> {
 #[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)
 }
 
@@ -51,6 +51,6 @@ pub fn inline_enum_const() -> E<i8, i16> {
 #[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)
 }
index 763f85748736e315a3210f342874e1d09cf926bf..71e764620d1404d5d1db460791a62010a5457c67 100644 (file)
@@ -4,7 +4,7 @@
 
 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,
 }
 
index 1c700d44dd80b7be19a54f8032a2e6c8677becfa..25dc7cdf129d5037a494425510a107d5df21ed85 100644 (file)
@@ -11,7 +11,7 @@ impl Tr for str {
     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() {}
index a137d7fadba107948f1ea1d6e8729f533ca67f75..8b09eade067046e68feae5b216914b5c60b5576b 100644 (file)
@@ -24,42 +24,42 @@ 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
 }
index ef98cf9c091481d9b9a53474bff539a6db130005..2853a0ac18b0dcdbcb55b2d0b371da1f84510f4d 100644 (file)
@@ -24,46 +24,46 @@ fn main() -> () {
 }
 
 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
 }
index c4f10064890a7e5a77871927e38e1778dfd31ef5..710ffeeda075a8a966f7568aea01215c0be8a062 100644 (file)
@@ -24,41 +24,41 @@ fn main() -> () {
 }
 
 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
 }
index b16b85c4e95ac1486c00cbdfd78ae19700e0171e..97a7f76f6bb5dba64d29f4af51d100c7522a02ca 100644 (file)
@@ -24,44 +24,44 @@ fn main() -> () {
 }
 
 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
 }
index 99d3a278d69228422629c2d4723df63eb5bff112..19d6c51bc75f316f5e185b8194eacdeeca77f0a8 100644 (file)
@@ -24,10 +24,10 @@ fn main() -> () {
 }
 
 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 â”‚ ................
index d6e49892d4c6ad7d90a7db15a837bed49d7f290c..94388b08c0ec0bd9c51b7d8069ebc13727ef6f41 100644 (file)
@@ -24,10 +24,10 @@ fn main() -> () {
 }
 
 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 â”‚ â”€â”€â”€â•¼............
index f2838638aca0e3c936f8b532402bfc1a13e30946..1f3e559c1b7f47d2f4381324a3d0b5f3d7215c4a 100644 (file)
@@ -6,19 +6,14 @@
       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
       }
   }
index a4d60ae25d0c4078c5c68c88c66bd1f6d936872a..8aab2299d26510c3e5ec78b239700ca36a064cda 100644 (file)
@@ -6,15 +6,15 @@
       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
       }
   }
index b20003bd7c67ec7cdcae252d9c90e14617ceb717..1ea51fec7106992eb821598dba86d45913196c4f 100644 (file)
@@ -7,10 +7,10 @@
       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
       }
index d07a4c0541e1b191b00bccc066bcd0107cf82817..48ab37a239c62f105204133536f54659ef4ae088 100644 (file)
@@ -8,10 +8,10 @@
       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>)) }
@@ -19,8 +19,8 @@
   
       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
       }
diff --git a/src/test/mir-opt/dest-prop/branch.main.DestinationPropagation.diff b/src/test/mir-opt/dest-prop/branch.main.DestinationPropagation.diff
new file mode 100644 (file)
index 0000000..9c213ea
--- /dev/null
@@ -0,0 +1,73 @@
+- // 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
+      }
+  }
+  
diff --git a/src/test/mir-opt/dest-prop/branch.rs b/src/test/mir-opt/dest-prop/branch.rs
new file mode 100644 (file)
index 0000000..7e0e406
--- /dev/null
@@ -0,0 +1,21 @@
+//! 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
+    };
+}
diff --git a/src/test/mir-opt/dest-prop/cycle.main.DestinationPropagation.diff b/src/test/mir-opt/dest-prop/cycle.main.DestinationPropagation.diff
new file mode 100644 (file)
index 0000000..dd717c1
--- /dev/null
@@ -0,0 +1,76 @@
+- // 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
+      }
+  }
+  
diff --git a/src/test/mir-opt/dest-prop/cycle.rs b/src/test/mir-opt/dest-prop/cycle.rs
new file mode 100644 (file)
index 0000000..7fbffb1
--- /dev/null
@@ -0,0 +1,15 @@
+//! 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);
+}
diff --git a/src/test/mir-opt/dest-prop/simple.nrvo.DestinationPropagation.diff b/src/test/mir-opt/dest-prop/simple.nrvo.DestinationPropagation.diff
new file mode 100644 (file)
index 0000000..1277c51
--- /dev/null
@@ -0,0 +1,45 @@
+- // 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
+      }
+  }
+  
diff --git a/src/test/mir-opt/dest-prop/simple.rs b/src/test/mir-opt/dest-prop/simple.rs
new file mode 100644 (file)
index 0000000..4655f96
--- /dev/null
@@ -0,0 +1,14 @@
+//! 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;
+    });
+}
diff --git a/src/test/mir-opt/dest-prop/union.main.DestinationPropagation.diff b/src/test/mir-opt/dest-prop/union.main.DestinationPropagation.diff
new file mode 100644 (file)
index 0000000..871f6e3
--- /dev/null
@@ -0,0 +1,46 @@
+- // 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
+      }
+  }
+  
diff --git a/src/test/mir-opt/dest-prop/union.rs b/src/test/mir-opt/dest-prop/union.rs
new file mode 100644 (file)
index 0000000..b9d8313
--- /dev/null
@@ -0,0 +1,16 @@
+//! 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 });
+}
index d3f92d389f5b2f72eb445f7f32d54f9bec0684b9..bcc6042f2fb622b8caddad6ae18151a7aa6aa825 100644 (file)
@@ -1,7 +1,7 @@
 // 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
index 0258e3c2e4b380f8afaf4081272917bbe99eed83..ab194cf532ff3e074878fed6b6f7eb0fc920a7e8 100644 (file)
@@ -10,15 +10,14 @@ fn foo(_1: T, _2: i32) -> (i32, T) {
     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
         }
     }
 
@@ -38,17 +37,14 @@ fn foo(_1: T, _2: i32) -> (i32, T) {
         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
index f86755cfa7f70a34bdc046832707c28ef24d11c7..a8662b96566cc7db862c617b77fdc58de78b31f1 100644 (file)
@@ -3,66 +3,59 @@
   
   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>)) }
index f86755cfa7f70a34bdc046832707c28ef24d11c7..a8662b96566cc7db862c617b77fdc58de78b31f1 100644 (file)
@@ -3,66 +3,59 @@
   
   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>)) }
diff --git a/src/test/mir-opt/issues/issue-75439.rs b/src/test/mir-opt/issues/issue-75439.rs
new file mode 100644 (file)
index 0000000..44d6bc6
--- /dev/null
@@ -0,0 +1,21 @@
+// 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]);
+}
diff --git a/src/test/mir-opt/issues/issue_75439.foo.MatchBranchSimplification.diff b/src/test/mir-opt/issues/issue_75439.foo.MatchBranchSimplification.diff
new file mode 100644 (file)
index 0000000..43422b3
--- /dev/null
@@ -0,0 +1,87 @@
+- // 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
+      }
+  }
+  
index f0eb711b3f0a77c598468023c0ac8dd64612efd8..ab46d7b94c72c09872aec2d17d961ae5f1cc4d97 100644 (file)
@@ -1,3 +1,5 @@
+// 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];
index 924e87ea8c0add79d6e1f8b22c0857405fa43857..f438eaa002780958f07d88a70f123bd229129de0 100644 (file)
@@ -2,39 +2,42 @@
 + // 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
       }
   }
   
diff --git a/src/test/mir-opt/rustc.try_identity.DestinationPropagation.diff b/src/test/mir-opt/rustc.try_identity.DestinationPropagation.diff
new file mode 100644 (file)
index 0000000..c3e503b
--- /dev/null
@@ -0,0 +1,72 @@
+- // 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
+      }
+  }
+  
index fa127de13dfd930778a1548160203911198c05e9..fca80bee89679df7dbdcbf074baf1796bfc21596 100644 (file)
@@ -1,6 +1,7 @@
 // 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?;
diff --git a/src/test/mir-opt/simplify_try.try_identity.DestinationPropagation.diff b/src/test/mir-opt/simplify_try.try_identity.DestinationPropagation.diff
new file mode 100644 (file)
index 0000000..187a3cf
--- /dev/null
@@ -0,0 +1,72 @@
+- // 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
+      }
+  }
+  
index 26ce290b5496a1c1dd76a4de020090d1d6ac0bed..0c687684c508ea25d83005607844dbc25820a519 100644 (file)
@@ -2,25 +2,25 @@
 + // 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
       }
   }
   
index dc4aae176f2c4714546d5170d5f6879118bd0684..9428d305c87319547ed2864aae42ac4279b0b73e 100644 (file)
@@ -1,35 +1,35 @@
 // 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 {
         }
     }
@@ -38,24 +38,24 @@ fn try_identity(_1: std::result::Result<u32, i32>) -> std::result::Result<u32, i
     }
 
     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
     }
 }
index d65a2b12c0fd38f61568b6bdc96bb56e733d4b33..a25472f6a5e05c96224b9b5ac5b7bb9b9e446e37 100644 (file)
@@ -1,13 +1,13 @@
 // 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
@@ -18,16 +18,16 @@ fn try_identity(_1: std::result::Result<u32, i32>) -> std::result::Result<u32, i
         }
     }
     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
     }
 }
index e6075f745776a5a6d663995af4ed8fbbc8ca9bbb..616ac9053fd539af2e3bdde5b3be319843a37a74 100644 (file)
@@ -1,38 +1,38 @@
 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() {
index 1b4326ea56aaaaa7baea21921be6166fcce37b9a..d9bb7386565fa83612499055fd0da8b1da85f88f 100644 (file)
@@ -1,31 +1,31 @@
-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;
@@ -36,7 +36,7 @@ note: ...which requires optimizing MIR for `<impl at $DIR/issue-24949-assoc-cons
 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
index 8efa56a9a2e63133c6fe770db3753a5e70e89dd5..d000d8ac097a486f99b580bfaff03ab7e7eeb0b2 100644 (file)
@@ -1,31 +1,31 @@
-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;
@@ -36,7 +36,7 @@ note: ...which requires optimizing MIR for `FooDefault::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
index 78ce1a28a3fdcfb1c8f0a6dd641b9d13aa9153ae..62d2051b6c23aab13a3bb8bc697f136ebf86768f 100644 (file)
@@ -1,31 +1,31 @@
-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;
@@ -36,7 +36,7 @@ note: ...which requires optimizing MIR for `<impl at $DIR/issue-24949-assoc-cons
 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
diff --git a/src/test/ui/closures/issue-72408-nested-closures-exponential.rs b/src/test/ui/closures/issue-72408-nested-closures-exponential.rs
new file mode 100644 (file)
index 0000000..2d6ba93
--- /dev/null
@@ -0,0 +1,59 @@
+// 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));
+}
diff --git a/src/test/ui/const-generics/const_evaluatable_checked/auxiliary/const_evaluatable_lib.rs b/src/test/ui/const-generics/const_evaluatable_checked/auxiliary/const_evaluatable_lib.rs
new file mode 100644 (file)
index 0000000..9745dfe
--- /dev/null
@@ -0,0 +1,9 @@
+#![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]
+}
diff --git a/src/test/ui/const-generics/const_evaluatable_checked/cross_crate.rs b/src/test/ui/const-generics/const_evaluatable_checked/cross_crate.rs
new file mode 100644 (file)
index 0000000..53b2378
--- /dev/null
@@ -0,0 +1,15 @@
+// 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>();
+}
diff --git a/src/test/ui/const-generics/const_evaluatable_checked/cross_crate_predicate.rs b/src/test/ui/const-generics/const_evaluatable_checked/cross_crate_predicate.rs
new file mode 100644 (file)
index 0000000..2236992
--- /dev/null
@@ -0,0 +1,13 @@
+// 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() {}
diff --git a/src/test/ui/const-generics/const_evaluatable_checked/cross_crate_predicate.stderr b/src/test/ui/const-generics/const_evaluatable_checked/cross_crate_predicate.stderr
new file mode 100644 (file)
index 0000000..63abb78
--- /dev/null
@@ -0,0 +1,36 @@
+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
+
diff --git a/src/test/ui/const-generics/const_evaluatable_checked/fn_call.rs b/src/test/ui/const-generics/const_evaluatable_checked/fn_call.rs
new file mode 100644 (file)
index 0000000..1b9ec01
--- /dev/null
@@ -0,0 +1,30 @@
+// 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>());
+}
diff --git a/src/test/ui/const-generics/const_evaluatable_checked/less_than.rs b/src/test/ui/const-generics/const_evaluatable_checked/less_than.rs
new file mode 100644 (file)
index 0000000..907ea25
--- /dev/null
@@ -0,0 +1,14 @@
+// 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>();
+}
diff --git a/src/test/ui/const-generics/const_evaluatable_checked/let-bindings.rs b/src/test/ui/const-generics/const_evaluatable_checked/let-bindings.rs
new file mode 100644 (file)
index 0000000..d96788f
--- /dev/null
@@ -0,0 +1,15 @@
+#![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]);
+}
diff --git a/src/test/ui/const-generics/const_evaluatable_checked/let-bindings.stderr b/src/test/ui/const-generics/const_evaluatable_checked/let-bindings.stderr
new file mode 100644 (file)
index 0000000..95fb48b
--- /dev/null
@@ -0,0 +1,18 @@
+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
+
index da8ccdaee414661f554d939f2b7b8f895476a35b..3cac604a7b33a0d1e1b419c2ba87139c29884344 100644 (file)
@@ -1,10 +1,18 @@
 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
 
index 27dc6b103200dc696517156b828103735d1bca33..dcf0071cb29b6eb5898367e390d3200939075243 100644 (file)
@@ -5,10 +5,9 @@
 #![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()
 }
 
diff --git a/src/test/ui/const-generics/const_evaluatable_checked/unop.rs b/src/test/ui/const-generics/const_evaluatable_checked/unop.rs
new file mode 100644 (file)
index 0000000..8e0768b
--- /dev/null
@@ -0,0 +1,14 @@
+// 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>();
+}
index a77258120111e70d668e6e87694f83a1a0dbfe88..9c02d232e134b1a9ea5afeff0fd2f526b5f32c36 100644 (file)
@@ -1,5 +1,7 @@
 // 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 {
@@ -12,9 +14,6 @@ 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);
@@ -31,11 +30,11 @@ fn main() {
     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);
 
index dc2661ee796856816b8865c3361dccf17717a507..8c57fd37e88f68c449f151b60f745020d6fe202b 100644 (file)
@@ -9,9 +9,9 @@ LL |     let x: &'static i32 = &(1 / 0);
    = 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
index d24491e1bc5cbf70e8dc1f61e3fbc3b2babde5be..fb0ed1bd5aa9486399254414edcf246b56adc60a 100644 (file)
@@ -36,7 +36,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $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.
 
@@ -76,7 +76,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $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.
 
@@ -100,7 +100,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $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.
 
@@ -148,7 +148,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $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.
 
@@ -188,7 +188,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $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.
 
@@ -212,7 +212,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $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.
 
index 8402d628856648f0d9ec022fc9a50a77e17e14cb..81f5dde450b478505413359ee05e6c66b877989c 100644 (file)
@@ -1,3 +1,9 @@
+// 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,
@@ -13,11 +19,14 @@ union Union {
     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() {}
diff --git a/src/test/ui/consts/const-eval/double_check2.stderr b/src/test/ui/consts/const-eval/double_check2.stderr
deleted file mode 100644 (file)
index 84f6080..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-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`.
index 7b3ee535c8ec67c3414f8916fcde616345106ccd..db95b996c18c9981921a2169443d2e1660074f53 100644 (file)
@@ -18,7 +18,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $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.
 
@@ -34,7 +34,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $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.
 
@@ -42,7 +42,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $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.
 
@@ -58,7 +58,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $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.
 
index 38e9bdecdb9d2b8245a5f840f4618dc1fbfaf1f3..afd8a4b9e59efbd414cd9e8ceca253254e4bd317 100644 (file)
@@ -13,7 +13,7 @@ LL | / const OUT_OF_BOUNDS_PTR: NonNull<u8> = { unsafe {
 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 | | } };
    | |____-
index cd270f2a533bf8e5e1e88ef06b69b3440d1b46cf..429ae69eabfdb0931c93acf885d3ed7e50da310c 100644 (file)
@@ -34,7 +34,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $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.
 
index f4bff31c995599eb76f5c8ae71652a114fbd4e1d..58d5e9ac58c2eab811a6bbd90df93994890a3ee1 100644 (file)
@@ -1,32 +1,32 @@
-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
    |
index 1ad5134e71c522d2e801a7fd5aead1905ab607cb..d016d236dbf81a5e24127f33099d13585c1078cf 100644 (file)
@@ -1,14 +1,10 @@
 // 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),
@@ -31,10 +27,10 @@ enum SingleVariant {
 
 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)));
 }
diff --git a/src/test/ui/consts/promote-no-mut.rs b/src/test/ui/consts/promote-no-mut.rs
deleted file mode 100644 (file)
index fb57c8b..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-// 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() {}
diff --git a/src/test/ui/consts/promote-no-mut.stderr b/src/test/ui/consts/promote-no-mut.stderr
deleted file mode 100644 (file)
index 49d9654..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-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`.
diff --git a/src/test/ui/consts/promote-not.rs b/src/test/ui/consts/promote-not.rs
new file mode 100644 (file)
index 0000000..8daac75
--- /dev/null
@@ -0,0 +1,30 @@
+// 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() {}
diff --git a/src/test/ui/consts/promote-not.stderr b/src/test/ui/consts/promote-not.stderr
new file mode 100644 (file)
index 0000000..efe921b
--- /dev/null
@@ -0,0 +1,43 @@
+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`.
index 3c5401e4212164541d75d36a29ccef7b97c06b9f..5f84030a9e96b4d0f68afaca43b23b5bd353dca2 100644 (file)
@@ -1,4 +1,4 @@
-// run-pass
+// check-pass
 
 // compile-flags: -O
 
index 9042c6f6be1912c0d85a60db229eddbff965230f..03f8f5c5a0e5da7e5c6e37538fbf02d3b707e045 100644 (file)
@@ -1,20 +1,16 @@
-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
 
index 29a467c006a492d6f16e3676672ce2452795ddbc..4e61634b349e0596baee98a5dc41e3f412d060b7 100644 (file)
@@ -7,7 +7,7 @@
 // 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
index 9042c6f6be1912c0d85a60db229eddbff965230f..03f8f5c5a0e5da7e5c6e37538fbf02d3b707e045 100644 (file)
@@ -1,20 +1,16 @@
-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
 
diff --git a/src/test/ui/dest-prop/skeptic-miscompile.rs b/src/test/ui/dest-prop/skeptic-miscompile.rs
new file mode 100644 (file)
index 0000000..c27a1f0
--- /dev/null
@@ -0,0 +1,24 @@
+// 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());
+}
index 1aaefea9f042c479952d759451c783169f7634c3..d27d14842ce99f1f61c6cdc35a6f515722c9d3a3 100644 (file)
@@ -1,4 +1,4 @@
-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());
index 8289a3db6fc5b6ee56c940318a25bc2a859f3be1..34580407926f18cf12d650e378efd406b903b2d1 100644 (file)
@@ -1,7 +1,12 @@
 //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() {}
index de0c579f6308990f401fd99c5c1180267c993814..3c106895305dcc41f0ad28962979eed1fa33e4da 100644 (file)
@@ -1,17 +1,17 @@
-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];
    |                  ^^^
index ee621a8cb147309deb514880bb1cf5e3eb806b14..0a27848b801c9539bf859faf79b9751a5d3e7911 100644 (file)
@@ -1,22 +1,22 @@
 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
index 72c16fddb4b12a6e052ab51922b62fa3f4da526b..89137538425bfbdb948e30b78ccc7572e366aee5 100644 (file)
@@ -51,9 +51,9 @@ pub fn matches<F: Fn()>(&self, f: &F) {
 
 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
     }
 }
 
index b0df46b11fadb30b787b6fe4d4f5f052300ed6c2..c4255b95b704e4016bc4dc93f6a4e3356e82077a 100644 (file)
@@ -1,10 +1,14 @@
-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
 
index b6c85b9e22749c9053cb5000a4d34efcc0744174..45372c7f53bd4811dca45cc4fe2bb96b0e9d050d 100644 (file)
@@ -1,21 +1,21 @@
-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
    |
index d014922fe2069a5c5838c8e7f5578fdaab635d39..33bc1f6c48d5e5096549e4bb9ed857432ce2ac55 100644 (file)
@@ -1,21 +1,21 @@
-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
    |
index b30b1214271a06354e0900c238c621e744a244c0..5233b832ecc796f1bf351011b9e376e400d521f0 100644 (file)
@@ -1,37 +1,37 @@
-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
index 7c2da9dce6e9da41cc45a1809c0d2efa07257910..3fd1f4b59beca79db78673b9c9ee1ecda4e0ad0b 100644 (file)
@@ -1,37 +1,37 @@
-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
    |
index fec4b17153609a847be596236c73388b5ed108bf..d3d5863ddb3c9b6d1c757b7bb4f64c12889f7451 100644 (file)
@@ -12,8 +12,8 @@ trait Foo {
 
 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
     }
 }
 
index 6229d90d4b477112990c56b6c480c44c029720a7..a94f190d6b25d2f566c5ec45b37ceba07946b5d4 100644 (file)
@@ -1,10 +1,14 @@
-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
 
index 8243e52039d489233b0d61fd2c1d5212426bb5a7..f3e73399b57ce7445ca61bdfca2f7f52239e4874 100644 (file)
@@ -1,4 +1,4 @@
-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))
index bc327123c6fe92192500064c74effcc3aa7bcc67..d9790d2b56e2895fed4a1ec169ed63fd8bfa07f1 100644 (file)
@@ -2,13 +2,18 @@
 #![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
         _ => {}
     }
 }
index a5544d9e9da405be0f4b6af4a3851bb41e773834..bdcd2fe1adc5a727636cea40fc055b4a0687ad3d 100644 (file)
@@ -1,5 +1,5 @@
 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
@@ -14,8 +14,30 @@ LL |         RANGE => {}
    |
    = 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`.
index dd57e69f2cff0c10de7f908df812df90f675cdb3..279e3ffbb4a41772ea53b7171172aa490fa3666a 100644 (file)
@@ -9,7 +9,7 @@ LL |     generic::<Option<T>>();
    = 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>>();
index 536e26d29556946c662e0b82836082bb723a703d..4d77b3d295c00bc203843fe98a6ecf64d669367b 100644 (file)
@@ -1,4 +1,4 @@
-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) {
index db4c99eeb8b167c4691da008cfa8290a9650d70c..085bf82ef8b9351773b4bafd488a96476dcfb256 100644 (file)
@@ -1,4 +1,4 @@
-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})}
index e816ce4e0c45261b562c7473ec99438dab05f8fb..f59ef7316d8905d4aaf1bc0287a45dd47929d12b 100644 (file)
@@ -1,4 +1,4 @@
 pub static FOO: u32 = FOO;
-//~^ ERROR cycle detected when const-evaluating `FOO`
+//~^ ERROR cycle detected when const-evaluating + checking `FOO`
 
 fn main() {}
index 093606e100cb3fa300003ba5799a603837ea05f9..ee73b026a0b75b14d9a2356b2df2e3ac34cf7d30 100644 (file)
@@ -1,20 +1,16 @@
-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
 
index bd8910bdb3f3f9af69c5b60cc87b023f28f53561..b9eff469177e6e62acc0a2c98cfc7c270b850c42 100644 (file)
@@ -1,4 +1,4 @@
-// check-pass
+// run-pass
 
 // Use of global static variables in literal values should be allowed for
 // promotion.
index 63b21faa62bd2ce0486cad546d4299ec5a6f6a88..8dadd77fc16d5d4bbd1bf7dcbd91306749132d62 100644 (file)
@@ -1,8 +1,8 @@
 #[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() {}
index db535b53fcf3743aa727baca240afca29f822e5d..fbe6279ca92267a076c6bc2b82284957d99b2a35 100644 (file)
@@ -1,28 +1,28 @@
-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() {}
index 1f1c8ad96269051104cd1acb50b832aaa4aa1b1a..921cded5037b67c3dcec87b9e8ababb67014e488 100644 (file)
@@ -4,7 +4,7 @@
 // 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) => {
index f12f259d2f6e25d8e93ce3a969c30e791be0b866..cf3d64d734ba0de7c28f986d1f75e1087e45dd4c 100644 (file)
@@ -1,10 +1,10 @@
-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
 
index 50dfce3448c341e7caee2515d367803ced13bdbd..789919bd1668d2949ddf245708434ceebc20ecaa 100644 (file)
@@ -4,23 +4,19 @@ error[E0080]: could not evaluate static initializer
 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
 
index ff9ee67763ba5dbb3f701414b029fca828163127..125f2d1f76cce75649fd990d02bf3d24a38d3e75 100644 (file)
     "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",
diff --git a/src/version b/src/version
new file mode 100644 (file)
index 0000000..9db5ea1
--- /dev/null
@@ -0,0 +1 @@
+1.48.0