]> git.lizzy.rs Git - rust.git/commitdiff
Rollup merge of #76728 - jyn514:rustdoc-extern-crate, r=ehuss
authorTyler Mandry <tmandry@gmail.com>
Wed, 16 Sep 2020 19:24:10 +0000 (12:24 -0700)
committerGitHub <noreply@github.com>
Wed, 16 Sep 2020 19:24:10 +0000 (12:24 -0700)
Add a comment why `extern crate` is necessary for rustdoc

r? @ehuss

From https://github.com/rust-lang/rust/pull/74293#discussion_r488335500.

253 files changed:
.github/workflows/ci.yml
.mailmap
Cargo.lock
Cargo.toml
compiler/rustc_ast/src/util/lev_distance.rs
compiler/rustc_ast_lowering/src/expr.rs
compiler/rustc_ast_passes/src/feature_gate.rs
compiler/rustc_expand/src/proc_macro_server.rs
compiler/rustc_feature/src/accepted.rs
compiler/rustc_feature/src/active.rs
compiler/rustc_hir/src/def.rs
compiler/rustc_infer/src/infer/error_reporting/mod.rs
compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
compiler/rustc_lint/src/array_into_iter.rs
compiler/rustc_lint/src/builtin.rs
compiler/rustc_lint/src/non_ascii_idents.rs
compiler/rustc_lint/src/nonstandard_style.rs
compiler/rustc_lint/src/redundant_semicolon.rs
compiler/rustc_lint/src/types.rs
compiler/rustc_lint/src/unused.rs
compiler/rustc_metadata/Cargo.toml
compiler/rustc_metadata/src/rmeta/encoder.rs
compiler/rustc_middle/src/infer/unify_key.rs
compiler/rustc_middle/src/mir/mod.rs
compiler/rustc_middle/src/traits/mod.rs
compiler/rustc_middle/src/ty/adjustment.rs
compiler/rustc_middle/src/ty/context.rs
compiler/rustc_middle/src/ty/diagnostics.rs
compiler/rustc_middle/src/ty/structural_impls.rs
compiler/rustc_middle/src/ty/sty.rs
compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs
compiler/rustc_mir/src/borrow_check/diagnostics/explain_borrow.rs
compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs
compiler/rustc_mir/src/borrow_check/diagnostics/move_errors.rs
compiler/rustc_mir/src/borrow_check/mod.rs
compiler/rustc_mir/src/monomorphize/partitioning/default.rs
compiler/rustc_mir/src/monomorphize/partitioning/merging.rs
compiler/rustc_mir/src/monomorphize/partitioning/mod.rs
compiler/rustc_mir/src/transform/check_const_item_mutation.rs
compiler/rustc_mir/src/transform/inline.rs
compiler/rustc_mir/src/transform/simplify_try.rs
compiler/rustc_mir/src/util/find_self_call.rs
compiler/rustc_mir_build/src/thir/cx/expr.rs
compiler/rustc_parse/src/parser/diagnostics.rs
compiler/rustc_parse/src/parser/stmt.rs
compiler/rustc_parse/src/parser/ty.rs
compiler/rustc_passes/src/dead.rs
compiler/rustc_resolve/src/diagnostics.rs
compiler/rustc_resolve/src/late.rs
compiler/rustc_resolve/src/lib.rs
compiler/rustc_session/src/lint.rs
compiler/rustc_session/src/lint/builtin.rs
compiler/rustc_span/src/lib.rs
compiler/rustc_span/src/symbol.rs
compiler/rustc_target/src/spec/mod.rs
compiler/rustc_target/src/spec/riscv32gc_unknown_linux_gnu.rs [new file with mode: 0644]
compiler/rustc_trait_selection/src/autoderef.rs
compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
compiler/rustc_traits/src/chalk/db.rs
compiler/rustc_typeck/src/astconv/mod.rs
compiler/rustc_typeck/src/check/_match.rs
compiler/rustc_typeck/src/check/autoderef.rs
compiler/rustc_typeck/src/check/coercion.rs
compiler/rustc_typeck/src/check/method/confirm.rs
compiler/rustc_typeck/src/check/method/probe.rs
compiler/rustc_typeck/src/check/mod.rs
compiler/rustc_typeck/src/check/pat.rs
compiler/rustc_typeck/src/check/place_op.rs
config.toml.example
library/alloc/src/collections/binary_heap.rs
library/alloc/src/collections/btree/node.rs
library/alloc/src/collections/vec_deque.rs
library/alloc/src/lib.rs
library/alloc/src/slice.rs
library/alloc/src/string.rs
library/alloc/src/vec.rs
library/alloc/tests/lib.rs
library/alloc/tests/str.rs
library/alloc/tests/string.rs
library/alloc/tests/vec.rs
library/alloc/tests/vec_deque.rs
library/core/src/cmp.rs
library/core/src/hint.rs
library/core/src/iter/adapters/chain.rs
library/core/src/iter/adapters/flatten.rs
library/core/src/iter/adapters/zip.rs
library/core/src/lib.rs
library/core/src/mem/maybe_uninit.rs
library/core/src/mem/mod.rs
library/core/src/num/dec2flt/algorithm.rs
library/core/src/ops/deref.rs
library/core/src/slice/ascii.rs [new file with mode: 0644]
library/core/src/slice/cmp.rs [new file with mode: 0644]
library/core/src/slice/index.rs [new file with mode: 0644]
library/core/src/slice/iter.rs [new file with mode: 0644]
library/core/src/slice/iter/macros.rs [new file with mode: 0644]
library/core/src/slice/mod.rs
library/core/src/slice/raw.rs [new file with mode: 0644]
library/core/src/slice/sort.rs
library/core/src/sync/atomic.rs
library/core/src/task/poll.rs
library/core/src/time.rs
library/core/tests/cmp.rs
library/core/tests/lib.rs
library/core/tests/num/i32.rs
library/core/tests/slice.rs
library/core/tests/time.rs
library/std/src/lazy.rs
library/std/src/lib.rs
library/std/src/process.rs
library/std/src/sync/once.rs
library/std/src/sys/sgx/fs.rs [deleted file]
library/std/src/sys/sgx/io.rs [deleted file]
library/std/src/sys/sgx/mod.rs
library/std/src/sys/sgx/pipe.rs [deleted file]
library/std/src/sys/sgx/process.rs [deleted file]
library/std/src/sys/sgx/rwlock/tests.rs
library/std/src/sys/unix/alloc.rs
library/std/src/sys/unix/ext/fs.rs
library/std/src/sys/unix/ext/mod.rs
library/std/src/sys/unix/ext/net.rs
library/std/src/sys/unix/ext/ucred.rs [new file with mode: 0644]
library/std/src/sys/unix/ext/ucred/tests.rs [new file with mode: 0644]
library/std/src/sys/unsupported/fs.rs
library/std/src/sys/unsupported/mod.rs
library/std/src/sys/unsupported/path.rs [deleted file]
library/std/src/sys/unsupported/process.rs
library/std/src/sys/vxworks/ext/fs.rs
library/std/src/sys/wasi/alloc.rs [deleted file]
library/std/src/sys/wasi/mod.rs
library/std/src/sys/wasi/path.rs [deleted file]
library/std/src/sys/wasi/pipe.rs [deleted file]
library/std/src/sys/wasi/process.rs [deleted file]
library/std/src/sys/wasm/mod.rs
library/std/src/thread/local.rs
library/stdarch
src/bootstrap/README.md
src/bootstrap/bootstrap.py
src/bootstrap/builder.rs
src/bootstrap/builder/tests.rs
src/bootstrap/config.rs
src/bootstrap/doc.rs
src/bootstrap/native.rs
src/bootstrap/test.rs
src/bootstrap/tool.rs
src/ci/docker/host-x86_64/dist-x86_64-linux/build-git.sh [deleted file]
src/ci/docker/host-x86_64/dist-x86_64-linux/build-headers.sh [deleted file]
src/ci/docker/host-x86_64/dist-x86_64-linux/build-perl.sh [deleted file]
src/ci/github-actions/ci.yml
src/ci/run.sh
src/doc/rustc/src/lints/groups.md
src/doc/rustc/src/lints/index.md
src/doc/rustc/src/lints/listing/allowed-by-default.md
src/doc/rustc/src/lints/listing/deny-by-default.md
src/doc/rustc/src/lints/listing/warn-by-default.md
src/doc/rustc/src/platform-support.md
src/doc/rustdoc/src/advanced-features.md
src/doc/rustdoc/src/lints.md
src/doc/rustdoc/src/unstable-features.md
src/doc/unstable-book/src/language-features/doc-alias.md [deleted file]
src/doc/unstable-book/src/library-features/asm.md
src/doc/unstable-book/src/library-features/llvm-asm.md
src/librustdoc/Cargo.toml
src/librustdoc/clean/inline.rs
src/librustdoc/clean/mod.rs
src/librustdoc/clean/utils.rs
src/librustdoc/html/markdown.rs
src/librustdoc/passes/collect_intra_doc_links.rs
src/librustdoc/passes/doc_test_lints.rs
src/test/codegen/issue-73396-bounds-check-after-position.rs [new file with mode: 0644]
src/test/mir-opt/inline/inline_any_operand.bar.Inline.after.mir
src/test/mir-opt/inline/inline_closure.foo.Inline.after.mir
src/test/mir-opt/inline/inline_closure_borrows_arg.foo.Inline.after.mir
src/test/mir-opt/inline/inline_closure_captures.foo.Inline.after.mir
src/test/rustdoc-ui/coverage/doc-examples.stdout
src/test/rustdoc-ui/intra-link-double-anchor.rs [new file with mode: 0644]
src/test/rustdoc-ui/intra-link-double-anchor.stderr [new file with mode: 0644]
src/test/rustdoc-ui/private-doc-test.rs [new file with mode: 0644]
src/test/rustdoc/auxiliary/real_gimli.rs [new file with mode: 0644]
src/test/rustdoc/auxiliary/realcore.rs [new file with mode: 0644]
src/test/rustdoc/issue-75588.rs [new file with mode: 0644]
src/test/ui/const-generics/cannot-infer-const-args.full.stderr [deleted file]
src/test/ui/const-generics/cannot-infer-const-args.min.stderr [deleted file]
src/test/ui/const-generics/cannot-infer-const-args.rs [deleted file]
src/test/ui/const-generics/infer/cannot-infer-const-args.full.stderr [new file with mode: 0644]
src/test/ui/const-generics/infer/cannot-infer-const-args.min.stderr [new file with mode: 0644]
src/test/ui/const-generics/infer/cannot-infer-const-args.rs [new file with mode: 0644]
src/test/ui/const-generics/infer/method-chain.full.stderr [new file with mode: 0644]
src/test/ui/const-generics/infer/method-chain.min.stderr [new file with mode: 0644]
src/test/ui/const-generics/infer/method-chain.rs [new file with mode: 0644]
src/test/ui/const-generics/infer/uninferred-consts.full.stderr [new file with mode: 0644]
src/test/ui/const-generics/infer/uninferred-consts.min.stderr [new file with mode: 0644]
src/test/ui/const-generics/infer/uninferred-consts.rs [new file with mode: 0644]
src/test/ui/const-generics/issues/issue-62504.min.stderr
src/test/ui/const-generics/issues/issue-62504.rs
src/test/ui/const-generics/issues/issue-64494.min.stderr
src/test/ui/const-generics/issues/issue-67739.min.stderr
src/test/ui/const-generics/issues/issue-76701-ty-param-in-const.full.stderr [new file with mode: 0644]
src/test/ui/const-generics/issues/issue-76701-ty-param-in-const.min.stderr [new file with mode: 0644]
src/test/ui/const-generics/issues/issue-76701-ty-param-in-const.rs [new file with mode: 0644]
src/test/ui/const-generics/min_const_generics/self-ty-in-const-1.rs [new file with mode: 0644]
src/test/ui/const-generics/min_const_generics/self-ty-in-const-1.stderr [new file with mode: 0644]
src/test/ui/const-generics/min_const_generics/self-ty-in-const-2.rs [new file with mode: 0644]
src/test/ui/const-generics/min_const_generics/self-ty-in-const-2.stderr [new file with mode: 0644]
src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.min.stderr
src/test/ui/const-generics/type-dependent/issue-61936.rs
src/test/ui/const-generics/uninferred-consts.full.stderr [deleted file]
src/test/ui/const-generics/uninferred-consts.min.stderr [deleted file]
src/test/ui/const-generics/uninferred-consts.rs [deleted file]
src/test/ui/consts/duration-consts-2.rs [deleted file]
src/test/ui/did_you_mean/issue-40396.rs
src/test/ui/did_you_mean/issue-40396.stderr
src/test/ui/error-codes/E0027-teach.rs [deleted file]
src/test/ui/error-codes/E0027-teach.stderr [deleted file]
src/test/ui/error-codes/E0027.rs
src/test/ui/error-codes/E0027.stderr
src/test/ui/feature-gates/feature-gate-doc_alias.rs [deleted file]
src/test/ui/feature-gates/feature-gate-doc_alias.stderr [deleted file]
src/test/ui/impl-trait/equality.stderr
src/test/ui/impl-trait/object-unsafe-trait-in-return-position-impl-trait.stderr
src/test/ui/lint/lint-unconditional-recursion.stderr
src/test/ui/mir/issue-71793-inline-args-storage.rs [new file with mode: 0644]
src/test/ui/moves/move-deref-coercion.rs [new file with mode: 0644]
src/test/ui/moves/move-deref-coercion.stderr [new file with mode: 0644]
src/test/ui/no-capture-arc.stderr
src/test/ui/no-reuse-move-arc.stderr
src/test/ui/numbers-arithmetic/arith-0.rs [deleted file]
src/test/ui/numbers-arithmetic/arith-1.rs [deleted file]
src/test/ui/numbers-arithmetic/arith-2.rs [deleted file]
src/test/ui/parser/issue-73568-lifetime-after-mut.rs [new file with mode: 0644]
src/test/ui/parser/issue-73568-lifetime-after-mut.stderr [new file with mode: 0644]
src/test/ui/point-to-type-err-cause-on-impl-trait-return.rs
src/test/ui/point-to-type-err-cause-on-impl-trait-return.stderr
src/test/ui/str-multiline.rs [deleted file]
src/test/ui/string-escapes.rs [deleted file]
src/test/ui/structs/struct-field-cfg.stderr
src/test/ui/structs/struct-pat-derived-error.stderr
src/test/ui/trait-impl-bound-suggestions.fixed [new file with mode: 0644]
src/test/ui/trait-impl-bound-suggestions.rs [new file with mode: 0644]
src/test/ui/trait-impl-bound-suggestions.stderr [new file with mode: 0644]
src/test/ui/type/type-check-defaults.stderr
src/test/ui/union/union-drop.rs
src/test/ui/union/union-move.rs [new file with mode: 0644]
src/test/ui/union/union-move.stderr [new file with mode: 0644]
src/tools/cargo
src/tools/clippy/clippy_lints/src/utils/paths.rs
src/tools/linkchecker/main.rs
src/tools/lint-docs/Cargo.toml [new file with mode: 0644]
src/tools/lint-docs/src/groups.rs [new file with mode: 0644]
src/tools/lint-docs/src/lib.rs [new file with mode: 0644]
src/tools/lint-docs/src/main.rs [new file with mode: 0644]
src/tools/rust-analyzer

index 8b6828fd49d27d3df552c38029fd966a3d2c524d..50ae8c313d6fcb152fb0e3f600296f23062050a2 100644 (file)
@@ -76,7 +76,7 @@ jobs:
         uses: rust-lang/simpleinfra/github-actions/cancel-outdated-builds@master
         with:
           github_token: "${{ secrets.github_token }}"
-        if: "success() && !env.SKIP_JOB && github.ref != 'refs/heads/try' && !env.RUST_CI_TEMP_SKIP_CANCEL_OUTDATED"
+        if: "success() && !env.SKIP_JOB && github.ref != 'refs/heads/try'"
       - name: collect CPU statistics
         run: src/ci/scripts/collect-cpu-stats.sh
         if: success() && !env.SKIP_JOB
@@ -180,7 +180,7 @@ jobs:
         uses: rust-lang/simpleinfra/github-actions/cancel-outdated-builds@master
         with:
           github_token: "${{ secrets.github_token }}"
-        if: "success() && !env.SKIP_JOB && github.ref != 'refs/heads/try' && !env.RUST_CI_TEMP_SKIP_CANCEL_OUTDATED"
+        if: "success() && !env.SKIP_JOB && github.ref != 'refs/heads/try'"
       - name: collect CPU statistics
         run: src/ci/scripts/collect-cpu-stats.sh
         if: success() && !env.SKIP_JOB
@@ -375,6 +375,64 @@ jobs:
             env:
               DEPLOY_TOOLSTATES_JSON: toolstates-linux.json
             os: ubuntu-latest-xl
+          - 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"
+              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: x86_64-msvc-1
             env:
               RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --enable-profiler"
@@ -499,7 +557,7 @@ jobs:
         uses: rust-lang/simpleinfra/github-actions/cancel-outdated-builds@master
         with:
           github_token: "${{ secrets.github_token }}"
-        if: "success() && !env.SKIP_JOB && github.ref != 'refs/heads/try' && !env.RUST_CI_TEMP_SKIP_CANCEL_OUTDATED"
+        if: "success() && !env.SKIP_JOB && github.ref != 'refs/heads/try'"
       - name: collect CPU statistics
         run: src/ci/scripts/collect-cpu-stats.sh
         if: success() && !env.SKIP_JOB
@@ -580,38 +638,6 @@ jobs:
               - self-hosted
               - ARM64
               - linux
-          - 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
-              RUST_CI_TEMP_SKIP_CANCEL_OUTDATED: 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
-              RUST_CI_TEMP_SKIP_CANCEL_OUTDATED: 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
-              RUST_CI_TEMP_SKIP_CANCEL_OUTDATED: 1
-            os: macos-latest
     timeout-minutes: 600
     runs-on: "${{ matrix.os }}"
     steps:
@@ -638,7 +664,7 @@ jobs:
         uses: rust-lang/simpleinfra/github-actions/cancel-outdated-builds@master
         with:
           github_token: "${{ secrets.github_token }}"
-        if: "success() && !env.SKIP_JOB && github.ref != 'refs/heads/try' && !env.RUST_CI_TEMP_SKIP_CANCEL_OUTDATED"
+        if: "success() && !env.SKIP_JOB && github.ref != 'refs/heads/try'"
       - name: collect CPU statistics
         run: src/ci/scripts/collect-cpu-stats.sh
         if: success() && !env.SKIP_JOB
index cc7b2a677baf6e056006558527a750e823e9c4c3..fa0728bd794612d969cc8a913225c69df7b7a087 100644 (file)
--- a/.mailmap
+++ b/.mailmap
@@ -55,6 +55,9 @@ Chris C Cerami <chrisccerami@users.noreply.github.com> Chris C Cerami <chrisccer
 Chris Pressey <cpressey@gmail.com>
 Chris Thorn <chris@thorn.co> Chris Thorn <thorn@thoughtbot.com>
 Chris Vittal <christopher.vittal@gmail.com> Christopher Vittal <christopher.vittal@gmail.com>
+Christiaan Dirkx <christiaan@dirkx.email> <christiaan@dirkx.com>
+Christiaan Dirkx <christiaan@dirkx.email> CDirkx <christiaan@dirkx.com>
+Christiaan Dirkx <christiaan@dirkx.email> CDirkx <christiaan@dirkx.email>
 Christian Poveda <git@christianpoveda.xyz> <christianpoveda@protonmail.com>
 Christian Poveda <git@christianpoveda.xyz> <cn.poveda.ruiz@gmail.com>
 Christian Poveda <git@christianpoveda.xyz> <z1mvader@protonmail.com>
index b448baf425baa1ced4bea1a33314d5dd6deefb09..d3f777bc663ddd250b9d13cf6f2ea5d0bbf33a0c 100644 (file)
@@ -534,7 +534,7 @@ dependencies = [
  "if_chain",
  "itertools 0.9.0",
  "lazy_static",
- "pulldown-cmark",
+ "pulldown-cmark 0.7.2",
  "quine-mc_cluskey",
  "quote",
  "regex-syntax",
@@ -1677,6 +1677,15 @@ version = "0.5.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8dd5a6d5999d9907cda8ed67bbd137d3af8085216c2ac62de5be860bd41f304a"
 
+[[package]]
+name = "lint-docs"
+version = "0.1.0"
+dependencies = [
+ "serde_json",
+ "tempfile",
+ "walkdir",
+]
+
 [[package]]
 name = "lock_api"
 version = "0.3.4"
@@ -1844,7 +1853,7 @@ dependencies = [
  "log",
  "memchr",
  "open",
- "pulldown-cmark",
+ "pulldown-cmark 0.7.2",
  "regex",
  "serde",
  "serde_derive",
@@ -2502,6 +2511,17 @@ dependencies = [
  "unicase",
 ]
 
+[[package]]
+name = "pulldown-cmark"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ffade02495f22453cd593159ea2f59827aae7f53fa8323f756799b670881dcf8"
+dependencies = [
+ "bitflags",
+ "memchr",
+ "unicase",
+]
+
 [[package]]
 name = "punycode"
 version = "0.4.1"
@@ -3703,6 +3723,7 @@ dependencies = [
  "rustc_data_structures",
  "rustc_errors",
  "rustc_expand",
+ "rustc_feature",
  "rustc_hir",
  "rustc_hir_pretty",
  "rustc_index",
@@ -4112,7 +4133,7 @@ dependencies = [
  "expect-test",
  "itertools 0.9.0",
  "minifier",
- "pulldown-cmark",
+ "pulldown-cmark 0.8.0",
  "rustc-rayon",
  "serde",
  "serde_json",
index fde1cb5a35c2ed36bee3f5bd60332b6fcf1c4cdd..02794d1028b506b4510a71e140de62a4fb210d31 100644 (file)
@@ -9,6 +9,7 @@ members = [
   "src/tools/compiletest",
   "src/tools/error_index_generator",
   "src/tools/linkchecker",
+  "src/tools/lint-docs",
   "src/tools/rustbook",
   "src/tools/unstable-book-gen",
   "src/tools/tidy",
index d4e0e3ba051c95c214f2561ce94757583d6a3787..754b1f13381cb5980e998e00b5b6e16f58dec5f6 100644 (file)
@@ -103,6 +103,7 @@ fn find_match_by_sorted_words<'a>(iter_names: Vec<&'a Symbol>, lookup: &str) ->
 
 fn sort_by_words(name: &str) -> String {
     let mut split_words: Vec<&str> = name.split('_').collect();
-    split_words.sort();
+    // We are sorting primitive &strs and can use unstable sort here
+    split_words.sort_unstable();
     split_words.join("_")
 }
index df452825bba5589a07224120ef76d4ccdebeb1ed..c97f80cf09ba17ceeddf36937ecbe75c2117e9f8 100644 (file)
@@ -1121,7 +1121,7 @@ fn lower_expr_asm(&mut self, sp: Span, asm: &InlineAsm) -> hir::ExprKind<'hir> {
                 // features. We check that at least one type is available for
                 // the current target.
                 let reg_class = reg.reg_class();
-                let mut required_features = vec![];
+                let mut required_features: Vec<&str> = vec![];
                 for &(_, feature) in reg_class.supported_types(asm_arch) {
                     if let Some(feature) = feature {
                         if self.sess.target_features.contains(&Symbol::intern(feature)) {
@@ -1135,7 +1135,8 @@ fn lower_expr_asm(&mut self, sp: Span, asm: &InlineAsm) -> hir::ExprKind<'hir> {
                         break;
                     }
                 }
-                required_features.sort();
+                // We are sorting primitive strs here and can use unstable sort here
+                required_features.sort_unstable();
                 required_features.dedup();
                 match &required_features[..] {
                     [] => {}
index 40643da2881a096e8d3f8c9b4cac5f8579b5d3f0..00d3db73766ac6fc62ee10d09693737702db0d1f 100644 (file)
@@ -260,7 +260,6 @@ macro_rules! gate_doc { ($($name:ident => $feature:ident)*) => {
                     cfg => doc_cfg
                     masked => doc_masked
                     spotlight => doc_spotlight
-                    alias => doc_alias
                     keyword => doc_keyword
                 );
             }
index ec41fd7a3eebe90132d9982db5b8c74f34b21b38..4cfb188783ba110c42165132188d698c3a535152 100644 (file)
@@ -584,12 +584,12 @@ fn subspan(
 
         let start = match start {
             Bound::Included(lo) => lo,
-            Bound::Excluded(lo) => lo + 1,
+            Bound::Excluded(lo) => lo.checked_add(1)?,
             Bound::Unbounded => 0,
         };
 
         let end = match end {
-            Bound::Included(hi) => hi + 1,
+            Bound::Included(hi) => hi.checked_add(1)?,
             Bound::Excluded(hi) => hi,
             Bound::Unbounded => length,
         };
index d16f023c00a6216109be48ace5e222590dcf5c10..0477f6f149b87584703693df5db7f95dde9f7b0d 100644 (file)
@@ -268,6 +268,8 @@ macro_rules! declare_features {
     /// Allows `#[track_caller]` to be used which provides
     /// accurate caller location reporting during panic (RFC 2091).
     (accepted, track_caller, "1.46.0", Some(47809), None),
+    /// Allows `#[doc(alias = "...")]`.
+    (accepted, doc_alias, "1.48.0", Some(50146), None),
 
     // -------------------------------------------------------------------------
     // feature-group-end: accepted features
index 1aeb0bd5ad9aafff2ac80cd9f6f7c6597c355142..d4664292a0cbd326da0735f3db38266d6737d048 100644 (file)
@@ -404,9 +404,6 @@ pub fn set(&self, features: &mut Features, span: Span) {
     /// Allows dereferencing raw pointers during const eval.
     (active, const_raw_ptr_deref, "1.27.0", Some(51911), None),
 
-    /// Allows `#[doc(alias = "...")]`.
-    (active, doc_alias, "1.27.0", Some(50146), None),
-
     /// Allows inconsistent bounds in where clauses.
     (active, trivial_bounds, "1.28.0", Some(48214), None),
 
index b019e518d0c5457b28c342d416663960dc05a23f..96fde48d96cc12c1b00b3a5f0f8aa6d08e4b6d9f 100644 (file)
@@ -199,7 +199,16 @@ pub enum Res<Id = hir::HirId> {
 
     // Type namespace
     PrimTy(hir::PrimTy),
-    SelfTy(Option<DefId> /* trait */, Option<DefId> /* impl */),
+    /// `Self`, with both an optional trait and impl `DefId`.
+    ///
+    /// HACK(min_const_generics): impl self types also have an optional requirement to not mention
+    /// any generic parameters to allow the following with `min_const_generics`:
+    /// ```rust
+    /// impl Foo { fn test() -> [u8; std::mem::size_of::<Self>()] {} }
+    /// ```
+    ///
+    /// FIXME(lazy_normalization_consts): Remove this bodge once this feature is stable.
+    SelfTy(Option<DefId> /* trait */, Option<(DefId, bool)> /* impl */),
     ToolMod, // e.g., `rustfmt` in `#[rustfmt::skip]`
 
     // Value namespace
index 1225776db4590e24a58e182335a4711f628a1f2f..bcfcee23d13fee878ff5efe780f611cd8958b6d9 100644 (file)
@@ -70,7 +70,7 @@
     subst::{Subst, SubstsRef},
     Region, Ty, TyCtxt, TypeFoldable,
 };
-use rustc_span::{DesugaringKind, Pos, Span};
+use rustc_span::{BytePos, DesugaringKind, Pos, Span};
 use rustc_target::spec::abi;
 use std::{cmp, fmt};
 
@@ -617,11 +617,20 @@ fn note_error_origin(
                 ref prior_arms,
                 last_ty,
                 scrut_hir_id,
+                opt_suggest_box_span,
+                arm_span,
                 ..
             }) => match source {
                 hir::MatchSource::IfLetDesugar { .. } => {
                     let msg = "`if let` arms have incompatible types";
                     err.span_label(cause.span, msg);
+                    if let Some(ret_sp) = opt_suggest_box_span {
+                        self.suggest_boxing_for_return_impl_trait(
+                            err,
+                            ret_sp,
+                            prior_arms.iter().chain(std::iter::once(&arm_span)).map(|s| *s),
+                        );
+                    }
                 }
                 hir::MatchSource::TryDesugar => {
                     if let Some(ty::error::ExpectedFound { expected, .. }) = exp_found {
@@ -675,9 +684,23 @@ fn note_error_origin(
                             Applicability::MachineApplicable,
                         );
                     }
+                    if let Some(ret_sp) = opt_suggest_box_span {
+                        // Get return type span and point to it.
+                        self.suggest_boxing_for_return_impl_trait(
+                            err,
+                            ret_sp,
+                            prior_arms.iter().chain(std::iter::once(&arm_span)).map(|s| *s),
+                        );
+                    }
                 }
             },
-            ObligationCauseCode::IfExpression(box IfExpressionCause { then, outer, semicolon }) => {
+            ObligationCauseCode::IfExpression(box IfExpressionCause {
+                then,
+                else_sp,
+                outer,
+                semicolon,
+                opt_suggest_box_span,
+            }) => {
                 err.span_label(then, "expected because of this");
                 if let Some(sp) = outer {
                     err.span_label(sp, "`if` and `else` have incompatible types");
@@ -690,11 +713,48 @@ fn note_error_origin(
                         Applicability::MachineApplicable,
                     );
                 }
+                if let Some(ret_sp) = opt_suggest_box_span {
+                    self.suggest_boxing_for_return_impl_trait(
+                        err,
+                        ret_sp,
+                        vec![then, else_sp].into_iter(),
+                    );
+                }
             }
             _ => (),
         }
     }
 
+    fn suggest_boxing_for_return_impl_trait(
+        &self,
+        err: &mut DiagnosticBuilder<'tcx>,
+        return_sp: Span,
+        arm_spans: impl Iterator<Item = Span>,
+    ) {
+        err.multipart_suggestion(
+            "you could change the return type to be a boxed trait object",
+            vec![
+                (return_sp.with_hi(return_sp.lo() + BytePos(4)), "Box<dyn".to_string()),
+                (return_sp.shrink_to_hi(), ">".to_string()),
+            ],
+            Applicability::MaybeIncorrect,
+        );
+        let sugg = arm_spans
+            .flat_map(|sp| {
+                vec![
+                    (sp.shrink_to_lo(), "Box::new(".to_string()),
+                    (sp.shrink_to_hi(), ")".to_string()),
+                ]
+                .into_iter()
+            })
+            .collect::<Vec<_>>();
+        err.multipart_suggestion(
+            "if you change the return type to expect trait objects, box the returned expressions",
+            sugg,
+            Applicability::MaybeIncorrect,
+        );
+    }
+
     /// Given that `other_ty` is the same as a type argument for `name` in `sub`, populate `value`
     /// highlighting `name` and every type argument that isn't at `pos` (which is `other_ty`), and
     /// populate `other_value` with `other_ty`.
index 4de84e5ba399c2dd243a9c90040049933ebc01c7..f87406c2ce469c97f15da28c3d9950abb90942d6 100644 (file)
@@ -6,9 +6,10 @@
 use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc_hir::{Body, Expr, ExprKind, FnRetTy, HirId, Local, Pat};
 use rustc_middle::hir::map::Map;
+use rustc_middle::infer::unify_key::ConstVariableOriginKind;
 use rustc_middle::ty::print::Print;
 use rustc_middle::ty::subst::{GenericArg, GenericArgKind};
-use rustc_middle::ty::{self, DefIdTree, Ty};
+use rustc_middle::ty::{self, DefIdTree, InferConst, Ty};
 use rustc_span::source_map::DesugaringKind;
 use rustc_span::symbol::kw;
 use rustc_span::Span;
@@ -569,14 +570,26 @@ pub fn need_type_info_err_const(
             local_visitor.visit_expr(expr);
         }
 
+        let mut param_name = None;
+        let span = if let ty::ConstKind::Infer(InferConst::Var(vid)) = ct.val {
+            let origin = self.inner.borrow_mut().const_unification_table().probe_value(vid).origin;
+            if let ConstVariableOriginKind::ConstParameterDefinition(param) = origin.kind {
+                param_name = Some(param);
+            }
+            origin.span
+        } else {
+            local_visitor.target_span
+        };
+
         let error_code = error_code.into();
-        let mut err = self.tcx.sess.struct_span_err_with_code(
-            local_visitor.target_span,
-            "type annotations needed",
-            error_code,
-        );
+        let mut err =
+            self.tcx.sess.struct_span_err_with_code(span, "type annotations needed", error_code);
 
-        err.note("unable to infer the value of a const parameter");
+        if let Some(param_name) = param_name {
+            err.note(&format!("cannot infer the value of the const parameter `{}`", param_name));
+        } else {
+            err.note("unable to infer the value of a const parameter");
+        }
 
         err
     }
index 1d27bdcb28261d7e26cf270353ded50675343910..e6be082da0e9967aba913bddbe6aacd70ff99de3 100644 (file)
@@ -7,6 +7,31 @@
 use rustc_span::symbol::sym;
 
 declare_lint! {
+    /// The `array_into_iter` lint detects calling `into_iter` on arrays.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// # #![allow(unused)]
+    /// [1, 2, 3].into_iter().for_each(|n| { *n; });
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// In the future, it is planned to add an `IntoIter` implementation for
+    /// arrays such that it will iterate over *values* of the array instead of
+    /// references. Due to how method resolution works, this will change
+    /// existing code that uses `into_iter` on arrays. The solution to avoid
+    /// this warning is to use `iter()` instead of `into_iter()`.
+    ///
+    /// This is a [future-incompatible] lint to transition this to a hard error
+    /// in the future. See [issue #66145] for more details and a more thorough
+    /// description of the lint.
+    ///
+    /// [issue #66145]: https://github.com/rust-lang/rust/issues/66145
+    /// [future-incompatible]: ../index.md#future-incompatible-lints
     pub ARRAY_INTO_ITER,
     Warn,
     "detects calling `into_iter` on arrays",
index 61ecd13c30768aab8e8eefb281f9ef024f98f440..efdb7489ba5b0d766ac18cc3de6d6f0e35f2923e 100644 (file)
 pub use rustc_session::lint::builtin::*;
 
 declare_lint! {
+    /// The `while_true` lint detects `while true { }`.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,no_run
+    /// while true {
+    ///
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// `while true` should be replaced with `loop`. A `loop` expression is
+    /// the preferred way to write an infinite loop because it more directly
+    /// expresses the intent of the loop.
     WHILE_TRUE,
     Warn,
     "suggest using `loop { }` instead of `while true { }`"
@@ -102,6 +119,24 @@ fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
 }
 
 declare_lint! {
+    /// The `box_pointers` lints use of the Box type.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// #![deny(box_pointers)]
+    /// struct Foo {
+    ///     x: Box<isize>,
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// This lint is mostly historical, and not particularly useful. `Box<T>`
+    /// used to be built into the language, and the only way to do heap
+    /// allocation. Today's Rust can call into other allocators, etc.
     BOX_POINTERS,
     Allow,
     "use of owned (Box type) heap memory"
@@ -156,6 +191,36 @@ fn check_expr(&mut self, cx: &LateContext<'_>, e: &hir::Expr<'_>) {
 }
 
 declare_lint! {
+    /// The `non_shorthand_field_patterns` lint detects using `Struct { x: x }`
+    /// instead of `Struct { x }` in a pattern.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// struct Point {
+    ///     x: i32,
+    ///     y: i32,
+    /// }
+    ///
+    ///
+    /// fn main() {
+    ///     let p = Point {
+    ///         x: 5,
+    ///         y: 5,
+    ///     };
+    ///
+    ///     match p {
+    ///         Point { x: x, y: y } => (),
+    ///     }
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// The preferred style is to avoid the repetition of specifying both the
+    /// field name and the binding name if both identifiers are the same.
     NON_SHORTHAND_FIELD_PATTERNS,
     Warn,
     "using `Struct { x: x }` instead of `Struct { x }` in a pattern"
@@ -216,6 +281,25 @@ fn check_pat(&mut self, cx: &LateContext<'_>, pat: &hir::Pat<'_>) {
 }
 
 declare_lint! {
+    /// The `unsafe_code` lint catches usage of `unsafe` code.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// #![deny(unsafe_code)]
+    /// fn main() {
+    ///     unsafe {
+    ///
+    ///     }
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// This lint is intended to restrict the usage of `unsafe`, which can be
+    /// difficult to use correctly.
     UNSAFE_CODE,
     Allow,
     "usage of `unsafe` code"
@@ -303,6 +387,25 @@ fn check_fn(&mut self, cx: &EarlyContext<'_>, fk: FnKind<'_>, span: Span, _: ast
 }
 
 declare_lint! {
+    /// The `missing_docs` lint detects missing documentation for public items.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// #![deny(missing_docs)]
+    /// pub fn foo() {}
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// This lint is intended to ensure that a library is well-documented.
+    /// Items without documentation can be difficult for users to understand
+    /// how to use properly.
+    ///
+    /// This lint is "allow" by default because it can be noisy, and not all
+    /// projects may want to enforce everything to be documented.
     pub MISSING_DOCS,
     Allow,
     "detects missing documentation for public members",
@@ -528,6 +631,34 @@ fn check_variant(&mut self, cx: &LateContext<'_>, v: &hir::Variant<'_>) {
 }
 
 declare_lint! {
+    /// The `missing_copy_implementations` lint detects potentially-forgotten
+    /// implementations of [`Copy`].
+    ///
+    /// [`Copy`]: https://doc.rust-lang.org/std/marker/trait.Copy.html
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// #![deny(missing_copy_implementations)]
+    /// pub struct Foo {
+    ///     pub field: i32
+    /// }
+    /// # fn main() {}
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Historically (before 1.0), types were automatically marked as `Copy`
+    /// if possible. This was changed so that it required an explicit opt-in
+    /// by implementing the `Copy` trait. As part of this change, a lint was
+    /// added to alert if a copyable type was not marked `Copy`.
+    ///
+    /// This lint is "allow" by default because this code isn't bad; it is
+    /// common to write newtypes like this specifically so that a `Copy` type
+    /// is no longer `Copy`. `Copy` types can result in unintended copies of
+    /// large data which can impact performance.
     pub MISSING_COPY_IMPLEMENTATIONS,
     Allow,
     "detects potentially-forgotten implementations of `Copy`"
@@ -584,6 +715,32 @@ fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
 }
 
 declare_lint! {
+    /// The `missing_debug_implementations` lint detects missing
+    /// implementations of [`fmt::Debug`].
+    ///
+    /// [`fmt::Debug`]: https://doc.rust-lang.org/std/fmt/trait.Debug.html
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// #![deny(missing_debug_implementations)]
+    /// pub struct Foo;
+    /// # fn main() {}
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Having a `Debug` implementation on all types can assist with
+    /// debugging, as it provides a convenient way to format and display a
+    /// value. Using the `#[derive(Debug)]` attribute will automatically
+    /// generate a typical implementation, or a custom implementation can be
+    /// added by manually implementing the `Debug` trait.
+    ///
+    /// This lint is "allow" by default because adding `Debug` to all types can
+    /// have a negative impact on compile time and code size. It also requires
+    /// boilerplate to be added to every type, which can be an impediment.
     MISSING_DEBUG_IMPLEMENTATIONS,
     Allow,
     "detects missing implementations of Debug"
@@ -640,6 +797,45 @@ fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
 }
 
 declare_lint! {
+    /// The `anonymous_parameters` lint detects anonymous parameters in trait
+    /// definitions.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,edition2015,compile_fail
+    /// #![deny(anonymous_parameters)]
+    /// // edition 2015
+    /// pub trait Foo {
+    ///     fn foo(usize);
+    /// }
+    /// fn main() {}
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// This syntax is mostly a historical accident, and can be worked around
+    /// quite easily by adding an `_` pattern or a descriptive identifier:
+    ///
+    /// ```rust
+    /// trait Foo {
+    ///     fn foo(_: usize);
+    /// }
+    /// ```
+    ///
+    /// This syntax is now a hard error in the 2018 edition. In the 2015
+    /// edition, this lint is "allow" by default, because the old code is
+    /// still valid, and warning for all old code can be noisy. This lint
+    /// enables the [`cargo fix`] tool with the `--edition` flag to
+    /// automatically transition old code from the 2015 edition to 2018. The
+    /// tool will switch this lint to "warn" and will automatically apply the
+    /// suggested fix from the compiler (which is to add `_` to each
+    /// parameter). This provides a completely automated way to update old
+    /// code for a new edition. See [issue #41686] for more details.
+    ///
+    /// [issue #41686]: https://github.com/rust-lang/rust/issues/41686
+    /// [`cargo fix`]: https://doc.rust-lang.org/cargo/commands/cargo-fix.html
     pub ANONYMOUS_PARAMETERS,
     Allow,
     "detects anonymous parameters",
@@ -806,12 +1002,54 @@ fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) {
 }
 
 declare_lint! {
+    /// The `no_mangle_const_items` lint detects any `const` items with the
+    /// [`no_mangle` attribute].
+    ///
+    /// [`no_mangle` attribute]: https://doc.rust-lang.org/reference/abi.html#the-no_mangle-attribute
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// #[no_mangle]
+    /// const FOO: i32 = 5;
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Constants do not have their symbols exported, and therefore, this
+    /// probably means you meant to use a [`static`], not a [`const`].
+    ///
+    /// [`static`]: https://doc.rust-lang.org/reference/items/static-items.html
+    /// [`const`]: https://doc.rust-lang.org/reference/items/constant-items.html
     NO_MANGLE_CONST_ITEMS,
     Deny,
     "const items will not have their symbols exported"
 }
 
 declare_lint! {
+    /// The `no_mangle_generic_items` lint detects generic items that must be
+    /// mangled.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// #[no_mangle]
+    /// fn foo<T>(t: T) {
+    ///
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// An function with generics must have its symbol mangled to accommodate
+    /// the generic parameter. The [`no_mangle` attribute] has no effect in
+    /// this situation, and should be removed.
+    ///
+    /// [`no_mangle` attribute]: https://doc.rust-lang.org/reference/abi.html#the-no_mangle-attribute
     NO_MANGLE_GENERIC_ITEMS,
     Warn,
     "generic items must be mangled"
@@ -882,6 +1120,27 @@ fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) {
 }
 
 declare_lint! {
+    /// The `mutable_transmutes` lint catches transmuting from `&T` to `&mut
+    /// T` because it is [undefined behavior].
+    ///
+    /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// unsafe {
+    ///     let y = std::mem::transmute::<&i32, &mut i32>(&5);
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Certain assumptions are made about aliasing of data, and this transmute
+    /// violates those assumptions. Consider using [`UnsafeCell`] instead.
+    ///
+    /// [`UnsafeCell`]: https://doc.rust-lang.org/std/cell/struct.UnsafeCell.html
     MUTABLE_TRANSMUTES,
     Deny,
     "mutating transmuted &mut T from &T may cause undefined behavior"
@@ -931,6 +1190,7 @@ fn def_id_is_transmute(cx: &LateContext<'_>, def_id: DefId) -> bool {
 }
 
 declare_lint! {
+    /// The `unstable_features` is deprecated and should no longer be used.
     UNSTABLE_FEATURES,
     Allow,
     "enabling unstable features (deprecated. do not use)"
@@ -956,6 +1216,32 @@ fn check_attribute(&mut self, cx: &LateContext<'_>, attr: &ast::Attribute) {
 }
 
 declare_lint! {
+    /// The `unreachable_pub` lint triggers for `pub` items not reachable from
+    /// the crate root.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// #![deny(unreachable_pub)]
+    /// mod foo {
+    ///     pub mod bar {
+    ///
+    ///     }
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// A bare `pub` visibility may be misleading if the item is not actually
+    /// publicly exported from the crate. The `pub(crate)` visibility is
+    /// recommended to be used instead, which more clearly expresses the intent
+    /// that the item is only visible within its own crate.
+    ///
+    /// This lint is "allow" by default because it will trigger for a large
+    /// amount existing Rust code, and has some false-positives. Eventually it
+    /// is desired for this to become warn-by-default.
     pub UNREACHABLE_PUB,
     Allow,
     "`pub` items not reachable from crate root"
@@ -1035,6 +1321,21 @@ fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &hir::ImplItem<'_
 }
 
 declare_lint! {
+    /// The `type_alias_bounds` lint detects bounds in type aliases.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// type SendVec<T: Send> = Vec<T>;
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// The trait bounds in a type alias are currently ignored, and should not
+    /// be included to avoid confusion. This was previously allowed
+    /// unintentionally; this may become a hard error in the future.
     TYPE_ALIAS_BOUNDS,
     Warn,
     "bounds in type aliases are not enforced"
@@ -1194,6 +1495,35 @@ fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) {
 }
 
 declare_lint! {
+    /// The `trivial_bounds` lint detects trait bounds that don't depend on
+    /// any type parameters.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// #![feature(trivial_bounds)]
+    /// pub struct A where i32: Copy;
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Usually you would not write a trait bound that you know is always
+    /// true, or never true. However, when using macros, the macro may not
+    /// know whether or not the constraint would hold or not at the time when
+    /// generating the code. Currently, the compiler does not alert you if the
+    /// constraint is always true, and generates an error if it is never true.
+    /// The `trivial_bounds` feature changes this to be a warning in both
+    /// cases, giving macros more freedom and flexibility to generate code,
+    /// while still providing a signal when writing non-macro code that
+    /// something is amiss.
+    ///
+    /// See [RFC 2056] for more details. This feature is currently only
+    /// available on the nightly channel, see [tracking issue #48214].
+    ///
+    /// [RFC 2056]: https://github.com/rust-lang/rfcs/blob/master/text/2056-allow-trivial-where-clause-constraints.md
+    /// [tracking issue #48214]: https://github.com/rust-lang/rust/issues/48214
     TRIVIAL_BOUNDS,
     Warn,
     "these bounds don't depend on an type parameters"
@@ -1270,6 +1600,29 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
 );
 
 declare_lint! {
+    /// The `ellipsis_inclusive_range_patterns` lint detects the [`...` range
+    /// pattern], which is deprecated.
+    ///
+    /// [`...` range pattern]: https://doc.rust-lang.org/reference/patterns.html#range-patterns
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// let x = 123;
+    /// match x {
+    ///     0...100 => {}
+    ///     _ => {}
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// The `...` range pattern syntax was changed to `..=` to avoid potential
+    /// confusion with the [`..` range expression]. Use the new form instead.
+    ///
+    /// [`..` range expression]: https://doc.rust-lang.org/reference/expressions/range-expr.html
     pub ELLIPSIS_INCLUSIVE_RANGE_PATTERNS,
     Warn,
     "`...` range patterns are deprecated"
@@ -1356,6 +1709,38 @@ fn check_pat_post(&mut self, _cx: &EarlyContext<'_>, pat: &ast::Pat) {
 }
 
 declare_lint! {
+    /// The `unnameable_test_items` lint detects [`#[test]`][test] functions
+    /// that are not able to be run by the test harness because they are in a
+    /// position where they are not nameable.
+    ///
+    /// [test]: https://doc.rust-lang.org/reference/attributes/testing.html#the-test-attribute
+    ///
+    /// ### Example
+    ///
+    /// ```rust,test
+    /// fn main() {
+    ///     #[test]
+    ///     fn foo() {
+    ///         // This test will not fail because it does not run.
+    ///         assert_eq!(1, 2);
+    ///     }
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// In order for the test harness to run a test, the test function must be
+    /// located in a position where it can be accessed from the crate root.
+    /// This generally means it must be defined in a module, and not anywhere
+    /// else such as inside another function. The compiler previously allowed
+    /// this without an error, so a lint was added as an alert that a test is
+    /// not being used. Whether or not this should be allowed has not yet been
+    /// decided, see [RFC 2471] and [issue #36629].
+    ///
+    /// [RFC 2471]: https://github.com/rust-lang/rfcs/pull/2471#issuecomment-397414443
+    /// [issue #36629]: https://github.com/rust-lang/rust/issues/36629
     UNNAMEABLE_TEST_ITEMS,
     Warn,
     "detects an item that cannot be named being marked as `#[test_case]`",
@@ -1401,6 +1786,41 @@ fn check_item_post(&mut self, _cx: &LateContext<'_>, it: &hir::Item<'_>) {
 }
 
 declare_lint! {
+    /// The `keyword_idents` lint detects edition keywords being used as an
+    /// identifier.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,edition2015,compile_fail
+    /// #![deny(keyword_idents)]
+    /// // edition 2015
+    /// fn dyn() {}
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Rust [editions] allow the language to evolve without breaking
+    /// backwards compatibility. This lint catches code that uses new keywords
+    /// that are added to the language that are used as identifiers (such as a
+    /// variable name, function name, etc.). If you switch the compiler to a
+    /// new edition without updating the code, then it will fail to compile if
+    /// you are using a new keyword as an identifier.
+    ///
+    /// You can manually change the identifiers to a non-keyword, or use a
+    /// [raw identifier], for example `r#dyn`, to transition to a new edition.
+    ///
+    /// This lint solves the problem automatically. It is "allow" by default
+    /// because the code is perfectly valid in older editions. The [`cargo
+    /// fix`] tool with the `--edition` flag will switch this lint to "warn"
+    /// and automatically apply the suggested fix from the compiler (which is
+    /// to use a raw identifier). This provides a completely automated way to
+    /// update old code for a new edition.
+    ///
+    /// [editions]: https://doc.rust-lang.org/edition-guide/
+    /// [raw identifier]: https://doc.rust-lang.org/reference/identifiers.html
+    /// [`cargo fix`]: https://doc.rust-lang.org/cargo/commands/cargo-fix.html
     pub KEYWORD_IDENTS,
     Allow,
     "detects edition keywords being used as an identifier",
@@ -1802,6 +2222,26 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
 }
 
 declare_lint! {
+    /// The `incomplete_features` lint detects unstable features enabled with
+    /// the [`feature` attribute] that may function improperly in some or all
+    /// cases.
+    ///
+    /// [`feature` attribute]: https://doc.rust-lang.org/nightly/unstable-book/
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// #![feature(generic_associated_types)]
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Although it is encouraged for people to experiment with unstable
+    /// features, some of them are known to be incomplete or faulty. This lint
+    /// is a signal that the feature has not yet been finished, and you may
+    /// experience problems with it.
     pub INCOMPLETE_FEATURES,
     Warn,
     "incomplete features that may function improperly in some or all cases"
@@ -1842,6 +2282,36 @@ fn check_crate(&mut self, cx: &EarlyContext<'_>, _: &ast::Crate) {
 }
 
 declare_lint! {
+    /// The `invalid_value` lint detects creating a value that is not valid,
+    /// such as a NULL reference.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,no_run
+    /// # #![allow(unused)]
+    /// unsafe {
+    ///     let x: &'static i32 = std::mem::zeroed();
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// In some situations the compiler can detect that the code is creating
+    /// an invalid value, which should be avoided.
+    ///
+    /// In particular, this lint will check for improper use of
+    /// [`mem::zeroed`], [`mem::uninitialized`], [`mem::transmute`], and
+    /// [`MaybeUninit::assume_init`] that can cause [undefined behavior]. The
+    /// lint should provide extra information to indicate what the problem is
+    /// and a possible solution.
+    ///
+    /// [`mem::zeroed`]: https://doc.rust-lang.org/std/mem/fn.zeroed.html
+    /// [`mem::uninitialized`]: https://doc.rust-lang.org/std/mem/fn.uninitialized.html
+    /// [`mem::transmute`]: https://doc.rust-lang.org/std/mem/fn.transmute.html
+    /// [`MaybeUninit::assume_init`]: https://doc.rust-lang.org/std/mem/union.MaybeUninit.html#method.assume_init
+    /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
     pub INVALID_VALUE,
     Warn,
     "an invalid value is being created (such as a NULL reference)"
@@ -2073,6 +2543,40 @@ fn ty_find_init_error<'tcx>(
 }
 
 declare_lint! {
+    /// The `clashing_extern_declarations` lint detects when an `extern fn`
+    /// has been declared with the same name but different types.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// mod m {
+    ///     extern "C" {
+    ///         fn foo();
+    ///     }
+    /// }
+    ///
+    /// extern "C" {
+    ///     fn foo(_: u32);
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Because two symbols of the same name cannot be resolved to two
+    /// different functions at link time, and one function cannot possibly
+    /// have two types, a clashing extern declaration is almost certainly a
+    /// mistake. Check to make sure that the `extern` definitions are correct
+    /// and equivalent, and possibly consider unifying them in one location.
+    ///
+    /// This lint does not run between crates because a project may have
+    /// dependencies which both rely on the same extern function, but declare
+    /// it in a different (but valid) way. For example, they may both declare
+    /// an opaque type for one or more of the arguments (which would end up
+    /// distinct types), or use types that are valid conversions in the
+    /// language the `extern fn` is defined in. In these cases, the compiler
+    /// can't say that the clashing declaration is incorrect.
     pub CLASHING_EXTERN_DECLARATIONS,
     Warn,
     "detects when an extern fn has been declared with the same name but different types"
index 2f0b2a8d6802806d378abbc9b1a53108683593e0..a1c7e47e749add17a11cfc1d52536fe937342371 100644 (file)
@@ -4,6 +4,32 @@
 use rustc_span::symbol::Symbol;
 
 declare_lint! {
+    /// The `non_ascii_idents` lint detects non-ASCII identifiers.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// # #![allow(unused)]
+    /// #![feature(non_ascii_idents)]
+    /// #![deny(non_ascii_idents)]
+    /// fn main() {
+    ///     let föö = 1;
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Currently on stable Rust, identifiers must contain ASCII characters.
+    /// The [`non_ascii_idents`] nightly-only feature allows identifiers to
+    /// contain non-ASCII characters. This lint allows projects that wish to
+    /// retain the limit of only using ASCII characters to switch this lint to
+    /// "forbid" (for example to ease collaboration or for security reasons).
+    /// See [RFC 2457] for more details.
+    ///
+    /// [`non_ascii_idents`]: https://doc.rust-lang.org/nightly/unstable-book/language-features/non-ascii-idents.html
+    /// [RFC 2457]: https://github.com/rust-lang/rfcs/blob/master/text/2457-non-ascii-idents.md
     pub NON_ASCII_IDENTS,
     Allow,
     "detects non-ASCII identifiers",
 }
 
 declare_lint! {
+    /// The `uncommon_codepoints` lint detects uncommon Unicode codepoints in
+    /// identifiers.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// # #![allow(unused)]
+    /// #![feature(non_ascii_idents)]
+    /// const µ: f64 = 0.000001;
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// With the [`non_ascii_idents`] nightly-only feature enabled,
+    /// identifiers are allowed to use non-ASCII characters. This lint warns
+    /// about using characters which are not commonly used, and may cause
+    /// visual confusion.
+    ///
+    /// This lint is triggered by identifiers that contain a codepoint that is
+    /// not part of the set of "Allowed" codepoints as described by [Unicode®
+    /// Technical Standard #39 Unicode Security Mechanisms Section 3.1 General
+    /// Security Profile for Identifiers][TR39Allowed].
+    ///
+    /// Note that the set of uncommon codepoints may change over time. Beware
+    /// that if you "forbid" this lint that existing code may fail in the
+    /// future.
+    ///
+    /// [`non_ascii_idents`]: https://doc.rust-lang.org/nightly/unstable-book/language-features/non-ascii-idents.html
+    /// [TR39Allowed]: https://www.unicode.org/reports/tr39/#General_Security_Profile
     pub UNCOMMON_CODEPOINTS,
     Warn,
     "detects uncommon Unicode codepoints in identifiers",
 }
 
 declare_lint! {
+    /// The `confusable_idents` lint detects visually confusable pairs between
+    /// identifiers.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// #![feature(non_ascii_idents)]
+    ///
+    /// // Latin Capital Letter E With Caron
+    /// pub const Ě: i32 = 1;
+    /// // Latin Capital Letter E With Breve
+    /// pub const Ĕ: i32 = 2;
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// With the [`non_ascii_idents`] nightly-only feature enabled,
+    /// identifiers are allowed to use non-ASCII characters. This lint warns
+    /// when different identifiers may appear visually similar, which can
+    /// cause confusion.
+    ///
+    /// The confusable detection algorithm is based on [Unicode® Technical
+    /// Standard #39 Unicode Security Mechanisms Section 4 Confusable
+    /// Detection][TR39Confusable]. For every distinct identifier X execute
+    /// the function `skeleton(X)`. If there exist two distinct identifiers X
+    /// and Y in the same crate where `skeleton(X) = skeleton(Y)` report it.
+    /// The compiler uses the same mechanism to check if an identifier is too
+    /// similar to a keyword.
+    ///
+    /// Note that the set of confusable characters may change over time.
+    /// Beware that if you "forbid" this lint that existing code may fail in
+    /// the future.
+    ///
+    /// [`non_ascii_idents`]: https://doc.rust-lang.org/nightly/unstable-book/language-features/non-ascii-idents.html
+    /// [TR39Confusable]: https://www.unicode.org/reports/tr39/#Confusable_Detection
     pub CONFUSABLE_IDENTS,
     Warn,
     "detects visually confusable pairs between identifiers",
 }
 
 declare_lint! {
+    /// The `mixed_script_confusables` lint detects visually confusable
+    /// characters in identifiers between different [scripts].
+    ///
+    /// [scripts]: https://en.wikipedia.org/wiki/Script_(Unicode)
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// #![feature(non_ascii_idents)]
+    ///
+    /// // The Japanese katakana character エ can be confused with the Han character 工.
+    /// const エ: &'static str = "アイウ";
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// With the [`non_ascii_idents`] nightly-only feature enabled,
+    /// identifiers are allowed to use non-ASCII characters. This lint warns
+    /// when characters between different scripts may appear visually similar,
+    /// which can cause confusion.
+    ///
+    /// If the crate contains other identifiers in the same script that have
+    /// non-confusable characters, then this lint will *not* be issued. For
+    /// example, if the example given above has another identifier with
+    /// katakana characters (such as `let カタカナ = 123;`), then this indicates
+    /// that you are intentionally using katakana, and it will not warn about
+    /// it.
+    ///
+    /// Note that the set of confusable characters may change over time.
+    /// Beware that if you "forbid" this lint that existing code may fail in
+    /// the future.
+    ///
+    /// [`non_ascii_idents`]: https://doc.rust-lang.org/nightly/unstable-book/language-features/non-ascii-idents.html
     pub MIXED_SCRIPT_CONFUSABLES,
     Warn,
     "detects Unicode scripts whose mixed script confusables codepoints are solely used",
@@ -212,7 +341,8 @@ enum ScriptSetUsage {
                         }
                     }
 
-                    ch_list.sort();
+                    // We sort primitive chars here and can use unstable sort
+                    ch_list.sort_unstable();
                     ch_list.dedup();
                     lint_reports.insert((sp, ch_list), augment_script_set);
                 }
index f23e8c5e20888dae297e89a1146f50023f5ec973..24467f811726abcce9dd5f7bb6c1d4ef69aa9eb3 100644 (file)
@@ -31,6 +31,24 @@ pub fn method_context(cx: &LateContext<'_>, id: hir::HirId) -> MethodLateContext
 }
 
 declare_lint! {
+    /// The `non_camel_case_types` lint detects types, variants, traits and
+    /// type parameters that don't have camel case names.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// struct my_struct;
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// The preferred style for these identifiers is to use "camel case", such
+    /// as `MyStruct`, where the first letter should not be lowercase, and
+    /// should not use underscores between letters. Underscores are allowed at
+    /// the beginning and end of the identifier, as well as between
+    /// non-letters (such as `X86_64`).
     pub NON_CAMEL_CASE_TYPES,
     Warn,
     "types, variants, traits and type parameters should have camel case names"
@@ -161,6 +179,22 @@ fn check_generic_param(&mut self, cx: &EarlyContext<'_>, param: &ast::GenericPar
 }
 
 declare_lint! {
+    /// The `non_snake_case` lint detects variables, methods, functions,
+    /// lifetime parameters and modules that don't have snake case names.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// let MY_VALUE = 5;
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// The preferred style for these identifiers is to use "snake case",
+    /// where all the characters are in lowercase, with words separated with a
+    /// single underscore, such as `my_value`.
     pub NON_SNAKE_CASE,
     Warn,
     "variables, methods, functions, lifetime parameters and modules should have snake case names"
@@ -379,6 +413,21 @@ fn check_struct_def(&mut self, cx: &LateContext<'_>, s: &hir::VariantData<'_>) {
 }
 
 declare_lint! {
+    /// The `non_upper_case_globals` lint detects static items that don't have
+    /// uppercase identifiers.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// static max_points: i32 = 5;
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// The preferred style is for static item names to use all uppercase
+    /// letters such as `MAX_POINTS`.
     pub NON_UPPER_CASE_GLOBALS,
     Warn,
     "static constants should have uppercase identifiers"
index d4aa4968f25ee6f6be590175b1660aa49cc4a481..a31deb87ff0d062fd37d7503a80570074642195b 100644 (file)
@@ -4,6 +4,21 @@
 use rustc_span::Span;
 
 declare_lint! {
+    /// The `redundant_semicolons` lint detects unnecessary trailing
+    /// semicolons.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// let _ = 123;;
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Extra semicolons are not needed, and may be removed to avoid confusion
+    /// and visual clutter.
     pub REDUNDANT_SEMICOLONS,
     Warn,
     "detects unnecessary trailing semicolons"
index af32c16bfe8dd9a6fcb81ab7e36aa8d8c05ca860..a202efa6edadd927f370bc1a6a90c40d8b439f37 100644 (file)
 use tracing::debug;
 
 declare_lint! {
+    /// The `unused_comparisons` lint detects comparisons made useless by
+    /// limits of the types involved.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// fn foo(x: u8) {
+    ///     x >= 0;
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// A useless comparison may indicate a mistake, and should be fixed or
+    /// removed.
     UNUSED_COMPARISONS,
     Warn,
     "comparisons made useless by limits of the types involved"
 }
 
 declare_lint! {
+    /// The `overflowing_literals` lint detects literal out of range for its
+    /// type.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// let x: u8 = 1000;
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// It is usually a mistake to use a literal that overflows the type where
+    /// it is used. Either use a literal that is within range, or change the
+    /// type to be within the range of the literal.
     OVERFLOWING_LITERALS,
     Deny,
     "literal out of range for its type"
 }
 
 declare_lint! {
+    /// The `variant_size_differences` lint detects enums with widely varying
+    /// variant sizes.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// #![deny(variant_size_differences)]
+    /// enum En {
+    ///     V0(u8),
+    ///     VBig([u8; 1024]),
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// It can be a mistake to add a variant to an enum that is much larger
+    /// than the other variants, bloating the overall size required for all
+    /// variants. This can impact performance and memory usage. This is
+    /// triggered if one variant is more than 3 times larger than the
+    /// second-largest variant.
+    ///
+    /// Consider placing the large variant's contents on the heap (for example
+    /// via [`Box`]) to keep the overall size of the enum itself down.
+    ///
+    /// This lint is "allow" by default because it can be noisy, and may not be
+    /// an actual problem. Decisions about this should be guided with
+    /// profiling and benchmarking.
+    ///
+    /// [`Box`]: https://doc.rust-lang.org/std/boxed/index.html
     VARIANT_SIZE_DIFFERENCES,
     Allow,
     "detects enums with widely varying variant sizes"
@@ -495,6 +559,27 @@ fn is_comparison(binop: hir::BinOp) -> bool {
 }
 
 declare_lint! {
+    /// The `improper_ctypes` lint detects incorrect use of types in foreign
+    /// modules.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// extern "C" {
+    ///     static STATIC: String;
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// The compiler has several checks to verify that types used in `extern`
+    /// blocks are safe and follow certain rules to ensure proper
+    /// compatibility with the foreign interfaces. This lint is issued when it
+    /// detects a probable mistake in a definition. The lint usually should
+    /// provide a description of the issue, along with possibly a hint on how
+    /// to resolve it.
     IMPROPER_CTYPES,
     Warn,
     "proper use of libc types in foreign modules"
@@ -503,6 +588,27 @@ fn is_comparison(binop: hir::BinOp) -> bool {
 declare_lint_pass!(ImproperCTypesDeclarations => [IMPROPER_CTYPES]);
 
 declare_lint! {
+    /// The `improper_ctypes_definitions` lint detects incorrect use of
+    /// [`extern` function] definitions.
+    ///
+    /// [`extern` function]: https://doc.rust-lang.org/reference/items/functions.html#extern-function-qualifier
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// # #![allow(unused)]
+    /// pub extern "C" fn str_type(p: &str) { }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// There are many parameter and return types that may be specified in an
+    /// `extern` function that are not compatible with the given ABI. This
+    /// lint is an alert that these types should not be used. The lint usually
+    /// should provide a description of the issue, along with possibly a hint
+    /// on how to resolve it.
     IMPROPER_CTYPES_DEFINITIONS,
     Warn,
     "proper use of libc types in foreign item definitions"
index 0c06b063e41fa0958058ace160a8c585e4f8375d..1e8c30071e762aecb5f1c06fb1c120498d58c422 100644 (file)
 use tracing::debug;
 
 declare_lint! {
+    /// The `unused_must_use` lint detects unused result of a type flagged as
+    /// `#[must_use]`.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// fn returns_result() -> Result<(), ()> {
+    ///     Ok(())
+    /// }
+    ///
+    /// fn main() {
+    ///     returns_result();
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// The `#[must_use]` attribute is an indicator that it is a mistake to
+    /// ignore the value. See [the reference] for more details.
+    ///
+    /// [the reference]: https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-must_use-attribute
     pub UNUSED_MUST_USE,
     Warn,
     "unused result of a type flagged as `#[must_use]`",
 }
 
 declare_lint! {
+    /// The `unused_results` lint checks for the unused result of an
+    /// expression in a statement.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// #![deny(unused_results)]
+    /// fn foo<T>() -> T { panic!() }
+    ///
+    /// fn main() {
+    ///     foo::<usize>();
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Ignoring the return value of a function may indicate a mistake. In
+    /// cases were it is almost certain that the result should be used, it is
+    /// recommended to annotate the function with the [`must_use` attribute].
+    /// Failure to use such a return value will trigger the [`unused_must_use`
+    /// lint] which is warn-by-default. The `unused_results` lint is
+    /// essentially the same, but triggers for *all* return values.
+    ///
+    /// This lint is "allow" by default because it can be noisy, and may not be
+    /// an actual problem. For example, calling the `remove` method of a `Vec`
+    /// or `HashMap` returns the previous value, which you may not care about.
+    /// Using this lint would require explicitly ignoring or discarding such
+    /// values.
+    ///
+    /// [`must_use` attribute]: https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-must_use-attribute
+    /// [`unused_must_use` lint]: warn-by-default.html#unused-must-use
     pub UNUSED_RESULTS,
     Allow,
     "unused result of an expression in a statement"
@@ -265,6 +321,21 @@ fn check_must_use_def(
 }
 
 declare_lint! {
+    /// The `path_statements` lint detects path statements with no effect.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// let x = 42;
+    ///
+    /// x;
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// It is usually a mistake to have a statement that has no effect.
     pub PATH_STATEMENTS,
     Warn,
     "path statements with no effect"
@@ -635,6 +706,21 @@ fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) {
 }
 
 declare_lint! {
+    /// The `unused_parens` lint detects `if`, `match`, `while` and `return`
+    /// with parentheses; they do not need them.
+    ///
+    /// ### Examples
+    ///
+    /// ```rust
+    /// if(true) {}
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// The parenthesis are not needed, and should be removed. This is the
+    /// preferred style for writing these expressions.
     pub(super) UNUSED_PARENS,
     Warn,
     "`if`, `match`, `while` and `return` do not need parentheses"
@@ -808,6 +894,23 @@ fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) {
 }
 
 declare_lint! {
+    /// The `unused_braces` lint detects unnecessary braces around an
+    /// expression.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// if { true } {
+    ///     // ...
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// The braces are not needed, and should be removed. This is the
+    /// preferred style for writing these expressions.
     pub(super) UNUSED_BRACES,
     Warn,
     "unnecessary braces around an expression"
@@ -929,6 +1032,30 @@ fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) {
 }
 
 declare_lint! {
+    /// The `unused_import_braces` lint catches unnecessary braces around an
+    /// imported item.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// #![deny(unused_import_braces)]
+    /// use test::{A};
+    ///
+    /// pub mod test {
+    ///     pub struct A;
+    /// }
+    /// # fn main() {}
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// If there is only a single item, then remove the braces (`use test::A;`
+    /// for example).
+    ///
+    /// This lint is "allow" by default because it is only enforcing a
+    /// stylistic choice.
     UNUSED_IMPORT_BRACES,
     Allow,
     "unnecessary braces around an imported item"
@@ -978,6 +1105,25 @@ fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) {
 }
 
 declare_lint! {
+    /// The `unused_allocation` lint detects unnecessary allocations that can
+    /// be eliminated.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// #![feature(box_syntax)]
+    /// fn main() {
+    ///     let a = (box [1,2,3]).len();
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// When a `box` expression is immediately coerced to a reference, then
+    /// the allocation is unnecessary, and a reference (using `&` or `&mut`)
+    /// should be used instead to avoid the allocation.
     pub(super) UNUSED_ALLOCATION,
     Warn,
     "detects unnecessary allocations that can be eliminated"
index 4b144f94ea70b6f5f838d1dfba95b317ce6900f7..f1975e78801ef9ba54d6b03a784fccef39405e4b 100644 (file)
@@ -17,6 +17,7 @@ rustc_middle = { path = "../rustc_middle" }
 rustc_attr = { path = "../rustc_attr" }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_errors = { path = "../rustc_errors" }
+rustc_feature = { path = "../rustc_feature" }
 rustc_hir = { path = "../rustc_hir" }
 rustc_hir_pretty = { path = "../rustc_hir_pretty" }
 rustc_target = { path = "../rustc_target" }
index 1786969a88905c37b4ac9a4c81f173359339dbc5..1e313b7edfc272131a230d2c9e29f16c7a2bc041 100644 (file)
@@ -40,6 +40,7 @@
 pub(super) struct EncodeContext<'a, 'tcx> {
     opaque: opaque::Encoder,
     tcx: TyCtxt<'tcx>,
+    feat: &'tcx rustc_feature::Features,
 
     tables: TableBuilders<'tcx>,
 
@@ -1132,15 +1133,25 @@ fn encode_inherent_implementations(&mut self, def_id: DefId) {
 
     fn encode_stability(&mut self, def_id: DefId) {
         debug!("EncodeContext::encode_stability({:?})", def_id);
-        if let Some(stab) = self.tcx.lookup_stability(def_id) {
-            record!(self.tables.stability[def_id] <- stab)
+
+        // The query lookup can take a measurable amount of time in crates with many items. Check if
+        // the stability attributes are even enabled before using their queries.
+        if self.feat.staged_api || self.tcx.sess.opts.debugging_opts.force_unstable_if_unmarked {
+            if let Some(stab) = self.tcx.lookup_stability(def_id) {
+                record!(self.tables.stability[def_id] <- stab)
+            }
         }
     }
 
     fn encode_const_stability(&mut self, def_id: DefId) {
         debug!("EncodeContext::encode_const_stability({:?})", def_id);
-        if let Some(stab) = self.tcx.lookup_const_stability(def_id) {
-            record!(self.tables.const_stability[def_id] <- stab)
+
+        // The query lookup can take a measurable amount of time in crates with many items. Check if
+        // the stability attributes are even enabled before using their queries.
+        if self.feat.staged_api || self.tcx.sess.opts.debugging_opts.force_unstable_if_unmarked {
+            if let Some(stab) = self.tcx.lookup_const_stability(def_id) {
+                record!(self.tables.const_stability[def_id] <- stab)
+            }
         }
     }
 
@@ -1979,6 +1990,7 @@ fn encode_metadata_impl(tcx: TyCtxt<'_>) -> EncodedMetadata {
     let mut ecx = EncodeContext {
         opaque: encoder,
         tcx,
+        feat: tcx.features(),
         tables: Default::default(),
         lazy_state: LazyState::NoNode,
         type_shorthands: Default::default(),
index 2580ac6bebd86cbfa437c0671aaf433c9b6b46ba..a60a17befeffdce2b344112e4508b5910445d03e 100644 (file)
@@ -124,6 +124,7 @@ pub struct ConstVariableOrigin {
 pub enum ConstVariableOriginKind {
     MiscVariable,
     ConstInference,
+    // FIXME(const_generics): Consider storing the `DefId` of the param here.
     ConstParameterDefinition(Symbol),
     SubstitutionPlaceholder,
 }
index d32a7a4062e27502e10fd91121a985e7b2e5536f..29daf7e9309aa36716a15ad9e430b5e5f3926580 100644 (file)
@@ -2285,8 +2285,8 @@ 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
-/// particular one must be wary of `NaN`!
+/// 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)]
 pub struct Constant<'tcx> {
index ae89b68942c96edadaba993440d24cec82293520..a554c80cdaa1a055ada188899a0f8893686e6a18 100644 (file)
@@ -348,13 +348,16 @@ pub struct MatchExpressionArmCause<'tcx> {
     pub prior_arms: Vec<Span>,
     pub last_ty: Ty<'tcx>,
     pub scrut_hir_id: hir::HirId,
+    pub opt_suggest_box_span: Option<Span>,
 }
 
 #[derive(Clone, Debug, PartialEq, Eq, Hash)]
 pub struct IfExpressionCause {
     pub then: Span,
+    pub else_sp: Span,
     pub outer: Option<Span>,
     pub semicolon: Option<Span>,
+    pub opt_suggest_box_span: Option<Span>,
 }
 
 #[derive(Clone, Debug, PartialEq, Eq, Hash, Lift)]
index 6a9bb8d6c284fc31d09a89c1e12ac8cd283cbfae..46ef5ff7dd8c5c97e71278b3df39e44040ef2716 100644 (file)
@@ -4,6 +4,7 @@
 use rustc_hir::def_id::DefId;
 use rustc_hir::lang_items::LangItem;
 use rustc_macros::HashStable;
+use rustc_span::Span;
 
 #[derive(Clone, Copy, Debug, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)]
 pub enum PointerCast {
@@ -113,6 +114,9 @@ pub enum Adjust<'tcx> {
 pub struct OverloadedDeref<'tcx> {
     pub region: ty::Region<'tcx>,
     pub mutbl: hir::Mutability,
+    /// The `Span` associated with the field access or method call
+    /// that triggered this overloaded deref.
+    pub span: Span,
 }
 
 impl<'tcx> OverloadedDeref<'tcx> {
index aacf61e5b425a28852d05b70b928ed7a160c026a..56746666e2f1fea12c9e2e1171b8a08201c08068 100644 (file)
@@ -66,8 +66,8 @@
 use std::ops::{Bound, Deref};
 use std::sync::Arc;
 
-/// A type that is not publicly constructable. This prevents people from making `TyKind::Error`
-/// except through `tcx.err*()`, which are in this module.
+/// A type that is not publicly constructable. This prevents people from making [`TyKind::Error`]s
+/// except through the error-reporting functions on a [`tcx`][TyCtxt].
 #[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
 #[derive(TyEncodable, TyDecodable, HashStable)]
 pub struct DelaySpanBugEmitted(());
index bc51c8b6cd41c6e1b3f9054678d9987d29f7d471..715319747e3900adf34732b690bc1e93a05ee94c 100644 (file)
@@ -202,33 +202,59 @@ pub fn suggest_constraining_type_param(
         //    Suggestion:
         //      fn foo<T>(t: T) where T: Foo, T: Bar {... }
         //                                          - insert: `, T: Zar`
+        //
+        // Additionally, there may be no `where` clause whatsoever in the case that this was
+        // reached because the generic parameter has a default:
+        //
+        //    Message:
+        //      trait Foo<T=()> {... }
+        //             - help: consider further restricting this type parameter with `where T: Zar`
+        //
+        //    Suggestion:
+        //      trait Foo<T=()> where T: Zar {... }
+        //                     - insert: `where T: Zar`
 
-        let mut param_spans = Vec::new();
+        if matches!(param.kind, hir::GenericParamKind::Type { default: Some(_), .. })
+            && generics.where_clause.predicates.len() == 0
+        {
+            // Suggest a bound, but there is no existing `where` clause *and* the type param has a
+            // default (`<T=Foo>`), so we suggest adding `where T: Bar`.
+            err.span_suggestion_verbose(
+                generics.where_clause.tail_span_for_suggestion(),
+                &msg_restrict_type_further,
+                format!(" where {}: {}", param_name, constraint),
+                Applicability::MachineApplicable,
+            );
+        } else {
+            let mut param_spans = Vec::new();
 
-        for predicate in generics.where_clause.predicates {
-            if let WherePredicate::BoundPredicate(WhereBoundPredicate {
-                span, bounded_ty, ..
-            }) = predicate
-            {
-                if let TyKind::Path(QPath::Resolved(_, path)) = &bounded_ty.kind {
-                    if let Some(segment) = path.segments.first() {
-                        if segment.ident.to_string() == param_name {
-                            param_spans.push(span);
+            for predicate in generics.where_clause.predicates {
+                if let WherePredicate::BoundPredicate(WhereBoundPredicate {
+                    span,
+                    bounded_ty,
+                    ..
+                }) = predicate
+                {
+                    if let TyKind::Path(QPath::Resolved(_, path)) = &bounded_ty.kind {
+                        if let Some(segment) = path.segments.first() {
+                            if segment.ident.to_string() == param_name {
+                                param_spans.push(span);
+                            }
                         }
                     }
                 }
             }
-        }
 
-        match &param_spans[..] {
-            &[&param_span] => suggest_restrict(param_span.shrink_to_hi()),
-            _ => {
-                err.span_suggestion_verbose(
-                    generics.where_clause.tail_span_for_suggestion(),
-                    &msg_restrict_type_further,
-                    format!(", {}: {}", param_name, constraint),
-                    Applicability::MachineApplicable,
-                );
+            match &param_spans[..] {
+                &[&param_span] => suggest_restrict(param_span.shrink_to_hi()),
+                _ => {
+                    err.span_suggestion_verbose(
+                        generics.where_clause.tail_span_for_suggestion(),
+                        &msg_restrict_type_further,
+                        format!(", {}: {}", param_name, constraint),
+                        Applicability::MachineApplicable,
+                    );
+                }
             }
         }
 
index afbf805975ce76e8f5875b5be86177c39a479255..6d9d23836fc69d920284317bde8689d07d6f887f 100644 (file)
@@ -612,8 +612,11 @@ fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
 impl<'a, 'tcx> Lift<'tcx> for ty::adjustment::OverloadedDeref<'a> {
     type Lifted = ty::adjustment::OverloadedDeref<'tcx>;
     fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
-        tcx.lift(&self.region)
-            .map(|region| ty::adjustment::OverloadedDeref { region, mutbl: self.mutbl })
+        tcx.lift(&self.region).map(|region| ty::adjustment::OverloadedDeref {
+            region,
+            mutbl: self.mutbl,
+            span: self.span,
+        })
     }
 }
 
index 9f5fc5a2d3fbccc428e429954403ada0e344e791..d4c8ba082751e89a13abeb1a95c9fc7e0ce6239e 100644 (file)
@@ -1233,13 +1233,13 @@ pub fn to_const(self, tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> &'tcx ty::Const<'tcx>
     /// particular, imagine a type like this:
     ///
     ///     for<'a> fn(for<'b> fn(&'b isize, &'a isize), &'a char)
-    ///     ^          ^            |        |         |
-    ///     |          |            |        |         |
-    ///     |          +------------+ 0      |         |
-    ///     |                                |         |
-    ///     +--------------------------------+ 1       |
-    ///     |                                          |
-    ///     +------------------------------------------+ 0
+    ///     ^          ^            |          |           |
+    ///     |          |            |          |           |
+    ///     |          +------------+ 0        |           |
+    ///     |                                  |           |
+    ///     +----------------------------------+ 1         |
+    ///     |                                              |
+    ///     +----------------------------------------------+ 0
     ///
     /// In this type, there are two binders (the outer fn and the inner
     /// fn). We need to be able to determine, for any given region, which
@@ -2280,6 +2280,12 @@ pub fn to_opt_closure_kind(&self) -> Option<ty::ClosureKind> {
     ///
     /// Returning true means the type is known to be sized. Returning
     /// `false` means nothing -- could be sized, might not be.
+    ///
+    /// Note that we could never rely on the fact that a type such as `[_]` is
+    /// trivially `!Sized` because we could be in a type environment with a
+    /// bound such as `[_]: Copy`. A function with such a bound obviously never
+    /// can be called, but that doesn't mean it shouldn't typecheck. This is why
+    /// this method doesn't return `Option<bool>`.
     pub fn is_trivially_sized(&self, tcx: TyCtxt<'tcx>) -> bool {
         match self.kind() {
             ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
index 676065007b7ef5cf107c8771e929e33306812359..11122b195c0c4bf2c7fe4173688afe12753fd3b5 100644 (file)
@@ -66,7 +66,10 @@ pub(in crate::borrow_check) fn report_use_of_moved_or_uninitialized(
         let span = use_spans.args_or_use();
 
         let move_site_vec = self.get_moved_indexes(location, mpi);
-        debug!("report_use_of_moved_or_uninitialized: move_site_vec={:?}", move_site_vec);
+        debug!(
+            "report_use_of_moved_or_uninitialized: move_site_vec={:?} use_spans={:?}",
+            move_site_vec, use_spans
+        );
         let move_out_indices: Vec<_> =
             move_site_vec.iter().map(|move_site| move_site.moi).collect();
 
@@ -229,6 +232,8 @@ pub(in crate::borrow_check) fn report_use_of_moved_or_uninitialized(
                                     );
                                 }
                             }
+                            // Deref::deref takes &self, which cannot cause a move
+                            FnSelfUseKind::DerefCoercion { .. } => unreachable!(),
                         }
                     } else {
                         err.span_label(
@@ -355,6 +360,20 @@ pub(in crate::borrow_check) fn report_use_of_moved_or_uninitialized(
                 self.note_type_does_not_implement_copy(&mut err, &note_msg, ty, span, partial_str);
             }
 
+            if let UseSpans::FnSelfUse {
+                kind: FnSelfUseKind::DerefCoercion { deref_target, deref_target_ty },
+                ..
+            } = use_spans
+            {
+                err.note(&format!(
+                    "{} occurs due to deref coercion to `{}`",
+                    desired_action.as_noun(),
+                    deref_target_ty
+                ));
+
+                err.span_note(deref_target, "deref defined here");
+            }
+
             if let Some((_, mut old_err)) =
                 self.move_error_reported.insert(move_out_indices, (used_place, err))
             {
@@ -945,7 +964,7 @@ fn report_local_value_does_not_live_long_enough(
         name: &str,
         borrow: &BorrowData<'tcx>,
         drop_span: Span,
-        borrow_spans: UseSpans,
+        borrow_spans: UseSpans<'tcx>,
         explanation: BorrowExplanation,
     ) -> DiagnosticBuilder<'cx> {
         debug!(
@@ -1146,7 +1165,7 @@ fn report_temporary_value_does_not_live_long_enough(
         location: Location,
         borrow: &BorrowData<'tcx>,
         drop_span: Span,
-        borrow_spans: UseSpans,
+        borrow_spans: UseSpans<'tcx>,
         proper_span: Span,
         explanation: BorrowExplanation,
     ) -> DiagnosticBuilder<'cx> {
@@ -1274,7 +1293,7 @@ fn try_report_cannot_return_reference_to_local(
 
     fn report_escaping_closure_capture(
         &mut self,
-        use_span: UseSpans,
+        use_span: UseSpans<'tcx>,
         var_span: Span,
         fr_name: &RegionName,
         category: ConstraintCategory,
index eaaf202f3bd13484a1bc7b3459d1c34189e79485..eccb6168229c29f5949ef6f468ff03bd6cfb1175 100644 (file)
@@ -501,7 +501,7 @@ fn is_back_edge(&self, source: Location, target: Location) -> bool {
     fn later_use_kind(
         &self,
         borrow: &BorrowData<'tcx>,
-        use_spans: UseSpans,
+        use_spans: UseSpans<'tcx>,
         location: Location,
     ) -> (LaterUseKind, Span) {
         match use_spans {
index 3cee32834beb7579b54382b5a14d19929d6b837a..4256f6e39d5e863234dcefda647b0994c5fc4bc2 100644 (file)
@@ -11,7 +11,7 @@
     PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind,
 };
 use rustc_middle::ty::print::Print;
-use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt};
+use rustc_middle::ty::{self, DefIdTree, Instance, Ty, TyCtxt};
 use rustc_span::{
     hygiene::{DesugaringKind, ForLoopLoc},
     symbol::sym,
@@ -538,7 +538,7 @@ pub(super) fn get_region_name_for_ty(&self, ty: Ty<'tcx>, counter: usize) -> Str
 
 /// The span(s) associated to a use of a place.
 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
-pub(super) enum UseSpans {
+pub(super) enum UseSpans<'tcx> {
     /// The access is caused by capturing a variable for a closure.
     ClosureUse {
         /// This is true if the captured variable was from a generator.
@@ -558,7 +558,7 @@ pub(super) enum UseSpans {
         fn_call_span: Span,
         /// The definition span of the method being called
         fn_span: Span,
-        kind: FnSelfUseKind,
+        kind: FnSelfUseKind<'tcx>,
     },
     /// This access is caused by a `match` or `if let` pattern.
     PatUse(Span),
@@ -567,22 +567,32 @@ pub(super) enum UseSpans {
 }
 
 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
-pub(super) enum FnSelfUseKind {
+pub(super) enum FnSelfUseKind<'tcx> {
     /// A normal method call of the form `receiver.foo(a, b, c)`
     Normal { self_arg: Ident, implicit_into_iter: bool },
     /// A call to `FnOnce::call_once`, desugared from `my_closure(a, b, c)`
     FnOnceCall,
     /// A call to an operator trait, desuraged from operator syntax (e.g. `a << b`)
     Operator { self_arg: Ident },
+    DerefCoercion {
+        /// The `Span` of the `Target` associated type
+        /// in the `Deref` impl we are using.
+        deref_target: Span,
+        /// The type `T::Deref` we are dereferencing to
+        deref_target_ty: Ty<'tcx>,
+    },
 }
 
-impl UseSpans {
+impl UseSpans<'_> {
     pub(super) fn args_or_use(self) -> Span {
         match self {
             UseSpans::ClosureUse { args_span: span, .. }
             | UseSpans::PatUse(span)
-            | UseSpans::FnSelfUse { var_span: span, .. }
             | UseSpans::OtherUse(span) => span,
+            UseSpans::FnSelfUse {
+                fn_call_span, kind: FnSelfUseKind::DerefCoercion { .. }, ..
+            } => fn_call_span,
+            UseSpans::FnSelfUse { var_span, .. } => var_span,
         }
     }
 
@@ -590,8 +600,11 @@ pub(super) fn var_or_use(self) -> Span {
         match self {
             UseSpans::ClosureUse { var_span: span, .. }
             | UseSpans::PatUse(span)
-            | UseSpans::FnSelfUse { var_span: span, .. }
             | UseSpans::OtherUse(span) => span,
+            UseSpans::FnSelfUse {
+                fn_call_span, kind: FnSelfUseKind::DerefCoercion { .. }, ..
+            } => fn_call_span,
+            UseSpans::FnSelfUse { var_span, .. } => var_span,
         }
     }
 
@@ -754,7 +767,7 @@ pub(super) fn move_spans(
         &self,
         moved_place: PlaceRef<'tcx>, // Could also be an upvar.
         location: Location,
-    ) -> UseSpans {
+    ) -> UseSpans<'tcx> {
         use self::UseSpans::*;
 
         let stmt = match self.body[location.block].statements.get(location.statement_index) {
@@ -809,36 +822,64 @@ pub(super) fn move_spans(
             kind: TerminatorKind::Call { fn_span, from_hir_call, .. }, ..
         }) = &self.body[location.block].terminator
         {
-            let method_did = if let Some(method_did) =
+            let (method_did, method_substs) = if let Some(info) =
                 crate::util::find_self_call(self.infcx.tcx, &self.body, target_temp, location.block)
             {
-                method_did
+                info
             } else {
                 return normal_ret;
             };
 
             let tcx = self.infcx.tcx;
-
             let parent = tcx.parent(method_did);
             let is_fn_once = parent == tcx.lang_items().fn_once_trait();
             let is_operator = !from_hir_call
                 && parent.map_or(false, |p| tcx.lang_items().group(LangItemGroup::Op).contains(&p));
+            let is_deref = !from_hir_call && tcx.is_diagnostic_item(sym::deref_method, method_did);
             let fn_call_span = *fn_span;
 
             let self_arg = tcx.fn_arg_names(method_did)[0];
 
+            debug!(
+                "terminator = {:?} from_hir_call={:?}",
+                self.body[location.block].terminator, from_hir_call
+            );
+
+            // Check for a 'special' use of 'self' -
+            // an FnOnce call, an operator (e.g. `<<`), or a
+            // deref coercion.
             let kind = if is_fn_once {
-                FnSelfUseKind::FnOnceCall
+                Some(FnSelfUseKind::FnOnceCall)
             } else if is_operator {
-                FnSelfUseKind::Operator { self_arg }
+                Some(FnSelfUseKind::Operator { self_arg })
+            } else if is_deref {
+                let deref_target =
+                    tcx.get_diagnostic_item(sym::deref_target).and_then(|deref_target| {
+                        Instance::resolve(tcx, self.param_env, deref_target, method_substs)
+                            .transpose()
+                    });
+                if let Some(Ok(instance)) = deref_target {
+                    let deref_target_ty = instance.ty(tcx, self.param_env);
+                    Some(FnSelfUseKind::DerefCoercion {
+                        deref_target: tcx.def_span(instance.def_id()),
+                        deref_target_ty,
+                    })
+                } else {
+                    None
+                }
             } else {
+                None
+            };
+
+            let kind = kind.unwrap_or_else(|| {
+                // This isn't a 'special' use of `self`
                 debug!("move_spans: method_did={:?}, fn_call_span={:?}", method_did, fn_call_span);
                 let implicit_into_iter = matches!(
                     fn_call_span.desugaring_kind(),
                     Some(DesugaringKind::ForLoop(ForLoopLoc::IntoIter))
                 );
                 FnSelfUseKind::Normal { self_arg, implicit_into_iter }
-            };
+            });
 
             return FnSelfUse {
                 var_span: stmt.source_info.span,
@@ -859,7 +900,7 @@ pub(super) fn move_spans(
     /// and its usage of the local assigned at `location`.
     /// This is done by searching in statements succeeding `location`
     /// and originating from `maybe_closure_span`.
-    pub(super) fn borrow_spans(&self, use_span: Span, location: Location) -> UseSpans {
+    pub(super) fn borrow_spans(&self, use_span: Span, location: Location) -> UseSpans<'tcx> {
         use self::UseSpans::*;
         debug!("borrow_spans: use_span={:?} location={:?}", use_span, location);
 
@@ -963,7 +1004,7 @@ fn closure_span(
 
     /// Helper to retrieve span(s) of given borrow from the current MIR
     /// representation
-    pub(super) fn retrieve_borrow_spans(&self, borrow: &BorrowData<'_>) -> UseSpans {
+    pub(super) fn retrieve_borrow_spans(&self, borrow: &BorrowData<'_>) -> UseSpans<'tcx> {
         let span = self.body.source_info(borrow.reserve_location).span;
         self.borrow_spans(span, borrow.reserve_location)
     }
index 6cf1cf20b5afd0f3a5183950d9a44e0acf564a36..e256fb55b124b70a2d3eec66140982b394056a05 100644 (file)
@@ -47,7 +47,7 @@ enum GroupedMoveError<'tcx> {
     // Everything that isn't from pattern matching.
     OtherIllegalMove {
         original_path: Place<'tcx>,
-        use_spans: UseSpans,
+        use_spans: UseSpans<'tcx>,
         kind: IllegalMoveOriginKind<'tcx>,
     },
 }
@@ -222,7 +222,7 @@ fn report(&mut self, error: GroupedMoveError<'tcx>) {
         let (mut err, err_span) = {
             let (span, use_spans, original_path, kind): (
                 Span,
-                Option<UseSpans>,
+                Option<UseSpans<'tcx>>,
                 Place<'tcx>,
                 &IllegalMoveOriginKind<'_>,
             ) = match error {
@@ -291,7 +291,7 @@ fn report_cannot_move_from_borrowed_content(
         move_place: Place<'tcx>,
         deref_target_place: Place<'tcx>,
         span: Span,
-        use_spans: Option<UseSpans>,
+        use_spans: Option<UseSpans<'tcx>>,
     ) -> DiagnosticBuilder<'a> {
         // Inspect the type of the content behind the
         // borrow to provide feedback about why this
index acd9e3dcf3fcd44a40343908ad7d71c80c192482..64ad0627720aa0286b26af7ab2a6bccfb4269ba4 100644 (file)
@@ -17,7 +17,7 @@
 use rustc_middle::mir::{Field, ProjectionElem, Promoted, Rvalue, Statement, StatementKind};
 use rustc_middle::mir::{InlineAsmOperand, Terminator, TerminatorKind};
 use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::{self, InstanceDef, RegionVid, TyCtxt};
+use rustc_middle::ty::{self, InstanceDef, ParamEnv, RegionVid, TyCtxt};
 use rustc_session::lint::builtin::{MUTABLE_BORROW_RESERVATION_CONFLICT, UNUSED_MUT};
 use rustc_span::{Span, Symbol, DUMMY_SP};
 
@@ -287,6 +287,7 @@ fn do_mir_borrowck<'a, 'tcx>(
         if let Err((move_data, move_errors)) = move_data_results {
             let mut promoted_mbcx = MirBorrowckCtxt {
                 infcx,
+                param_env,
                 body: promoted_body,
                 mir_def_id: def.did,
                 move_data: &move_data,
@@ -320,6 +321,7 @@ fn do_mir_borrowck<'a, 'tcx>(
 
     let mut mbcx = MirBorrowckCtxt {
         infcx,
+        param_env,
         body,
         mir_def_id: def.did,
         move_data: &mdpe.move_data,
@@ -473,6 +475,7 @@ fn do_mir_borrowck<'a, 'tcx>(
 
 crate struct MirBorrowckCtxt<'cx, 'tcx> {
     crate infcx: &'cx InferCtxt<'cx, 'tcx>,
+    param_env: ParamEnv<'tcx>,
     body: &'cx Body<'tcx>,
     mir_def_id: LocalDefId,
     move_data: &'cx MoveData<'tcx>,
index b48bae837877979462f3da9ce6b2d998df8d1da1..827d037f3198888888f36188d4470fbb122b2544 100644 (file)
@@ -11,6 +11,7 @@
 use rustc_middle::ty::{self, DefIdTree, InstanceDef, TyCtxt};
 use rustc_span::symbol::Symbol;
 
+use super::PartitioningCx;
 use crate::monomorphize::collector::InliningMap;
 use crate::monomorphize::partitioning::merging;
 use crate::monomorphize::partitioning::{
 impl<'tcx> Partitioner<'tcx> for DefaultPartitioning {
     fn place_root_mono_items(
         &mut self,
-        tcx: TyCtxt<'tcx>,
+        cx: &PartitioningCx<'_, 'tcx>,
         mono_items: &mut dyn Iterator<Item = MonoItem<'tcx>>,
     ) -> PreInliningPartitioning<'tcx> {
         let mut roots = FxHashSet::default();
         let mut codegen_units = FxHashMap::default();
-        let is_incremental_build = tcx.sess.opts.incremental.is_some();
+        let is_incremental_build = cx.tcx.sess.opts.incremental.is_some();
         let mut internalization_candidates = FxHashSet::default();
 
         // Determine if monomorphizations instantiated in this crate will be made
         // available to downstream crates. This depends on whether we are in
         // share-generics mode and whether the current crate can even have
         // downstream crates.
-        let export_generics = tcx.sess.opts.share_generics() && tcx.local_crate_exports_generics();
+        let export_generics =
+            cx.tcx.sess.opts.share_generics() && cx.tcx.local_crate_exports_generics();
 
-        let cgu_name_builder = &mut CodegenUnitNameBuilder::new(tcx);
+        let cgu_name_builder = &mut CodegenUnitNameBuilder::new(cx.tcx);
         let cgu_name_cache = &mut FxHashMap::default();
 
         for mono_item in mono_items {
-            match mono_item.instantiation_mode(tcx) {
+            match mono_item.instantiation_mode(cx.tcx) {
                 InstantiationMode::GloballyShared { .. } => {}
                 InstantiationMode::LocalCopy => continue,
             }
 
-            let characteristic_def_id = characteristic_def_id_of_mono_item(tcx, mono_item);
+            let characteristic_def_id = characteristic_def_id_of_mono_item(cx.tcx, mono_item);
             let is_volatile = is_incremental_build && mono_item.is_generic_fn();
 
             let codegen_unit_name = match characteristic_def_id {
                 Some(def_id) => compute_codegen_unit_name(
-                    tcx,
+                    cx.tcx,
                     cgu_name_builder,
                     def_id,
                     is_volatile,
@@ -65,7 +67,7 @@ fn place_root_mono_items(
 
             let mut can_be_internalized = true;
             let (linkage, visibility) = mono_item_linkage_and_visibility(
-                tcx,
+                cx.tcx,
                 &mono_item,
                 &mut can_be_internalized,
                 export_generics,
@@ -97,17 +99,16 @@ fn place_root_mono_items(
 
     fn merge_codegen_units(
         &mut self,
-        tcx: TyCtxt<'tcx>,
+        cx: &PartitioningCx<'_, 'tcx>,
         initial_partitioning: &mut PreInliningPartitioning<'tcx>,
-        target_cgu_count: usize,
     ) {
-        merging::merge_codegen_units(tcx, initial_partitioning, target_cgu_count);
+        merging::merge_codegen_units(cx, initial_partitioning);
     }
 
     fn place_inlined_mono_items(
         &mut self,
+        cx: &PartitioningCx<'_, 'tcx>,
         initial_partitioning: PreInliningPartitioning<'tcx>,
-        inlining_map: &InliningMap<'tcx>,
     ) -> PostInliningPartitioning<'tcx> {
         let mut new_partitioning = Vec::new();
         let mut mono_item_placements = FxHashMap::default();
@@ -124,7 +125,7 @@ fn place_inlined_mono_items(
             // Collect all items that need to be available in this codegen unit.
             let mut reachable = FxHashSet::default();
             for root in old_codegen_unit.items().keys() {
-                follow_inlining(*root, inlining_map, &mut reachable);
+                follow_inlining(*root, cx.inlining_map, &mut reachable);
             }
 
             let mut new_codegen_unit = CodegenUnit::new(old_codegen_unit.name());
@@ -198,9 +199,8 @@ fn follow_inlining<'tcx>(
 
     fn internalize_symbols(
         &mut self,
-        _tcx: TyCtxt<'tcx>,
+        cx: &PartitioningCx<'_, 'tcx>,
         partitioning: &mut PostInliningPartitioning<'tcx>,
-        inlining_map: &InliningMap<'tcx>,
     ) {
         if partitioning.codegen_units.len() == 1 {
             // Fast path for when there is only one codegen unit. In this case we
@@ -218,7 +218,7 @@ fn internalize_symbols(
         // Build a map from every monomorphization to all the monomorphizations that
         // reference it.
         let mut accessor_map: FxHashMap<MonoItem<'tcx>, Vec<MonoItem<'tcx>>> = Default::default();
-        inlining_map.iter_accesses(|accessor, accessees| {
+        cx.inlining_map.iter_accesses(|accessor, accessees| {
             for accessee in accessees {
                 accessor_map.entry(*accessee).or_default().push(accessor);
             }
index 1787e6df1b9c720c79096e472d7b068a4046f90a..5107e6972632c2d2a295c6e4e8a2608697bacd97 100644 (file)
@@ -3,17 +3,16 @@
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::def_id::LOCAL_CRATE;
 use rustc_middle::mir::mono::{CodegenUnit, CodegenUnitNameBuilder};
-use rustc_middle::ty::TyCtxt;
 use rustc_span::symbol::{Symbol, SymbolStr};
 
+use super::PartitioningCx;
 use crate::monomorphize::partitioning::PreInliningPartitioning;
 
 pub fn merge_codegen_units<'tcx>(
-    tcx: TyCtxt<'tcx>,
+    cx: &PartitioningCx<'_, 'tcx>,
     initial_partitioning: &mut PreInliningPartitioning<'tcx>,
-    target_cgu_count: usize,
 ) {
-    assert!(target_cgu_count >= 1);
+    assert!(cx.target_cgu_count >= 1);
     let codegen_units = &mut initial_partitioning.codegen_units;
 
     // Note that at this point in time the `codegen_units` here may not be in a
@@ -32,7 +31,7 @@ pub fn merge_codegen_units<'tcx>(
         codegen_units.iter().map(|cgu| (cgu.name(), vec![cgu.name().as_str()])).collect();
 
     // Merge the two smallest codegen units until the target size is reached.
-    while codegen_units.len() > target_cgu_count {
+    while codegen_units.len() > cx.target_cgu_count {
         // Sort small cgus to the back
         codegen_units.sort_by_cached_key(|cgu| cmp::Reverse(cgu.size_estimate()));
         let mut smallest = codegen_units.pop().unwrap();
@@ -56,9 +55,9 @@ pub fn merge_codegen_units<'tcx>(
         );
     }
 
-    let cgu_name_builder = &mut CodegenUnitNameBuilder::new(tcx);
+    let cgu_name_builder = &mut CodegenUnitNameBuilder::new(cx.tcx);
 
-    if tcx.sess.opts.incremental.is_some() {
+    if cx.tcx.sess.opts.incremental.is_some() {
         // If we are doing incremental compilation, we want CGU names to
         // reflect the path of the source level module they correspond to.
         // For CGUs that contain the code of multiple modules because of the
@@ -74,7 +73,9 @@ pub fn merge_codegen_units<'tcx>(
 
                 // Sort the names, so things are deterministic and easy to
                 // predict.
-                cgu_contents.sort();
+
+                // We are sorting primitive &strs here so we can use unstable sort
+                cgu_contents.sort_unstable();
 
                 (current_cgu_name, cgu_contents.join("--"))
             })
@@ -82,7 +83,7 @@ pub fn merge_codegen_units<'tcx>(
 
         for cgu in codegen_units.iter_mut() {
             if let Some(new_cgu_name) = new_cgu_names.get(&cgu.name()) {
-                if tcx.sess.opts.debugging_opts.human_readable_cgu_names {
+                if cx.tcx.sess.opts.debugging_opts.human_readable_cgu_names {
                     cgu.set_name(Symbol::intern(&new_cgu_name));
                 } else {
                     // If we don't require CGU names to be human-readable, we
index 0f6f078d9686f07e6163c8cd6175120353a21159..b60beca688068c8494e5e4211e92bcfd01543463 100644 (file)
 use crate::monomorphize::collector::InliningMap;
 use crate::monomorphize::collector::{self, MonoItemCollectionMode};
 
+pub struct PartitioningCx<'a, 'tcx> {
+    tcx: TyCtxt<'tcx>,
+    target_cgu_count: usize,
+    inlining_map: &'a InliningMap<'tcx>,
+}
+
 trait Partitioner<'tcx> {
     fn place_root_mono_items(
         &mut self,
-        tcx: TyCtxt<'tcx>,
+        cx: &PartitioningCx<'_, 'tcx>,
         mono_items: &mut dyn Iterator<Item = MonoItem<'tcx>>,
     ) -> PreInliningPartitioning<'tcx>;
 
     fn merge_codegen_units(
         &mut self,
-        tcx: TyCtxt<'tcx>,
+        cx: &PartitioningCx<'_, 'tcx>,
         initial_partitioning: &mut PreInliningPartitioning<'tcx>,
-        target_cgu_count: usize,
     );
 
     fn place_inlined_mono_items(
         &mut self,
+        cx: &PartitioningCx<'_, 'tcx>,
         initial_partitioning: PreInliningPartitioning<'tcx>,
-        inlining_map: &InliningMap<'tcx>,
     ) -> PostInliningPartitioning<'tcx>;
 
     fn internalize_symbols(
         &mut self,
-        tcx: TyCtxt<'tcx>,
+        cx: &PartitioningCx<'_, 'tcx>,
         partitioning: &mut PostInliningPartitioning<'tcx>,
-        inlining_map: &InliningMap<'tcx>,
     );
 }
 
@@ -157,12 +161,13 @@ pub fn partition<'tcx>(
     let _prof_timer = tcx.prof.generic_activity("cgu_partitioning");
 
     let mut partitioner = get_partitioner(tcx);
+    let cx = &PartitioningCx { tcx, target_cgu_count: max_cgu_count, inlining_map };
     // In the first step, we place all regular monomorphizations into their
     // respective 'home' codegen unit. Regular monomorphizations are all
     // functions and statics defined in the local crate.
     let mut initial_partitioning = {
         let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_place_roots");
-        partitioner.place_root_mono_items(tcx, mono_items)
+        partitioner.place_root_mono_items(cx, mono_items)
     };
 
     initial_partitioning.codegen_units.iter_mut().for_each(|cgu| cgu.estimate_size(tcx));
@@ -172,7 +177,7 @@ pub fn partition<'tcx>(
     // Merge until we have at most `max_cgu_count` codegen units.
     {
         let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_merge_cgus");
-        partitioner.merge_codegen_units(tcx, &mut initial_partitioning, max_cgu_count);
+        partitioner.merge_codegen_units(cx, &mut initial_partitioning);
         debug_dump(tcx, "POST MERGING:", initial_partitioning.codegen_units.iter());
     }
 
@@ -182,7 +187,7 @@ pub fn partition<'tcx>(
     // local functions the definition of which is marked with `#[inline]`.
     let mut post_inlining = {
         let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_place_inline_items");
-        partitioner.place_inlined_mono_items(initial_partitioning, inlining_map)
+        partitioner.place_inlined_mono_items(cx, initial_partitioning)
     };
 
     post_inlining.codegen_units.iter_mut().for_each(|cgu| cgu.estimate_size(tcx));
@@ -193,7 +198,7 @@ pub fn partition<'tcx>(
     // more freedom to optimize.
     if !tcx.sess.link_dead_code() {
         let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_internalize_symbols");
-        partitioner.internalize_symbols(tcx, &mut post_inlining, inlining_map);
+        partitioner.internalize_symbols(cx, &mut post_inlining);
     }
 
     // Finally, sort by codegen unit name, so that we get deterministic results.
index 589268e39bda9146e9ed1e2d86d8457b7f13db4f..70c1aed0957f8554279a33ca93924c8c1f7c800f 100644 (file)
@@ -101,7 +101,7 @@ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, loc: Location) {
                         .note("each usage of a `const` item creates a new temporary")
                         .note("the mutable reference will refer to this temporary, not the original `const` item");
 
-                    if let Some(method_did) = method_did {
+                    if let Some((method_did, _substs)) = method_did {
                         lint.span_note(self.tcx.def_span(method_did), "mutable reference created due to call to this method");
                     }
 
index d6e6371e886c4c0bd1cb0b6b088d8e024ce79b74..4e7cacc2f4af7b615eb43a92b16e40348bd2e88f 100644 (file)
@@ -506,7 +506,7 @@ fn dest_needs_borrow(place: Place<'_>) -> bool {
                 let return_block = destination.1;
 
                 // Copy the arguments if needed.
-                let args: Vec<_> = self.make_call_args(args, &callsite, caller_body);
+                let args: Vec<_> = self.make_call_args(args, &callsite, caller_body, return_block);
 
                 let bb_len = caller_body.basic_blocks().len();
                 let mut integrator = Integrator {
@@ -553,6 +553,7 @@ fn make_call_args(
         args: Vec<Operand<'tcx>>,
         callsite: &CallSite<'tcx>,
         caller_body: &mut Body<'tcx>,
+        return_block: BasicBlock,
     ) -> Vec<Local> {
         let tcx = self.tcx;
 
@@ -581,8 +582,18 @@ fn make_call_args(
         // and the vector is `[closure_ref, tmp0, tmp1, tmp2]`.
         if tcx.is_closure(callsite.callee) {
             let mut args = args.into_iter();
-            let self_ = self.create_temp_if_necessary(args.next().unwrap(), callsite, caller_body);
-            let tuple = self.create_temp_if_necessary(args.next().unwrap(), callsite, caller_body);
+            let self_ = self.create_temp_if_necessary(
+                args.next().unwrap(),
+                callsite,
+                caller_body,
+                return_block,
+            );
+            let tuple = self.create_temp_if_necessary(
+                args.next().unwrap(),
+                callsite,
+                caller_body,
+                return_block,
+            );
             assert!(args.next().is_none());
 
             let tuple = Place::from(tuple);
@@ -602,13 +613,13 @@ fn make_call_args(
                     Operand::Move(tcx.mk_place_field(tuple, Field::new(i), ty.expect_ty()));
 
                 // Spill to a local to make e.g., `tmp0`.
-                self.create_temp_if_necessary(tuple_field, callsite, caller_body)
+                self.create_temp_if_necessary(tuple_field, callsite, caller_body, return_block)
             });
 
             closure_ref_arg.chain(tuple_tmp_args).collect()
         } else {
             args.into_iter()
-                .map(|a| self.create_temp_if_necessary(a, callsite, caller_body))
+                .map(|a| self.create_temp_if_necessary(a, callsite, caller_body, return_block))
                 .collect()
         }
     }
@@ -620,6 +631,7 @@ fn create_temp_if_necessary(
         arg: Operand<'tcx>,
         callsite: &CallSite<'tcx>,
         caller_body: &mut Body<'tcx>,
+        return_block: BasicBlock,
     ) -> Local {
         // FIXME: Analysis of the usage of the arguments to avoid
         // unnecessary temporaries.
@@ -642,11 +654,19 @@ fn create_temp_if_necessary(
         let arg_tmp = LocalDecl::new(ty, callsite.location.span);
         let arg_tmp = caller_body.local_decls.push(arg_tmp);
 
-        let stmt = Statement {
+        caller_body[callsite.bb].statements.push(Statement {
+            source_info: callsite.location,
+            kind: StatementKind::StorageLive(arg_tmp),
+        });
+        caller_body[callsite.bb].statements.push(Statement {
             source_info: callsite.location,
             kind: StatementKind::Assign(box (Place::from(arg_tmp), arg)),
-        };
-        caller_body[callsite.bb].statements.push(stmt);
+        });
+        caller_body[return_block].statements.insert(
+            0,
+            Statement { source_info: callsite.location, kind: StatementKind::StorageDead(arg_tmp) },
+        );
+
         arg_tmp
     }
 }
index a320d00614d40b68afb63ff0cb91fdd67d741435..76a60c45575b8674e6520a7e740c6a1c5edb84af 100644 (file)
@@ -230,8 +230,8 @@ fn find_storage_live_dead_stmts_for_local<'tcx>(
             }
         }
     }
-
-    nop_stmts.sort();
+    // We sort primitive usize here so we can use unstable sort
+    nop_stmts.sort_unstable();
 
     // Use one of the statements we're going to discard between the point
     // where the storage location for the variant field becomes live and
index 049b5f01214cf49a8ccb76de10bd7202936994f0..5b146eeb87c044956846f6f5c4a33e7e9ad1a5cc 100644 (file)
@@ -1,30 +1,31 @@
 use rustc_middle::mir::*;
+use rustc_middle::ty::subst::SubstsRef;
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_span::def_id::DefId;
 
 /// Checks if the specified `local` is used as the `self` prameter of a method call
 /// in the provided `BasicBlock`. If it is, then the `DefId` of the called method is
 /// returned.
-pub fn find_self_call(
-    tcx: TyCtxt<'_>,
-    body: &Body<'_>,
+pub fn find_self_call<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    body: &Body<'tcx>,
     local: Local,
     block: BasicBlock,
-) -> Option<DefId> {
+) -> Option<(DefId, SubstsRef<'tcx>)> {
     debug!("find_self_call(local={:?}): terminator={:?}", local, &body[block].terminator);
     if let Some(Terminator { kind: TerminatorKind::Call { func, args, .. }, .. }) =
         &body[block].terminator
     {
         debug!("find_self_call: func={:?}", func);
         if let Operand::Constant(box Constant { literal: ty::Const { ty, .. }, .. }) = func {
-            if let ty::FnDef(def_id, _) = *ty.kind() {
+            if let ty::FnDef(def_id, substs) = *ty.kind() {
                 if let Some(ty::AssocItem { fn_has_self_parameter: true, .. }) =
                     tcx.opt_associated_item(def_id)
                 {
                     debug!("find_self_call: args={:?}", args);
                     if let [Operand::Move(self_place) | Operand::Copy(self_place), ..] = **args {
                         if self_place.as_local() == Some(local) {
-                            return Some(def_id);
+                            return Some((def_id, substs));
                         }
                     }
                 }
index 70c7abc2654927519d18758b8b8fbf1682b24d57..13e69474cfb965b706f45ff1d4ce092803a8b2f1 100644 (file)
@@ -117,7 +117,14 @@ fn apply_adjustment<'a, 'tcx>(
                 },
             };
 
-            overloaded_place(cx, hir_expr, adjustment.target, Some(call), vec![expr.to_ref()])
+            overloaded_place(
+                cx,
+                hir_expr,
+                adjustment.target,
+                Some(call),
+                vec![expr.to_ref()],
+                deref.span,
+            )
         }
         Adjust::Borrow(AutoBorrow::Ref(_, m)) => {
             ExprKind::Borrow { borrow_kind: m.to_borrow_kind(), arg: expr.to_ref() }
@@ -277,7 +284,14 @@ fn make_mirror_unadjusted<'a, 'tcx>(
 
         hir::ExprKind::Index(ref lhs, ref index) => {
             if cx.typeck_results().is_method_call(expr) {
-                overloaded_place(cx, expr, expr_ty, None, vec![lhs.to_ref(), index.to_ref()])
+                overloaded_place(
+                    cx,
+                    expr,
+                    expr_ty,
+                    None,
+                    vec![lhs.to_ref(), index.to_ref()],
+                    expr.span,
+                )
             } else {
                 ExprKind::Index { lhs: lhs.to_ref(), index: index.to_ref() }
             }
@@ -285,7 +299,7 @@ fn make_mirror_unadjusted<'a, 'tcx>(
 
         hir::ExprKind::Unary(hir::UnOp::UnDeref, ref arg) => {
             if cx.typeck_results().is_method_call(expr) {
-                overloaded_place(cx, expr, expr_ty, None, vec![arg.to_ref()])
+                overloaded_place(cx, expr, expr_ty, None, vec![arg.to_ref()], expr.span)
             } else {
                 ExprKind::Deref { arg: arg.to_ref() }
             }
@@ -1025,6 +1039,7 @@ fn overloaded_place<'a, 'tcx>(
     place_ty: Ty<'tcx>,
     overloaded_callee: Option<(DefId, SubstsRef<'tcx>)>,
     args: Vec<ExprRef<'tcx>>,
+    span: Span,
 ) -> ExprKind<'tcx> {
     // For an overloaded *x or x[y] expression of type T, the method
     // call returns an &T and we must add the deref so that the types
@@ -1040,24 +1055,24 @@ fn overloaded_place<'a, 'tcx>(
     // `Deref(Mut)::Deref(_mut)` and `Index(Mut)::index(_mut)`.
     let (region, mutbl) = match *recv_ty.kind() {
         ty::Ref(region, _, mutbl) => (region, mutbl),
-        _ => span_bug!(expr.span, "overloaded_place: receiver is not a reference"),
+        _ => span_bug!(span, "overloaded_place: receiver is not a reference"),
     };
     let ref_ty = cx.tcx.mk_ref(region, ty::TypeAndMut { ty: place_ty, mutbl });
 
     // construct the complete expression `foo()` for the overloaded call,
     // which will yield the &T type
     let temp_lifetime = cx.region_scope_tree.temporary_scope(expr.hir_id.local_id);
-    let fun = method_callee(cx, expr, expr.span, overloaded_callee);
+    let fun = method_callee(cx, expr, span, overloaded_callee);
     let ref_expr = Expr {
         temp_lifetime,
         ty: ref_ty,
-        span: expr.span,
+        span,
         kind: ExprKind::Call {
             ty: fun.ty,
             fun: fun.to_ref(),
             args,
             from_hir_call: false,
-            fn_span: expr.span,
+            fn_span: span,
         },
     };
 
index e2a735188f95ced5501d65c959c8a3419f6dd4c2..9ab13db4b5f9650991e24cd1fd35bb2423ce70b7 100644 (file)
@@ -553,6 +553,52 @@ pub(super) fn check_turbofish_missing_angle_brackets(&mut self, segment: &mut Pa
         }
     }
 
+    /// When writing a turbofish with multiple type parameters missing the leading `::`, we will
+    /// encounter a parse error when encountering the first `,`.
+    pub(super) fn check_mistyped_turbofish_with_multiple_type_params(
+        &mut self,
+        mut e: DiagnosticBuilder<'a>,
+        expr: &mut P<Expr>,
+    ) -> PResult<'a, ()> {
+        if let ExprKind::Binary(binop, _, _) = &expr.kind {
+            if let ast::BinOpKind::Lt = binop.node {
+                if self.eat(&token::Comma) {
+                    let x = self.parse_seq_to_before_end(
+                        &token::Gt,
+                        SeqSep::trailing_allowed(token::Comma),
+                        |p| p.parse_ty(),
+                    );
+                    match x {
+                        Ok((_, _, false)) => {
+                            self.bump(); // `>`
+                            match self.parse_expr() {
+                                Ok(_) => {
+                                    e.span_suggestion_verbose(
+                                        binop.span.shrink_to_lo(),
+                                        "use `::<...>` instead of `<...>` to specify type arguments",
+                                        "::".to_string(),
+                                        Applicability::MaybeIncorrect,
+                                    );
+                                    e.emit();
+                                    *expr = self.mk_expr_err(expr.span.to(self.prev_token.span));
+                                    return Ok(());
+                                }
+                                Err(mut err) => {
+                                    err.cancel();
+                                }
+                            }
+                        }
+                        Err(mut err) => {
+                            err.cancel();
+                        }
+                        _ => {}
+                    }
+                }
+            }
+        }
+        Err(e)
+    }
+
     /// Check to see if a pair of chained operators looks like an attempt at chained comparison,
     /// e.g. `1 < x <= 3`. If so, suggest either splitting the comparison into two, or
     /// parenthesising the leftmost comparison.
index 64b959e83251d2c29c316c364546fffdfb1a2cd3..fd1c6b25aec63eb8c1c56aab2777cffac5e8b335 100644 (file)
@@ -364,7 +364,7 @@ pub fn parse_full_stmt(&mut self) -> PResult<'a, Option<Stmt>> {
         let mut eat_semi = true;
         match stmt.kind {
             // Expression without semicolon.
-            StmtKind::Expr(ref expr)
+            StmtKind::Expr(ref mut expr)
                 if self.token != token::Eof && classify::expr_requires_semi_to_be_stmt(expr) =>
             {
                 // Just check for errors and recover; do not eat semicolon yet.
@@ -388,15 +388,29 @@ pub fn parse_full_stmt(&mut self) -> PResult<'a, Option<Stmt>> {
                             );
                         }
                     }
-                    e.emit();
-                    self.recover_stmt();
+                    if let Err(mut e) =
+                        self.check_mistyped_turbofish_with_multiple_type_params(e, expr)
+                    {
+                        e.emit();
+                        self.recover_stmt();
+                    }
                     // Don't complain about type errors in body tail after parse error (#57383).
                     let sp = expr.span.to(self.prev_token.span);
-                    stmt.kind = StmtKind::Expr(self.mk_expr_err(sp));
+                    *expr = self.mk_expr_err(sp);
                 }
             }
-            StmtKind::Local(..) => {
-                self.expect_semi()?;
+            StmtKind::Local(ref mut local) => {
+                if let Err(e) = self.expect_semi() {
+                    // We might be at the `,` in `let x = foo<bar, baz>;`. Try to recover.
+                    match &mut local.init {
+                        Some(ref mut expr) => {
+                            self.check_mistyped_turbofish_with_multiple_type_params(e, expr)?;
+                            // We found `foo<bar, baz>`, have we fully recovered?
+                            self.expect_semi()?;
+                        }
+                        None => return Err(e),
+                    }
+                }
                 eat_semi = false;
             }
             StmtKind::Empty => eat_semi = false,
index 259764a317df808aea6dddfde6b50d43ad88f431..fc4c62ccbd90e7b4865827d2bc3997b2360ce012 100644 (file)
@@ -276,8 +276,34 @@ fn parse_array_or_slice_ty(&mut self) -> PResult<'a, TyKind> {
     }
 
     fn parse_borrowed_pointee(&mut self) -> PResult<'a, TyKind> {
-        let opt_lifetime = if self.check_lifetime() { Some(self.expect_lifetime()) } else { None };
+        let and_span = self.prev_token.span;
+        let mut opt_lifetime =
+            if self.check_lifetime() { Some(self.expect_lifetime()) } else { None };
         let mutbl = self.parse_mutability();
+        if self.token.is_lifetime() && mutbl == Mutability::Mut && opt_lifetime.is_none() {
+            // A lifetime is invalid here: it would be part of a bare trait bound, which requires
+            // it to be followed by a plus, but we disallow plus in the pointee type.
+            // So we can handle this case as an error here, and suggest `'a mut`.
+            // If there *is* a plus next though, handling the error later provides better suggestions
+            // (like adding parentheses)
+            if !self.look_ahead(1, |t| t.is_like_plus()) {
+                let lifetime_span = self.token.span;
+                let span = and_span.to(lifetime_span);
+
+                let mut err = self.struct_span_err(span, "lifetime must precede `mut`");
+                if let Ok(lifetime_src) = self.span_to_snippet(lifetime_span) {
+                    err.span_suggestion(
+                        span,
+                        "place the lifetime before `mut`",
+                        format!("&{} mut", lifetime_src),
+                        Applicability::MaybeIncorrect,
+                    );
+                }
+                err.emit();
+
+                opt_lifetime = Some(self.expect_lifetime());
+            }
+        }
         let ty = self.parse_ty_no_plus()?;
         Ok(TyKind::Rptr(opt_lifetime, MutTy { ty, mutbl }))
     }
index c79542342ba78ba5a58a1a97abe0a42e028c7608..fe6653e98da89cb0d72ff77dfaed2e37be78fdbf 100644 (file)
@@ -104,7 +104,7 @@ fn handle_res(&mut self, res: Res) {
                 if let Some(t) = t {
                     self.check_def_id(t);
                 }
-                if let Some(i) = i {
+                if let Some((i, _)) = i {
                     self.check_def_id(i);
                 }
             }
index 7a0503d68f348d04a350d608bd928b025ee1383d..612bc3e74911c44d788189c4398b2cf2b50936c9 100644 (file)
@@ -112,7 +112,7 @@ impl<'a> Resolver<'a> {
                 match outer_res {
                     Res::SelfTy(maybe_trait_defid, maybe_impl_defid) => {
                         if let Some(impl_span) =
-                            maybe_impl_defid.and_then(|def_id| self.opt_span(def_id))
+                            maybe_impl_defid.and_then(|(def_id, _)| self.opt_span(def_id))
                         {
                             err.span_label(
                                 reduce_impl_span_to_impl_keyword(sm, impl_span),
@@ -466,7 +466,7 @@ impl<'a> Resolver<'a> {
                 );
                 err
             }
-            ResolutionError::ParamInNonTrivialAnonConst(name) => {
+            ResolutionError::ParamInNonTrivialAnonConst { name, is_type } => {
                 let mut err = self.session.struct_span_err(
                     span,
                     "generic parameters must not be used inside of non trivial constant values",
@@ -478,9 +478,17 @@ impl<'a> Resolver<'a> {
                         name
                     ),
                 );
-                err.help(
-                    &format!("it is currently only allowed to use either `{0}` or `{{ {0} }}` as generic constants", name)
-                );
+
+                if is_type {
+                    err.note("type parameters are currently not permitted in anonymous constants");
+                } else {
+                    err.help(
+                        &format!("it is currently only allowed to use either `{0}` or `{{ {0} }}` as generic constants",
+                                 name
+                        )
+                    );
+                }
+
                 err
             }
             ResolutionError::SelfInTyParamDefault => {
index 07f36c7b7ad36bef645c3a77cb9afc373dedbcf9..6788df9be7820489bbcdb694f4c5debc6517ded9 100644 (file)
@@ -110,6 +110,9 @@ enum PatBoundCtx {
     ItemRibKind(HasGenericParams),
 
     /// We're in a constant item. Can't refer to dynamic stuff.
+    ///
+    /// The `bool` indicates if this constant may reference generic parameters
+    /// and is used to only allow generic parameters to be used in trivial constant expressions.
     ConstantItemRibKind(bool),
 
     /// We passed through a module.
@@ -848,7 +851,7 @@ fn resolve_adt(&mut self, item: &'ast Item, generics: &'ast Generics) {
         self.with_current_self_item(item, |this| {
             this.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| {
                 let item_def_id = this.r.local_def_id(item.id).to_def_id();
-                this.with_self_rib(Res::SelfTy(None, Some(item_def_id)), |this| {
+                this.with_self_rib(Res::SelfTy(None, Some((item_def_id, false))), |this| {
                     visit::walk_item(this, item);
                 });
             });
@@ -1215,7 +1218,7 @@ fn resolve_implementation(
                 // Resolve the trait reference, if necessary.
                 this.with_optional_trait_ref(opt_trait_reference.as_ref(), |this, trait_id| {
                     let item_def_id = this.r.local_def_id(item_id).to_def_id();
-                    this.with_self_rib(Res::SelfTy(trait_id, Some(item_def_id)), |this| {
+                    this.with_self_rib(Res::SelfTy(trait_id, Some((item_def_id, false))), |this| {
                         if let Some(trait_ref) = opt_trait_reference.as_ref() {
                             // Resolve type arguments in the trait path.
                             visit::walk_trait_ref(this, trait_ref);
index 0f5b9b518163f899d5fd5c0540fcface5b0d4915..85ddc5f55d110b389f288f839c35e2eb50417831 100644 (file)
@@ -221,7 +221,7 @@ enum ResolutionError<'a> {
     /// generic parameters must not be used inside of non trivial constant values.
     ///
     /// This error is only emitted when using `min_const_generics`.
-    ParamInNonTrivialAnonConst(Symbol),
+    ParamInNonTrivialAnonConst { name: Symbol, is_type: bool },
     /// Error E0735: type parameters with a default cannot use `Self`
     SelfInTyParamDefault,
     /// Error E0767: use of unreachable label
@@ -2539,7 +2539,7 @@ fn validate_res_from_ribs(
         &mut self,
         rib_index: usize,
         rib_ident: Ident,
-        res: Res,
+        mut res: Res,
         record_used: bool,
         span: Span,
         all_ribs: &[Rib<'a>],
@@ -2629,13 +2629,23 @@ fn validate_res_from_ribs(
                         ConstantItemRibKind(trivial) => {
                             // HACK(min_const_generics): We currently only allow `N` or `{ N }`.
                             if !trivial && self.session.features_untracked().min_const_generics {
-                                if record_used {
-                                    self.report_error(
-                                        span,
-                                        ResolutionError::ParamInNonTrivialAnonConst(rib_ident.name),
-                                    );
+                                // HACK(min_const_generics): If we encounter `Self` in an anonymous constant
+                                // we can't easily tell if it's generic at this stage, so we instead remember
+                                // this and then enforce the self type to be concrete later on.
+                                if let Res::SelfTy(trait_def, Some((impl_def, _))) = res {
+                                    res = Res::SelfTy(trait_def, Some((impl_def, true)));
+                                } else {
+                                    if record_used {
+                                        self.report_error(
+                                            span,
+                                            ResolutionError::ParamInNonTrivialAnonConst {
+                                                name: rib_ident.name,
+                                                is_type: true,
+                                            },
+                                        );
+                                    }
+                                    return Res::Err;
                                 }
-                                return Res::Err;
                             }
 
                             if in_ty_param_default {
@@ -2709,7 +2719,10 @@ fn validate_res_from_ribs(
                                 if record_used {
                                     self.report_error(
                                         span,
-                                        ResolutionError::ParamInNonTrivialAnonConst(rib_ident.name),
+                                        ResolutionError::ParamInNonTrivialAnonConst {
+                                            name: rib_ident.name,
+                                            is_type: false,
+                                        },
                                     );
                                 }
                                 return Res::Err;
index 0dcbee08abea1f7d1d473fe832112573a09cb740..62e021d5e45bd42eec9073fd84aec74133bb04d4 100644 (file)
@@ -65,9 +65,15 @@ pub struct Lint {
     ///
     /// The name is written with underscores, e.g., "unused_imports".
     /// On the command line, underscores become dashes.
+    ///
+    /// See https://rustc-dev-guide.rust-lang.org/diagnostics.html#lint-naming
+    /// for naming guidelines.
     pub name: &'static str,
 
     /// Default level for the lint.
+    ///
+    /// See https://rustc-dev-guide.rust-lang.org/diagnostics.html#diagnostic-levels
+    /// for guidelines on choosing a default level.
     pub default_level: Level,
 
     /// Description of the lint or the issue it detects.
@@ -275,17 +281,60 @@ pub fn buffer_lint_with_diagnostic(
 }
 
 /// Declares a static item of type `&'static Lint`.
+///
+/// See https://rustc-dev-guide.rust-lang.org/diagnostics.html for documentation
+/// and guidelines on writing lints.
+///
+/// The macro call should start with a doc comment explaining the lint
+/// which will be embedded in the rustc user documentation book. It should
+/// be written in markdown and have a format that looks like this:
+///
+/// ```rust,ignore (doc-example)
+/// /// The `my_lint_name` lint detects [short explanation here].
+/// ///
+/// /// ### Example
+/// ///
+/// /// ```rust
+/// /// [insert a concise example that triggers the lint]
+/// /// ```
+/// ///
+/// /// {{produces}}
+/// ///
+/// /// ### Explanation
+/// ///
+/// /// This should be a detailed explanation of *why* the lint exists,
+/// /// and also include suggestions on how the user should fix the problem.
+/// /// Try to keep the text simple enough that a beginner can understand,
+/// /// and include links to other documentation for terminology that a
+/// /// beginner may not be familiar with. If this is "allow" by default,
+/// /// it should explain why (are there false positives or other issues?). If
+/// /// this is a future-incompatible lint, it should say so, with text that
+/// /// looks roughly like this:
+/// ///
+/// /// This is a [future-incompatible] lint to transition this to a hard
+/// /// error in the future. See [issue #xxxxx] for more details.
+/// ///
+/// /// [issue #xxxxx]: https://github.com/rust-lang/rust/issues/xxxxx
+/// ```
+///
+/// The `{{produces}}` tag will be automatically replaced with the output from
+/// the example by the build system. You can build and view the rustc book
+/// with `x.py doc --stage=1 src/doc/rustc --open`. If the lint example is too
+/// complex to run as a simple example (for example, it needs an extern
+/// crate), mark it with `ignore` and manually paste the expected output below
+/// the example.
 #[macro_export]
 macro_rules! declare_lint {
-    ($vis: vis $NAME: ident, $Level: ident, $desc: expr) => (
+    ($(#[$attr:meta])* $vis: vis $NAME: ident, $Level: ident, $desc: expr) => (
         $crate::declare_lint!(
-            $vis $NAME, $Level, $desc,
+            $(#[$attr])* $vis $NAME, $Level, $desc,
         );
     );
-    ($vis: vis $NAME: ident, $Level: ident, $desc: expr,
+    ($(#[$attr:meta])* $vis: vis $NAME: ident, $Level: ident, $desc: expr,
      $(@future_incompatible = $fi:expr;)?
      $(@feature_gate = $gate:expr;)?
      $($v:ident),*) => (
+        $(#[$attr])*
         $vis static $NAME: &$crate::lint::Lint = &$crate::lint::Lint {
             name: stringify!($NAME),
             default_level: $crate::lint::$Level,
@@ -298,9 +347,10 @@ macro_rules! declare_lint {
             ..$crate::lint::Lint::default_fields_for_macro()
         };
     );
-    ($vis: vis $NAME: ident, $Level: ident, $desc: expr,
+    ($(#[$attr:meta])* $vis: vis $NAME: ident, $Level: ident, $desc: expr,
      $lint_edition: expr => $edition_level: ident
     ) => (
+        $(#[$attr])*
         $vis static $NAME: &$crate::lint::Lint = &$crate::lint::Lint {
             name: stringify!($NAME),
             default_level: $crate::lint::$Level,
index 0fd6cc1038284f5bb68a4cc04f856dd4728ef715..562df176b14a7aea895fd6bb98affff3acb780b4 100644 (file)
 use rustc_span::symbol::sym;
 
 declare_lint! {
+    /// The `ill_formed_attribute_input` lint detects ill-formed attribute
+    /// inputs that were previously accepted and used in practice.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// #[inline = "this is not valid"]
+    /// fn foo() {}
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Previously, inputs for many built-in attributes weren't validated and
+    /// nonsensical attribute inputs were accepted. After validation was
+    /// added, it was determined that some existing projects made use of these
+    /// invalid forms. This is a [future-incompatible] lint to transition this
+    /// to a hard error in the future. See [issue #57571] for more details.
+    ///
+    /// Check the [attribute reference] for details on the valid inputs for
+    /// attributes.
+    ///
+    /// [issue #57571]: https://github.com/rust-lang/rust/issues/57571
+    /// [attribute reference]: https://doc.rust-lang.org/nightly/reference/attributes.html
+    /// [future-incompatible]: ../index.md#future-incompatible-lints
     pub ILL_FORMED_ATTRIBUTE_INPUT,
     Deny,
     "ill-formed attribute inputs that were previously accepted and used in practice",
 }
 
 declare_lint! {
+    /// The `conflicting_repr_hints` lint detects [`repr` attributes] with
+    /// conflicting hints.
+    ///
+    /// [`repr` attributes]: https://doc.rust-lang.org/reference/type-layout.html#representations
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// #[repr(u32, u64)]
+    /// enum Foo {
+    ///     Variant1,
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// The compiler incorrectly accepted these conflicting representations in
+    /// the past. This is a [future-incompatible] lint to transition this to a
+    /// hard error in the future. See [issue #68585] for more details.
+    ///
+    /// To correct the issue, remove one of the conflicting hints.
+    ///
+    /// [issue #68585]: https://github.com/rust-lang/rust/issues/68585
+    /// [future-incompatible]: ../index.md#future-incompatible-lints
     pub CONFLICTING_REPR_HINTS,
     Deny,
     "conflicts between `#[repr(..)]` hints that were previously accepted and used in practice",
 }
 
 declare_lint! {
+    /// The `meta_variable_misuse` lint detects possible meta-variable misuse
+    /// in macro definitions.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// #![deny(meta_variable_misuse)]
+    ///
+    /// macro_rules! foo {
+    ///     () => {};
+    ///     ($( $i:ident = $($j:ident),+ );*) => { $( $( $i = $k; )+ )* };
+    /// }
+    ///
+    /// fn main() {
+    ///     foo!();
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// There are quite a few different ways a [`macro_rules`] macro can be
+    /// improperly defined. Many of these errors were previously only detected
+    /// when the macro was expanded or not at all. This lint is an attempt to
+    /// catch some of these problems when the macro is *defined*.
+    ///
+    /// This lint is "allow" by default because it may have false positives
+    /// and other issues. See [issue #61053] for more details.
+    ///
+    /// [`macro_rules`]: https://doc.rust-lang.org/reference/macros-by-example.html
+    /// [issue #61053]: https://github.com/rust-lang/rust/issues/61053
     pub META_VARIABLE_MISUSE,
     Allow,
     "possible meta-variable misuse at macro definition"
 }
 
 declare_lint! {
+    /// The `incomplete_include` lint detects the use of the [`include!`]
+    /// macro with a file that contains more than one expression.
+    ///
+    /// [`include!`]: https://doc.rust-lang.org/std/macro.include.html
+    ///
+    /// ### Example
+    ///
+    /// ```rust,ignore (needs separate file)
+    /// fn main() {
+    ///     include!("foo.txt");
+    /// }
+    /// ```
+    ///
+    /// where the file `foo.txt` contains:
+    ///
+    /// ```text
+    /// println!("hi!");
+    /// ```
+    ///
+    /// produces:
+    ///
+    /// ```text
+    /// error: include macro expected single expression in source
+    ///  --> foo.txt:1:14
+    ///   |
+    /// 1 | println!("1");
+    ///   |              ^
+    ///   |
+    ///   = note: `#[deny(incomplete_include)]` on by default
+    /// ```
+    ///
+    /// ### Explanation
+    ///
+    /// The [`include!`] macro is currently only intended to be used to
+    /// include a single [expression] or multiple [items]. Historically it
+    /// would ignore any contents after the first expression, but that can be
+    /// confusing. In the example above, the `println!` expression ends just
+    /// before the semicolon, making the semicolon "extra" information that is
+    /// ignored. Perhaps even more surprising, if the included file had
+    /// multiple print statements, the subsequent ones would be ignored!
+    ///
+    /// One workaround is to place the contents in braces to create a [block
+    /// expression]. Also consider alternatives, like using functions to
+    /// encapsulate the expressions, or use [proc-macros].
+    ///
+    /// This is a lint instead of a hard error because existing projects were
+    /// found to hit this error. To be cautious, it is a lint for now. The
+    /// future semantics of the `include!` macro are also uncertain, see
+    /// [issue #35560].
+    ///
+    /// [items]: https://doc.rust-lang.org/reference/items.html
+    /// [expression]: https://doc.rust-lang.org/reference/expressions.html
+    /// [block expression]: https://doc.rust-lang.org/reference/expressions/block-expr.html
+    /// [proc-macros]: https://doc.rust-lang.org/reference/procedural-macros.html
+    /// [issue #35560]: https://github.com/rust-lang/rust/issues/35560
     pub INCOMPLETE_INCLUDE,
     Deny,
     "trailing content in included file"
 }
 
 declare_lint! {
+    /// The `arithmetic_overflow` lint detects that an arithmetic operation
+    /// will [overflow].
+    ///
+    /// [overflow]: https://doc.rust-lang.org/reference/expressions/operator-expr.html#overflow
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// 1_i32 << 32;
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// It is very likely a mistake to perform an arithmetic operation that
+    /// overflows its value. If the compiler is able to detect these kinds of
+    /// overflows at compile-time, it will trigger this lint. Consider
+    /// adjusting the expression to avoid overflow, or use a data type that
+    /// will not overflow.
     pub ARITHMETIC_OVERFLOW,
     Deny,
     "arithmetic operation overflows"
 }
 
 declare_lint! {
+    /// The `unconditional_panic` lint detects an operation that will cause a
+    /// panic at runtime.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// # #![allow(unused)]
+    /// let x = 1 / 0;
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// This lint detects code that is very likely incorrect. When possible,
+    /// the compiler will attempt to detect situations where code can be
+    /// evaluated at compile-time to generate more efficient code. While
+    /// evaluating such code, if it detects that the code will unconditionally
+    /// panic, this usually indicates that it is doing something incorrectly.
+    /// If this lint is allowed, then the code will not be evaluated at
+    /// compile-time, and instead continue to generate code to evaluate at
+    /// runtime, which may panic during runtime.
     pub UNCONDITIONAL_PANIC,
     Deny,
     "operation will cause a panic at runtime"
 }
 
 declare_lint! {
+    /// The `const_err` lint detects an erroneous expression while doing
+    /// constant evaluation.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// #![allow(unconditional_panic)]
+    /// let x: &'static i32 = &(1 / 0);
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// This lint detects code that is very likely incorrect. If this lint is
+    /// allowed, then the code will not be evaluated at compile-time, and
+    /// instead continue to generate code to evaluate at runtime, which may
+    /// panic during runtime.
+    ///
+    /// Note that this lint may trigger in either inside or outside of a
+    /// [const context]. Outside of a [const context], the compiler can
+    /// sometimes evaluate an expression at compile-time in order to generate
+    /// more efficient code. As the compiler becomes better at doing this, it
+    /// needs to decide what to do when it encounters code that it knows for
+    /// certain will panic or is otherwise incorrect. Making this a hard error
+    /// would prevent existing code that exhibited this behavior from
+    /// compiling, breaking backwards-compatibility. However, this is almost
+    /// certainly incorrect code, so this is a deny-by-default lint. For more
+    /// details, see [RFC 1229] and [issue #28238].
+    ///
+    /// Note that there are several other more specific lints associated with
+    /// compile-time evaluation, such as [`arithmetic_overflow`],
+    /// [`unconditional_panic`].
+    ///
+    /// [const context]: https://doc.rust-lang.org/reference/const_eval.html#const-context
+    /// [RFC 1229]: https://github.com/rust-lang/rfcs/blob/master/text/1229-compile-time-asserts.md
+    /// [issue #28238]: https://github.com/rust-lang/rust/issues/28238
+    /// [`arithmetic_overflow`]: deny-by-default.html#arithmetic-overflow
+    /// [`unconditional_panic`]: deny-by-default.html#unconditional-panic
     pub CONST_ERR,
     Deny,
     "constant evaluation detected erroneous expression",
 }
 
 declare_lint! {
+    /// The `unused_imports` lint detects imports that are never used.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// use std::collections::HashMap;
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Unused imports may signal a mistake or unfinished code, and clutter
+    /// the code, and should be removed. If you intended to re-export the item
+    /// to make it available outside of the module, add a visibility modifier
+    /// like `pub`.
     pub UNUSED_IMPORTS,
     Warn,
     "imports that are never used"
 }
 
 declare_lint! {
+    /// The `unused_extern_crates` lint guards against `extern crate` items
+    /// that are never used.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// #![deny(unused_extern_crates)]
+    /// extern crate proc_macro;
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// `extern crate` items that are unused have no effect and should be
+    /// removed. Note that there are some cases where specifying an `extern
+    /// crate` is desired for the side effect of ensuring the given crate is
+    /// linked, even though it is not otherwise directly referenced. The lint
+    /// can be silenced by aliasing the crate to an underscore, such as
+    /// `extern crate foo as _`. Also note that it is no longer idiomatic to
+    /// use `extern crate` in the [2018 edition], as extern crates are now
+    /// automatically added in scope.
+    ///
+    /// This lint is "allow" by default because it can be noisy, and produce
+    /// false-positives. If a dependency is being removed from a project, it
+    /// is recommended to remove it from the build configuration (such as
+    /// `Cargo.toml`) to ensure stale build entries aren't left behind.
+    ///
+    /// [2018 edition]: https://doc.rust-lang.org/edition-guide/rust-2018/module-system/path-clarity.html#no-more-extern-crate
     pub UNUSED_EXTERN_CRATES,
     Allow,
     "extern crates that are never used"
 }
 
 declare_lint! {
+    /// The `unused_crate_dependencies` lint detects crate dependencies that
+    /// are never used.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,ignore (needs extern crate)
+    /// #![deny(unused_crate_dependencies)]
+    /// ```
+    ///
+    /// This will produce:
+    ///
+    /// ```text
+    /// error: external crate `regex` unused in `lint_example`: remove the dependency or add `use regex as _;`
+    ///   |
+    /// note: the lint level is defined here
+    ///  --> src/lib.rs:1:9
+    ///   |
+    /// 1 | #![deny(unused_crate_dependencies)]
+    ///   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
+    /// ```
+    ///
+    /// ### Explanation
+    ///
+    /// After removing the code that uses a dependency, this usually also
+    /// requires removing the dependency from the build configuration.
+    /// However, sometimes that step can be missed, which leads to time wasted
+    /// building dependencies that are no longer used. This lint can be
+    /// enabled to detect dependencies that are never used (more specifically,
+    /// any dependency passed with the `--extern` command-line flag that is
+    /// never referenced via [`use`], [`extern crate`], or in any [path]).
+    ///
+    /// This lint is "allow" by default because it can provide false positives
+    /// depending on how the build system is configured. For example, when
+    /// using Cargo, a "package" consists of multiple crates (such as a
+    /// library and a binary), but the dependencies are defined for the
+    /// package as a whole. If there is a dependency that is only used in the
+    /// binary, but not the library, then the lint will be incorrectly issued
+    /// in the library.
+    ///
+    /// [path]: https://doc.rust-lang.org/reference/paths.html
+    /// [`use`]: https://doc.rust-lang.org/reference/items/use-declarations.html
+    /// [`extern crate`]: https://doc.rust-lang.org/reference/items/extern-crates.html
     pub UNUSED_CRATE_DEPENDENCIES,
     Allow,
     "crate dependencies that are never used",
 }
 
 declare_lint! {
+    /// The `unused_qualifications` lint detects unnecessarily qualified
+    /// names.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// #![deny(unused_qualifications)]
+    /// mod foo {
+    ///     pub fn bar() {}
+    /// }
+    ///
+    /// fn main() {
+    ///     use foo::bar;
+    ///     foo::bar();
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// If an item from another module is already brought into scope, then
+    /// there is no need to qualify it in this case. You can call `bar()`
+    /// directly, without the `foo::`.
+    ///
+    /// This lint is "allow" by default because it is somewhat pedantic, and
+    /// doesn't indicate an actual problem, but rather a stylistic choice, and
+    /// can be noisy when refactoring or moving around code.
     pub UNUSED_QUALIFICATIONS,
     Allow,
     "detects unnecessarily qualified names"
 }
 
 declare_lint! {
+    /// The `unknown_lints` lint detects unrecognized lint attribute.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// #![allow(not_a_real_lint)]
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// It is usually a mistake to specify a lint that does not exist. Check
+    /// the spelling, and check the lint listing for the correct name. Also
+    /// consider if you are using an old version of the compiler, and the lint
+    /// is only available in a newer version.
     pub UNKNOWN_LINTS,
     Warn,
     "unrecognized lint attribute"
 }
 
 declare_lint! {
+    /// The `unused_variables` lint detects variables which are not used in
+    /// any way.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// let x = 5;
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Unused variables may signal a mistake or unfinished code. To silence
+    /// the warning for the individual variable, prefix it with an underscore
+    /// such as `_x`.
     pub UNUSED_VARIABLES,
     Warn,
     "detect variables which are not used in any way"
 }
 
 declare_lint! {
+    /// The `unused_assignments` lint detects assignments that will never be read.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// let mut x = 5;
+    /// x = 6;
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Unused assignments may signal a mistake or unfinished code. If the
+    /// variable is never used after being assigned, then the assignment can
+    /// be removed. Variables with an underscore prefix such as `_x` will not
+    /// trigger this lint.
     pub UNUSED_ASSIGNMENTS,
     Warn,
     "detect assignments that will never be read"
 }
 
 declare_lint! {
+    /// The `dead_code` lint detects unused, unexported items.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// fn foo() {}
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Dead code may signal a mistake or unfinished code. To silence the
+    /// warning for individual items, prefix the name with an underscore such
+    /// as `_foo`. If it was intended to expose the item outside of the crate,
+    /// consider adding a visibility modifier like `pub`. Otherwise consider
+    /// removing the unused code.
     pub DEAD_CODE,
     Warn,
     "detect unused, unexported items"
 }
 
 declare_lint! {
+    /// The `unused_attributes` lint detects attributes that were not used by
+    /// the compiler.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// #![macro_export]
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Unused [attributes] may indicate the attribute is placed in the wrong
+    /// position. Consider removing it, or placing it in the correct position.
+    /// Also consider if you intended to use an _inner attribute_ (with a `!`
+    /// such as `#![allow(unused)]`) which applies to the item the attribute
+    /// is within, or an _outer attribute_ (without a `!` such as
+    /// `#[allow(unsued)]`) which applies to the item *following* the
+    /// attribute.
+    ///
+    /// [attributes]: https://doc.rust-lang.org/reference/attributes.html
     pub UNUSED_ATTRIBUTES,
     Warn,
     "detects attributes that were not used by the compiler"
 }
 
 declare_lint! {
+    /// The `unreachable_code` lint detects unreachable code paths.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,no_run
+    /// panic!("we never go past here!");
+    ///
+    /// let x = 5;
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Unreachable code may signal a mistake or unfinished code. If the code
+    /// is no longer in use, consider removing it.
     pub UNREACHABLE_CODE,
     Warn,
     "detects unreachable code paths",
 }
 
 declare_lint! {
+    /// The `unreachable_patterns` lint detects unreachable patterns.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// let x = 5;
+    /// match x {
+    ///     y => (),
+    ///     5 => (),
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// This usually indicates a mistake in how the patterns are specified or
+    /// ordered. In this example, the `y` pattern will always match, so the
+    /// five is impossible to reach. Remember, match arms match in order, you
+    /// probably wanted to put the `5` case above the `y` case.
     pub UNREACHABLE_PATTERNS,
     Warn,
     "detects unreachable patterns"
 }
 
 declare_lint! {
+    /// The `overlapping_patterns` lint detects `match` arms that have
+    /// [range patterns] that overlap.
+    ///
+    /// [range patterns]: https://doc.rust-lang.org/nightly/reference/patterns.html#range-patterns
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// let x = 123u8;
+    /// match x {
+    ///     0..=100 => { println!("small"); }
+    ///     100..=255 => { println!("large"); }
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// It is likely a mistake to have range patterns in a match expression
+    /// that overlap. Check that the beginning and end values are what you
+    /// expect, and keep in mind that with `..=` the left and right bounds are
+    /// inclusive.
     pub OVERLAPPING_PATTERNS,
     Warn,
     "detects overlapping patterns"
 }
 
 declare_lint! {
+    /// The `bindings_with_variant_name` lint detects pattern bindings with
+    /// the same name as one of the matched variants.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// pub enum Enum {
+    ///     Foo,
+    ///     Bar,
+    /// }
+    ///
+    /// pub fn foo(x: Enum) {
+    ///     match x {
+    ///         Foo => {}
+    ///         Bar => {}
+    ///     }
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// It is usually a mistake to specify an enum variant name as an
+    /// [identifier pattern]. In the example above, the `match` arms are
+    /// specifying a variable name to bind the value of `x` to. The second arm
+    /// is ignored because the first one matches *all* values. The likely
+    /// intent is that the arm was intended to match on the enum variant.
+    ///
+    /// Two possible solutions are:
+    ///
+    /// * Specify the enum variant using a [path pattern], such as
+    ///   `Enum::Foo`.
+    /// * Bring the enum variants into local scope, such as adding `use
+    ///   Enum::*;` to the beginning of the `foo` function in the example
+    ///   above.
+    ///
+    /// [identifier pattern]: https://doc.rust-lang.org/reference/patterns.html#identifier-patterns
+    /// [path pattern]: https://doc.rust-lang.org/reference/patterns.html#path-patterns
     pub BINDINGS_WITH_VARIANT_NAME,
     Warn,
     "detects pattern bindings with the same name as one of the matched variants"
 }
 
 declare_lint! {
+    /// The `unused_macros` lint detects macros that were not used.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// macro_rules! unused {
+    ///     () => {};
+    /// }
+    ///
+    /// fn main() {
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Unused macros may signal a mistake or unfinished code. To silence the
+    /// warning for the individual macro, prefix the name with an underscore
+    /// such as `_my_macro`. If you intended to export the macro to make it
+    /// available outside of the crate, use the [`macro_export` attribute].
+    ///
+    /// [`macro_export` attribute]: https://doc.rust-lang.org/reference/macros-by-example.html#path-based-scope
     pub UNUSED_MACROS,
     Warn,
     "detects macros that were not used"
 }
 
 declare_lint! {
+    /// The `warnings` lint allows you to change the level of other
+    /// lints which produce warnings.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// #![deny(warnings)]
+    /// fn foo() {}
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// The `warnings` lint is a bit special; by changing its level, you
+    /// change every other warning that would produce a warning to whatever
+    /// value you'd like. As such, you won't ever trigger this lint in your
+    /// code directly.
     pub WARNINGS,
     Warn,
     "mass-change the level for lints which produce warnings"
 }
 
 declare_lint! {
+    /// The `unused_features` lint detects unused or unknown features found in
+    /// crate-level [`feature` attributes].
+    ///
+    /// [`feature` attributes]: https://doc.rust-lang.org/nightly/unstable-book/
+    ///
+    /// Note: This lint is currently not functional, see [issue #44232] for
+    /// more details.
+    ///
+    /// [issue #44232]: https://github.com/rust-lang/rust/issues/44232
     pub UNUSED_FEATURES,
     Warn,
     "unused features found in crate-level `#[feature]` directives"
 }
 
 declare_lint! {
+    /// The `stable_features` lint detects a [`feature` attribute] that
+    /// has since been made stable.
+    ///
+    /// [`feature` attribute]: https://doc.rust-lang.org/nightly/unstable-book/
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// #![feature(test_accepted_feature)]
+    /// fn main() {}
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// When a feature is stabilized, it is no longer necessary to include a
+    /// `#![feature]` attribute for it. To fix, simply remove the
+    /// `#![feature]` attribute.
     pub STABLE_FEATURES,
     Warn,
     "stable features found in `#[feature]` directive"
 }
 
 declare_lint! {
+    /// The `unknown_crate_types` lint detects an unknown crate type found in
+    /// a [`crate_type` attribute].
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// #![crate_type="lol"]
+    /// fn main() {}
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// An unknown value give to the `crate_type` attribute is almost
+    /// certainly a mistake.
+    ///
+    /// [`crate_type` attribute]: https://doc.rust-lang.org/reference/linkage.html
     pub UNKNOWN_CRATE_TYPES,
     Deny,
     "unknown crate type found in `#[crate_type]` directive",
 }
 
 declare_lint! {
+    /// The `trivial_casts` lint detects trivial casts which could be replaced
+    /// with coercion, which may require [type ascription] or a temporary
+    /// variable.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// #![deny(trivial_casts)]
+    /// let x: &u32 = &42;
+    /// let y = x as *const u32;
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// A trivial cast is a cast `e as T` where `e` has type `U` and `U` is a
+    /// subtype of `T`. This type of cast is usually unnecessary, as it can be
+    /// usually be inferred.
+    ///
+    /// This lint is "allow" by default because there are situations, such as
+    /// with FFI interfaces or complex type aliases, where it triggers
+    /// incorrectly, or in situations where it will be more difficult to
+    /// clearly express the intent. It may be possible that this will become a
+    /// warning in the future, possibly with [type ascription] providing a
+    /// convenient way to work around the current issues. See [RFC 401] for
+    /// historical context.
+    ///
+    /// [type ascription]: https://github.com/rust-lang/rust/issues/23416
+    /// [RFC 401]: https://github.com/rust-lang/rfcs/blob/master/text/0401-coercions.md
     pub TRIVIAL_CASTS,
     Allow,
     "detects trivial casts which could be removed"
 }
 
 declare_lint! {
+    /// The `trivial_numeric_casts` lint detects trivial numeric casts of types
+    /// which could be removed.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// #![deny(trivial_numeric_casts)]
+    /// let x = 42_i32 as i32;
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// A trivial numeric cast is a cast of a numeric type to the same numeric
+    /// type. This type of cast is usually unnecessary.
+    ///
+    /// This lint is "allow" by default because there are situations, such as
+    /// with FFI interfaces or complex type aliases, where it triggers
+    /// incorrectly, or in situations where it will be more difficult to
+    /// clearly express the intent. It may be possible that this will become a
+    /// warning in the future, possibly with [type ascription] providing a
+    /// convenient way to work around the current issues. See [RFC 401] for
+    /// historical context.
+    ///
+    /// [type ascription]: https://github.com/rust-lang/rust/issues/23416
+    /// [RFC 401]: https://github.com/rust-lang/rfcs/blob/master/text/0401-coercions.md
     pub TRIVIAL_NUMERIC_CASTS,
     Allow,
     "detects trivial casts of numeric types which could be removed"
 }
 
 declare_lint! {
+    /// The `private_in_public` lint detects private items in public
+    /// interfaces not caught by the old implementation.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// # #![allow(unused)]
+    /// struct SemiPriv;
+    ///
+    /// mod m1 {
+    ///     struct Priv;
+    ///     impl super::SemiPriv {
+    ///         pub fn f(_: Priv) {}
+    ///     }
+    /// }
+    /// # fn main() {}
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// The visibility rules are intended to prevent exposing private items in
+    /// public interfaces. This is a [future-incompatible] lint to transition
+    /// this to a hard error in the future. See [issue #34537] for more
+    /// details.
+    ///
+    /// [issue #34537]: https://github.com/rust-lang/rust/issues/34537
+    /// [future-incompatible]: ../index.md#future-incompatible-lints
     pub PRIVATE_IN_PUBLIC,
     Warn,
     "detect private items in public interfaces not caught by the old implementation",
 }
 
 declare_lint! {
+    /// The `exported_private_dependencies` lint detects private dependencies
+    /// that are exposed in a public interface.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,ignore (needs-dependency)
+    /// pub fn foo() -> Option<some_private_dependency::Thing> {
+    ///     None
+    /// }
+    /// ```
+    ///
+    /// This will produce:
+    ///
+    /// ```text
+    /// warning: type `bar::Thing` from private dependency 'bar' in public interface
+    ///  --> src/lib.rs:3:1
+    ///   |
+    /// 3 | pub fn foo() -> Option<bar::Thing> {
+    ///   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+    ///   |
+    ///   = note: `#[warn(exported_private_dependencies)]` on by default
+    /// ```
+    ///
+    /// ### Explanation
+    ///
+    /// Dependencies can be marked as "private" to indicate that they are not
+    /// exposed in the public interface of a crate. This can be used by Cargo
+    /// to independently resolve those dependencies because it can assume it
+    /// does not need to unify them with other packages using that same
+    /// dependency. This lint is an indication of a violation of that
+    /// contract.
+    ///
+    /// To fix this, avoid exposing the dependency in your public interface.
+    /// Or, switch the dependency to a public dependency.
+    ///
+    /// Note that support for this is only available on the nightly channel.
+    /// See [RFC 1977] for more details, as well as the [Cargo documentation].
+    ///
+    /// [RFC 1977]: https://github.com/rust-lang/rfcs/blob/master/text/1977-public-private-dependencies.md
+    /// [Cargo documentation]: https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#public-dependency
     pub EXPORTED_PRIVATE_DEPENDENCIES,
     Warn,
     "public interface leaks type from a private dependency"
 }
 
 declare_lint! {
+    /// The `pub_use_of_private_extern_crate` lint detects a specific
+    /// situation of re-exporting a private `extern crate`.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// extern crate core;
+    /// pub use core as reexported_core;
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// A public `use` declaration should not be used to publicly re-export a
+    /// private `extern crate`. `pub extern crate` should be used instead.
+    ///
+    /// This was historically allowed, but is not the intended behavior
+    /// according to the visibility rules. This is a [future-incompatible]
+    /// lint to transition this to a hard error in the future. See [issue
+    /// #34537] for more details.
+    ///
+    /// [issue #34537]: https://github.com/rust-lang/rust/issues/34537
+    /// [future-incompatible]: ../index.md#future-incompatible-lints
     pub PUB_USE_OF_PRIVATE_EXTERN_CRATE,
     Deny,
     "detect public re-exports of private extern crates",
 }
 
 declare_lint! {
+    /// The `invalid_type_param_default` lint detects type parameter defaults
+    /// erroneously allowed in an invalid location.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// fn foo<T=i32>(t: T) {}
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Default type parameters were only intended to be allowed in certain
+    /// situations, but historically the compiler allowed them everywhere.
+    /// This is a [future-incompatible] lint to transition this to a hard
+    /// error in the future. See [issue #36887] for more details.
+    ///
+    /// [issue #36887]: https://github.com/rust-lang/rust/issues/36887
+    /// [future-incompatible]: ../index.md#future-incompatible-lints
     pub INVALID_TYPE_PARAM_DEFAULT,
     Deny,
     "type parameter default erroneously allowed in invalid location",
 }
 
 declare_lint! {
+    /// The `renamed_and_removed_lints` lint detects lints that have been
+    /// renamed or removed.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// #![deny(raw_pointer_derive)]
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// To fix this, either remove the lint or use the new name. This can help
+    /// avoid confusion about lints that are no longer valid, and help
+    /// maintain consistency for renamed lints.
     pub RENAMED_AND_REMOVED_LINTS,
     Warn,
     "lints that have been renamed or removed"
 }
 
 declare_lint! {
+    /// The `unaligned_references` lint detects unaligned references to fields
+    /// of [packed] structs.
+    ///
+    /// [packed]: https://doc.rust-lang.org/reference/type-layout.html#the-alignment-modifiers
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// #![deny(unaligned_references)]
+    ///
+    /// #[repr(packed)]
+    /// pub struct Foo {
+    ///     field1: u64,
+    ///     field2: u8,
+    /// }
+    ///
+    /// fn main() {
+    ///     unsafe {
+    ///         let foo = Foo { field1: 0, field2: 0 };
+    ///         let _ = &foo.field1;
+    ///     }
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Creating a reference to an insufficiently aligned packed field is
+    /// [undefined behavior] and should be disallowed.
+    ///
+    /// This lint is "allow" by default because there is no stable
+    /// alternative, and it is not yet certain how widespread existing code
+    /// will trigger this lint.
+    ///
+    /// See [issue #27060] for more discussion.
+    ///
+    /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
+    /// [issue #27060]: https://github.com/rust-lang/rust/issues/27060
     pub UNALIGNED_REFERENCES,
     Allow,
     "detects unaligned references to fields of packed structs",
 }
 
 declare_lint! {
+    /// The `const_item_mutation` lint detects attempts to mutate a `const`
+    /// item.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// const FOO: [i32; 1] = [0];
+    ///
+    /// fn main() {
+    ///     FOO[0] = 1;
+    ///     // This will print "[0]".
+    ///     println!("{:?}", FOO);
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Trying to directly mutate a `const` item is almost always a mistake.
+    /// What is happening in the example above is that a temporary copy of the
+    /// `const` is mutated, but the original `const` is not. Each time you
+    /// refer to the `const` by name (such as `FOO` in the example above), a
+    /// separate copy of the value is inlined at that location.
+    ///
+    /// This lint checks for writing directly to a field (`FOO.field =
+    /// some_value`) or array entry (`FOO[0] = val`), or taking a mutable
+    /// reference to the const item (`&mut FOO`), including through an
+    /// autoderef (`FOO.some_mut_self_method()`).
+    ///
+    /// There are various alternatives depending on what you are trying to
+    /// accomplish:
+    ///
+    /// * First, always reconsider using mutable globals, as they can be
+    ///   difficult to use correctly, and can make the code more difficult to
+    ///   use or understand.
+    /// * If you are trying to perform a one-time initialization of a global:
+    ///     * If the value can be computed at compile-time, consider using
+    ///       const-compatible values (see [Constant Evaluation]).
+    ///     * For more complex single-initialization cases, consider using a
+    ///       third-party crate, such as [`lazy_static`] or [`once_cell`].
+    ///     * If you are using the [nightly channel], consider the new
+    ///       [`lazy`] module in the standard library.
+    /// * If you truly need a mutable global, consider using a [`static`],
+    ///   which has a variety of options:
+    ///   * Simple data types can be directly defined and mutated with an
+    ///     [`atomic`] type.
+    ///   * More complex types can be placed in a synchronization primitive
+    ///     like a [`Mutex`], which can be initialized with one of the options
+    ///     listed above.
+    ///   * A [mutable `static`] is a low-level primitive, requiring unsafe.
+    ///     Typically This should be avoided in preference of something
+    ///     higher-level like one of the above.
+    ///
+    /// [Constant Evaluation]: https://doc.rust-lang.org/reference/const_eval.html
+    /// [`static`]: https://doc.rust-lang.org/reference/items/static-items.html
+    /// [mutable `static`]: https://doc.rust-lang.org/reference/items/static-items.html#mutable-statics
+    /// [`lazy`]: https://doc.rust-lang.org/nightly/std/lazy/index.html
+    /// [`lazy_static`]: https://crates.io/crates/lazy_static
+    /// [`once_cell`]: https://crates.io/crates/once_cell
+    /// [`atomic`]: https://doc.rust-lang.org/std/sync/atomic/index.html
+    /// [`Mutex`]: https://doc.rust-lang.org/std/sync/struct.Mutex.html
     pub CONST_ITEM_MUTATION,
     Warn,
     "detects attempts to mutate a `const` item",
 }
 
 declare_lint! {
+    /// The `safe_packed_borrows` lint detects borrowing a field in the
+    /// interior of a packed structure with alignment other than 1.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// #[repr(packed)]
+    /// pub struct Unaligned<T>(pub T);
+    ///
+    /// pub struct Foo {
+    ///     start: u8,
+    ///     data: Unaligned<u32>,
+    /// }
+    ///
+    /// fn main() {
+    ///     let x = Foo { start: 0, data: Unaligned(1) };
+    ///     let y = &x.data.0;
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// This type of borrow is unsafe and can cause errors on some platforms
+    /// and violates some assumptions made by the compiler. This was
+    /// previously allowed unintentionally. This is a [future-incompatible]
+    /// lint to transition this to a hard error in the future. See [issue
+    /// #46043] for more details, including guidance on how to solve the
+    /// problem.
+    ///
+    /// [issue #46043]: https://github.com/rust-lang/rust/issues/46043
+    /// [future-incompatible]: ../index.md#future-incompatible-lints
     pub SAFE_PACKED_BORROWS,
     Warn,
     "safe borrows of fields of packed structs were erroneously allowed",
 }
 
 declare_lint! {
+    /// The `patterns_in_fns_without_body` lint detects `mut` identifier
+    /// patterns as a parameter in functions without a body.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// trait Trait {
+    ///     fn foo(mut arg: u8);
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// To fix this, remove `mut` from the parameter in the trait definition;
+    /// it can be used in the implementation. That is, the following is OK:
+    ///
+    /// ```rust
+    /// trait Trait {
+    ///     fn foo(arg: u8); // Removed `mut` here
+    /// }
+    ///
+    /// impl Trait for i32 {
+    ///     fn foo(mut arg: u8) { // `mut` here is OK
+    ///
+    ///     }
+    /// }
+    /// ```
+    ///
+    /// Trait definitions can define functions without a body to specify a
+    /// function that implementors must define. The parameter names in the
+    /// body-less functions are only allowed to be `_` or an [identifier] for
+    /// documentation purposes (only the type is relevant). Previous versions
+    /// of the compiler erroneously allowed [identifier patterns] with the
+    /// `mut` keyword, but this was not intended to be allowed. This is a
+    /// [future-incompatible] lint to transition this to a hard error in the
+    /// future. See [issue #35203] for more details.
+    ///
+    /// [identifier]: https://doc.rust-lang.org/reference/identifiers.html
+    /// [identifier patterns]: https://doc.rust-lang.org/reference/patterns.html#identifier-patterns
+    /// [issue #35203]: https://github.com/rust-lang/rust/issues/35203
+    /// [future-incompatible]: ../index.md#future-incompatible-lints
     pub PATTERNS_IN_FNS_WITHOUT_BODY,
     Deny,
     "patterns in functions without body were erroneously allowed",
 }
 
 declare_lint! {
+    /// The `late_bound_lifetime_arguments` lint detects generic lifetime
+    /// arguments in path segments with late bound lifetime parameters.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// struct S;
+    ///
+    /// impl S {
+    ///     fn late<'a, 'b>(self, _: &'a u8, _: &'b u8) {}
+    /// }
+    ///
+    /// fn main() {
+    ///     S.late::<'static>(&0, &0);
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// It is not clear how to provide arguments for early-bound lifetime
+    /// parameters if they are intermixed with late-bound parameters in the
+    /// same list. For now, providing any explicit arguments will trigger this
+    /// lint if late-bound parameters are present, so in the future a solution
+    /// can be adopted without hitting backward compatibility issues. This is
+    /// a [future-incompatible] lint to transition this to a hard error in the
+    /// future. See [issue #42868] for more details, along with a description
+    /// of the difference between early and late-bound parameters.
+    ///
+    /// [issue #42868]: https://github.com/rust-lang/rust/issues/42868
+    /// [future-incompatible]: ../index.md#future-incompatible-lints
     pub LATE_BOUND_LIFETIME_ARGUMENTS,
     Warn,
     "detects generic lifetime arguments in path segments with late bound lifetime parameters",
 }
 
 declare_lint! {
+    /// The `order_dependent_trait_objects` lint detects a trait coherency
+    /// violation that would allow creating two trait impls for the same
+    /// dynamic trait object involving marker traits.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// pub trait Trait {}
+    ///
+    /// impl Trait for dyn Send + Sync { }
+    /// impl Trait for dyn Sync + Send { }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// A previous bug caused the compiler to interpret traits with different
+    /// orders (such as `Send + Sync` and `Sync + Send`) as distinct types
+    /// when they were intended to be treated the same. This allowed code to
+    /// define separate trait implementations when there should be a coherence
+    /// error. This is a [future-incompatible] lint to transition this to a
+    /// hard error in the future. See [issue #56484] for more details.
+    ///
+    /// [issue #56484]: https://github.com/rust-lang/rust/issues/56484
+    /// [future-incompatible]: ../index.md#future-incompatible-lints
     pub ORDER_DEPENDENT_TRAIT_OBJECTS,
     Deny,
     "trait-object types were treated as different depending on marker-trait order",
 }
 
 declare_lint! {
+    /// The `coherence_leak_check` lint detects conflicting implementations of
+    /// a trait that are only distinguished by the old leak-check code.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// trait SomeTrait { }
+    /// impl SomeTrait for for<'a> fn(&'a u8) { }
+    /// impl<'a> SomeTrait for fn(&'a u8) { }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// In the past, the compiler would accept trait implementations for
+    /// identical functions that differed only in where the lifetime binder
+    /// appeared. Due to a change in the borrow checker implementation to fix
+    /// several bugs, this is no longer allowed. However, since this affects
+    /// existing code, this is a [future-incompatible] lint to transition this
+    /// to a hard error in the future.
+    ///
+    /// Code relying on this pattern should introduce "[newtypes]",
+    /// like `struct Foo(for<'a> fn(&'a u8))`.
+    ///
+    /// See [issue #56105] for more details.
+    ///
+    /// [issue #56105]: https://github.com/rust-lang/rust/issues/56105
+    /// [newtypes]: https://doc.rust-lang.org/book/ch19-04-advanced-types.html#using-the-newtype-pattern-for-type-safety-and-abstraction
+    /// [future-incompatible]: ../index.md#future-incompatible-lints
     pub COHERENCE_LEAK_CHECK,
     Warn,
     "distinct impls distinguished only by the leak-check code",
 }
 
 declare_lint! {
+    /// The `deprecated` lint detects use of deprecated items.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// #[deprecated]
+    /// fn foo() {}
+    ///
+    /// fn bar() {
+    ///     foo();
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Items may be marked "deprecated" with the [`deprecated` attribute] to
+    /// indicate that they should no longer be used. Usually the attribute
+    /// should include a note on what to use instead, or check the
+    /// documentation.
+    ///
+    /// [`deprecated` attribute]: https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-deprecated-attribute
     pub DEPRECATED,
     Warn,
     "detects use of deprecated items",
 }
 
 declare_lint! {
+    /// The `unused_unsafe` lint detects unnecessary use of an `unsafe` block.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// unsafe {}
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// If nothing within the block requires `unsafe`, then remove the
+    /// `unsafe` marker because it is not required and may cause confusion.
     pub UNUSED_UNSAFE,
     Warn,
     "unnecessary use of an `unsafe` block"
 }
 
 declare_lint! {
+    /// The `unused_mut` lint detects mut variables which don't need to be
+    /// mutable.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// let mut x = 5;
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// The preferred style is to only mark variables as `mut` if it is
+    /// required.
     pub UNUSED_MUT,
     Warn,
     "detect mut variables which don't need to be mutable"
 }
 
 declare_lint! {
+    /// The `unconditional_recursion` lint detects functions that cannot
+    /// return without calling themselves.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// fn foo() {
+    ///     foo();
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// It is usually a mistake to have a recursive call that does not have
+    /// some condition to cause it to terminate. If you really intend to have
+    /// an infinite loop, using a `loop` expression is recommended.
     pub UNCONDITIONAL_RECURSION,
     Warn,
     "functions that cannot return without calling themselves"
 }
 
 declare_lint! {
+    /// The `single_use_lifetimes` lint detects lifetimes that are only used
+    /// once.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// #![deny(single_use_lifetimes)]
+    ///
+    /// fn foo<'a>(x: &'a u32) {}
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Specifying an explicit lifetime like `'a` in a function or `impl`
+    /// should only be used to link together two things. Otherwise, you should
+    /// just use `'_` to indicate that the lifetime is not linked to anything,
+    /// or elide the lifetime altogether if possible.
+    ///
+    /// This lint is "allow" by default because it was introduced at a time
+    /// when `'_` and elided lifetimes were first being introduced, and this
+    /// lint would be too noisy. Also, there are some known false positives
+    /// that it produces. See [RFC 2115] for historical context, and [issue
+    /// #44752] for more details.
+    ///
+    /// [RFC 2115]: https://github.com/rust-lang/rfcs/blob/master/text/2115-argument-lifetimes.md
+    /// [issue #44752]: https://github.com/rust-lang/rust/issues/44752
     pub SINGLE_USE_LIFETIMES,
     Allow,
     "detects lifetime parameters that are only used once"
 }
 
 declare_lint! {
+    /// The `unused_lifetimes` lint detects lifetime parameters that are never
+    /// used.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// #[deny(unused_lifetimes)]
+    ///
+    /// pub fn foo<'a>() {}
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Unused lifetime parameters may signal a mistake or unfinished code.
+    /// Consider removing the parameter.
     pub UNUSED_LIFETIMES,
     Allow,
     "detects lifetime parameters that are never used"
 }
 
 declare_lint! {
+    /// The `tyvar_behind_raw_pointer` lint detects raw pointer to an
+    /// inference variable.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,edition2015
+    /// // edition 2015
+    /// let data = std::ptr::null();
+    /// let _ = &data as *const *const ();
+    ///
+    /// if data.is_null() {}
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// This kind of inference was previously allowed, but with the future
+    /// arrival of [arbitrary self types], this can introduce ambiguity. To
+    /// resolve this, use an explicit type instead of relying on type
+    /// inference.
+    ///
+    /// This is a [future-incompatible] lint to transition this to a hard
+    /// error in the 2018 edition. See [issue #46906] for more details. This
+    /// is currently a hard-error on the 2018 edition, and is "warn" by
+    /// default in the 2015 edition.
+    ///
+    /// [arbitrary self types]: https://github.com/rust-lang/rust/issues/44874
+    /// [issue #46906]: https://github.com/rust-lang/rust/issues/46906
+    /// [future-incompatible]: ../index.md#future-incompatible-lints
     pub TYVAR_BEHIND_RAW_POINTER,
     Warn,
     "raw pointer to an inference variable",
 }
 
 declare_lint! {
+    /// The `elided_lifetimes_in_paths` lint detects the use of hidden
+    /// lifetime parameters.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// #![deny(elided_lifetimes_in_paths)]
+    /// struct Foo<'a> {
+    ///     x: &'a u32
+    /// }
+    ///
+    /// fn foo(x: &Foo) {
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Elided lifetime parameters can make it difficult to see at a glance
+    /// that borrowing is occurring. This lint ensures that lifetime
+    /// parameters are always explicitly stated, even if it is the `'_`
+    /// [placeholder lifetime].
+    ///
+    /// This lint is "allow" by default because it has some known issues, and
+    /// may require a significant transition for old code.
+    ///
+    /// [placeholder lifetime]: https://doc.rust-lang.org/reference/lifetime-elision.html#lifetime-elision-in-functions
     pub ELIDED_LIFETIMES_IN_PATHS,
     Allow,
     "hidden lifetime parameters in types are deprecated",
 }
 
 declare_lint! {
+    /// The `bare_trait_objects` lint suggests using `dyn Trait` for trait
+    /// objects.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// trait Trait { }
+    ///
+    /// fn takes_trait_object(_: Box<Trait>) {
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Without the `dyn` indicator, it can be ambiguous or confusing when
+    /// reading code as to whether or not you are looking at a trait object.
+    /// The `dyn` keyword makes it explicit, and adds a symmetry to contrast
+    /// with [`impl Trait`].
+    ///
+    /// [`impl Trait`]: https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
     pub BARE_TRAIT_OBJECTS,
     Warn,
     "suggest using `dyn Trait` for trait objects"
 }
 
 declare_lint! {
+    /// The `absolute_paths_not_starting_with_crate` lint detects fully
+    /// qualified paths that start with a module name instead of `crate`,
+    /// `self`, or an extern crate name
+    ///
+    /// ### Example
+    ///
+    /// ```rust,edition2015,compile_fail
+    /// #![deny(absolute_paths_not_starting_with_crate)]
+    ///
+    /// mod foo {
+    ///     pub fn bar() {}
+    /// }
+    ///
+    /// fn main() {
+    ///     ::foo::bar();
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Rust [editions] allow the language to evolve without breaking
+    /// backwards compatibility. This lint catches code that uses absolute
+    /// paths in the style of the 2015 edition. In the 2015 edition, absolute
+    /// paths (those starting with `::`) refer to either the crate root or an
+    /// external crate. In the 2018 edition it was changed so that they only
+    /// refer to external crates. The path prefix `crate::` should be used
+    /// instead to reference items from the crate root.
+    ///
+    /// If you switch the compiler from the 2015 to 2018 edition without
+    /// updating the code, then it will fail to compile if the old style paths
+    /// are used. You can manually change the paths to use the `crate::`
+    /// prefix to transition to the 2018 edition.
+    ///
+    /// This lint solves the problem automatically. It is "allow" by default
+    /// because the code is perfectly valid in the 2015 edition. The [`cargo
+    /// fix`] tool with the `--edition` flag will switch this lint to "warn"
+    /// and automatically apply the suggested fix from the compiler. This
+    /// provides a completely automated way to update old code to the 2018
+    /// edition.
+    ///
+    /// [editions]: https://doc.rust-lang.org/edition-guide/
+    /// [`cargo fix`]: https://doc.rust-lang.org/cargo/commands/cargo-fix.html
     pub ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE,
     Allow,
     "fully qualified paths that start with a module name \
 }
 
 declare_lint! {
+    /// The `illegal_floating_point_literal_pattern` lint detects
+    /// floating-point literals used in patterns.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// let x = 42.0;
+    ///
+    /// match x {
+    ///     5.0 => {}
+    ///     _ => {}
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Previous versions of the compiler accepted floating-point literals in
+    /// patterns, but it was later determined this was a mistake. The
+    /// semantics of comparing floating-point values may not be clear in a
+    /// pattern when contrasted with "structural equality". Typically you can
+    /// work around this by using a [match guard], such as:
+    ///
+    /// ```rust
+    /// # let x = 42.0;
+    ///
+    /// match x {
+    ///     y if y == 5.0 => {}
+    ///     _ => {}
+    /// }
+    /// ```
+    ///
+    /// This is a [future-incompatible] lint to transition this to a hard
+    /// error in the future. See [issue #41620] for more details.
+    ///
+    /// [issue #41620]: https://github.com/rust-lang/rust/issues/41620
+    /// [match guard]: https://doc.rust-lang.org/reference/expressions/match-expr.html#match-guards
+    /// [future-incompatible]: ../index.md#future-incompatible-lints
     pub ILLEGAL_FLOATING_POINT_LITERAL_PATTERN,
     Warn,
     "floating-point literals cannot be used in patterns",
 }
 
 declare_lint! {
+    /// The `unstable_name_collisions` lint detects that you have used a name
+    /// that the standard library plans to add in the future.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// trait MyIterator : Iterator {
+    ///     // is_sorted is an unstable method that already exists on the Iterator trait
+    ///     fn is_sorted(self) -> bool where Self: Sized {true}
+    /// }
+    ///
+    /// impl<T: ?Sized> MyIterator for T where T: Iterator { }
+    ///
+    /// let x = vec![1,2,3];
+    /// let _ = x.iter().is_sorted();
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// When new methods are added to traits in the standard library, they are
+    /// usually added in an "unstable" form which is only available on the
+    /// [nightly channel] with a [`feature` attribute]. If there is any
+    /// pre-existing code which extends a trait to have a method with the same
+    /// name, then the names will collide. In the future, when the method is
+    /// stabilized, this will cause an error due to the ambiguity. This lint
+    /// is an early-warning to let you know that there may be a collision in
+    /// the future. This can be avoided by adding type annotations to
+    /// disambiguate which trait method you intend to call, such as
+    /// `MyIterator::is_sorted(my_iter)` or renaming or removing the method.
+    ///
+    /// [nightly channel]: https://doc.rust-lang.org/book/appendix-07-nightly-rust.html
+    /// [`feature` attribute]: https://doc.rust-lang.org/nightly/unstable-book/
     pub UNSTABLE_NAME_COLLISIONS,
     Warn,
     "detects name collision with an existing but unstable method",
 }
 
 declare_lint! {
+    /// The `irrefutable_let_patterns` lint detects detects [irrefutable
+    /// patterns] in [if-let] and [while-let] statements.
+    ///
+    ///
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// if let _ = 123 {
+    ///     println!("always runs!");
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// There usually isn't a reason to have an irrefutable pattern in an
+    /// if-let or while-let statement, because the pattern will always match
+    /// successfully. A [`let`] or [`loop`] statement will suffice. However,
+    /// when generating code with a macro, forbidding irrefutable patterns
+    /// would require awkward workarounds in situations where the macro
+    /// doesn't know if the pattern is refutable or not. This lint allows
+    /// macros to accept this form, while alerting for a possibly incorrect
+    /// use in normal code.
+    ///
+    /// See [RFC 2086] for more details.
+    ///
+    /// [irrefutable patterns]: https://doc.rust-lang.org/reference/patterns.html#refutability
+    /// [if-let]: https://doc.rust-lang.org/reference/expressions/if-expr.html#if-let-expressions
+    /// [while-let]: https://doc.rust-lang.org/reference/expressions/loop-expr.html#predicate-pattern-loops
+    /// [`let`]: https://doc.rust-lang.org/reference/statements.html#let-statements
+    /// [`loop`]: https://doc.rust-lang.org/reference/expressions/loop-expr.html#infinite-loops
+    /// [RFC 2086]: https://github.com/rust-lang/rfcs/blob/master/text/2086-allow-if-let-irrefutables.md
     pub IRREFUTABLE_LET_PATTERNS,
     Warn,
     "detects irrefutable patterns in if-let and while-let statements"
 }
 
 declare_lint! {
+    /// The `unused_labels` lint detects [labels] that are never used.
+    ///
+    /// [labels]: https://doc.rust-lang.org/reference/expressions/loop-expr.html#loop-labels
+    ///
+    /// ### Example
+    ///
+    /// ```rust,no_run
+    /// 'unused_label: loop {}
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Unused labels may signal a mistake or unfinished code. To silence the
+    /// warning for the individual label, prefix it with an underscore such as
+    /// `'_my_label:`.
     pub UNUSED_LABELS,
     Warn,
     "detects labels that are never used"
 }
 
 declare_lint! {
+    /// The `broken_intra_doc_links` lint detects failures in resolving
+    /// intra-doc link targets. This is a `rustdoc` only lint, see the
+    /// documentation in the [rustdoc book].
+    ///
+    /// [rustdoc book]: ../../../rustdoc/lints.html#broken_intra_doc_links
     pub BROKEN_INTRA_DOC_LINKS,
     Warn,
     "failures in resolving intra-doc link targets"
 }
 
 declare_lint! {
+    /// The `invalid_codeblock_attributes` lint detects code block attributes
+    /// in documentation examples that have potentially mis-typed values. This
+    /// is a `rustdoc` only lint, see the documentation in the [rustdoc book].
+    ///
+    /// [rustdoc book]: ../../../rustdoc/lints.html#invalid_codeblock_attributes
     pub INVALID_CODEBLOCK_ATTRIBUTES,
     Warn,
     "codeblock attribute looks a lot like a known one"
 }
 
 declare_lint! {
+    /// The `missing_crate_level_docs` lint detects if documentation is
+    /// missing at the crate root. This is a `rustdoc` only lint, see the
+    /// documentation in the [rustdoc book].
+    ///
+    /// [rustdoc book]: ../../../rustdoc/lints.html#missing_crate_level_docs
     pub MISSING_CRATE_LEVEL_DOCS,
     Allow,
     "detects crates with no crate-level documentation"
 }
 
 declare_lint! {
+    /// The `missing_doc_code_examples` lint detects publicly-exported items
+    /// without code samples in their documentation. This is a `rustdoc` only
+    /// lint, see the documentation in the [rustdoc book].
+    ///
+    /// [rustdoc book]: ../../../rustdoc/lints.html#missing_doc_code_examples
     pub MISSING_DOC_CODE_EXAMPLES,
     Allow,
     "detects publicly-exported items without code samples in their documentation"
 }
 
 declare_lint! {
+    /// The `private_doc_tests` lint detects code samples in docs of private
+    /// items not documented by `rustdoc`. This is a `rustdoc` only lint, see
+    /// the documentation in the [rustdoc book].
+    ///
+    /// [rustdoc book]: ../../../rustdoc/lints.html#private_doc_tests
     pub PRIVATE_DOC_TESTS,
     Allow,
     "detects code samples in docs of private items not documented by rustdoc"
 }
 
 declare_lint! {
+    /// The `where_clauses_object_safety` lint detects for [object safety] of
+    /// [where clauses].
+    ///
+    /// [object safety]: https://doc.rust-lang.org/reference/items/traits.html#object-safety
+    /// [where clauses]: https://doc.rust-lang.org/reference/items/generics.html#where-clauses
+    ///
+    /// ### Example
+    ///
+    /// ```rust,no_run
+    /// trait Trait {}
+    ///
+    /// trait X { fn foo(&self) where Self: Trait; }
+    ///
+    /// impl X for () { fn foo(&self) {} }
+    ///
+    /// impl Trait for dyn X {}
+    ///
+    /// // Segfault at opt-level 0, SIGILL otherwise.
+    /// pub fn main() { <dyn X as X>::foo(&()); }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// The compiler previously allowed these object-unsafe bounds, which was
+    /// incorrect. This is a [future-incompatible] lint to transition this to
+    /// a hard error in the future. See [issue #51443] for more details.
+    ///
+    /// [issue #51443]: https://github.com/rust-lang/rust/issues/51443
+    /// [future-incompatible]: ../index.md#future-incompatible-lints
     pub WHERE_CLAUSES_OBJECT_SAFETY,
     Warn,
     "checks the object safety of where clauses",
 }
 
 declare_lint! {
+    /// The `proc_macro_derive_resolution_fallback` lint detects proc macro
+    /// derives using inaccessible names from parent modules.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,ignore (proc-macro)
+    /// // foo.rs
+    /// #![crate_type = "proc-macro"]
+    ///
+    /// extern crate proc_macro;
+    ///
+    /// use proc_macro::*;
+    ///
+    /// #[proc_macro_derive(Foo)]
+    /// pub fn foo1(a: TokenStream) -> TokenStream {
+    ///     drop(a);
+    ///     "mod __bar { static mut BAR: Option<Something> = None; }".parse().unwrap()
+    /// }
+    /// ```
+    ///
+    /// ```rust,ignore (needs-dependency)
+    /// // bar.rs
+    /// #[macro_use]
+    /// extern crate foo;
+    ///
+    /// struct Something;
+    ///
+    /// #[derive(Foo)]
+    /// struct Another;
+    ///
+    /// fn main() {}
+    /// ```
+    ///
+    /// This will produce:
+    ///
+    /// ```text
+    /// warning: cannot find type `Something` in this scope
+    ///  --> src/main.rs:8:10
+    ///   |
+    /// 8 | #[derive(Foo)]
+    ///   |          ^^^ names from parent modules are not accessible without an explicit import
+    ///   |
+    ///   = note: `#[warn(proc_macro_derive_resolution_fallback)]` on by default
+    ///   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+    ///   = note: for more information, see issue #50504 <https://github.com/rust-lang/rust/issues/50504>
+    /// ```
+    ///
+    /// ### Explanation
+    ///
+    /// If a proc-macro generates a module, the compiler unintentionally
+    /// allowed items in that module to refer to items in the crate root
+    /// without importing them. This is a [future-incompatible] lint to
+    /// transition this to a hard error in the future. See [issue #50504] for
+    /// more details.
+    ///
+    /// [issue #50504]: https://github.com/rust-lang/rust/issues/50504
+    /// [future-incompatible]: ../index.md#future-incompatible-lints
     pub PROC_MACRO_DERIVE_RESOLUTION_FALLBACK,
     Warn,
     "detects proc macro derives using inaccessible names from parent modules",
 }
 
 declare_lint! {
+    /// The `macro_use_extern_crate` lint detects the use of the
+    /// [`macro_use` attribute].
+    ///
+    /// ### Example
+    ///
+    /// ```rust,ignore (needs extern crate)
+    /// #![deny(macro_use_extern_crate)]
+    ///
+    /// #[macro_use]
+    /// extern crate serde_json;
+    ///
+    /// fn main() {
+    ///     let _ = json!{{}};
+    /// }
+    /// ```
+    ///
+    /// This will produce:
+    ///
+    /// ```text
+    /// error: deprecated `#[macro_use]` attribute used to import macros should be replaced at use sites with a `use` item to import the macro instead
+    ///  --> src/main.rs:3:1
+    ///   |
+    /// 3 | #[macro_use]
+    ///   | ^^^^^^^^^^^^
+    ///   |
+    /// note: the lint level is defined here
+    ///  --> src/main.rs:1:9
+    ///   |
+    /// 1 | #![deny(macro_use_extern_crate)]
+    ///   |         ^^^^^^^^^^^^^^^^^^^^^^
+    /// ```
+    ///
+    /// ### Explanation
+    ///
+    /// The [`macro_use` attribute] on an [`extern crate`] item causes
+    /// macros in that external crate to be brought into the prelude of the
+    /// crate, making the macros in scope everywhere. As part of the efforts
+    /// to simplify handling of dependencies in the [2018 edition], the use of
+    /// `extern crate` is being phased out. To bring macros from extern crates
+    /// into scope, it is recommended to use a [`use` import].
+    ///
+    /// This lint is "allow" by default because this is a stylistic choice
+    /// that has not been settled, see [issue #52043] for more information.
+    ///
+    /// [`macro_use` attribute]: https://doc.rust-lang.org/reference/macros-by-example.html#the-macro_use-attribute
+    /// [`use` import]: https://doc.rust-lang.org/reference/items/use-declarations.html
+    /// [issue #52043]: https://github.com/rust-lang/rust/issues/52043
     pub MACRO_USE_EXTERN_CRATE,
     Allow,
     "the `#[macro_use]` attribute is now deprecated in favor of using macros \
 }
 
 declare_lint! {
+    /// The `macro_expanded_macro_exports_accessed_by_absolute_paths` lint
+    /// detects macro-expanded [`macro_export`] macros from the current crate
+    /// that cannot be referred to by absolute paths.
+    ///
+    /// [`macro_export`]: https://doc.rust-lang.org/reference/macros-by-example.html#path-based-scope
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// macro_rules! define_exported {
+    ///     () => {
+    ///         #[macro_export]
+    ///         macro_rules! exported {
+    ///             () => {};
+    ///         }
+    ///     };
+    /// }
+    ///
+    /// define_exported!();
+    ///
+    /// fn main() {
+    ///     crate::exported!();
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// The intent is that all macros marked with the `#[macro_export]`
+    /// attribute are made available in the root of the crate. However, when a
+    /// `macro_rules!` definition is generated by another macro, the macro
+    /// expansion is unable to uphold this rule. This is a
+    /// [future-incompatible] lint to transition this to a hard error in the
+    /// future. See [issue #53495] for more details.
+    ///
+    /// [issue #53495]: https://github.com/rust-lang/rust/issues/53495
+    /// [future-incompatible]: ../index.md#future-incompatible-lints
     pub MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS,
     Deny,
     "macro-expanded `macro_export` macros from the current crate \
 }
 
 declare_lint! {
+    /// The `explicit_outlives_requirements` lint detects unnecessary
+    /// lifetime bounds that can be inferred.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// # #![allow(unused)]
+    /// #![deny(explicit_outlives_requirements)]
+    ///
+    /// struct SharedRef<'a, T>
+    /// where
+    ///     T: 'a,
+    /// {
+    ///     data: &'a T,
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// If a `struct` contains a reference, such as `&'a T`, the compiler
+    /// requires that `T` outlives the lifetime `'a`. This historically
+    /// required writing an explicit lifetime bound to indicate this
+    /// requirement. However, this can be overly explicit, causing clutter and
+    /// unnecessary complexity. The language was changed to automatically
+    /// infer the bound if it is not specified. Specifically, if the struct
+    /// contains a reference, directly or indirectly, to `T` with lifetime
+    /// `'x`, then it will infer that `T: 'x` is a requirement.
+    ///
+    /// This lint is "allow" by default because it can be noisy for existing
+    /// code that already had these requirements. This is a stylistic choice,
+    /// as it is still valid to explicitly state the bound. It also has some
+    /// false positives that can cause confusion.
+    ///
+    /// See [RFC 2093] for more details.
+    ///
+    /// [RFC 2093]: https://github.com/rust-lang/rfcs/blob/master/text/2093-infer-outlives.md
     pub EXPLICIT_OUTLIVES_REQUIREMENTS,
     Allow,
     "outlives requirements can be inferred"
 }
 
 declare_lint! {
+    /// The `indirect_structural_match` lint detects a `const` in a pattern
+    /// that manually implements [`PartialEq`] and [`Eq`].
+    ///
+    /// [`PartialEq`]: https://doc.rust-lang.org/std/cmp/trait.PartialEq.html
+    /// [`Eq`]: https://doc.rust-lang.org/std/cmp/trait.Eq.html
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// #![deny(indirect_structural_match)]
+    ///
+    /// struct Plus(i32, i32);
+    /// const ONE_PLUS_TWO: &&Plus = &&Plus(1, 2);
+    ///
+    /// impl PartialEq for Plus {
+    ///     fn eq(&self, other: &Self) -> bool {
+    ///         self.0 + self.1 == other.0 + other.1
+    ///     }
+    /// }
+    ///
+    /// impl Eq for Plus {}
+    ///
+    /// fn main() {
+    ///     if let ONE_PLUS_TWO = &&Plus(3, 0) {
+    ///         println!("semantic!");
+    ///     } else {
+    ///         println!("structural!");
+    ///     }
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// The compiler unintentionally accepted this form in the past. This is a
+    /// [future-incompatible] lint to transition this to a hard error in the
+    /// future. See [issue #62411] for a complete description of the problem,
+    /// and some possible solutions.
+    ///
+    /// [issue #62411]: https://github.com/rust-lang/rust/issues/62411
+    /// [future-incompatible]: ../index.md#future-incompatible-lints
     pub INDIRECT_STRUCTURAL_MATCH,
     // defaulting to allow until rust-lang/rust#62614 is fixed.
     Allow,
 }
 
 declare_lint! {
+    /// The `deprecated_in_future` lint is internal to rustc and should not be
+    /// used by user code.
+    ///
+    /// This lint is only enabled in the standard library. It works with the
+    /// use of `#[rustc_deprecated]` with a `since` field of a version in the
+    /// future. This allows something to be marked as deprecated in a future
+    /// version, and then this lint will ensure that the item is no longer
+    /// used in the standard library. See the [stability documentation] for
+    /// more details.
+    ///
+    /// [stability documentation]: https://rustc-dev-guide.rust-lang.org/stability.html#rustc_deprecated
     pub DEPRECATED_IN_FUTURE,
     Allow,
     "detects use of items that will be deprecated in a future version",
 }
 
 declare_lint! {
+    /// The `ambiguous_associated_items` lint detects ambiguity between
+    /// [associated items] and [enum variants].
+    ///
+    /// [associated items]: https://doc.rust-lang.org/reference/items/associated-items.html
+    /// [enum variants]: https://doc.rust-lang.org/reference/items/enumerations.html
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// enum E {
+    ///     V
+    /// }
+    ///
+    /// trait Tr {
+    ///     type V;
+    ///     fn foo() -> Self::V;
+    /// }
+    ///
+    /// impl Tr for E {
+    ///     type V = u8;
+    ///     // `Self::V` is ambiguous because it may refer to the associated type or
+    ///     // the enum variant.
+    ///     fn foo() -> Self::V { 0 }
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Previous versions of Rust did not allow accessing enum variants
+    /// through [type aliases]. When this ability was added (see [RFC 2338]), this
+    /// introduced some situations where it can be ambiguous what a type
+    /// was referring to.
+    ///
+    /// To fix this ambiguity, you should use a [qualified path] to explicitly
+    /// state which type to use. For example, in the above example the
+    /// function can be written as `fn f() -> <Self as Tr>::V { 0 }` to
+    /// specifically refer to the associated type.
+    ///
+    /// This is a [future-incompatible] lint to transition this to a hard
+    /// error in the future. See [issue #57644] for more details.
+    ///
+    /// [issue #57644]: https://github.com/rust-lang/rust/issues/57644
+    /// [type aliases]: https://doc.rust-lang.org/reference/items/type-aliases.html#type-aliases
+    /// [RFC 2338]: https://github.com/rust-lang/rfcs/blob/master/text/2338-type-alias-enum-variants.md
+    /// [qualified path]: https://doc.rust-lang.org/reference/paths.html#qualified-paths
+    /// [future-incompatible]: ../index.md#future-incompatible-lints
     pub AMBIGUOUS_ASSOCIATED_ITEMS,
     Deny,
     "ambiguous associated items",
 }
 
 declare_lint! {
+    /// The `mutable_borrow_reservation_conflict` lint detects the reservation
+    /// of a two-phased borrow that conflicts with other shared borrows.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// let mut v = vec![0, 1, 2];
+    /// let shared = &v;
+    /// v.push(shared.len());
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// This is a [future-incompatible] lint to transition this to a hard error
+    /// in the future. See [issue #59159] for a complete description of the
+    /// problem, and some possible solutions.
+    ///
+    /// [issue #59159]: https://github.com/rust-lang/rust/issues/59159
+    /// [future-incompatible]: ../index.md#future-incompatible-lints
     pub MUTABLE_BORROW_RESERVATION_CONFLICT,
     Warn,
     "reservation of a two-phased borrow conflicts with other shared borrows",
 }
 
 declare_lint! {
+    /// The `soft_unstable` lint detects unstable features that were
+    /// unintentionally allowed on stable.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// #[cfg(test)]
+    /// extern crate test;
+    ///
+    /// #[bench]
+    /// fn name(b: &mut test::Bencher) {
+    ///     b.iter(|| 123)
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// The [`bench` attribute] was accidentally allowed to be specified on
+    /// the [stable release channel]. Turning this to a hard error would have
+    /// broken some projects. This lint allows those projects to continue to
+    /// build correctly when [`--cap-lints`] is used, but otherwise signal an
+    /// error that `#[bench]` should not be used on the stable channel. This
+    /// is a [future-incompatible] lint to transition this to a hard error in
+    /// the future. See [issue #64266] for more details.
+    ///
+    /// [issue #64266]: https://github.com/rust-lang/rust/issues/64266
+    /// [`bench` attribute]: https://doc.rust-lang.org/nightly/unstable-book/library-features/test.html
+    /// [stable release channel]: https://doc.rust-lang.org/book/appendix-07-nightly-rust.html
+    /// [`--cap-lints`]: https://doc.rust-lang.org/rustc/lints/levels.html#capping-lints
+    /// [future-incompatible]: ../index.md#future-incompatible-lints
     pub SOFT_UNSTABLE,
     Deny,
     "a feature gate that doesn't break dependent crates",
 }
 
 declare_lint! {
+    /// The `inline_no_sanitize` lint detects incompatible use of
+    /// [`#[inline(always)]`][inline] and [`#[no_sanitize(...)]`][no_sanitize].
+    ///
+    /// [inline]: https://doc.rust-lang.org/reference/attributes/codegen.html#the-inline-attribute
+    /// [no_sanitize]: https://doc.rust-lang.org/nightly/unstable-book/language-features/no-sanitize.html
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// #![feature(no_sanitize)]
+    ///
+    /// #[inline(always)]
+    /// #[no_sanitize(address)]
+    /// fn x() {}
+    ///
+    /// fn main() {
+    ///     x()
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// The use of the [`#[inline(always)]`][inline] attribute prevents the
+    /// the [`#[no_sanitize(...)]`][no_sanitize] attribute from working.
+    /// Consider temporarily removing `inline` attribute.
     pub INLINE_NO_SANITIZE,
     Warn,
     "detects incompatible use of `#[inline(always)]` and `#[no_sanitize(...)]`",
 }
 
 declare_lint! {
+    /// The `asm_sub_register` lint detects using only a subset of a register
+    /// for inline asm inputs.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,ignore (fails on system llvm)
+    /// #![feature(asm)]
+    ///
+    /// fn main() {
+    ///     #[cfg(target_arch="x86_64")]
+    ///     unsafe {
+    ///         asm!("mov {0}, {0}", in(reg) 0i16);
+    ///     }
+    /// }
+    /// ```
+    ///
+    /// This will produce:
+    ///
+    /// ```text
+    /// warning: formatting may not be suitable for sub-register argument
+    ///  --> src/main.rs:6:19
+    ///   |
+    /// 6 |         asm!("mov {0}, {0}", in(reg) 0i16);
+    ///   |                   ^^^  ^^^           ---- for this argument
+    ///   |
+    ///   = note: `#[warn(asm_sub_register)]` on by default
+    ///   = help: use the `x` modifier to have the register formatted as `ax`
+    ///   = help: or use the `r` modifier to keep the default formatting of `rax`
+    /// ```
+    ///
+    /// ### Explanation
+    ///
+    /// Registers on some architectures can use different names to refer to a
+    /// subset of the register. By default, the compiler will use the name for
+    /// the full register size. To explicitly use a subset of the register,
+    /// you can override the default by using a modifier on the template
+    /// string operand to specify when subregister to use. This lint is issued
+    /// if you pass in a value with a smaller data type than the default
+    /// register size, to alert you of possibly using the incorrect width. To
+    /// fix this, add the suggested modifier to the template, or cast the
+    /// value to the correct size.
+    ///
+    /// See [register template modifiers] for more details.
+    ///
+    /// [register template modifiers]: https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#register-template-modifiers
     pub ASM_SUB_REGISTER,
     Warn,
     "using only a subset of a register for inline asm inputs",
 }
 
 declare_lint! {
+    /// The `unsafe_op_in_unsafe_fn` lint detects unsafe operations in unsafe
+    /// functions without an explicit unsafe block. This lint only works on
+    /// the [**nightly channel**] with the
+    /// `#![feature(unsafe_block_in_unsafe_fn)]` feature.
+    ///
+    /// [**nightly channel**]: https://doc.rust-lang.org/book/appendix-07-nightly-rust.html
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// #![feature(unsafe_block_in_unsafe_fn)]
+    /// #![deny(unsafe_op_in_unsafe_fn)]
+    ///
+    /// unsafe fn foo() {}
+    ///
+    /// unsafe fn bar() {
+    ///     foo();
+    /// }
+    ///
+    /// fn main() {}
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Currently, an [`unsafe fn`] allows any [unsafe] operation within its
+    /// body. However, this can increase the surface area of code that needs
+    /// to be scrutinized for proper behavior. The [`unsafe` block] provides a
+    /// convenient way to make it clear exactly which parts of the code are
+    /// performing unsafe operations. In the future, it is desired to change
+    /// it so that unsafe operations cannot be performed in an `unsafe fn`
+    /// without an `unsafe` block.
+    ///
+    /// The fix to this is to wrap the unsafe code in an `unsafe` block.
+    ///
+    /// This lint is "allow" by default because it has not yet been
+    /// stabilized, and is not yet complete. See [RFC #2585] and [issue
+    /// #71668] for more details
+    ///
+    /// [`unsafe fn`]: https://doc.rust-lang.org/reference/unsafe-functions.html
+    /// [`unsafe` block]: https://doc.rust-lang.org/reference/expressions/block-expr.html#unsafe-blocks
+    /// [unsafe]: https://doc.rust-lang.org/reference/unsafety.html
+    /// [RFC #2585]: https://github.com/rust-lang/rfcs/blob/master/text/2585-unsafe-block-in-unsafe-fn.md
+    /// [issue #71668]: https://github.com/rust-lang/rust/issues/71668
     pub UNSAFE_OP_IN_UNSAFE_FN,
     Allow,
     "unsafe operations in unsafe functions without an explicit unsafe block are deprecated",
 }
 
 declare_lint! {
+    /// The `cenum_impl_drop_cast` lint detects an `as` cast of a field-less
+    /// `enum` that implements [`Drop`].
+    ///
+    /// [`Drop`]: https://doc.rust-lang.org/std/ops/trait.Drop.html
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// # #![allow(unused)]
+    /// enum E {
+    ///     A,
+    /// }
+    ///
+    /// impl Drop for E {
+    ///     fn drop(&mut self) {
+    ///         println!("Drop");
+    ///     }
+    /// }
+    ///
+    /// fn main() {
+    ///     let e = E::A;
+    ///     let i = e as u32;
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Casting a field-less `enum` that does not implement [`Copy`] to an
+    /// integer moves the value without calling `drop`. This can result in
+    /// surprising behavior if it was expected that `drop` should be called.
+    /// Calling `drop` automatically would be inconsistent with other move
+    /// operations. Since neither behavior is clear or consistent, it was
+    /// decided that a cast of this nature will no longer be allowed.
+    ///
+    /// This is a [future-incompatible] lint to transition this to a hard error
+    /// in the future. See [issue #73333] for more details.
+    ///
+    /// [future-incompatible]: ../index.md#future-incompatible-lints
+    /// [issue #73333]: https://github.com/rust-lang/rust/issues/73333
+    /// [`Copy`]: https://doc.rust-lang.org/std/marker/trait.Copy.html
     pub CENUM_IMPL_DROP_CAST,
     Warn,
     "a C-like enum implementing Drop is cast",
 }
 
 declare_lint! {
+    /// The `const_evaluatable_unchecked` lint detects a generic constant used
+    /// in a type.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// const fn foo<T>() -> usize {
+    ///     if std::mem::size_of::<*mut T>() < 8 { // size of *mut T does not depend on T
+    ///         4
+    ///     } else {
+    ///         8
+    ///     }
+    /// }
+    ///
+    /// fn test<T>() {
+    ///     let _ = [0; foo::<T>()];
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// In the 1.43 release, some uses of generic parameters in array repeat
+    /// expressions were accidentally allowed. This is a [future-incompatible]
+    /// lint to transition this to a hard error in the future. See [issue
+    /// #76200] for a more detailed description and possible fixes.
+    ///
+    /// [future-incompatible]: ../index.md#future-incompatible-lints
+    /// [issue #76200]: https://github.com/rust-lang/rust/issues/76200
     pub CONST_EVALUATABLE_UNCHECKED,
     Warn,
     "detects a generic constant is used in a type without a emitting a warning",
 }
 
 declare_lint! {
+    /// The `unused_doc_comments` lint detects doc comments that aren't used
+    /// by `rustdoc`.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// /// docs for x
+    /// let x = 12;
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// `rustdoc` does not use doc comments in all positions, and so the doc
+    /// comment will be ignored. Try changing it to a normal comment with `//`
+    /// to avoid the warning.
     pub UNUSED_DOC_COMMENTS,
     Warn,
     "detects doc comments that aren't used by rustdoc"
index b478a1d15c5065cc574c0e49b8d141f5319c13c0..e38cd516b91ac16edb12e91cd9791d6bda347f6a 100644 (file)
@@ -544,6 +544,12 @@ pub fn macro_backtrace(mut self) -> impl Iterator<Item = ExpnData> {
     }
 
     /// Returns a `Span` that would enclose both `self` and `end`.
+    ///
+    /// ```text
+    ///     ____             ___
+    ///     self lorem ipsum end
+    ///     ^^^^^^^^^^^^^^^^^^^^
+    /// ```
     pub fn to(self, end: Span) -> Span {
         let span_data = self.data();
         let end_data = end.data();
@@ -567,6 +573,12 @@ pub fn to(self, end: Span) -> Span {
     }
 
     /// Returns a `Span` between the end of `self` to the beginning of `end`.
+    ///
+    /// ```text
+    ///     ____             ___
+    ///     self lorem ipsum end
+    ///         ^^^^^^^^^^^^^
+    /// ```
     pub fn between(self, end: Span) -> Span {
         let span = self.data();
         let end = end.data();
@@ -577,7 +589,13 @@ pub fn between(self, end: Span) -> Span {
         )
     }
 
-    /// Returns a `Span` between the beginning of `self` to the beginning of `end`.
+    /// Returns a `Span` from the beginning of `self` until the beginning of `end`.
+    ///
+    /// ```text
+    ///     ____             ___
+    ///     self lorem ipsum end
+    ///     ^^^^^^^^^^^^^^^^^
+    /// ```
     pub fn until(self, end: Span) -> Span {
         let span = self.data();
         let end = end.data();
index 407663e57577affefe9243c00389a46861ee339d..94f795b11ea4d3047b72efdb3d93c8eec1c8a46f 100644 (file)
         deny,
         deprecated,
         deref,
+        deref_method,
         deref_mut,
+        deref_target,
         derive,
         diagnostic,
         direct,
index d6e8b304380ca51a383dc927839164bedb20239f..f1e8330425e25c099c5e3669e6c64dfa57045939 100644 (file)
@@ -654,6 +654,7 @@ fn $module() {
     ("riscv32i-unknown-none-elf", riscv32i_unknown_none_elf),
     ("riscv32imc-unknown-none-elf", riscv32imc_unknown_none_elf),
     ("riscv32imac-unknown-none-elf", riscv32imac_unknown_none_elf),
+    ("riscv32gc-unknown-linux-gnu", riscv32gc_unknown_linux_gnu),
     ("riscv64imac-unknown-none-elf", riscv64imac_unknown_none_elf),
     ("riscv64gc-unknown-none-elf", riscv64gc_unknown_none_elf),
     ("riscv64gc-unknown-linux-gnu", riscv64gc_unknown_linux_gnu),
diff --git a/compiler/rustc_target/src/spec/riscv32gc_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/riscv32gc_unknown_linux_gnu.rs
new file mode 100644 (file)
index 0000000..28710c6
--- /dev/null
@@ -0,0 +1,25 @@
+use crate::spec::{CodeModel, LinkerFlavor, Target, TargetOptions, TargetResult};
+
+pub fn target() -> TargetResult {
+    Ok(Target {
+        llvm_target: "riscv32-unknown-linux-gnu".to_string(),
+        target_endian: "little".to_string(),
+        target_pointer_width: "32".to_string(),
+        target_c_int_width: "32".to_string(),
+        target_env: "gnu".to_string(),
+        data_layout: "e-m:e-p:32:32-i64:64-n32-S128".to_string(),
+        arch: "riscv32".to_string(),
+        target_os: "linux".to_string(),
+        target_vendor: "unknown".to_string(),
+        linker_flavor: LinkerFlavor::Gcc,
+        options: TargetOptions {
+            unsupported_abis: super::riscv_base::unsupported_abis(),
+            code_model: Some(CodeModel::Medium),
+            cpu: "generic-rv32".to_string(),
+            features: "+m,+a,+f,+d,+c".to_string(),
+            llvm_abiname: "ilp32d".to_string(),
+            max_atomic_width: Some(32),
+            ..super::linux_base::opts()
+        },
+    })
+}
index 02eefe5622384a8e4319a99c196466b2027f7897..b9c5123e49a0ea3b35f3aa7c18e260647cce8f96 100644 (file)
@@ -27,6 +27,7 @@ pub struct Autoderef<'a, 'tcx> {
     // Meta infos:
     infcx: &'a InferCtxt<'a, 'tcx>,
     span: Span,
+    overloaded_span: Span,
     body_id: hir::HirId,
     param_env: ty::ParamEnv<'tcx>,
 
@@ -98,10 +99,12 @@ pub fn new(
         body_id: hir::HirId,
         span: Span,
         base_ty: Ty<'tcx>,
+        overloaded_span: Span,
     ) -> Autoderef<'a, 'tcx> {
         Autoderef {
             infcx,
             span,
+            overloaded_span,
             body_id,
             param_env,
             state: AutoderefSnapshot {
@@ -190,6 +193,10 @@ pub fn span(&self) -> Span {
         self.span
     }
 
+    pub fn overloaded_span(&self) -> Span {
+        self.overloaded_span
+    }
+
     pub fn reached_recursion_limit(&self) -> bool {
         self.state.reached_recursion_limit
     }
index a9651144e597adad3c9a66dc5ba66c1315cb1ae4..bda4351b2f2d8437623583a2d208eae41526a296 100644 (file)
@@ -1512,12 +1512,7 @@ fn maybe_report_ambiguity(
                 // avoid inundating the user with unnecessary errors, but we now
                 // check upstream for type errors and don't add the obligations to
                 // begin with in those cases.
-                if self
-                    .tcx
-                    .lang_items()
-                    .sized_trait()
-                    .map_or(false, |sized_id| sized_id == trait_ref.def_id())
-                {
+                if self.tcx.lang_items().sized_trait() == Some(trait_ref.def_id()) {
                     self.need_type_info_err(body_id, span, self_ty, ErrorCode::E0282).emit();
                     return;
                 }
index 82e809d014dd06050a1a750e107d9d81c1414b82..90a8d9634ae1e183907226e7831c6bf12ec9a3ba 100644 (file)
@@ -483,7 +483,7 @@ fn suggest_dereferences(
         };
 
         if let ty::Ref(region, base_ty, mutbl) = *real_ty.kind() {
-            let mut autoderef = Autoderef::new(self, param_env, body_id, span, base_ty);
+            let mut autoderef = Autoderef::new(self, param_env, body_id, span, base_ty, span);
             if let Some(steps) = autoderef.find_map(|(ty, steps)| {
                 // Re-add the `&`
                 let ty = self.tcx.mk_ref(region, TypeAndMut { ty, mutbl });
index 7cc567dabb28f7f59daaaab5a96670b1428a54f5..2fad54013ad5bebc5d836fb7963b129f98f8658d 100644 (file)
@@ -110,25 +110,15 @@ fn trait_datum(
             .map(|i| chalk_ir::AssocTypeId(i.def_id))
             .collect();
 
-        let well_known = if self
-            .interner
-            .tcx
-            .lang_items()
-            .sized_trait()
-            .map(|t| def_id == t)
-            .unwrap_or(false)
-        {
+        let well_known = if self.interner.tcx.lang_items().sized_trait() == Some(def_id) {
             Some(chalk_solve::rust_ir::WellKnownTrait::Sized)
-        } else if self.interner.tcx.lang_items().copy_trait().map(|t| def_id == t).unwrap_or(false)
-        {
+        } else if self.interner.tcx.lang_items().copy_trait() == Some(def_id) {
             Some(chalk_solve::rust_ir::WellKnownTrait::Copy)
-        } else if self.interner.tcx.lang_items().clone_trait().map(|t| def_id == t).unwrap_or(false)
-        {
+        } else if self.interner.tcx.lang_items().clone_trait() == Some(def_id) {
             Some(chalk_solve::rust_ir::WellKnownTrait::Clone)
-        } else if self.interner.tcx.lang_items().drop_trait().map(|t| def_id == t).unwrap_or(false)
-        {
+        } else if self.interner.tcx.lang_items().drop_trait() == Some(def_id) {
             Some(chalk_solve::rust_ir::WellKnownTrait::Drop)
-        } else if self.interner.tcx.lang_items().fn_trait().map(|t| def_id == t).unwrap_or(false) {
+        } else if self.interner.tcx.lang_items().fn_trait() == Some(def_id) {
             Some(chalk_solve::rust_ir::WellKnownTrait::Fn)
         } else if self
             .interner
index 9e339b1082cb8673b680521b868545df19276b93..a743dc1cd2086fda39b467b26293979e6ec74415 100644 (file)
@@ -1460,7 +1460,7 @@ pub fn associated_path_to_ty(
         // Find the type of the associated item, and the trait where the associated
         // item is declared.
         let bound = match (&qself_ty.kind(), qself_res) {
-            (_, Res::SelfTy(Some(_), Some(impl_def_id))) => {
+            (_, Res::SelfTy(Some(_), Some((impl_def_id, _)))) => {
                 // `Self` in an impl of a trait -- we have a concrete self type and a
                 // trait reference.
                 let trait_ref = match tcx.impl_trait_ref(impl_def_id) {
@@ -1917,12 +1917,29 @@ pub fn res_to_ty(
                 self.prohibit_generics(path.segments);
                 tcx.types.self_param
             }
-            Res::SelfTy(_, Some(def_id)) => {
+            Res::SelfTy(_, Some((def_id, forbid_generic))) => {
                 // `Self` in impl (we know the concrete type).
                 assert_eq!(opt_self_ty, None);
                 self.prohibit_generics(path.segments);
                 // Try to evaluate any array length constants.
-                self.normalize_ty(span, tcx.at(span).type_of(def_id))
+                let normalized_ty = self.normalize_ty(span, tcx.at(span).type_of(def_id));
+                if forbid_generic && normalized_ty.needs_subst() {
+                    let mut err = tcx.sess.struct_span_err(
+                        path.span,
+                        "generic `Self` types are currently not permitted in anonymous constants",
+                    );
+                    if let Some(hir::Node::Item(&hir::Item {
+                        kind: hir::ItemKind::Impl { self_ty, .. },
+                        ..
+                    })) = tcx.hir().get_if_local(def_id)
+                    {
+                        err.span_note(self_ty.span, "not a concrete type");
+                    }
+                    err.emit();
+                    tcx.ty_error()
+                } else {
+                    normalized_ty
+                }
             }
             Res::Def(DefKind::AssocTy, def_id) => {
                 debug_assert!(path.segments.len() >= 2);
index afd4413069ee10df5879f1eae2fb6aaba4198ab8..836a4ff78c79e1705c48a0b8cd19a7466564cb61 100644 (file)
@@ -1,12 +1,15 @@
 use crate::check::coercion::CoerceMany;
 use crate::check::{Diverges, Expectation, FnCtxt, Needs};
-use rustc_hir as hir;
-use rustc_hir::ExprKind;
+use rustc_hir::{self as hir, ExprKind};
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
-use rustc_middle::ty::Ty;
+use rustc_infer::traits::Obligation;
+use rustc_middle::ty::{self, ToPredicate, Ty};
 use rustc_span::Span;
-use rustc_trait_selection::traits::ObligationCauseCode;
-use rustc_trait_selection::traits::{IfExpressionCause, MatchExpressionArmCause, ObligationCause};
+use rustc_trait_selection::opaque_types::InferCtxtExt as _;
+use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
+use rustc_trait_selection::traits::{
+    IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode,
+};
 
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     pub fn check_match(
@@ -14,7 +17,7 @@ pub fn check_match(
         expr: &'tcx hir::Expr<'tcx>,
         scrut: &'tcx hir::Expr<'tcx>,
         arms: &'tcx [hir::Arm<'tcx>],
-        expected: Expectation<'tcx>,
+        orig_expected: Expectation<'tcx>,
         match_src: hir::MatchSource,
     ) -> Ty<'tcx> {
         let tcx = self.tcx;
@@ -22,7 +25,7 @@ pub fn check_match(
         use hir::MatchSource::*;
         let (source_if, if_no_else, force_scrutinee_bool) = match match_src {
             IfDesugar { contains_else_clause } => (true, !contains_else_clause, true),
-            IfLetDesugar { contains_else_clause } => (true, !contains_else_clause, false),
+            IfLetDesugar { contains_else_clause, .. } => (true, !contains_else_clause, false),
             WhileDesugar => (false, false, true),
             _ => (false, false, false),
         };
@@ -69,7 +72,7 @@ pub fn check_match(
         // type in that case)
         let mut all_arms_diverge = Diverges::WarnedAlways;
 
-        let expected = expected.adjust_for_branches(self);
+        let expected = orig_expected.adjust_for_branches(self);
 
         let mut coercion = {
             let coerce_first = match expected {
@@ -112,6 +115,60 @@ pub fn check_match(
                 self.check_expr_with_expectation(&arm.body, expected)
             };
             all_arms_diverge &= self.diverges.get();
+
+            // When we have a `match` as a tail expression in a `fn` with a returned `impl Trait`
+            // we check if the different arms would work with boxed trait objects instead and
+            // provide a structured suggestion in that case.
+            let opt_suggest_box_span = match (
+                orig_expected,
+                self.ret_coercion_impl_trait.map(|ty| (self.body_id.owner, ty)),
+            ) {
+                (Expectation::ExpectHasType(expected), Some((id, ty)))
+                    if self.in_tail_expr && self.can_coerce(arm_ty, expected) =>
+                {
+                    let impl_trait_ret_ty = self.infcx.instantiate_opaque_types(
+                        id,
+                        self.body_id,
+                        self.param_env,
+                        &ty,
+                        arm.body.span,
+                    );
+                    let mut suggest_box = !impl_trait_ret_ty.obligations.is_empty();
+                    for o in impl_trait_ret_ty.obligations {
+                        match o.predicate.skip_binders_unchecked() {
+                            ty::PredicateAtom::Trait(t, constness) => {
+                                let pred = ty::PredicateAtom::Trait(
+                                    ty::TraitPredicate {
+                                        trait_ref: ty::TraitRef {
+                                            def_id: t.def_id(),
+                                            substs: self.infcx.tcx.mk_substs_trait(arm_ty, &[]),
+                                        },
+                                    },
+                                    constness,
+                                );
+                                let obl = Obligation::new(
+                                    o.cause.clone(),
+                                    self.param_env,
+                                    pred.to_predicate(self.infcx.tcx),
+                                );
+                                suggest_box &= self.infcx.predicate_must_hold_modulo_regions(&obl);
+                                if !suggest_box {
+                                    // We've encountered some obligation that didn't hold, so the
+                                    // return expression can't just be boxed. We don't need to
+                                    // evaluate the rest of the obligations.
+                                    break;
+                                }
+                            }
+                            _ => {}
+                        }
+                    }
+                    // If all the obligations hold (or there are no obligations) the tail expression
+                    // we can suggest to return a boxed trait object instead of an opaque type.
+                    if suggest_box { self.ret_type_span.clone() } else { None }
+                }
+                _ => None,
+            };
+
             if source_if {
                 let then_expr = &arms[0].body;
                 match (i, if_no_else) {
@@ -119,7 +176,14 @@ pub fn check_match(
                     (_, true) => {} // Handled above to avoid duplicated type errors (#60254).
                     (_, _) => {
                         let then_ty = prior_arm_ty.unwrap();
-                        let cause = self.if_cause(expr.span, then_expr, &arm.body, then_ty, arm_ty);
+                        let cause = self.if_cause(
+                            expr.span,
+                            then_expr,
+                            &arm.body,
+                            then_ty,
+                            arm_ty,
+                            opt_suggest_box_span,
+                        );
                         coercion.coerce(self, &cause, &arm.body, arm_ty);
                     }
                 }
@@ -142,6 +206,7 @@ pub fn check_match(
                             prior_arms: other_arms.clone(),
                             last_ty: prior_arm_ty.unwrap(),
                             scrut_hir_id: scrut.hir_id,
+                            opt_suggest_box_span,
                         }),
                     ),
                 };
@@ -266,6 +331,7 @@ fn if_cause(
         else_expr: &'tcx hir::Expr<'tcx>,
         then_ty: Ty<'tcx>,
         else_ty: Ty<'tcx>,
+        opt_suggest_box_span: Option<Span>,
     ) -> ObligationCause<'tcx> {
         let mut outer_sp = if self.tcx.sess.source_map().is_multiline(span) {
             // The `if`/`else` isn't in one line in the output, include some context to make it
@@ -353,8 +419,10 @@ fn if_cause(
             error_sp,
             ObligationCauseCode::IfExpression(box IfExpressionCause {
                 then: then_sp,
+                else_sp: error_sp,
                 outer: outer_sp,
                 semicolon: remove_semicolon,
+                opt_suggest_box_span,
             }),
         )
     }
index 17364897bde13a75671d4c7f5ba33add21174ecf..59c366ad7d776cb41868bc18140e042f70ccab60 100644 (file)
 
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     pub fn autoderef(&'a self, span: Span, base_ty: Ty<'tcx>) -> Autoderef<'a, 'tcx> {
-        Autoderef::new(self, self.param_env, self.body_id, span, base_ty)
+        Autoderef::new(self, self.param_env, self.body_id, span, base_ty, span)
+    }
+
+    /// Like `autoderef`, but provides a custom `Span` to use for calls to
+    /// an overloaded `Deref` operator
+    pub fn autoderef_overloaded_span(
+        &'a self,
+        span: Span,
+        base_ty: Ty<'tcx>,
+        overloaded_span: Span,
+    ) -> Autoderef<'a, 'tcx> {
+        Autoderef::new(self, self.param_env, self.body_id, span, base_ty, overloaded_span)
     }
 
     pub fn try_overloaded_deref(
@@ -44,7 +55,11 @@ pub fn adjust_steps_as_infer_ok(
                         |InferOk { value: method, obligations: o }| {
                             obligations.extend(o);
                             if let ty::Ref(region, _, mutbl) = *method.sig.output().kind() {
-                                Some(OverloadedDeref { region, mutbl })
+                                Some(OverloadedDeref {
+                                    region,
+                                    mutbl,
+                                    span: autoderef.overloaded_span(),
+                                })
                             } else {
                                 None
                             }
index e19130112970d6fb87f65901e2c9737cfef846d0..4addee1a4c97643c1d094b4d646c163005ae12cf 100644 (file)
@@ -37,7 +37,7 @@
 
 use crate::astconv::AstConv;
 use crate::check::FnCtxt;
-use rustc_errors::{struct_span_err, DiagnosticBuilder};
+use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
 use rustc_hir as hir;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_infer::infer::{Coercion, InferOk, InferResult};
@@ -51,7 +51,7 @@
 use rustc_middle::ty::{self, Ty, TypeAndMut};
 use rustc_session::parse::feature_err;
 use rustc_span::symbol::sym;
-use rustc_span::{self, Span};
+use rustc_span::{self, BytePos, Span};
 use rustc_target::spec::abi::Abi;
 use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
 use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode};
@@ -1459,7 +1459,7 @@ fn report_return_mismatched_types<'a>(
             }
         }
         if let (Some(sp), Some(fn_output)) = (fcx.ret_coercion_span.borrow().as_ref(), fn_output) {
-            self.add_impl_trait_explanation(&mut err, fcx, expected, *sp, fn_output);
+            self.add_impl_trait_explanation(&mut err, cause, fcx, expected, *sp, fn_output);
         }
         err
     }
@@ -1467,6 +1467,7 @@ fn report_return_mismatched_types<'a>(
     fn add_impl_trait_explanation<'a>(
         &self,
         err: &mut DiagnosticBuilder<'a>,
+        cause: &ObligationCause<'tcx>,
         fcx: &FnCtxt<'a, 'tcx>,
         expected: Ty<'tcx>,
         sp: Span,
@@ -1523,10 +1524,30 @@ fn add_impl_trait_explanation<'a>(
         };
         if has_impl {
             if is_object_safe {
-                err.help(&format!(
-                    "you can instead return a boxed trait object using `Box<dyn {}>`",
-                    &snippet[5..]
-                ));
+                err.multipart_suggestion(
+                    "you could change the return type to be a boxed trait object",
+                    vec![
+                        (return_sp.with_hi(return_sp.lo() + BytePos(4)), "Box<dyn".to_string()),
+                        (return_sp.shrink_to_hi(), ">".to_string()),
+                    ],
+                    Applicability::MachineApplicable,
+                );
+                let sugg = vec![sp, cause.span]
+                    .into_iter()
+                    .flat_map(|sp| {
+                        vec![
+                            (sp.shrink_to_lo(), "Box::new(".to_string()),
+                            (sp.shrink_to_hi(), ")".to_string()),
+                        ]
+                        .into_iter()
+                    })
+                    .collect::<Vec<_>>();
+                err.multipart_suggestion(
+                    "if you change the return type to expect trait objects, box the returned \
+                     expressions",
+                    sugg,
+                    Applicability::MaybeIncorrect,
+                );
             } else {
                 err.help(&format!(
                     "if the trait `{}` were object safe, you could return a boxed trait object",
@@ -1535,7 +1556,7 @@ fn add_impl_trait_explanation<'a>(
             }
             err.note(trait_obj_msg);
         }
-        err.help("alternatively, create a new `enum` with a variant for each returned type");
+        err.help("you could instead create a new `enum` with a variant for each returned type");
     }
 
     fn is_return_ty_unsized(&self, fcx: &FnCtxt<'a, 'tcx>, blk_id: hir::HirId) -> bool {
index ae338cccf797791ab1e77e881f37d0f279557a17..fd2700b85e2790a7721e523f4e0a272880babb21 100644 (file)
@@ -137,7 +137,8 @@ fn adjust_self_ty(
     ) -> Ty<'tcx> {
         // Commit the autoderefs by calling `autoderef` again, but this
         // time writing the results into the various typeck results.
-        let mut autoderef = self.autoderef(self.span, unadjusted_self_ty);
+        let mut autoderef =
+            self.autoderef_overloaded_span(self.span, unadjusted_self_ty, self.call_expr.span);
         let (_, n) = match autoderef.nth(pick.autoderefs) {
             Some(n) => n,
             None => {
index ebe71b86c9221f52de120bd9adfa3a01024fe2b2..8a62031ec887caed2885f04f843ec053dfcc8701 100644 (file)
@@ -446,9 +446,10 @@ fn method_autoderef_steps<'tcx>(
     tcx.infer_ctxt().enter_with_canonical(DUMMY_SP, &goal, |ref infcx, goal, inference_vars| {
         let ParamEnvAnd { param_env, value: self_ty } = goal;
 
-        let mut autoderef = Autoderef::new(infcx, param_env, hir::CRATE_HIR_ID, DUMMY_SP, self_ty)
-            .include_raw_pointers()
-            .silence_errors();
+        let mut autoderef =
+            Autoderef::new(infcx, param_env, hir::CRATE_HIR_ID, DUMMY_SP, self_ty, DUMMY_SP)
+                .include_raw_pointers()
+                .silence_errors();
         let mut reached_raw_pointer = false;
         let mut steps: Vec<_> = autoderef
             .by_ref()
index b95034adb24d1a4f58e106cd604ace7dfbdc4356..9a9e57638d7589ad10c85c3c13f94709bcf5407a 100644 (file)
@@ -570,6 +570,14 @@ pub struct FnCtxt<'a, 'tcx> {
     /// any).
     ret_coercion: Option<RefCell<DynamicCoerceMany<'tcx>>>,
 
+    ret_coercion_impl_trait: Option<Ty<'tcx>>,
+
+    ret_type_span: Option<Span>,
+
+    /// Used exclusively to reduce cost of advanced evaluation used for
+    /// more helpful diagnostics.
+    in_tail_expr: bool,
+
     /// First span of a return site that we find. Used in error messages.
     ret_coercion_span: RefCell<Option<Span>>,
 
@@ -1302,10 +1310,15 @@ fn check_fn<'a, 'tcx>(
     let hir = tcx.hir();
 
     let declared_ret_ty = fn_sig.output();
+
     let revealed_ret_ty =
         fcx.instantiate_opaque_types_from_value(fn_id, &declared_ret_ty, decl.output.span());
     debug!("check_fn: declared_ret_ty: {}, revealed_ret_ty: {}", declared_ret_ty, revealed_ret_ty);
     fcx.ret_coercion = Some(RefCell::new(CoerceMany::new(revealed_ret_ty)));
+    fcx.ret_type_span = Some(decl.output.span());
+    if let ty::Opaque(..) = declared_ret_ty.kind() {
+        fcx.ret_coercion_impl_trait = Some(declared_ret_ty);
+    }
     fn_sig = tcx.mk_fn_sig(
         fn_sig.inputs().iter().cloned(),
         revealed_ret_ty,
@@ -1366,6 +1379,7 @@ fn check_fn<'a, 'tcx>(
 
     inherited.typeck_results.borrow_mut().liberated_fn_sigs_mut().insert(fn_id, fn_sig);
 
+    fcx.in_tail_expr = true;
     if let ty::Dynamic(..) = declared_ret_ty.kind() {
         // FIXME: We need to verify that the return type is `Sized` after the return expression has
         // been evaluated so that we have types available for all the nodes being returned, but that
@@ -1385,6 +1399,7 @@ fn check_fn<'a, 'tcx>(
         fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType);
         fcx.check_return_expr(&body.value);
     }
+    fcx.in_tail_expr = false;
 
     // We insert the deferred_generator_interiors entry after visiting the body.
     // This ensures that all nested generators appear before the entry of this generator.
@@ -3084,6 +3099,9 @@ pub fn new(
             param_env,
             err_count_on_creation: inh.tcx.sess.err_count(),
             ret_coercion: None,
+            ret_coercion_impl_trait: None,
+            ret_type_span: None,
+            in_tail_expr: false,
             ret_coercion_span: RefCell::new(None),
             resume_yield_tys: None,
             ps: RefCell::new(UnsafetyState::function(hir::Unsafety::Normal, hir::CRATE_HIR_ID)),
@@ -4267,11 +4285,13 @@ fn point_at_arg_instead_of_call_if_possible(
                             None
                         }
                     })
-                    .collect::<Vec<_>>();
+                    .collect::<Vec<usize>>();
 
                 // Both checked and coerced types could have matched, thus we need to remove
                 // duplicates.
-                referenced_in.sort();
+
+                // We sort primitive type usize here and can use unstable sort
+                referenced_in.sort_unstable();
                 referenced_in.dedup();
 
                 if let (Some(ref_in), None) = (referenced_in.pop(), referenced_in.pop()) {
index 171d5ee4ff206bc838f0c01e07cd1ac7a4268863..6be2fdf9f19047c0cd8c9580c317ec159bc7ebef 100644 (file)
@@ -1150,7 +1150,8 @@ fn check_struct_pat_fields(
             if no_accessible_unmentioned_fields {
                 unmentioned_err = Some(self.error_no_accessible_fields(pat, &fields));
             } else {
-                unmentioned_err = Some(self.error_unmentioned_fields(pat, &unmentioned_fields));
+                unmentioned_err =
+                    Some(self.error_unmentioned_fields(pat, &unmentioned_fields, &fields));
             }
         }
         match (inexistent_fields_err, unmentioned_err) {
@@ -1405,6 +1406,7 @@ fn error_unmentioned_fields(
         &self,
         pat: &Pat<'_>,
         unmentioned_fields: &[(&ty::FieldDef, Ident)],
+        fields: &'tcx [hir::FieldPat<'tcx>],
     ) -> DiagnosticBuilder<'tcx> {
         let field_names = if unmentioned_fields.len() == 1 {
             format!("field `{}`", unmentioned_fields[0].1)
@@ -1424,14 +1426,52 @@ fn error_unmentioned_fields(
             field_names
         );
         err.span_label(pat.span, format!("missing {}", field_names));
-        if self.tcx.sess.teach(&err.get_code().unwrap()) {
-            err.note(
-                "This error indicates that a pattern for a struct fails to specify a \
-                 sub-pattern for every one of the struct's fields. Ensure that each field \
-                 from the struct's definition is mentioned in the pattern, or use `..` to \
-                 ignore unwanted fields.",
-            );
-        }
+        let len = unmentioned_fields.len();
+        let (prefix, postfix, sp) = match fields {
+            [] => match &pat.kind {
+                PatKind::Struct(path, [], false) => {
+                    (" { ", " }", path.span().shrink_to_hi().until(pat.span.shrink_to_hi()))
+                }
+                _ => return err,
+            },
+            [.., field] => (
+                match pat.kind {
+                    PatKind::Struct(_, [_, ..], _) => ", ",
+                    _ => "",
+                },
+                "",
+                field.span.shrink_to_hi(),
+            ),
+        };
+        err.span_suggestion(
+            sp,
+            &format!(
+                "include the missing field{} in the pattern",
+                if len == 1 { "" } else { "s" },
+            ),
+            format!(
+                "{}{}{}",
+                prefix,
+                unmentioned_fields
+                    .iter()
+                    .map(|(_, name)| name.to_string())
+                    .collect::<Vec<_>>()
+                    .join(", "),
+                postfix,
+            ),
+            Applicability::MachineApplicable,
+        );
+        err.span_suggestion(
+            sp,
+            &format!(
+                "if you don't care about {} missing field{}, you can explicitely ignore {}",
+                if len == 1 { "this" } else { "these" },
+                if len == 1 { "" } else { "s" },
+                if len == 1 { "it" } else { "them" },
+            ),
+            format!("{}..{}", prefix, postfix),
+            Applicability::MachineApplicable,
+        );
         err
     }
 
index aed2af20e5271f192dea23e913402bb52bc9c3f2..502cb562385e0de9432f10d4ab88b95ff4e51955 100644 (file)
@@ -242,7 +242,7 @@ pub fn convert_place_derefs_to_mutable(&self, expr: &hir::Expr<'_>) {
                         ) {
                             let method = self.register_infer_ok_obligations(ok);
                             if let ty::Ref(region, _, mutbl) = *method.sig.output().kind() {
-                                *deref = OverloadedDeref { region, mutbl };
+                                *deref = OverloadedDeref { region, mutbl, span: deref.span };
                             }
                             // If this is a union field, also throw an error for `DerefMut` of `ManuallyDrop` (see RFC 2514).
                             // This helps avoid accidental drops.
index 39c94d41e3a7f5f65c82a3e74c1c2d56425adc0b..99e6f9dceb41c8de420983db2d795980d27c575b 100644 (file)
 # General build configuration options
 # =============================================================================
 [build]
+# The default stage to use for the `doc` subcommand
+#doc-stage = 0
+
+# The default stage to use for the `build` subcommand
+#build-stage = 1
+
+# The default stage to use for the `test` subcommand
+#test-stage = 1
+
+# The default stage to use for the `dist` subcommand
+#dist-stage = 2
+
+# The default stage to use for the `install` subcommand
+#install-stage = 2
+
+# The default stage to use for the `bench` subcommand
+#bench-stage = 2
 
 # Build triple for the original snapshot compiler. This must be a compiler that
 # nightlies are already produced for. The current platform must be able to run
 #incremental = false
 
 # Build a multi-threaded rustc
+# FIXME(#75760): Some UI tests fail when this option is enabled.
 #parallel-compiler = false
 
 # The default linker that will be hard-coded into the generated compiler for
index 40aa4d850f59ddc0798b156ae97f67a8e5c6a006..24d17fdd880ba8bc9585f93ce7c4e08dbaf7b59e 100644 (file)
@@ -1343,6 +1343,10 @@ fn from(vec: Vec<T>) -> BinaryHeap<T> {
 
 #[stable(feature = "binary_heap_extras_15", since = "1.5.0")]
 impl<T> From<BinaryHeap<T>> for Vec<T> {
+    /// Converts a `BinaryHeap<T>` into a `Vec<T>`.
+    ///
+    /// This conversion requires no data movement or allocation, and has
+    /// constant time complexity.
     fn from(heap: BinaryHeap<T>) -> Vec<T> {
         heap.data
     }
index 8832619a404cb252506adcdf48d574b635595bef..6c343b17264404fb80a94cdbab26085adfe98794 100644 (file)
@@ -78,8 +78,8 @@ unsafe fn new() -> Self {
         LeafNode {
             // As a general policy, we leave fields uninitialized if they can be, as this should
             // be both slightly faster and easier to track in Valgrind.
-            keys: [MaybeUninit::UNINIT; CAPACITY],
-            vals: [MaybeUninit::UNINIT; CAPACITY],
+            keys: MaybeUninit::uninit_array(),
+            vals: MaybeUninit::uninit_array(),
             parent: ptr::null(),
             parent_idx: MaybeUninit::uninit(),
             len: 0,
@@ -111,7 +111,7 @@ impl<K, V> InternalNode<K, V> {
     /// `len` of 0), there must be one initialized and valid edge. This function does not set up
     /// such an edge.
     unsafe fn new() -> Self {
-        InternalNode { data: unsafe { LeafNode::new() }, edges: [MaybeUninit::UNINIT; 2 * B] }
+        InternalNode { data: unsafe { LeafNode::new() }, edges: MaybeUninit::uninit_array() }
     }
 }
 
index 253a3e9f2bea91e130c29c3a5ca49d51dc861240..65cfe9a9b49965c3b1576952c64f977c312b0ca4 100644 (file)
@@ -1089,11 +1089,7 @@ fn range_tail_head<R>(&self, range: R) -> (usize, usize)
     where
         R: RangeBounds<usize>,
     {
-        // SAFETY: This buffer is only used to check the range. It might be partially
-        // uninitialized, but `check_range` needs a contiguous slice.
-        // https://github.com/rust-lang/rust/pull/75207#discussion_r471193682
-        let buffer = unsafe { slice::from_raw_parts(self.ptr(), self.len()) };
-        let Range { start, end } = buffer.check_range(range);
+        let Range { start, end } = slice::check_range(self.len(), range);
         let tail = self.wrap_add(self.tail, start);
         let head = self.wrap_add(self.tail, end);
         (tail, head)
index 48313f9af98e6346b90dd70376f633d76c128c4a..7881c101f9f60f496f1b6f62b525c7cb330a2a2b 100644 (file)
@@ -76,6 +76,7 @@
 #![cfg_attr(test, feature(test))]
 #![feature(allocator_api)]
 #![feature(array_chunks)]
+#![feature(array_windows)]
 #![feature(allow_internal_unstable)]
 #![feature(arbitrary_self_types)]
 #![feature(box_patterns)]
 #![feature(fn_traits)]
 #![feature(fundamental)]
 #![feature(inplace_iteration)]
-#![feature(internal_uninit_const)]
 #![feature(lang_items)]
 #![feature(layout_for_ptr)]
 #![feature(libc)]
 #![feature(unsized_locals)]
 #![feature(allocator_internals)]
 #![feature(slice_partition_dedup)]
-#![feature(maybe_uninit_extra, maybe_uninit_slice)]
+#![feature(maybe_uninit_extra, maybe_uninit_slice, maybe_uninit_uninit_array)]
 #![feature(alloc_layout_extra)]
 #![feature(trusted_random_access)]
 #![feature(try_trait)]
index 677bfdd2349ec4c17f2a492a93408b0db0913cfa..79403cf86873ed28c13cb3a9f19b9892ed669c8f 100644 (file)
 use crate::boxed::Box;
 use crate::vec::Vec;
 
+#[unstable(feature = "slice_check_range", issue = "76393")]
+pub use core::slice::check_range;
 #[unstable(feature = "array_chunks", issue = "74985")]
 pub use core::slice::ArrayChunks;
 #[unstable(feature = "array_chunks", issue = "74985")]
 pub use core::slice::ArrayChunksMut;
+#[unstable(feature = "array_windows", issue = "75027")]
+pub use core::slice::ArrayWindows;
 #[stable(feature = "slice_get_slice", since = "1.28.0")]
 pub use core::slice::SliceIndex;
 #[stable(feature = "from_ref", since = "1.28.0")]
index e1724bf3c9a90ce4c67f688784de874384ce1fff..2b0ce5ede56308b1a907def495bc12d5215b0d27 100644 (file)
@@ -49,6 +49,7 @@
 use core::ops::Bound::{Excluded, Included, Unbounded};
 use core::ops::{self, Add, AddAssign, Index, IndexMut, Range, RangeBounds};
 use core::ptr;
+use core::slice;
 use core::str::{lossy, pattern::Pattern};
 
 use crate::borrow::{Cow, ToOwned};
@@ -1506,7 +1507,7 @@ pub fn drain<R>(&mut self, range: R) -> Drain<'_>
         // of the vector version. The data is just plain bytes.
         // Because the range removal happens in Drop, if the Drain iterator is leaked,
         // the removal will not happen.
-        let Range { start, end } = self.as_bytes().check_range(range);
+        let Range { start, end } = slice::check_range(self.len(), range);
         assert!(self.is_char_boundary(start));
         assert!(self.is_char_boundary(end));
 
index baa6c0919defe01c886b5366fc4da9a10893faf0..9dbea0dc9e68b9296d8d2dbdaebdb48635cb07d4 100644 (file)
 ///
 /// // ... and that's all!
 /// // you can also do it like this:
-/// let x : &[usize] = &v;
+/// let u: &[usize] = &v;
+/// // or like this:
+/// let u: &[_] = &v;
 /// ```
 ///
 /// In Rust, it's more common to pass slices as arguments rather than vectors
@@ -1310,7 +1312,7 @@ pub fn drain<R>(&mut self, range: R) -> Drain<'_, T>
         // the hole, and the vector length is restored to the new length.
         //
         let len = self.len();
-        let Range { start, end } = self.check_range(range);
+        let Range { start, end } = slice::check_range(len, range);
 
         unsafe {
             // set self.vec length's to start, to be safe in case Drain is leaked
@@ -1410,6 +1412,11 @@ fn assert_failed(at: usize, len: usize) -> ! {
             assert_failed(at, self.len());
         }
 
+        if at == 0 {
+            // the new vector can take over the original buffer and avoid the copy
+            return mem::replace(self, Vec::with_capacity(self.capacity()));
+        }
+
         let other_len = self.len - at;
         let mut other = Vec::with_capacity(other_len);
 
@@ -3032,6 +3039,7 @@ fn as_into_iter(&mut self) -> &mut IntoIter<Self::Item> {
 /// A draining iterator for `Vec<T>`.
 ///
 /// This `struct` is created by [`Vec::drain`].
+/// See its documentation for more.
 #[stable(feature = "drain", since = "1.6.0")]
 pub struct Drain<'a, T: 'a> {
     /// Index of tail to preserve
index 590639d983481bdc0b3f0518ff820941d5fbf0cc..03737e1ef1f4dcd4d8be3439edffbd365ea8741f 100644 (file)
@@ -15,6 +15,7 @@
 #![feature(slice_ptr_get)]
 #![feature(split_inclusive)]
 #![feature(binary_heap_retain)]
+#![feature(deque_range)]
 #![feature(inplace_iteration)]
 #![feature(iter_map_while)]
 
index b20cf076aca3cac5dacea42cfc143ea5525b93fd..ed8ee2d8823c022449bdbf27caf8b4269fc140df 100644 (file)
@@ -1921,3 +1921,24 @@ fn foo<'a, P>(p: P)
 
     foo::<&str>("x");
 }
+
+#[test]
+fn test_str_multiline() {
+    let a: String = "this \
+is a test"
+        .to_string();
+    let b: String = "this \
+              is \
+              another \
+              test"
+        .to_string();
+    assert_eq!(a, "this is a test".to_string());
+    assert_eq!(b, "this is another test".to_string());
+}
+
+#[test]
+fn test_str_escapes() {
+    let x = "\\\\\
+    ";
+    assert_eq!(x, r"\\"); // extraneous whitespace stripped
+}
index 6059bec8c5a3d911b26c409172f49af36aca75f6..4e6043541226f77310e96628c9b23a7a5026354e 100644 (file)
@@ -1,6 +1,7 @@
 use std::borrow::Cow;
 use std::collections::TryReserveError::*;
 use std::mem::size_of;
+use std::ops::Bound::*;
 
 pub trait IntoCow<'a, B: ?Sized>
 where
@@ -271,24 +272,28 @@ fn test_split_off_past_end() {
 #[test]
 #[should_panic]
 fn test_split_off_mid_char() {
-    let mut orig = String::from("山");
-    let _ = orig.split_off(1);
+    let mut shan = String::from("山");
+    let _broken_mountain = shan.split_off(1);
 }
 
 #[test]
 fn test_split_off_ascii() {
     let mut ab = String::from("ABCD");
+    let orig_capacity = ab.capacity();
     let cd = ab.split_off(2);
     assert_eq!(ab, "AB");
     assert_eq!(cd, "CD");
+    assert_eq!(ab.capacity(), orig_capacity);
 }
 
 #[test]
 fn test_split_off_unicode() {
     let mut nihon = String::from("日本語");
+    let orig_capacity = nihon.capacity();
     let go = nihon.split_off("日本".len());
     assert_eq!(nihon, "日本");
     assert_eq!(go, "語");
+    assert_eq!(nihon.capacity(), orig_capacity);
 }
 
 #[test]
@@ -463,6 +468,20 @@ fn test_drain() {
     assert_eq!(t, "");
 }
 
+#[test]
+#[should_panic]
+fn test_drain_start_overflow() {
+    let mut s = String::from("abc");
+    s.drain((Excluded(usize::MAX), Included(0)));
+}
+
+#[test]
+#[should_panic]
+fn test_drain_end_overflow() {
+    let mut s = String::from("abc");
+    s.drain((Included(0), Included(usize::MAX)));
+}
+
 #[test]
 fn test_replace_range() {
     let mut s = "Hello, world!".to_owned();
@@ -500,6 +519,20 @@ fn test_replace_range_inclusive_out_of_bounds() {
     s.replace_range(5..=5, "789");
 }
 
+#[test]
+#[should_panic]
+fn test_replace_range_start_overflow() {
+    let mut s = String::from("123");
+    s.replace_range((Excluded(usize::MAX), Included(0)), "");
+}
+
+#[test]
+#[should_panic]
+fn test_replace_range_end_overflow() {
+    let mut s = String::from("456");
+    s.replace_range((Included(0), Included(usize::MAX)), "");
+}
+
 #[test]
 fn test_replace_range_empty() {
     let mut s = String::from("12345");
index 53b0d0a2718445328ee7f3605f4ab695130e66fe..368ca4c543219a50d0d8e8a601185eeea7d4c5da 100644 (file)
@@ -3,6 +3,7 @@
 use std::fmt::Debug;
 use std::iter::InPlaceIterable;
 use std::mem::size_of;
+use std::ops::Bound::*;
 use std::panic::{catch_unwind, AssertUnwindSafe};
 use std::rc::Rc;
 use std::vec::{Drain, IntoIter};
@@ -645,6 +646,16 @@ fn test_drain_max_vec_size() {
     assert_eq!(v.len(), usize::MAX - 1);
 }
 
+#[test]
+#[should_panic]
+fn test_drain_index_overflow() {
+    let mut v = Vec::<()>::with_capacity(usize::MAX);
+    unsafe {
+        v.set_len(usize::MAX);
+    }
+    v.drain(0..=usize::MAX);
+}
+
 #[test]
 #[should_panic]
 fn test_drain_inclusive_out_of_bounds() {
@@ -652,6 +663,20 @@ fn test_drain_inclusive_out_of_bounds() {
     v.drain(5..=5);
 }
 
+#[test]
+#[should_panic]
+fn test_drain_start_overflow() {
+    let mut v = vec![1, 2, 3];
+    v.drain((Excluded(usize::MAX), Included(0)));
+}
+
+#[test]
+#[should_panic]
+fn test_drain_end_overflow() {
+    let mut v = vec![1, 2, 3];
+    v.drain((Included(0), Included(usize::MAX)));
+}
+
 #[test]
 fn test_drain_leak() {
     static mut DROPS: i32 = 0;
@@ -772,9 +797,23 @@ fn test_append() {
 #[test]
 fn test_split_off() {
     let mut vec = vec![1, 2, 3, 4, 5, 6];
+    let orig_capacity = vec.capacity();
     let vec2 = vec.split_off(4);
     assert_eq!(vec, [1, 2, 3, 4]);
     assert_eq!(vec2, [5, 6]);
+    assert_eq!(vec.capacity(), orig_capacity);
+}
+
+#[test]
+fn test_split_off_take_all() {
+    let mut vec = vec![1, 2, 3, 4, 5, 6];
+    let orig_ptr = vec.as_ptr();
+    let orig_capacity = vec.capacity();
+    let vec2 = vec.split_off(0);
+    assert_eq!(vec, []);
+    assert_eq!(vec2, [1, 2, 3, 4, 5, 6]);
+    assert_eq!(vec.capacity(), orig_capacity);
+    assert_eq!(vec2.as_ptr(), orig_ptr);
 }
 
 #[test]
@@ -880,7 +919,7 @@ fn test_from_iter_partially_drained_in_place_specialization() {
 #[test]
 fn test_from_iter_specialization_with_iterator_adapters() {
     fn assert_in_place_trait<T: InPlaceIterable>(_: &T) {};
-    let src: Vec<usize> = vec![0usize; 65535];
+    let src: Vec<usize> = vec![0usize; 256];
     let srcptr = src.as_ptr();
     let iter = src
         .into_iter()
@@ -1511,6 +1550,9 @@ fn next_then_drop<I: Iterator>(mut i: I) {
     // Test that, if we reserved enough space, adding and removing elements does not
     // invalidate references into the vector (such as `v0`).  This test also
     // runs in Miri, which would detect such problems.
+    // Note that this test does *not* constitute a stable guarantee that all these functions do not
+    // reallocate! Only what is explicitly documented at
+    // <https://doc.rust-lang.org/nightly/std/vec/struct.Vec.html#guarantees> is stably guaranteed.
     let mut v = Vec::with_capacity(128);
     v.push(13);
 
index 762dc4be44d6208950d4bd03e2fba8de66c45fcc..46d8a3c4cb4931126d578fd51d675e3f8758ff79 100644 (file)
@@ -2,6 +2,7 @@
 use std::collections::{vec_deque::Drain, VecDeque};
 use std::fmt::Debug;
 use std::mem::size_of;
+use std::ops::Bound::*;
 use std::panic::{catch_unwind, AssertUnwindSafe};
 
 use crate::hash;
@@ -115,6 +116,20 @@ fn test_index_out_of_bounds() {
     deq[3];
 }
 
+#[test]
+#[should_panic]
+fn test_range_start_overflow() {
+    let deq = VecDeque::from(vec![1, 2, 3]);
+    deq.range((Included(0), Included(usize::MAX)));
+}
+
+#[test]
+#[should_panic]
+fn test_range_end_overflow() {
+    let deq = VecDeque::from(vec![1, 2, 3]);
+    deq.range((Excluded(usize::MAX), Included(0)));
+}
+
 #[derive(Clone, PartialEq, Debug)]
 enum Taggy {
     One(i32),
index 3953c73319fe419e5b33d735e68020a2cad20c85..dde442aa7b52de84c2a3810c6627c70fb99f6295 100644 (file)
@@ -356,8 +356,9 @@ impl Ordering {
     /// ```
     #[inline]
     #[must_use]
+    #[rustc_const_stable(feature = "const_ordering", since = "1.48.0")]
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn reverse(self) -> Ordering {
+    pub const fn reverse(self) -> Ordering {
         match self {
             Less => Greater,
             Equal => Equal,
@@ -394,8 +395,9 @@ pub fn reverse(self) -> Ordering {
     /// ```
     #[inline]
     #[must_use]
+    #[rustc_const_stable(feature = "const_ordering", since = "1.48.0")]
     #[stable(feature = "ordering_chaining", since = "1.17.0")]
-    pub fn then(self, other: Ordering) -> Ordering {
+    pub const fn then(self, other: Ordering) -> Ordering {
         match self {
             Equal => other,
             _ => self,
index d40a3802867624dd8d3dcd425ff2eaf3662f7956..1192b9e164a1450efb5ec71bf4bf59798f5649dd 100644 (file)
@@ -111,7 +111,7 @@ pub fn spin_loop() {
 #[inline]
 #[unstable(feature = "test", issue = "50297")]
 #[allow(unreachable_code)] // this makes #[cfg] a bit easier below.
-pub fn black_box<T>(dummy: T) -> T {
+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
     // this. LLVM's interpretation of inline assembly is that it's, well, a black
@@ -121,7 +121,8 @@ pub fn black_box<T>(dummy: T) -> T {
     #[cfg(not(miri))] // This is just a hint, so it is fine to skip in Miri.
     // SAFETY: the inline assembly is a no-op.
     unsafe {
-        llvm_asm!("" : : "r"(&dummy));
+        // FIXME: Cannot use `asm!` because it doesn't support MIPS and other architectures.
+        llvm_asm!("" : : "r"(&mut dummy) : "memory" : "volatile");
     }
 
     dummy
index 6700ef017bde43922f51411083d3f99d4b9ce134..13c6a75d58b5c101512308fac928784d7fa4cad9 100644 (file)
@@ -4,11 +4,8 @@
 
 /// An iterator that links two iterators together, in a chain.
 ///
-/// This `struct` is created by the [`chain`] method on [`Iterator`]. See its
-/// documentation for more.
-///
-/// [`chain`]: trait.Iterator.html#method.chain
-/// [`Iterator`]: trait.Iterator.html
+/// This `struct` is created by [`Iterator::chain`]. See its documentation
+/// for more.
 #[derive(Clone, Debug)]
 #[must_use = "iterators are lazy and do nothing unless consumed"]
 #[stable(feature = "rust1", since = "1.0.0")]
index 4202e52448dcfc358a865fb4cb9fe58d404a870e..ddb1aaebc1f3ecd3fd1869e9360badc273fe4845 100644 (file)
@@ -7,11 +7,8 @@
 /// An iterator that maps each element to an iterator, and yields the elements
 /// of the produced iterators.
 ///
-/// This `struct` is created by the [`flat_map`] method on [`Iterator`]. See its
-/// documentation for more.
-///
-/// [`flat_map`]: trait.Iterator.html#method.flat_map
-/// [`Iterator`]: trait.Iterator.html
+/// This `struct` is created by [`Iterator::flat_map`]. See its documentation
+/// for more.
 #[must_use = "iterators are lazy and do nothing unless consumed"]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct FlatMap<I, U: IntoIterator, F> {
index e02de0ce45dff75156d2978ff7987268cb3dc24c..a854f70dcd0bac5a5371f16857058e943587b043 100644 (file)
@@ -8,11 +8,8 @@
 
 /// An iterator that iterates two other iterators simultaneously.
 ///
-/// This `struct` is created by the [`zip`] method on [`Iterator`]. See its
-/// documentation for more.
-///
-/// [`zip`]: trait.Iterator.html#method.zip
-/// [`Iterator`]: trait.Iterator.html
+/// This `struct` is created by [`Iterator::zip`]. See its documentation
+/// for more.
 #[derive(Clone)]
 #[must_use = "iterators are lazy and do nothing unless consumed"]
 #[stable(feature = "rust1", since = "1.0.0")]
index c3cadcbb01e31b339071c6d3bb8c12d4ab76bb75..3bddc3772e60050177bb6594967b42647e903d88 100644 (file)
 #![feature(untagged_unions)]
 #![feature(unwind_attributes)]
 #![feature(variant_count)]
-#![feature(doc_alias)]
+#![cfg_attr(bootstrap, feature(doc_alias))]
 #![feature(mmx_target_feature)]
 #![feature(tbm_target_feature)]
 #![feature(sse4a_target_feature)]
index b0ebaa6a12b51186c8dbf433813b8e44225e1329..e629d28eae163c018a99f44bee0960ff0e9644f6 100644 (file)
@@ -306,14 +306,6 @@ pub const fn uninit() -> MaybeUninit<T> {
         unsafe { MaybeUninit::<[MaybeUninit<T>; LEN]>::uninit().assume_init() }
     }
 
-    /// A promotable constant, equivalent to `uninit()`.
-    #[unstable(
-        feature = "internal_uninit_const",
-        issue = "none",
-        reason = "hack to work around promotability"
-    )]
-    pub const UNINIT: Self = Self::uninit();
-
     /// Creates a new `MaybeUninit<T>` in an uninitialized state, with the memory being
     /// filled with `0` bytes. It depends on `T` whether that already makes for
     /// proper initialization. For example, `MaybeUninit<usize>::zeroed()` is initialized,
index 6d8ed2f4ffb1a158e9e62f845259d185e57f11d5..aa1b5529df22247a777697edb846a25c2f5194de 100644 (file)
 /// forever in an unreachable state. However, it does not guarantee that pointers
 /// to this memory will remain valid.
 ///
-/// * If you want to leak memory, see [`Box::leak`][leak].
-/// * If you want to obtain a raw pointer to the memory, see [`Box::into_raw`][into_raw].
+/// * If you want to leak memory, see [`Box::leak`].
+/// * If you want to obtain a raw pointer to the memory, see [`Box::into_raw`].
 /// * If you want to dispose of a value properly, running its destructor, see
-/// [`mem::drop`][drop].
+/// [`mem::drop`].
 ///
 /// # Safety
 ///
 /// ownership to `s` — the final step of interacting with `v` to dispose of it without
 /// running its destructor is entirely avoided.
 ///
-/// [drop]: fn.drop.html
-/// [uninit]: fn.uninitialized.html
-/// [clone]: ../clone/trait.Clone.html
-/// [swap]: fn.swap.html
-/// [box]: ../../std/boxed/struct.Box.html
-/// [leak]: ../../std/boxed/struct.Box.html#method.leak
-/// [into_raw]: ../../std/boxed/struct.Box.html#method.into_raw
+/// [`Box`]: ../../std/boxed/struct.Box.html
+/// [`Box::leak`]: ../../std/boxed/struct.Box.html#method.leak
+/// [`Box::into_raw`]: ../../std/boxed/struct.Box.html#method.into_raw
+/// [`mem::drop`]: drop
 /// [ub]: ../../reference/behavior-considered-undefined.html
-/// [`ManuallyDrop`]: struct.ManuallyDrop.html
 #[inline]
 #[rustc_const_stable(feature = "const_forget", since = "1.46.0")]
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -152,8 +148,6 @@ pub const fn forget<T>(t: T) {
 ///
 /// This function is just a shim intended to be removed when the `unsized_locals` feature gets
 /// stabilized.
-///
-/// [`forget`]: fn.forget.html
 #[inline]
 #[unstable(feature = "forget_unsized", issue = "none")]
 pub fn forget_unsized<T: ?Sized>(t: T) {
@@ -301,7 +295,7 @@ pub fn forget_unsized<T: ?Sized>(t: T) {
 /// assert_eq!(2, mem::size_of::<ExampleUnion>());
 /// ```
 ///
-/// [alignment]: ./fn.align_of.html
+/// [alignment]: align_of
 #[inline(always)]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_promotable]
@@ -365,7 +359,6 @@ pub const fn size_of_val<T: ?Sized>(val: &T) -> usize {
 /// [slice]: ../../std/primitive.slice.html
 /// [trait object]: ../../book/ch17-02-trait-objects.html
 /// [extern type]: ../../unstable-book/language-features/extern-types.html
-/// [`size_of_val`]: ../../core/mem/fn.size_of_val.html
 ///
 /// # Examples
 ///
@@ -501,7 +494,6 @@ pub const fn align_of_val<T: ?Sized>(val: &T) -> usize {
 /// [slice]: ../../std/primitive.slice.html
 /// [trait object]: ../../book/ch17-02-trait-objects.html
 /// [extern type]: ../../unstable-book/language-features/extern-types.html
-/// [`align_of_val`]: ../../core/mem/fn.align_of_val.html
 ///
 /// # Examples
 ///
@@ -540,7 +532,7 @@ pub unsafe fn align_of_val_raw<T: ?Sized>(val: *const T) -> usize {
 /// `needs_drop` explicitly. Types like [`HashMap`], on the other hand, have to drop
 /// values one at a time and should use this API.
 ///
-/// [`drop_in_place`]: ../ptr/fn.drop_in_place.html
+/// [`drop_in_place`]: crate::ptr::drop_in_place
 /// [`HashMap`]: ../../std/collections/struct.HashMap.html
 ///
 /// # Examples
@@ -595,9 +587,9 @@ pub const fn needs_drop<T>() -> bool {
 /// This has the same effect as [`MaybeUninit::zeroed().assume_init()`][zeroed].
 /// It is useful for FFI sometimes, but should generally be avoided.
 ///
-/// [zeroed]: union.MaybeUninit.html#method.zeroed
+/// [zeroed]: MaybeUninit::zeroed
 /// [ub]: ../../reference/behavior-considered-undefined.html
-/// [inv]: union.MaybeUninit.html#initialization-invariant
+/// [inv]: MaybeUninit#initialization-invariant
 ///
 /// # Examples
 ///
@@ -650,10 +642,10 @@ pub unsafe fn zeroed<T>() -> T {
 /// (Notice that the rules around uninitialized integers are not finalized yet, but
 /// until they are, it is advisable to avoid them.)
 ///
-/// [`MaybeUninit<T>`]: union.MaybeUninit.html
-/// [uninit]: union.MaybeUninit.html#method.uninit
-/// [assume_init]: union.MaybeUninit.html#method.assume_init
-/// [inv]: union.MaybeUninit.html#initialization-invariant
+/// [`MaybeUninit<T>`]: MaybeUninit
+/// [uninit]: MaybeUninit::uninit
+/// [assume_init]: MaybeUninit::assume_init
+/// [inv]: MaybeUninit#initialization-invariant
 #[inline(always)]
 #[rustc_deprecated(since = "1.39.0", reason = "use `mem::MaybeUninit` instead")]
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -686,9 +678,6 @@ pub unsafe fn uninitialized<T>() -> T {
 /// assert_eq!(42, x);
 /// assert_eq!(5, y);
 /// ```
-///
-/// [`replace`]: fn.replace.html
-/// [`take`]: fn.take.html
 #[inline]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub fn swap<T>(x: &mut T, y: &mut T) {
@@ -754,10 +743,6 @@ pub fn swap<T>(x: &mut T, y: &mut T) {
 /// assert_eq!(buffer.get_and_reset(), vec![0, 1]);
 /// assert_eq!(buffer.buf.len(), 0);
 /// ```
-///
-/// [`Clone`]: ../../std/clone/trait.Clone.html
-/// [`replace`]: fn.replace.html
-/// [`swap`]: fn.swap.html
 #[inline]
 #[stable(feature = "mem_take", since = "1.40.0")]
 pub fn take<T: Default>(dest: &mut T) -> T {
@@ -822,10 +807,6 @@ pub fn take<T: Default>(dest: &mut T) -> T {
 /// assert_eq!(buffer.replace_index(0, 2), 0);
 /// assert_eq!(buffer.buf[0], 2);
 /// ```
-///
-/// [`Clone`]: ../../std/clone/trait.Clone.html
-/// [`swap`]: fn.swap.html
-/// [`take`]: fn.take.html
 #[inline]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[must_use = "if you don't need the old value, you can just assign the new value directly"]
@@ -851,7 +832,7 @@ pub fn replace<T>(dest: &mut T, mut src: T) -> T {
 /// Because `_x` is moved into the function, it is automatically dropped before
 /// the function returns.
 ///
-/// [drop]: ../ops/trait.Drop.html
+/// [drop]: Drop
 ///
 /// # Examples
 ///
@@ -894,8 +875,7 @@ pub fn replace<T>(dest: &mut T, mut src: T) -> T {
 /// println!("x: {}, y: {}", x, y.0); // still available
 /// ```
 ///
-/// [`RefCell`]: ../../std/cell/struct.RefCell.html
-/// [`Copy`]: ../../std/marker/trait.Copy.html
+/// [`RefCell`]: crate::cell::RefCell
 #[inline]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub fn drop<T>(_x: T) {}
@@ -914,7 +894,6 @@ pub fn drop<T>(_x: T) {}
 /// `T`.
 ///
 /// [ub]: ../../reference/behavior-considered-undefined.html
-/// [size_of]: fn.size_of.html
 ///
 /// # Examples
 ///
@@ -960,8 +939,6 @@ pub unsafe fn transmute_copy<T, U>(src: &T) -> U {
 /// Opaque type representing the discriminant of an enum.
 ///
 /// See the [`discriminant`] function in this module for more information.
-///
-/// [`discriminant`]: fn.discriminant.html
 #[stable(feature = "discriminant_value", since = "1.21.0")]
 pub struct Discriminant<T>(<T as DiscriminantKind>::Discriminant);
 
index aaeb4d8a22c297eee22fb9514d1fe85ee60e6ad6..a5fbdc6ee2d4802528349acde70af9ff94e994f3 100644 (file)
@@ -60,12 +60,19 @@ mod fpu_precision {
     fn set_cw(cw: u16) {
         // SAFETY: the `fldcw` instruction has been audited to be able to work correctly with
         // any `u16`
-        unsafe { llvm_asm!("fldcw $0" :: "m" (cw) :: "volatile") }
+        unsafe {
+            asm!(
+                "fldcw ({})",
+                in(reg) &cw,
+                // FIXME: We are using ATT syntax to support LLVM 8 and LLVM 9.
+                options(att_syntax, nostack),
+            )
+        }
     }
 
     /// Sets the precision field of the FPU to `T` and returns a `FPUControlWord`.
     pub fn set_precision<T>() -> FPUControlWord {
-        let cw = 0u16;
+        let mut cw = 0_u16;
 
         // Compute the value for the Precision Control field that is appropriate for `T`.
         let cw_precision = match size_of::<T>() {
@@ -78,7 +85,14 @@ pub fn set_precision<T>() -> FPUControlWord {
         // `FPUControlWord` structure is dropped
         // SAFETY: the `fnstcw` instruction has been audited to be able to work correctly with
         // any `u16`
-        unsafe { llvm_asm!("fnstcw $0" : "=*m" (&cw) ::: "volatile") }
+        unsafe {
+            asm!(
+                "fnstcw ({})",
+                in(reg) &mut cw,
+                // FIXME: We are using ATT syntax to support LLVM 8 and LLVM 9.
+                options(att_syntax, nostack),
+            )
+        }
 
         // Set the control word to the desired precision. This is achieved by masking away the old
         // precision (bits 8 and 9, 0x300) and replacing it with the precision flag computed above.
index d6c097eee17bf96ff18540667972043d8b1e86c8..245152e5490d8c5e87c35f1479463985d428cce4 100644 (file)
 pub trait Deref {
     /// The resulting type after dereferencing.
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_diagnostic_item = "deref_target"]
     type Target: ?Sized;
 
     /// Dereferences the value.
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_diagnostic_item = "deref_method"]
     fn deref(&self) -> &Self::Target;
 }
 
diff --git a/library/core/src/slice/ascii.rs b/library/core/src/slice/ascii.rs
new file mode 100644 (file)
index 0000000..42032bc
--- /dev/null
@@ -0,0 +1,156 @@
+//! Operations on ASCII `[u8]`.
+
+use crate::mem;
+
+#[lang = "slice_u8"]
+#[cfg(not(test))]
+impl [u8] {
+    /// Checks if all bytes in this slice are within the ASCII range.
+    #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
+    #[inline]
+    pub fn is_ascii(&self) -> bool {
+        is_ascii(self)
+    }
+
+    /// Checks that two slices are an ASCII case-insensitive match.
+    ///
+    /// Same as `to_ascii_lowercase(a) == to_ascii_lowercase(b)`,
+    /// but without allocating and copying temporaries.
+    #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
+    #[inline]
+    pub fn eq_ignore_ascii_case(&self, other: &[u8]) -> bool {
+        self.len() == other.len() && self.iter().zip(other).all(|(a, b)| a.eq_ignore_ascii_case(b))
+    }
+
+    /// Converts this slice to its ASCII upper case equivalent in-place.
+    ///
+    /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z',
+    /// but non-ASCII letters are unchanged.
+    ///
+    /// To return a new uppercased value without modifying the existing one, use
+    /// [`to_ascii_uppercase`].
+    ///
+    /// [`to_ascii_uppercase`]: #method.to_ascii_uppercase
+    #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
+    #[inline]
+    pub fn make_ascii_uppercase(&mut self) {
+        for byte in self {
+            byte.make_ascii_uppercase();
+        }
+    }
+
+    /// Converts this slice to its ASCII lower case equivalent in-place.
+    ///
+    /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z',
+    /// but non-ASCII letters are unchanged.
+    ///
+    /// To return a new lowercased value without modifying the existing one, use
+    /// [`to_ascii_lowercase`].
+    ///
+    /// [`to_ascii_lowercase`]: #method.to_ascii_lowercase
+    #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
+    #[inline]
+    pub fn make_ascii_lowercase(&mut self) {
+        for byte in self {
+            byte.make_ascii_lowercase();
+        }
+    }
+}
+
+/// Returns `true` if any byte in the word `v` is nonascii (>= 128). Snarfed
+/// from `../str/mod.rs`, which does something similar for utf8 validation.
+#[inline]
+fn contains_nonascii(v: usize) -> bool {
+    const NONASCII_MASK: usize = 0x80808080_80808080u64 as usize;
+    (NONASCII_MASK & v) != 0
+}
+
+/// Optimized ASCII test that will use usize-at-a-time operations instead of
+/// byte-at-a-time operations (when possible).
+///
+/// The algorithm we use here is pretty simple. If `s` is too short, we just
+/// check each byte and be done with it. Otherwise:
+///
+/// - Read the first word with an unaligned load.
+/// - Align the pointer, read subsequent words until end with aligned loads.
+/// - Read the last `usize` from `s` with an unaligned load.
+///
+/// If any of these loads produces something for which `contains_nonascii`
+/// (above) returns true, then we know the answer is false.
+#[inline]
+fn is_ascii(s: &[u8]) -> bool {
+    const USIZE_SIZE: usize = mem::size_of::<usize>();
+
+    let len = s.len();
+    let align_offset = s.as_ptr().align_offset(USIZE_SIZE);
+
+    // If we wouldn't gain anything from the word-at-a-time implementation, fall
+    // back to a scalar loop.
+    //
+    // We also do this for architectures where `size_of::<usize>()` isn't
+    // sufficient alignment for `usize`, because it's a weird edge case.
+    if len < USIZE_SIZE || len < align_offset || USIZE_SIZE < mem::align_of::<usize>() {
+        return s.iter().all(|b| b.is_ascii());
+    }
+
+    // We always read the first word unaligned, which means `align_offset` is
+    // 0, we'd read the same value again for the aligned read.
+    let offset_to_aligned = if align_offset == 0 { USIZE_SIZE } else { align_offset };
+
+    let start = s.as_ptr();
+    // SAFETY: We verify `len < USIZE_SIZE` above.
+    let first_word = unsafe { (start as *const usize).read_unaligned() };
+
+    if contains_nonascii(first_word) {
+        return false;
+    }
+    // We checked this above, somewhat implicitly. Note that `offset_to_aligned`
+    // is either `align_offset` or `USIZE_SIZE`, both of are explicitly checked
+    // above.
+    debug_assert!(offset_to_aligned <= len);
+
+    // SAFETY: word_ptr is the (properly aligned) usize ptr we use to read the
+    // middle chunk of the slice.
+    let mut word_ptr = unsafe { start.add(offset_to_aligned) as *const usize };
+
+    // `byte_pos` is the byte index of `word_ptr`, used for loop end checks.
+    let mut byte_pos = offset_to_aligned;
+
+    // Paranoia check about alignment, since we're about to do a bunch of
+    // unaligned loads. In practice this should be impossible barring a bug in
+    // `align_offset` though.
+    debug_assert_eq!((word_ptr as usize) % mem::align_of::<usize>(), 0);
+
+    // Read subsequent words until the last aligned word, excluding the last
+    // aligned word by itself to be done in tail check later, to ensure that
+    // tail is always one `usize` at most to extra branch `byte_pos == len`.
+    while byte_pos < len - USIZE_SIZE {
+        debug_assert!(
+            // Sanity check that the read is in bounds
+            (word_ptr as usize + USIZE_SIZE) <= (start.wrapping_add(len) as usize) &&
+            // And that our assumptions about `byte_pos` hold.
+            (word_ptr as usize) - (start as usize) == byte_pos
+        );
+
+        // SAFETY: We know `word_ptr` is properly aligned (because of
+        // `align_offset`), and we know that we have enough bytes between `word_ptr` and the end
+        let word = unsafe { word_ptr.read() };
+        if contains_nonascii(word) {
+            return false;
+        }
+
+        byte_pos += USIZE_SIZE;
+        // SAFETY: We know that `byte_pos <= len - USIZE_SIZE`, which means that
+        // after this `add`, `word_ptr` will be at most one-past-the-end.
+        word_ptr = unsafe { word_ptr.add(1) };
+    }
+
+    // Sanity check to ensure there really is only one `usize` left. This should
+    // be guaranteed by our loop condition.
+    debug_assert!(byte_pos <= len && len - byte_pos <= USIZE_SIZE);
+
+    // SAFETY: This relies on `len >= USIZE_SIZE`, which we check at the start.
+    let last_word = unsafe { (start.add(len - USIZE_SIZE) as *const usize).read_unaligned() };
+
+    !contains_nonascii(last_word)
+}
diff --git a/library/core/src/slice/cmp.rs b/library/core/src/slice/cmp.rs
new file mode 100644 (file)
index 0000000..27a358b
--- /dev/null
@@ -0,0 +1,286 @@
+//! Comparison traits for `[T]`.
+
+use crate::cmp;
+use crate::cmp::Ordering::{self, Greater, Less};
+use crate::mem;
+
+use super::from_raw_parts;
+use super::memchr;
+
+extern "C" {
+    /// Calls implementation provided memcmp.
+    ///
+    /// Interprets the data as u8.
+    ///
+    /// Returns 0 for equal, < 0 for less than and > 0 for greater
+    /// than.
+    // FIXME(#32610): Return type should be c_int
+    fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32;
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<A, B> PartialEq<[B]> for [A]
+where
+    A: PartialEq<B>,
+{
+    fn eq(&self, other: &[B]) -> bool {
+        SlicePartialEq::equal(self, other)
+    }
+
+    fn ne(&self, other: &[B]) -> bool {
+        SlicePartialEq::not_equal(self, other)
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: Eq> Eq for [T] {}
+
+/// Implements comparison of vectors lexicographically.
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: Ord> Ord for [T] {
+    fn cmp(&self, other: &[T]) -> Ordering {
+        SliceOrd::compare(self, other)
+    }
+}
+
+/// Implements comparison of vectors lexicographically.
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: PartialOrd> PartialOrd for [T] {
+    fn partial_cmp(&self, other: &[T]) -> Option<Ordering> {
+        SlicePartialOrd::partial_compare(self, other)
+    }
+}
+
+#[doc(hidden)]
+// intermediate trait for specialization of slice's PartialEq
+trait SlicePartialEq<B> {
+    fn equal(&self, other: &[B]) -> bool;
+
+    fn not_equal(&self, other: &[B]) -> bool {
+        !self.equal(other)
+    }
+}
+
+// Generic slice equality
+impl<A, B> SlicePartialEq<B> for [A]
+where
+    A: PartialEq<B>,
+{
+    default fn equal(&self, other: &[B]) -> bool {
+        if self.len() != other.len() {
+            return false;
+        }
+
+        self.iter().zip(other.iter()).all(|(x, y)| x == y)
+    }
+}
+
+// Use an equal-pointer optimization when types are `Eq`
+// We can't make `A` and `B` the same type because `min_specialization` won't
+// allow it.
+impl<A, B> SlicePartialEq<B> for [A]
+where
+    A: MarkerEq<B>,
+{
+    default fn equal(&self, other: &[B]) -> bool {
+        if self.len() != other.len() {
+            return false;
+        }
+
+        // While performance would suffer if `guaranteed_eq` just returned `false`
+        // for all arguments, correctness and return value of this function are not affected.
+        if self.as_ptr().guaranteed_eq(other.as_ptr() as *const A) {
+            return true;
+        }
+
+        self.iter().zip(other.iter()).all(|(x, y)| x == y)
+    }
+}
+
+// Use memcmp for bytewise equality when the types allow
+impl<A, B> SlicePartialEq<B> for [A]
+where
+    A: BytewiseEquality<B>,
+{
+    fn equal(&self, other: &[B]) -> bool {
+        if self.len() != other.len() {
+            return false;
+        }
+
+        // While performance would suffer if `guaranteed_eq` just returned `false`
+        // for all arguments, correctness and return value of this function are not affected.
+        if self.as_ptr().guaranteed_eq(other.as_ptr() as *const A) {
+            return true;
+        }
+        // SAFETY: `self` and `other` are references and are thus guaranteed to be valid.
+        // The two slices have been checked to have the same size above.
+        unsafe {
+            let size = mem::size_of_val(self);
+            memcmp(self.as_ptr() as *const u8, other.as_ptr() as *const u8, size) == 0
+        }
+    }
+}
+
+#[doc(hidden)]
+// intermediate trait for specialization of slice's PartialOrd
+trait SlicePartialOrd: Sized {
+    fn partial_compare(left: &[Self], right: &[Self]) -> Option<Ordering>;
+}
+
+impl<A: PartialOrd> SlicePartialOrd for A {
+    default fn partial_compare(left: &[A], right: &[A]) -> Option<Ordering> {
+        let l = cmp::min(left.len(), right.len());
+
+        // Slice to the loop iteration range to enable bound check
+        // elimination in the compiler
+        let lhs = &left[..l];
+        let rhs = &right[..l];
+
+        for i in 0..l {
+            match lhs[i].partial_cmp(&rhs[i]) {
+                Some(Ordering::Equal) => (),
+                non_eq => return non_eq,
+            }
+        }
+
+        left.len().partial_cmp(&right.len())
+    }
+}
+
+// This is the impl that we would like to have. Unfortunately it's not sound.
+// See `partial_ord_slice.rs`.
+/*
+impl<A> SlicePartialOrd for A
+where
+    A: Ord,
+{
+    default fn partial_compare(left: &[A], right: &[A]) -> Option<Ordering> {
+        Some(SliceOrd::compare(left, right))
+    }
+}
+*/
+
+impl<A: AlwaysApplicableOrd> SlicePartialOrd for A {
+    fn partial_compare(left: &[A], right: &[A]) -> Option<Ordering> {
+        Some(SliceOrd::compare(left, right))
+    }
+}
+
+#[rustc_specialization_trait]
+trait AlwaysApplicableOrd: SliceOrd + Ord {}
+
+macro_rules! always_applicable_ord {
+    ($([$($p:tt)*] $t:ty,)*) => {
+        $(impl<$($p)*> AlwaysApplicableOrd for $t {})*
+    }
+}
+
+always_applicable_ord! {
+    [] u8, [] u16, [] u32, [] u64, [] u128, [] usize,
+    [] i8, [] i16, [] i32, [] i64, [] i128, [] isize,
+    [] bool, [] char,
+    [T: ?Sized] *const T, [T: ?Sized] *mut T,
+    [T: AlwaysApplicableOrd] &T,
+    [T: AlwaysApplicableOrd] &mut T,
+    [T: AlwaysApplicableOrd] Option<T>,
+}
+
+#[doc(hidden)]
+// intermediate trait for specialization of slice's Ord
+trait SliceOrd: Sized {
+    fn compare(left: &[Self], right: &[Self]) -> Ordering;
+}
+
+impl<A: Ord> SliceOrd for A {
+    default fn compare(left: &[Self], right: &[Self]) -> Ordering {
+        let l = cmp::min(left.len(), right.len());
+
+        // Slice to the loop iteration range to enable bound check
+        // elimination in the compiler
+        let lhs = &left[..l];
+        let rhs = &right[..l];
+
+        for i in 0..l {
+            match lhs[i].cmp(&rhs[i]) {
+                Ordering::Equal => (),
+                non_eq => return non_eq,
+            }
+        }
+
+        left.len().cmp(&right.len())
+    }
+}
+
+// memcmp compares a sequence of unsigned bytes lexicographically.
+// this matches the order we want for [u8], but no others (not even [i8]).
+impl SliceOrd for u8 {
+    #[inline]
+    fn compare(left: &[Self], right: &[Self]) -> Ordering {
+        let order =
+            // SAFETY: `left` and `right` are references and are thus guaranteed to be valid.
+            // We use the minimum of both lengths which guarantees that both regions are
+            // valid for reads in that interval.
+            unsafe { memcmp(left.as_ptr(), right.as_ptr(), cmp::min(left.len(), right.len())) };
+        if order == 0 {
+            left.len().cmp(&right.len())
+        } else if order < 0 {
+            Less
+        } else {
+            Greater
+        }
+    }
+}
+
+// Hack to allow specializing on `Eq` even though `Eq` has a method.
+#[rustc_unsafe_specialization_marker]
+trait MarkerEq<T>: PartialEq<T> {}
+
+impl<T: Eq> MarkerEq<T> for T {}
+
+#[doc(hidden)]
+/// Trait implemented for types that can be compared for equality using
+/// their bytewise representation
+#[rustc_specialization_trait]
+trait BytewiseEquality<T>: MarkerEq<T> + Copy {}
+
+macro_rules! impl_marker_for {
+    ($traitname:ident, $($ty:ty)*) => {
+        $(
+            impl $traitname<$ty> for $ty { }
+        )*
+    }
+}
+
+impl_marker_for!(BytewiseEquality,
+                 u8 i8 u16 i16 u32 i32 u64 i64 u128 i128 usize isize char bool);
+
+pub(super) trait SliceContains: Sized {
+    fn slice_contains(&self, x: &[Self]) -> bool;
+}
+
+impl<T> SliceContains for T
+where
+    T: PartialEq,
+{
+    default fn slice_contains(&self, x: &[Self]) -> bool {
+        x.iter().any(|y| *y == *self)
+    }
+}
+
+impl SliceContains for u8 {
+    fn slice_contains(&self, x: &[Self]) -> bool {
+        memchr::memchr(*self, x).is_some()
+    }
+}
+
+impl SliceContains for i8 {
+    fn slice_contains(&self, x: &[Self]) -> bool {
+        let byte = *self as u8;
+        // SAFETY: `i8` and `u8` have the same memory layout, thus casting `x.as_ptr()`
+        // as `*const u8` is safe. The `x.as_ptr()` comes from a reference and is thus guaranteed
+        // to be valid for reads for the length of the slice `x.len()`, which cannot be larger
+        // than `isize::MAX`. The returned slice is never mutated.
+        let bytes: &[u8] = unsafe { from_raw_parts(x.as_ptr() as *const u8, x.len()) };
+        memchr::memchr(byte, bytes).is_some()
+    }
+}
diff --git a/library/core/src/slice/index.rs b/library/core/src/slice/index.rs
new file mode 100644 (file)
index 0000000..16fcb62
--- /dev/null
@@ -0,0 +1,528 @@
+//! Indexing implementations for `[T]`.
+
+use crate::ops::{self, Bound, Range, RangeBounds};
+use crate::ptr;
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T, I> ops::Index<I> for [T]
+where
+    I: SliceIndex<[T]>,
+{
+    type Output = I::Output;
+
+    #[inline]
+    fn index(&self, index: I) -> &I::Output {
+        index.index(self)
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T, I> ops::IndexMut<I> for [T]
+where
+    I: SliceIndex<[T]>,
+{
+    #[inline]
+    fn index_mut(&mut self, index: I) -> &mut I::Output {
+        index.index_mut(self)
+    }
+}
+
+#[inline(never)]
+#[cold]
+#[track_caller]
+fn slice_start_index_len_fail(index: usize, len: usize) -> ! {
+    panic!("range start index {} out of range for slice of length {}", index, len);
+}
+
+#[inline(never)]
+#[cold]
+#[track_caller]
+pub(super) fn slice_end_index_len_fail(index: usize, len: usize) -> ! {
+    panic!("range end index {} out of range for slice of length {}", index, len);
+}
+
+#[inline(never)]
+#[cold]
+#[track_caller]
+pub(super) fn slice_index_order_fail(index: usize, end: usize) -> ! {
+    panic!("slice index starts at {} but ends at {}", index, end);
+}
+
+#[inline(never)]
+#[cold]
+#[track_caller]
+pub(super) fn slice_start_index_overflow_fail() -> ! {
+    panic!("attempted to index slice from after maximum usize");
+}
+
+#[inline(never)]
+#[cold]
+#[track_caller]
+pub(super) fn slice_end_index_overflow_fail() -> ! {
+    panic!("attempted to index slice up to maximum usize");
+}
+
+/// Performs bounds-checking of the given range.
+/// The returned [`Range`] is safe to pass to [`get_unchecked`] and [`get_unchecked_mut`]
+/// for slices of the given length.
+///
+/// [`get_unchecked`]: ../../std/primitive.slice.html#method.get_unchecked
+/// [`get_unchecked_mut`]: ../../std/primitive.slice.html#method.get_unchecked_mut
+///
+/// # Panics
+///
+/// Panics if the range is out of bounds.
+///
+/// # Examples
+///
+/// ```
+/// #![feature(slice_check_range)]
+/// use std::slice;
+///
+/// let v = [10, 40, 30];
+/// assert_eq!(1..2, slice::check_range(v.len(), 1..2));
+/// assert_eq!(0..2, slice::check_range(v.len(), ..2));
+/// assert_eq!(1..3, slice::check_range(v.len(), 1..));
+/// ```
+///
+/// Panics when [`Index::index`] would panic:
+///
+/// ```should_panic
+/// #![feature(slice_check_range)]
+///
+/// std::slice::check_range(3, 2..1);
+/// ```
+///
+/// ```should_panic
+/// #![feature(slice_check_range)]
+///
+/// std::slice::check_range(3, 1..4);
+/// ```
+///
+/// ```should_panic
+/// #![feature(slice_check_range)]
+///
+/// std::slice::check_range(3, 1..=usize::MAX);
+/// ```
+///
+/// [`Index::index`]: ops::Index::index
+#[track_caller]
+#[unstable(feature = "slice_check_range", issue = "76393")]
+pub fn check_range<R: RangeBounds<usize>>(len: usize, range: R) -> Range<usize> {
+    let start = match range.start_bound() {
+        Bound::Included(&start) => start,
+        Bound::Excluded(start) => {
+            start.checked_add(1).unwrap_or_else(|| slice_start_index_overflow_fail())
+        }
+        Bound::Unbounded => 0,
+    };
+
+    let end = match range.end_bound() {
+        Bound::Included(end) => {
+            end.checked_add(1).unwrap_or_else(|| slice_end_index_overflow_fail())
+        }
+        Bound::Excluded(&end) => end,
+        Bound::Unbounded => len,
+    };
+
+    if start > end {
+        slice_index_order_fail(start, end);
+    }
+    if end > len {
+        slice_end_index_len_fail(end, len);
+    }
+
+    Range { start, end }
+}
+
+mod private_slice_index {
+    use super::ops;
+    #[stable(feature = "slice_get_slice", since = "1.28.0")]
+    pub trait Sealed {}
+
+    #[stable(feature = "slice_get_slice", since = "1.28.0")]
+    impl Sealed for usize {}
+    #[stable(feature = "slice_get_slice", since = "1.28.0")]
+    impl Sealed for ops::Range<usize> {}
+    #[stable(feature = "slice_get_slice", since = "1.28.0")]
+    impl Sealed for ops::RangeTo<usize> {}
+    #[stable(feature = "slice_get_slice", since = "1.28.0")]
+    impl Sealed for ops::RangeFrom<usize> {}
+    #[stable(feature = "slice_get_slice", since = "1.28.0")]
+    impl Sealed for ops::RangeFull {}
+    #[stable(feature = "slice_get_slice", since = "1.28.0")]
+    impl Sealed for ops::RangeInclusive<usize> {}
+    #[stable(feature = "slice_get_slice", since = "1.28.0")]
+    impl Sealed for ops::RangeToInclusive<usize> {}
+}
+
+/// A helper trait used for indexing operations.
+///
+/// Implementations of this trait have to promise that if the argument
+/// to `get_(mut_)unchecked` is a safe reference, then so is the result.
+#[stable(feature = "slice_get_slice", since = "1.28.0")]
+#[rustc_on_unimplemented(
+    on(T = "str", label = "string indices are ranges of `usize`",),
+    on(
+        all(any(T = "str", T = "&str", T = "std::string::String"), _Self = "{integer}"),
+        note = "you can use `.chars().nth()` or `.bytes().nth()`\n\
+                for more information, see chapter 8 in The Book: \
+                <https://doc.rust-lang.org/book/ch08-02-strings.html#indexing-into-strings>"
+    ),
+    message = "the type `{T}` cannot be indexed by `{Self}`",
+    label = "slice indices are of type `usize` or ranges of `usize`"
+)]
+pub unsafe trait SliceIndex<T: ?Sized>: private_slice_index::Sealed {
+    /// The output type returned by methods.
+    #[stable(feature = "slice_get_slice", since = "1.28.0")]
+    type Output: ?Sized;
+
+    /// Returns a shared reference to the output at this location, if in
+    /// bounds.
+    #[unstable(feature = "slice_index_methods", issue = "none")]
+    fn get(self, slice: &T) -> Option<&Self::Output>;
+
+    /// Returns a mutable reference to the output at this location, if in
+    /// bounds.
+    #[unstable(feature = "slice_index_methods", issue = "none")]
+    fn get_mut(self, slice: &mut T) -> Option<&mut Self::Output>;
+
+    /// Returns a shared reference to the output at this location, without
+    /// performing any bounds checking.
+    /// Calling this method with an out-of-bounds index or a dangling `slice` pointer
+    /// is *[undefined behavior]* even if the resulting reference is not used.
+    ///
+    /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
+    #[unstable(feature = "slice_index_methods", issue = "none")]
+    unsafe fn get_unchecked(self, slice: *const T) -> *const Self::Output;
+
+    /// Returns a mutable reference to the output at this location, without
+    /// performing any bounds checking.
+    /// Calling this method with an out-of-bounds index or a dangling `slice` pointer
+    /// is *[undefined behavior]* even if the resulting reference is not used.
+    ///
+    /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
+    #[unstable(feature = "slice_index_methods", issue = "none")]
+    unsafe fn get_unchecked_mut(self, slice: *mut T) -> *mut Self::Output;
+
+    /// Returns a shared reference to the output at this location, panicking
+    /// if out of bounds.
+    #[unstable(feature = "slice_index_methods", issue = "none")]
+    #[track_caller]
+    fn index(self, slice: &T) -> &Self::Output;
+
+    /// Returns a mutable reference to the output at this location, panicking
+    /// if out of bounds.
+    #[unstable(feature = "slice_index_methods", issue = "none")]
+    #[track_caller]
+    fn index_mut(self, slice: &mut T) -> &mut Self::Output;
+}
+
+#[stable(feature = "slice_get_slice_impls", since = "1.15.0")]
+unsafe impl<T> SliceIndex<[T]> for usize {
+    type Output = T;
+
+    #[inline]
+    fn get(self, slice: &[T]) -> Option<&T> {
+        // SAFETY: `self` is checked to be in bounds.
+        if self < slice.len() { unsafe { Some(&*self.get_unchecked(slice)) } } else { None }
+    }
+
+    #[inline]
+    fn get_mut(self, slice: &mut [T]) -> Option<&mut T> {
+        // SAFETY: `self` is checked to be in bounds.
+        if self < slice.len() { unsafe { Some(&mut *self.get_unchecked_mut(slice)) } } else { None }
+    }
+
+    #[inline]
+    unsafe fn get_unchecked(self, slice: *const [T]) -> *const T {
+        // SAFETY: the caller guarantees that `slice` is not dangling, so it
+        // cannot be longer than `isize::MAX`. They also guarantee that
+        // `self` is in bounds of `slice` so `self` cannot overflow an `isize`,
+        // so the call to `add` is safe.
+        unsafe { slice.as_ptr().add(self) }
+    }
+
+    #[inline]
+    unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut T {
+        // SAFETY: see comments for `get_unchecked` above.
+        unsafe { slice.as_mut_ptr().add(self) }
+    }
+
+    #[inline]
+    fn index(self, slice: &[T]) -> &T {
+        // N.B., use intrinsic indexing
+        &(*slice)[self]
+    }
+
+    #[inline]
+    fn index_mut(self, slice: &mut [T]) -> &mut T {
+        // N.B., use intrinsic indexing
+        &mut (*slice)[self]
+    }
+}
+
+#[stable(feature = "slice_get_slice_impls", since = "1.15.0")]
+unsafe impl<T> SliceIndex<[T]> for ops::Range<usize> {
+    type Output = [T];
+
+    #[inline]
+    fn get(self, slice: &[T]) -> Option<&[T]> {
+        if self.start > self.end || self.end > slice.len() {
+            None
+        } else {
+            // SAFETY: `self` is checked to be valid and in bounds above.
+            unsafe { Some(&*self.get_unchecked(slice)) }
+        }
+    }
+
+    #[inline]
+    fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> {
+        if self.start > self.end || self.end > slice.len() {
+            None
+        } else {
+            // SAFETY: `self` is checked to be valid and in bounds above.
+            unsafe { Some(&mut *self.get_unchecked_mut(slice)) }
+        }
+    }
+
+    #[inline]
+    unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] {
+        // SAFETY: the caller guarantees that `slice` is not dangling, so it
+        // cannot be longer than `isize::MAX`. They also guarantee that
+        // `self` is in bounds of `slice` so `self` cannot overflow an `isize`,
+        // so the call to `add` is safe.
+        unsafe { ptr::slice_from_raw_parts(slice.as_ptr().add(self.start), self.end - self.start) }
+    }
+
+    #[inline]
+    unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] {
+        // SAFETY: see comments for `get_unchecked` above.
+        unsafe {
+            ptr::slice_from_raw_parts_mut(slice.as_mut_ptr().add(self.start), self.end - self.start)
+        }
+    }
+
+    #[inline]
+    fn index(self, slice: &[T]) -> &[T] {
+        if self.start > self.end {
+            slice_index_order_fail(self.start, self.end);
+        } else if self.end > slice.len() {
+            slice_end_index_len_fail(self.end, slice.len());
+        }
+        // SAFETY: `self` is checked to be valid and in bounds above.
+        unsafe { &*self.get_unchecked(slice) }
+    }
+
+    #[inline]
+    fn index_mut(self, slice: &mut [T]) -> &mut [T] {
+        if self.start > self.end {
+            slice_index_order_fail(self.start, self.end);
+        } else if self.end > slice.len() {
+            slice_end_index_len_fail(self.end, slice.len());
+        }
+        // SAFETY: `self` is checked to be valid and in bounds above.
+        unsafe { &mut *self.get_unchecked_mut(slice) }
+    }
+}
+
+#[stable(feature = "slice_get_slice_impls", since = "1.15.0")]
+unsafe impl<T> SliceIndex<[T]> for ops::RangeTo<usize> {
+    type Output = [T];
+
+    #[inline]
+    fn get(self, slice: &[T]) -> Option<&[T]> {
+        (0..self.end).get(slice)
+    }
+
+    #[inline]
+    fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> {
+        (0..self.end).get_mut(slice)
+    }
+
+    #[inline]
+    unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] {
+        // SAFETY: the caller has to uphold the safety contract for `get_unchecked`.
+        unsafe { (0..self.end).get_unchecked(slice) }
+    }
+
+    #[inline]
+    unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] {
+        // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`.
+        unsafe { (0..self.end).get_unchecked_mut(slice) }
+    }
+
+    #[inline]
+    fn index(self, slice: &[T]) -> &[T] {
+        (0..self.end).index(slice)
+    }
+
+    #[inline]
+    fn index_mut(self, slice: &mut [T]) -> &mut [T] {
+        (0..self.end).index_mut(slice)
+    }
+}
+
+#[stable(feature = "slice_get_slice_impls", since = "1.15.0")]
+unsafe impl<T> SliceIndex<[T]> for ops::RangeFrom<usize> {
+    type Output = [T];
+
+    #[inline]
+    fn get(self, slice: &[T]) -> Option<&[T]> {
+        (self.start..slice.len()).get(slice)
+    }
+
+    #[inline]
+    fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> {
+        (self.start..slice.len()).get_mut(slice)
+    }
+
+    #[inline]
+    unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] {
+        // SAFETY: the caller has to uphold the safety contract for `get_unchecked`.
+        unsafe { (self.start..slice.len()).get_unchecked(slice) }
+    }
+
+    #[inline]
+    unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] {
+        // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`.
+        unsafe { (self.start..slice.len()).get_unchecked_mut(slice) }
+    }
+
+    #[inline]
+    fn index(self, slice: &[T]) -> &[T] {
+        if self.start > slice.len() {
+            slice_start_index_len_fail(self.start, slice.len());
+        }
+        // SAFETY: `self` is checked to be valid and in bounds above.
+        unsafe { &*self.get_unchecked(slice) }
+    }
+
+    #[inline]
+    fn index_mut(self, slice: &mut [T]) -> &mut [T] {
+        if self.start > slice.len() {
+            slice_start_index_len_fail(self.start, slice.len());
+        }
+        // SAFETY: `self` is checked to be valid and in bounds above.
+        unsafe { &mut *self.get_unchecked_mut(slice) }
+    }
+}
+
+#[stable(feature = "slice_get_slice_impls", since = "1.15.0")]
+unsafe impl<T> SliceIndex<[T]> for ops::RangeFull {
+    type Output = [T];
+
+    #[inline]
+    fn get(self, slice: &[T]) -> Option<&[T]> {
+        Some(slice)
+    }
+
+    #[inline]
+    fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> {
+        Some(slice)
+    }
+
+    #[inline]
+    unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] {
+        slice
+    }
+
+    #[inline]
+    unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] {
+        slice
+    }
+
+    #[inline]
+    fn index(self, slice: &[T]) -> &[T] {
+        slice
+    }
+
+    #[inline]
+    fn index_mut(self, slice: &mut [T]) -> &mut [T] {
+        slice
+    }
+}
+
+#[stable(feature = "inclusive_range", since = "1.26.0")]
+unsafe impl<T> SliceIndex<[T]> for ops::RangeInclusive<usize> {
+    type Output = [T];
+
+    #[inline]
+    fn get(self, slice: &[T]) -> Option<&[T]> {
+        if *self.end() == usize::MAX { None } else { (*self.start()..self.end() + 1).get(slice) }
+    }
+
+    #[inline]
+    fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> {
+        if *self.end() == usize::MAX {
+            None
+        } else {
+            (*self.start()..self.end() + 1).get_mut(slice)
+        }
+    }
+
+    #[inline]
+    unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] {
+        // SAFETY: the caller has to uphold the safety contract for `get_unchecked`.
+        unsafe { (*self.start()..self.end() + 1).get_unchecked(slice) }
+    }
+
+    #[inline]
+    unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] {
+        // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`.
+        unsafe { (*self.start()..self.end() + 1).get_unchecked_mut(slice) }
+    }
+
+    #[inline]
+    fn index(self, slice: &[T]) -> &[T] {
+        if *self.end() == usize::MAX {
+            slice_end_index_overflow_fail();
+        }
+        (*self.start()..self.end() + 1).index(slice)
+    }
+
+    #[inline]
+    fn index_mut(self, slice: &mut [T]) -> &mut [T] {
+        if *self.end() == usize::MAX {
+            slice_end_index_overflow_fail();
+        }
+        (*self.start()..self.end() + 1).index_mut(slice)
+    }
+}
+
+#[stable(feature = "inclusive_range", since = "1.26.0")]
+unsafe impl<T> SliceIndex<[T]> for ops::RangeToInclusive<usize> {
+    type Output = [T];
+
+    #[inline]
+    fn get(self, slice: &[T]) -> Option<&[T]> {
+        (0..=self.end).get(slice)
+    }
+
+    #[inline]
+    fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> {
+        (0..=self.end).get_mut(slice)
+    }
+
+    #[inline]
+    unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] {
+        // SAFETY: the caller has to uphold the safety contract for `get_unchecked`.
+        unsafe { (0..=self.end).get_unchecked(slice) }
+    }
+
+    #[inline]
+    unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] {
+        // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`.
+        unsafe { (0..=self.end).get_unchecked_mut(slice) }
+    }
+
+    #[inline]
+    fn index(self, slice: &[T]) -> &[T] {
+        (0..=self.end).index(slice)
+    }
+
+    #[inline]
+    fn index_mut(self, slice: &mut [T]) -> &mut [T] {
+        (0..=self.end).index_mut(slice)
+    }
+}
diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs
new file mode 100644 (file)
index 0000000..84fa34c
--- /dev/null
@@ -0,0 +1,2595 @@
+//! Definitions of a bunch of iterators for `[T]`.
+
+#[macro_use] // import iterator! and forward_iterator!
+mod macros;
+
+use crate::cmp;
+use crate::cmp::Ordering;
+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::mem;
+use crate::ptr::NonNull;
+
+use super::{from_raw_parts, from_raw_parts_mut};
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a, T> IntoIterator for &'a [T] {
+    type Item = &'a T;
+    type IntoIter = Iter<'a, T>;
+
+    fn into_iter(self) -> Iter<'a, T> {
+        self.iter()
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a, T> IntoIterator for &'a mut [T] {
+    type Item = &'a mut T;
+    type IntoIter = IterMut<'a, T>;
+
+    fn into_iter(self) -> IterMut<'a, T> {
+        self.iter_mut()
+    }
+}
+
+// Macro helper functions
+#[inline(always)]
+fn size_from_ptr<T>(_: *const T) -> usize {
+    mem::size_of::<T>()
+}
+
+/// Immutable slice iterator
+///
+/// This struct is created by the [`iter`] method on [slices].
+///
+/// # Examples
+///
+/// Basic usage:
+///
+/// ```
+/// // First, we declare a type which has `iter` method to get the `Iter` struct (&[usize here]):
+/// let slice = &[1, 2, 3];
+///
+/// // Then, we iterate over it:
+/// for element in slice.iter() {
+///     println!("{}", element);
+/// }
+/// ```
+///
+/// [`iter`]: ../../std/primitive.slice.html#method.iter
+/// [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 == 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>,
+}
+
+#[stable(feature = "core_impl_debug", since = "1.9.0")]
+impl<T: fmt::Debug> fmt::Debug for Iter<'_, T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_tuple("Iter").field(&self.as_slice()).finish()
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+unsafe impl<T: Sync> Sync for Iter<'_, T> {}
+#[stable(feature = "rust1", since = "1.0.0")]
+unsafe impl<T: Sync> Send for Iter<'_, T> {}
+
+impl<'a, T> Iter<'a, T> {
+    /// Views the underlying data as a subslice of the original data.
+    ///
+    /// This has the same lifetime as the original slice, and so the
+    /// iterator can continue to be used while this exists.
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// // First, we declare a type which has the `iter` method to get the `Iter`
+    /// // struct (&[usize here]):
+    /// let slice = &[1, 2, 3];
+    ///
+    /// // Then, we get the iterator:
+    /// let mut iter = slice.iter();
+    /// // So if we print what `as_slice` method returns here, we have "[1, 2, 3]":
+    /// println!("{:?}", iter.as_slice());
+    ///
+    /// // Next, we move to the second element of the slice:
+    /// iter.next();
+    /// // Now `as_slice` returns "[2, 3]":
+    /// println!("{:?}", iter.as_slice());
+    /// ```
+    #[stable(feature = "iter_to_slice", since = "1.4.0")]
+    pub fn as_slice(&self) -> &'a [T] {
+        self.make_slice()
+    }
+}
+
+iterator! {struct Iter -> *const T, &'a T, const, {/* no mut */}, {
+    fn is_sorted_by<F>(self, mut compare: F) -> bool
+    where
+        Self: Sized,
+        F: FnMut(&Self::Item, &Self::Item) -> Option<Ordering>,
+    {
+        self.as_slice().windows(2).all(|w| {
+            compare(&&w[0], &&w[1]).map(|o| o != Ordering::Greater).unwrap_or(false)
+        })
+    }
+}}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T> Clone for Iter<'_, T> {
+    fn clone(&self) -> Self {
+        Iter { ptr: self.ptr, end: self.end, _marker: self._marker }
+    }
+}
+
+#[stable(feature = "slice_iter_as_ref", since = "1.13.0")]
+impl<T> AsRef<[T]> for Iter<'_, T> {
+    fn as_ref(&self) -> &[T] {
+        self.as_slice()
+    }
+}
+
+/// Mutable slice iterator.
+///
+/// This struct is created by the [`iter_mut`] method on [slices].
+///
+/// # Examples
+///
+/// Basic usage:
+///
+/// ```
+/// // First, we declare a type which has `iter_mut` method to get the `IterMut`
+/// // struct (&[usize here]):
+/// let mut slice = &mut [1, 2, 3];
+///
+/// // Then, we iterate over it and increment each element value:
+/// for element in slice.iter_mut() {
+///     *element += 1;
+/// }
+///
+/// // We now have "[2, 3, 4]":
+/// println!("{:?}", slice);
+/// ```
+///
+/// [`iter_mut`]: ../../std/primitive.slice.html#method.iter_mut
+/// [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 == 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>,
+}
+
+#[stable(feature = "core_impl_debug", since = "1.9.0")]
+impl<T: fmt::Debug> fmt::Debug for IterMut<'_, T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_tuple("IterMut").field(&self.make_slice()).finish()
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+unsafe impl<T: Sync> Sync for IterMut<'_, T> {}
+#[stable(feature = "rust1", since = "1.0.0")]
+unsafe impl<T: Send> Send for IterMut<'_, T> {}
+
+impl<'a, T> IterMut<'a, T> {
+    /// Views the underlying data as a subslice of the original data.
+    ///
+    /// To avoid creating `&mut` references that alias, this is forced
+    /// to consume the iterator.
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// // First, we declare a type which has `iter_mut` method to get the `IterMut`
+    /// // struct (&[usize here]):
+    /// let mut slice = &mut [1, 2, 3];
+    ///
+    /// {
+    ///     // Then, we get the iterator:
+    ///     let mut iter = slice.iter_mut();
+    ///     // We move to next element:
+    ///     iter.next();
+    ///     // So if we print what `into_slice` method returns here, we have "[2, 3]":
+    ///     println!("{:?}", iter.into_slice());
+    /// }
+    ///
+    /// // Now let's modify a value of the slice:
+    /// {
+    ///     // First we get back the iterator:
+    ///     let mut iter = slice.iter_mut();
+    ///     // We change the value of the first element of the slice returned by the `next` method:
+    ///     *iter.next().unwrap() += 1;
+    /// }
+    /// // Now slice is "[2, 2, 3]":
+    /// println!("{:?}", slice);
+    /// ```
+    #[stable(feature = "iter_to_slice", since = "1.4.0")]
+    pub fn into_slice(self) -> &'a mut [T] {
+        // SAFETY: the iterator was created from a mutable slice with pointer
+        // `self.ptr` and length `len!(self)`. This guarantees that all the prerequisites
+        // for `from_raw_parts_mut` are fulfilled.
+        unsafe { from_raw_parts_mut(self.ptr.as_ptr(), len!(self)) }
+    }
+
+    /// Views the underlying data as a subslice of the original data.
+    ///
+    /// To avoid creating `&mut [T]` references that alias, the returned slice
+    /// borrows its lifetime from the iterator the method is applied on.
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// # #![feature(slice_iter_mut_as_slice)]
+    /// let mut slice: &mut [usize] = &mut [1, 2, 3];
+    ///
+    /// // First, we get the iterator:
+    /// let mut iter = slice.iter_mut();
+    /// // So if we check what the `as_slice` method returns here, we have "[1, 2, 3]":
+    /// assert_eq!(iter.as_slice(), &[1, 2, 3]);
+    ///
+    /// // Next, we move to the second element of the slice:
+    /// iter.next();
+    /// // Now `as_slice` returns "[2, 3]":
+    /// assert_eq!(iter.as_slice(), &[2, 3]);
+    /// ```
+    #[unstable(feature = "slice_iter_mut_as_slice", reason = "recently added", issue = "58957")]
+    pub fn as_slice(&self) -> &[T] {
+        self.make_slice()
+    }
+}
+
+iterator! {struct IterMut -> *mut T, &'a mut T, mut, {mut}, {}}
+
+/// An internal abstraction over the splitting iterators, so that
+/// splitn, splitn_mut etc can be implemented once.
+#[doc(hidden)]
+pub(super) trait SplitIter: DoubleEndedIterator {
+    /// Marks the underlying iterator as complete, extracting the remaining
+    /// portion of the slice.
+    fn finish(&mut self) -> Option<Self::Item>;
+}
+
+/// An iterator over subslices separated by elements that match a predicate
+/// function.
+///
+/// This struct is created by the [`split`] method on [slices].
+///
+/// [`split`]: ../../std/primitive.slice.html#method.split
+/// [slices]: ../../std/primitive.slice.html
+#[stable(feature = "rust1", since = "1.0.0")]
+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,
+}
+
+#[stable(feature = "core_impl_debug", since = "1.9.0")]
+impl<T: fmt::Debug, P> fmt::Debug for Split<'_, T, P>
+where
+    P: FnMut(&T) -> bool,
+{
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_struct("Split").field("v", &self.v).field("finished", &self.finished).finish()
+    }
+}
+
+// FIXME(#26925) Remove in favor of `#[derive(Clone)]`
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T, P> Clone for Split<'_, T, P>
+where
+    P: Clone + FnMut(&T) -> bool,
+{
+    fn clone(&self) -> Self {
+        Split { v: self.v, pred: self.pred.clone(), finished: self.finished }
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a, T, P> Iterator for Split<'a, T, P>
+where
+    P: FnMut(&T) -> bool,
+{
+    type Item = &'a [T];
+
+    #[inline]
+    fn next(&mut self) -> Option<&'a [T]> {
+        if self.finished {
+            return None;
+        }
+
+        match self.v.iter().position(|x| (self.pred)(x)) {
+            None => self.finish(),
+            Some(idx) => {
+                let ret = Some(&self.v[..idx]);
+                self.v = &self.v[idx + 1..];
+                ret
+            }
+        }
+    }
+
+    #[inline]
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        if self.finished { (0, Some(0)) } else { (1, Some(self.v.len() + 1)) }
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a, T, P> DoubleEndedIterator for Split<'a, T, P>
+where
+    P: FnMut(&T) -> bool,
+{
+    #[inline]
+    fn next_back(&mut self) -> Option<&'a [T]> {
+        if self.finished {
+            return None;
+        }
+
+        match self.v.iter().rposition(|x| (self.pred)(x)) {
+            None => self.finish(),
+            Some(idx) => {
+                let ret = Some(&self.v[idx + 1..]);
+                self.v = &self.v[..idx];
+                ret
+            }
+        }
+    }
+}
+
+impl<'a, T, P> SplitIter for Split<'a, T, P>
+where
+    P: FnMut(&T) -> bool,
+{
+    #[inline]
+    fn finish(&mut self) -> Option<&'a [T]> {
+        if self.finished {
+            None
+        } else {
+            self.finished = true;
+            Some(self.v)
+        }
+    }
+}
+
+#[stable(feature = "fused", since = "1.26.0")]
+impl<T, P> FusedIterator for Split<'_, T, P> where P: FnMut(&T) -> bool {}
+
+/// An iterator over subslices separated by elements that match a predicate
+/// function. Unlike `Split`, it contains the matched part as a terminator
+/// of the subslice.
+///
+/// This struct is created by the [`split_inclusive`] method on [slices].
+///
+/// [`split_inclusive`]: ../../std/primitive.slice.html#method.split_inclusive
+/// [slices]: ../../std/primitive.slice.html
+#[unstable(feature = "split_inclusive", issue = "72360")]
+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,
+}
+
+#[unstable(feature = "split_inclusive", issue = "72360")]
+impl<T: fmt::Debug, P> fmt::Debug for SplitInclusive<'_, T, P>
+where
+    P: FnMut(&T) -> bool,
+{
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_struct("SplitInclusive")
+            .field("v", &self.v)
+            .field("finished", &self.finished)
+            .finish()
+    }
+}
+
+// FIXME(#26925) Remove in favor of `#[derive(Clone)]`
+#[unstable(feature = "split_inclusive", issue = "72360")]
+impl<T, P> Clone for SplitInclusive<'_, T, P>
+where
+    P: Clone + FnMut(&T) -> bool,
+{
+    fn clone(&self) -> Self {
+        SplitInclusive { v: self.v, pred: self.pred.clone(), finished: self.finished }
+    }
+}
+
+#[unstable(feature = "split_inclusive", issue = "72360")]
+impl<'a, T, P> Iterator for SplitInclusive<'a, T, P>
+where
+    P: FnMut(&T) -> bool,
+{
+    type Item = &'a [T];
+
+    #[inline]
+    fn next(&mut self) -> Option<&'a [T]> {
+        if self.finished {
+            return None;
+        }
+
+        let idx =
+            self.v.iter().position(|x| (self.pred)(x)).map(|idx| idx + 1).unwrap_or(self.v.len());
+        if idx == self.v.len() {
+            self.finished = true;
+        }
+        let ret = Some(&self.v[..idx]);
+        self.v = &self.v[idx..];
+        ret
+    }
+
+    #[inline]
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        if self.finished { (0, Some(0)) } else { (1, Some(self.v.len() + 1)) }
+    }
+}
+
+#[unstable(feature = "split_inclusive", issue = "72360")]
+impl<'a, T, P> DoubleEndedIterator for SplitInclusive<'a, T, P>
+where
+    P: FnMut(&T) -> bool,
+{
+    #[inline]
+    fn next_back(&mut self) -> Option<&'a [T]> {
+        if self.finished {
+            return None;
+        }
+
+        // The last index of self.v is already checked and found to match
+        // by the last iteration, so we start searching a new match
+        // one index to the left.
+        let remainder = if self.v.is_empty() { &[] } else { &self.v[..(self.v.len() - 1)] };
+        let idx = remainder.iter().rposition(|x| (self.pred)(x)).map(|idx| idx + 1).unwrap_or(0);
+        if idx == 0 {
+            self.finished = true;
+        }
+        let ret = Some(&self.v[idx..]);
+        self.v = &self.v[..idx];
+        ret
+    }
+}
+
+#[unstable(feature = "split_inclusive", issue = "72360")]
+impl<T, P> FusedIterator for SplitInclusive<'_, T, P> where P: FnMut(&T) -> bool {}
+
+/// An iterator over the mutable subslices of the vector which are separated
+/// by elements that match `pred`.
+///
+/// This struct is created by the [`split_mut`] method on [slices].
+///
+/// [`split_mut`]: ../../std/primitive.slice.html#method.split_mut
+/// [slices]: ../../std/primitive.slice.html
+#[stable(feature = "rust1", since = "1.0.0")]
+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,
+}
+
+#[stable(feature = "core_impl_debug", since = "1.9.0")]
+impl<T: fmt::Debug, P> fmt::Debug for SplitMut<'_, T, P>
+where
+    P: FnMut(&T) -> bool,
+{
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_struct("SplitMut").field("v", &self.v).field("finished", &self.finished).finish()
+    }
+}
+
+impl<'a, T, P> SplitIter for SplitMut<'a, T, P>
+where
+    P: FnMut(&T) -> bool,
+{
+    #[inline]
+    fn finish(&mut self) -> Option<&'a mut [T]> {
+        if self.finished {
+            None
+        } else {
+            self.finished = true;
+            Some(mem::replace(&mut self.v, &mut []))
+        }
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a, T, P> Iterator for SplitMut<'a, T, P>
+where
+    P: FnMut(&T) -> bool,
+{
+    type Item = &'a mut [T];
+
+    #[inline]
+    fn next(&mut self) -> Option<&'a mut [T]> {
+        if self.finished {
+            return None;
+        }
+
+        let idx_opt = {
+            // work around borrowck limitations
+            let pred = &mut self.pred;
+            self.v.iter().position(|x| (*pred)(x))
+        };
+        match idx_opt {
+            None => self.finish(),
+            Some(idx) => {
+                let tmp = mem::replace(&mut self.v, &mut []);
+                let (head, tail) = tmp.split_at_mut(idx);
+                self.v = &mut tail[1..];
+                Some(head)
+            }
+        }
+    }
+
+    #[inline]
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        if self.finished {
+            (0, Some(0))
+        } else {
+            // if the predicate doesn't match anything, we yield one slice
+            // if it matches every element, we yield len+1 empty slices.
+            (1, Some(self.v.len() + 1))
+        }
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a, T, P> DoubleEndedIterator for SplitMut<'a, T, P>
+where
+    P: FnMut(&T) -> bool,
+{
+    #[inline]
+    fn next_back(&mut self) -> Option<&'a mut [T]> {
+        if self.finished {
+            return None;
+        }
+
+        let idx_opt = {
+            // work around borrowck limitations
+            let pred = &mut self.pred;
+            self.v.iter().rposition(|x| (*pred)(x))
+        };
+        match idx_opt {
+            None => self.finish(),
+            Some(idx) => {
+                let tmp = mem::replace(&mut self.v, &mut []);
+                let (head, tail) = tmp.split_at_mut(idx);
+                self.v = head;
+                Some(&mut tail[1..])
+            }
+        }
+    }
+}
+
+#[stable(feature = "fused", since = "1.26.0")]
+impl<T, P> FusedIterator for SplitMut<'_, T, P> where P: FnMut(&T) -> bool {}
+
+/// An iterator over the mutable subslices of the vector which are separated
+/// by elements that match `pred`. Unlike `SplitMut`, it contains the matched
+/// parts in the ends of the subslices.
+///
+/// This struct is created by the [`split_inclusive_mut`] method on [slices].
+///
+/// [`split_inclusive_mut`]: ../../std/primitive.slice.html#method.split_inclusive_mut
+/// [slices]: ../../std/primitive.slice.html
+#[unstable(feature = "split_inclusive", issue = "72360")]
+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,
+}
+
+#[unstable(feature = "split_inclusive", issue = "72360")]
+impl<T: fmt::Debug, P> fmt::Debug for SplitInclusiveMut<'_, T, P>
+where
+    P: FnMut(&T) -> bool,
+{
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_struct("SplitInclusiveMut")
+            .field("v", &self.v)
+            .field("finished", &self.finished)
+            .finish()
+    }
+}
+
+#[unstable(feature = "split_inclusive", issue = "72360")]
+impl<'a, T, P> Iterator for SplitInclusiveMut<'a, T, P>
+where
+    P: FnMut(&T) -> bool,
+{
+    type Item = &'a mut [T];
+
+    #[inline]
+    fn next(&mut self) -> Option<&'a mut [T]> {
+        if self.finished {
+            return None;
+        }
+
+        let idx_opt = {
+            // work around borrowck limitations
+            let pred = &mut self.pred;
+            self.v.iter().position(|x| (*pred)(x))
+        };
+        let idx = idx_opt.map(|idx| idx + 1).unwrap_or(self.v.len());
+        if idx == self.v.len() {
+            self.finished = true;
+        }
+        let tmp = mem::replace(&mut self.v, &mut []);
+        let (head, tail) = tmp.split_at_mut(idx);
+        self.v = tail;
+        Some(head)
+    }
+
+    #[inline]
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        if self.finished {
+            (0, Some(0))
+        } else {
+            // if the predicate doesn't match anything, we yield one slice
+            // if it matches every element, we yield len+1 empty slices.
+            (1, Some(self.v.len() + 1))
+        }
+    }
+}
+
+#[unstable(feature = "split_inclusive", issue = "72360")]
+impl<'a, T, P> DoubleEndedIterator for SplitInclusiveMut<'a, T, P>
+where
+    P: FnMut(&T) -> bool,
+{
+    #[inline]
+    fn next_back(&mut self) -> Option<&'a mut [T]> {
+        if self.finished {
+            return None;
+        }
+
+        let idx_opt = if self.v.is_empty() {
+            None
+        } else {
+            // work around borrowck limitations
+            let pred = &mut self.pred;
+
+            // The last index of self.v is already checked and found to match
+            // by the last iteration, so we start searching a new match
+            // one index to the left.
+            let remainder = &self.v[..(self.v.len() - 1)];
+            remainder.iter().rposition(|x| (*pred)(x))
+        };
+        let idx = idx_opt.map(|idx| idx + 1).unwrap_or(0);
+        if idx == 0 {
+            self.finished = true;
+        }
+        let tmp = mem::replace(&mut self.v, &mut []);
+        let (head, tail) = tmp.split_at_mut(idx);
+        self.v = head;
+        Some(tail)
+    }
+}
+
+#[unstable(feature = "split_inclusive", issue = "72360")]
+impl<T, P> FusedIterator for SplitInclusiveMut<'_, T, P> where P: FnMut(&T) -> bool {}
+
+/// An iterator over subslices separated by elements that match a predicate
+/// function, starting from the end of the slice.
+///
+/// This struct is created by the [`rsplit`] method on [slices].
+///
+/// [`rsplit`]: ../../std/primitive.slice.html#method.rsplit
+/// [slices]: ../../std/primitive.slice.html
+#[stable(feature = "slice_rsplit", since = "1.27.0")]
+#[derive(Clone)] // Is this correct, or does it incorrectly require `T: Clone`?
+pub struct RSplit<'a, T: 'a, P>
+where
+    P: FnMut(&T) -> bool,
+{
+    pub(super) inner: Split<'a, T, P>,
+}
+
+#[stable(feature = "slice_rsplit", since = "1.27.0")]
+impl<T: fmt::Debug, P> fmt::Debug for RSplit<'_, T, P>
+where
+    P: FnMut(&T) -> bool,
+{
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_struct("RSplit")
+            .field("v", &self.inner.v)
+            .field("finished", &self.inner.finished)
+            .finish()
+    }
+}
+
+#[stable(feature = "slice_rsplit", since = "1.27.0")]
+impl<'a, T, P> Iterator for RSplit<'a, T, P>
+where
+    P: FnMut(&T) -> bool,
+{
+    type Item = &'a [T];
+
+    #[inline]
+    fn next(&mut self) -> Option<&'a [T]> {
+        self.inner.next_back()
+    }
+
+    #[inline]
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        self.inner.size_hint()
+    }
+}
+
+#[stable(feature = "slice_rsplit", since = "1.27.0")]
+impl<'a, T, P> DoubleEndedIterator for RSplit<'a, T, P>
+where
+    P: FnMut(&T) -> bool,
+{
+    #[inline]
+    fn next_back(&mut self) -> Option<&'a [T]> {
+        self.inner.next()
+    }
+}
+
+#[stable(feature = "slice_rsplit", since = "1.27.0")]
+impl<'a, T, P> SplitIter for RSplit<'a, T, P>
+where
+    P: FnMut(&T) -> bool,
+{
+    #[inline]
+    fn finish(&mut self) -> Option<&'a [T]> {
+        self.inner.finish()
+    }
+}
+
+#[stable(feature = "slice_rsplit", since = "1.27.0")]
+impl<T, P> FusedIterator for RSplit<'_, T, P> where P: FnMut(&T) -> bool {}
+
+/// An iterator over the subslices of the vector which are separated
+/// by elements that match `pred`, starting from the end of the slice.
+///
+/// This struct is created by the [`rsplit_mut`] method on [slices].
+///
+/// [`rsplit_mut`]: ../../std/primitive.slice.html#method.rsplit_mut
+/// [slices]: ../../std/primitive.slice.html
+#[stable(feature = "slice_rsplit", since = "1.27.0")]
+pub struct RSplitMut<'a, T: 'a, P>
+where
+    P: FnMut(&T) -> bool,
+{
+    pub(super) inner: SplitMut<'a, T, P>,
+}
+
+#[stable(feature = "slice_rsplit", since = "1.27.0")]
+impl<T: fmt::Debug, P> fmt::Debug for RSplitMut<'_, T, P>
+where
+    P: FnMut(&T) -> bool,
+{
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_struct("RSplitMut")
+            .field("v", &self.inner.v)
+            .field("finished", &self.inner.finished)
+            .finish()
+    }
+}
+
+#[stable(feature = "slice_rsplit", since = "1.27.0")]
+impl<'a, T, P> SplitIter for RSplitMut<'a, T, P>
+where
+    P: FnMut(&T) -> bool,
+{
+    #[inline]
+    fn finish(&mut self) -> Option<&'a mut [T]> {
+        self.inner.finish()
+    }
+}
+
+#[stable(feature = "slice_rsplit", since = "1.27.0")]
+impl<'a, T, P> Iterator for RSplitMut<'a, T, P>
+where
+    P: FnMut(&T) -> bool,
+{
+    type Item = &'a mut [T];
+
+    #[inline]
+    fn next(&mut self) -> Option<&'a mut [T]> {
+        self.inner.next_back()
+    }
+
+    #[inline]
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        self.inner.size_hint()
+    }
+}
+
+#[stable(feature = "slice_rsplit", since = "1.27.0")]
+impl<'a, T, P> DoubleEndedIterator for RSplitMut<'a, T, P>
+where
+    P: FnMut(&T) -> bool,
+{
+    #[inline]
+    fn next_back(&mut self) -> Option<&'a mut [T]> {
+        self.inner.next()
+    }
+}
+
+#[stable(feature = "slice_rsplit", since = "1.27.0")]
+impl<T, P> FusedIterator for RSplitMut<'_, T, P> where P: FnMut(&T) -> bool {}
+
+/// An private iterator over subslices separated by elements that
+/// 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,
+}
+
+impl<T, I: SplitIter<Item = T>> Iterator for GenericSplitN<I> {
+    type Item = T;
+
+    #[inline]
+    fn next(&mut self) -> Option<T> {
+        match self.count {
+            0 => None,
+            1 => {
+                self.count -= 1;
+                self.iter.finish()
+            }
+            _ => {
+                self.count -= 1;
+                self.iter.next()
+            }
+        }
+    }
+
+    #[inline]
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        let (lower, upper_opt) = self.iter.size_hint();
+        (lower, upper_opt.map(|upper| cmp::min(self.count, upper)))
+    }
+}
+
+/// An iterator over subslices separated by elements that match a predicate
+/// function, limited to a given number of splits.
+///
+/// This struct is created by the [`splitn`] method on [slices].
+///
+/// [`splitn`]: ../../std/primitive.slice.html#method.splitn
+/// [slices]: ../../std/primitive.slice.html
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct SplitN<'a, T: 'a, P>
+where
+    P: FnMut(&T) -> bool,
+{
+    pub(super) inner: GenericSplitN<Split<'a, T, P>>,
+}
+
+#[stable(feature = "core_impl_debug", since = "1.9.0")]
+impl<T: fmt::Debug, P> fmt::Debug for SplitN<'_, T, P>
+where
+    P: FnMut(&T) -> bool,
+{
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_struct("SplitN").field("inner", &self.inner).finish()
+    }
+}
+
+/// An iterator over subslices separated by elements that match a
+/// predicate function, limited to a given number of splits, starting
+/// from the end of the slice.
+///
+/// This struct is created by the [`rsplitn`] method on [slices].
+///
+/// [`rsplitn`]: ../../std/primitive.slice.html#method.rsplitn
+/// [slices]: ../../std/primitive.slice.html
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct RSplitN<'a, T: 'a, P>
+where
+    P: FnMut(&T) -> bool,
+{
+    pub(super) inner: GenericSplitN<RSplit<'a, T, P>>,
+}
+
+#[stable(feature = "core_impl_debug", since = "1.9.0")]
+impl<T: fmt::Debug, P> fmt::Debug for RSplitN<'_, T, P>
+where
+    P: FnMut(&T) -> bool,
+{
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_struct("RSplitN").field("inner", &self.inner).finish()
+    }
+}
+
+/// An iterator over subslices separated by elements that match a predicate
+/// function, limited to a given number of splits.
+///
+/// This struct is created by the [`splitn_mut`] method on [slices].
+///
+/// [`splitn_mut`]: ../../std/primitive.slice.html#method.splitn_mut
+/// [slices]: ../../std/primitive.slice.html
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct SplitNMut<'a, T: 'a, P>
+where
+    P: FnMut(&T) -> bool,
+{
+    pub(super) inner: GenericSplitN<SplitMut<'a, T, P>>,
+}
+
+#[stable(feature = "core_impl_debug", since = "1.9.0")]
+impl<T: fmt::Debug, P> fmt::Debug for SplitNMut<'_, T, P>
+where
+    P: FnMut(&T) -> bool,
+{
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_struct("SplitNMut").field("inner", &self.inner).finish()
+    }
+}
+
+/// An iterator over subslices separated by elements that match a
+/// predicate function, limited to a given number of splits, starting
+/// from the end of the slice.
+///
+/// This struct is created by the [`rsplitn_mut`] method on [slices].
+///
+/// [`rsplitn_mut`]: ../../std/primitive.slice.html#method.rsplitn_mut
+/// [slices]: ../../std/primitive.slice.html
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct RSplitNMut<'a, T: 'a, P>
+where
+    P: FnMut(&T) -> bool,
+{
+    pub(super) inner: GenericSplitN<RSplitMut<'a, T, P>>,
+}
+
+#[stable(feature = "core_impl_debug", since = "1.9.0")]
+impl<T: fmt::Debug, P> fmt::Debug for RSplitNMut<'_, T, P>
+where
+    P: FnMut(&T) -> bool,
+{
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_struct("RSplitNMut").field("inner", &self.inner).finish()
+    }
+}
+
+forward_iterator! { SplitN: T, &'a [T] }
+forward_iterator! { RSplitN: T, &'a [T] }
+forward_iterator! { SplitNMut: T, &'a mut [T] }
+forward_iterator! { RSplitNMut: T, &'a mut [T] }
+
+/// An iterator over overlapping subslices of length `size`.
+///
+/// This struct is created by the [`windows`] method on [slices].
+///
+/// [`windows`]: ../../std/primitive.slice.html#method.windows
+/// [slices]: ../../std/primitive.slice.html
+#[derive(Debug)]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct Windows<'a, T: 'a> {
+    pub(super) v: &'a [T],
+    pub(super) size: usize,
+}
+
+// FIXME(#26925) Remove in favor of `#[derive(Clone)]`
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T> Clone for Windows<'_, T> {
+    fn clone(&self) -> Self {
+        Windows { v: self.v, size: self.size }
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a, T> Iterator for Windows<'a, T> {
+    type Item = &'a [T];
+
+    #[inline]
+    fn next(&mut self) -> Option<&'a [T]> {
+        if self.size > self.v.len() {
+            None
+        } else {
+            let ret = Some(&self.v[..self.size]);
+            self.v = &self.v[1..];
+            ret
+        }
+    }
+
+    #[inline]
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        if self.size > self.v.len() {
+            (0, Some(0))
+        } else {
+            let size = self.v.len() - self.size + 1;
+            (size, Some(size))
+        }
+    }
+
+    #[inline]
+    fn count(self) -> usize {
+        self.len()
+    }
+
+    #[inline]
+    fn nth(&mut self, n: usize) -> Option<Self::Item> {
+        let (end, overflow) = self.size.overflowing_add(n);
+        if end > self.v.len() || overflow {
+            self.v = &[];
+            None
+        } else {
+            let nth = &self.v[n..end];
+            self.v = &self.v[n + 1..];
+            Some(nth)
+        }
+    }
+
+    #[inline]
+    fn last(self) -> Option<Self::Item> {
+        if self.size > self.v.len() {
+            None
+        } else {
+            let start = self.v.len() - self.size;
+            Some(&self.v[start..])
+        }
+    }
+
+    #[doc(hidden)]
+    unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item {
+        // SAFETY: since the caller guarantees that `i` is in bounds,
+        // which means that `i` cannot overflow an `isize`, and the
+        // slice created by `from_raw_parts` is a subslice of `self.v`
+        // thus is guaranteed to be valid for the lifetime `'a` of `self.v`.
+        unsafe { from_raw_parts(self.v.as_ptr().add(idx), self.size) }
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a, T> DoubleEndedIterator for Windows<'a, T> {
+    #[inline]
+    fn next_back(&mut self) -> Option<&'a [T]> {
+        if self.size > self.v.len() {
+            None
+        } else {
+            let ret = Some(&self.v[self.v.len() - self.size..]);
+            self.v = &self.v[..self.v.len() - 1];
+            ret
+        }
+    }
+
+    #[inline]
+    fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
+        let (end, overflow) = self.v.len().overflowing_sub(n);
+        if end < self.size || overflow {
+            self.v = &[];
+            None
+        } else {
+            let ret = &self.v[end - self.size..end];
+            self.v = &self.v[..end - 1];
+            Some(ret)
+        }
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T> ExactSizeIterator for Windows<'_, T> {}
+
+#[unstable(feature = "trusted_len", issue = "37572")]
+unsafe impl<T> TrustedLen for Windows<'_, T> {}
+
+#[stable(feature = "fused", since = "1.26.0")]
+impl<T> FusedIterator for Windows<'_, T> {}
+
+#[doc(hidden)]
+#[unstable(feature = "trusted_random_access", issue = "none")]
+unsafe impl<'a, T> TrustedRandomAccess for Windows<'a, T> {
+    fn may_have_side_effect() -> bool {
+        false
+    }
+}
+
+/// An iterator over a slice in (non-overlapping) chunks (`chunk_size` elements at a
+/// time), starting at the beginning of the slice.
+///
+/// When the slice len is not evenly divided by the chunk size, the last slice
+/// of the iteration will be the remainder.
+///
+/// This struct is created by the [`chunks`] method on [slices].
+///
+/// [`chunks`]: ../../std/primitive.slice.html#method.chunks
+/// [slices]: ../../std/primitive.slice.html
+#[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,
+}
+
+// FIXME(#26925) Remove in favor of `#[derive(Clone)]`
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T> Clone for Chunks<'_, T> {
+    fn clone(&self) -> Self {
+        Chunks { v: self.v, chunk_size: self.chunk_size }
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a, T> Iterator for Chunks<'a, T> {
+    type Item = &'a [T];
+
+    #[inline]
+    fn next(&mut self) -> Option<&'a [T]> {
+        if self.v.is_empty() {
+            None
+        } else {
+            let chunksz = cmp::min(self.v.len(), self.chunk_size);
+            let (fst, snd) = self.v.split_at(chunksz);
+            self.v = snd;
+            Some(fst)
+        }
+    }
+
+    #[inline]
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        if self.v.is_empty() {
+            (0, Some(0))
+        } else {
+            let n = self.v.len() / self.chunk_size;
+            let rem = self.v.len() % self.chunk_size;
+            let n = if rem > 0 { n + 1 } else { n };
+            (n, Some(n))
+        }
+    }
+
+    #[inline]
+    fn count(self) -> usize {
+        self.len()
+    }
+
+    #[inline]
+    fn nth(&mut self, n: usize) -> Option<Self::Item> {
+        let (start, overflow) = n.overflowing_mul(self.chunk_size);
+        if start >= self.v.len() || overflow {
+            self.v = &[];
+            None
+        } else {
+            let end = match start.checked_add(self.chunk_size) {
+                Some(sum) => cmp::min(self.v.len(), sum),
+                None => self.v.len(),
+            };
+            let nth = &self.v[start..end];
+            self.v = &self.v[end..];
+            Some(nth)
+        }
+    }
+
+    #[inline]
+    fn last(self) -> Option<Self::Item> {
+        if self.v.is_empty() {
+            None
+        } else {
+            let start = (self.v.len() - 1) / self.chunk_size * self.chunk_size;
+            Some(&self.v[start..])
+        }
+    }
+
+    #[doc(hidden)]
+    unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item {
+        let start = idx * self.chunk_size;
+        let end = match start.checked_add(self.chunk_size) {
+            None => self.v.len(),
+            Some(end) => cmp::min(end, self.v.len()),
+        };
+        // SAFETY: the caller guarantees that `i` is in bounds,
+        // which means that `start` must be in bounds of the
+        // underlying `self.v` slice, and we made sure that `end`
+        // is also in bounds of `self.v`. Thus, `start` cannot overflow
+        // an `isize`, and the slice constructed by `from_raw_parts`
+        // is a subslice of `self.v` which is guaranteed to be valid
+        // for the lifetime `'a` of `self.v`.
+        unsafe { from_raw_parts(self.v.as_ptr().add(start), end - start) }
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a, T> DoubleEndedIterator for Chunks<'a, T> {
+    #[inline]
+    fn next_back(&mut self) -> Option<&'a [T]> {
+        if self.v.is_empty() {
+            None
+        } else {
+            let remainder = self.v.len() % self.chunk_size;
+            let chunksz = if remainder != 0 { remainder } else { self.chunk_size };
+            let (fst, snd) = self.v.split_at(self.v.len() - chunksz);
+            self.v = fst;
+            Some(snd)
+        }
+    }
+
+    #[inline]
+    fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
+        let len = self.len();
+        if n >= len {
+            self.v = &[];
+            None
+        } else {
+            let start = (len - 1 - n) * self.chunk_size;
+            let end = match start.checked_add(self.chunk_size) {
+                Some(res) => cmp::min(res, self.v.len()),
+                None => self.v.len(),
+            };
+            let nth_back = &self.v[start..end];
+            self.v = &self.v[..start];
+            Some(nth_back)
+        }
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T> ExactSizeIterator for Chunks<'_, T> {}
+
+#[unstable(feature = "trusted_len", issue = "37572")]
+unsafe impl<T> TrustedLen for Chunks<'_, T> {}
+
+#[stable(feature = "fused", since = "1.26.0")]
+impl<T> FusedIterator for Chunks<'_, T> {}
+
+#[doc(hidden)]
+#[unstable(feature = "trusted_random_access", issue = "none")]
+unsafe impl<'a, T> TrustedRandomAccess for Chunks<'a, T> {
+    fn may_have_side_effect() -> bool {
+        false
+    }
+}
+
+/// An iterator over a slice in (non-overlapping) mutable chunks (`chunk_size`
+/// elements at a time), starting at the beginning of the slice.
+///
+/// When the slice len is not evenly divided by the chunk size, the last slice
+/// of the iteration will be the remainder.
+///
+/// This struct is created by the [`chunks_mut`] method on [slices].
+///
+/// [`chunks_mut`]: ../../std/primitive.slice.html#method.chunks_mut
+/// [slices]: ../../std/primitive.slice.html
+#[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,
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a, T> Iterator for ChunksMut<'a, T> {
+    type Item = &'a mut [T];
+
+    #[inline]
+    fn next(&mut self) -> Option<&'a mut [T]> {
+        if self.v.is_empty() {
+            None
+        } else {
+            let sz = cmp::min(self.v.len(), self.chunk_size);
+            let tmp = mem::replace(&mut self.v, &mut []);
+            let (head, tail) = tmp.split_at_mut(sz);
+            self.v = tail;
+            Some(head)
+        }
+    }
+
+    #[inline]
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        if self.v.is_empty() {
+            (0, Some(0))
+        } else {
+            let n = self.v.len() / self.chunk_size;
+            let rem = self.v.len() % self.chunk_size;
+            let n = if rem > 0 { n + 1 } else { n };
+            (n, Some(n))
+        }
+    }
+
+    #[inline]
+    fn count(self) -> usize {
+        self.len()
+    }
+
+    #[inline]
+    fn nth(&mut self, n: usize) -> Option<&'a mut [T]> {
+        let (start, overflow) = n.overflowing_mul(self.chunk_size);
+        if start >= self.v.len() || overflow {
+            self.v = &mut [];
+            None
+        } else {
+            let end = match start.checked_add(self.chunk_size) {
+                Some(sum) => cmp::min(self.v.len(), sum),
+                None => self.v.len(),
+            };
+            let tmp = mem::replace(&mut self.v, &mut []);
+            let (head, tail) = tmp.split_at_mut(end);
+            let (_, nth) = head.split_at_mut(start);
+            self.v = tail;
+            Some(nth)
+        }
+    }
+
+    #[inline]
+    fn last(self) -> Option<Self::Item> {
+        if self.v.is_empty() {
+            None
+        } else {
+            let start = (self.v.len() - 1) / self.chunk_size * self.chunk_size;
+            Some(&mut self.v[start..])
+        }
+    }
+
+    #[doc(hidden)]
+    unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item {
+        let start = idx * self.chunk_size;
+        let end = match start.checked_add(self.chunk_size) {
+            None => self.v.len(),
+            Some(end) => cmp::min(end, self.v.len()),
+        };
+        // SAFETY: see comments for `Chunks::get_unchecked`.
+        //
+        // Also note that the caller also guarantees that we're never called
+        // with the same index again, and that no other methods that will
+        // access this subslice are called, so it is valid for the returned
+        // slice to be mutable.
+        unsafe { from_raw_parts_mut(self.v.as_mut_ptr().add(start), end - start) }
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a, T> DoubleEndedIterator for ChunksMut<'a, T> {
+    #[inline]
+    fn next_back(&mut self) -> Option<&'a mut [T]> {
+        if self.v.is_empty() {
+            None
+        } else {
+            let remainder = self.v.len() % self.chunk_size;
+            let sz = if remainder != 0 { remainder } else { self.chunk_size };
+            let tmp = mem::replace(&mut self.v, &mut []);
+            let tmp_len = tmp.len();
+            let (head, tail) = tmp.split_at_mut(tmp_len - sz);
+            self.v = head;
+            Some(tail)
+        }
+    }
+
+    #[inline]
+    fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
+        let len = self.len();
+        if n >= len {
+            self.v = &mut [];
+            None
+        } else {
+            let start = (len - 1 - n) * self.chunk_size;
+            let end = match start.checked_add(self.chunk_size) {
+                Some(res) => cmp::min(res, self.v.len()),
+                None => self.v.len(),
+            };
+            let (temp, _tail) = mem::replace(&mut self.v, &mut []).split_at_mut(end);
+            let (head, nth_back) = temp.split_at_mut(start);
+            self.v = head;
+            Some(nth_back)
+        }
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T> ExactSizeIterator for ChunksMut<'_, T> {}
+
+#[unstable(feature = "trusted_len", issue = "37572")]
+unsafe impl<T> TrustedLen for ChunksMut<'_, T> {}
+
+#[stable(feature = "fused", since = "1.26.0")]
+impl<T> FusedIterator for ChunksMut<'_, T> {}
+
+#[doc(hidden)]
+#[unstable(feature = "trusted_random_access", issue = "none")]
+unsafe impl<'a, T> TrustedRandomAccess for ChunksMut<'a, T> {
+    fn may_have_side_effect() -> bool {
+        false
+    }
+}
+
+/// An iterator over a slice in (non-overlapping) chunks (`chunk_size` elements at a
+/// time), starting at the beginning of the slice.
+///
+/// When the slice len is not evenly divided by the chunk size, the last
+/// up to `chunk_size-1` elements will be omitted but can be retrieved from
+/// the [`remainder`] function from the iterator.
+///
+/// This struct is created by the [`chunks_exact`] method on [slices].
+///
+/// [`chunks_exact`]: ../../std/primitive.slice.html#method.chunks_exact
+/// [`remainder`]: ChunksExact::remainder
+/// [slices]: ../../std/primitive.slice.html
+#[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,
+}
+
+impl<'a, T> ChunksExact<'a, T> {
+    /// Returns the remainder of the original slice that is not going to be
+    /// returned by the iterator. The returned slice has at most `chunk_size-1`
+    /// elements.
+    #[stable(feature = "chunks_exact", since = "1.31.0")]
+    pub fn remainder(&self) -> &'a [T] {
+        self.rem
+    }
+}
+
+// FIXME(#26925) Remove in favor of `#[derive(Clone)]`
+#[stable(feature = "chunks_exact", since = "1.31.0")]
+impl<T> Clone for ChunksExact<'_, T> {
+    fn clone(&self) -> Self {
+        ChunksExact { v: self.v, rem: self.rem, chunk_size: self.chunk_size }
+    }
+}
+
+#[stable(feature = "chunks_exact", since = "1.31.0")]
+impl<'a, T> Iterator for ChunksExact<'a, T> {
+    type Item = &'a [T];
+
+    #[inline]
+    fn next(&mut self) -> Option<&'a [T]> {
+        if self.v.len() < self.chunk_size {
+            None
+        } else {
+            let (fst, snd) = self.v.split_at(self.chunk_size);
+            self.v = snd;
+            Some(fst)
+        }
+    }
+
+    #[inline]
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        let n = self.v.len() / self.chunk_size;
+        (n, Some(n))
+    }
+
+    #[inline]
+    fn count(self) -> usize {
+        self.len()
+    }
+
+    #[inline]
+    fn nth(&mut self, n: usize) -> Option<Self::Item> {
+        let (start, overflow) = n.overflowing_mul(self.chunk_size);
+        if start >= self.v.len() || overflow {
+            self.v = &[];
+            None
+        } else {
+            let (_, snd) = self.v.split_at(start);
+            self.v = snd;
+            self.next()
+        }
+    }
+
+    #[inline]
+    fn last(mut self) -> Option<Self::Item> {
+        self.next_back()
+    }
+
+    #[doc(hidden)]
+    unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item {
+        let start = idx * self.chunk_size;
+        // SAFETY: mostly identical to `Chunks::get_unchecked`.
+        unsafe { from_raw_parts(self.v.as_ptr().add(start), self.chunk_size) }
+    }
+}
+
+#[stable(feature = "chunks_exact", since = "1.31.0")]
+impl<'a, T> DoubleEndedIterator for ChunksExact<'a, T> {
+    #[inline]
+    fn next_back(&mut self) -> Option<&'a [T]> {
+        if self.v.len() < self.chunk_size {
+            None
+        } else {
+            let (fst, snd) = self.v.split_at(self.v.len() - self.chunk_size);
+            self.v = fst;
+            Some(snd)
+        }
+    }
+
+    #[inline]
+    fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
+        let len = self.len();
+        if n >= len {
+            self.v = &[];
+            None
+        } else {
+            let start = (len - 1 - n) * self.chunk_size;
+            let end = start + self.chunk_size;
+            let nth_back = &self.v[start..end];
+            self.v = &self.v[..start];
+            Some(nth_back)
+        }
+    }
+}
+
+#[stable(feature = "chunks_exact", since = "1.31.0")]
+impl<T> ExactSizeIterator for ChunksExact<'_, T> {
+    fn is_empty(&self) -> bool {
+        self.v.is_empty()
+    }
+}
+
+#[unstable(feature = "trusted_len", issue = "37572")]
+unsafe impl<T> TrustedLen for ChunksExact<'_, T> {}
+
+#[stable(feature = "chunks_exact", since = "1.31.0")]
+impl<T> FusedIterator for ChunksExact<'_, T> {}
+
+#[doc(hidden)]
+#[unstable(feature = "trusted_random_access", issue = "none")]
+unsafe impl<'a, T> TrustedRandomAccess for ChunksExact<'a, T> {
+    fn may_have_side_effect() -> bool {
+        false
+    }
+}
+
+/// An iterator over a slice in (non-overlapping) mutable chunks (`chunk_size`
+/// elements at a time), starting at the beginning of the slice.
+///
+/// When the slice len is not evenly divided by the chunk size, the last up to
+/// `chunk_size-1` elements will be omitted but can be retrieved from the
+/// [`into_remainder`] function from the iterator.
+///
+/// This struct is created by the [`chunks_exact_mut`] method on [slices].
+///
+/// [`chunks_exact_mut`]: ../../std/primitive.slice.html#method.chunks_exact_mut
+/// [`into_remainder`]: ChunksExactMut::into_remainder
+/// [slices]: ../../std/primitive.slice.html
+#[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,
+}
+
+impl<'a, T> ChunksExactMut<'a, T> {
+    /// Returns the remainder of the original slice that is not going to be
+    /// returned by the iterator. The returned slice has at most `chunk_size-1`
+    /// elements.
+    #[stable(feature = "chunks_exact", since = "1.31.0")]
+    pub fn into_remainder(self) -> &'a mut [T] {
+        self.rem
+    }
+}
+
+#[stable(feature = "chunks_exact", since = "1.31.0")]
+impl<'a, T> Iterator for ChunksExactMut<'a, T> {
+    type Item = &'a mut [T];
+
+    #[inline]
+    fn next(&mut self) -> Option<&'a mut [T]> {
+        if self.v.len() < self.chunk_size {
+            None
+        } else {
+            let tmp = mem::replace(&mut self.v, &mut []);
+            let (head, tail) = tmp.split_at_mut(self.chunk_size);
+            self.v = tail;
+            Some(head)
+        }
+    }
+
+    #[inline]
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        let n = self.v.len() / self.chunk_size;
+        (n, Some(n))
+    }
+
+    #[inline]
+    fn count(self) -> usize {
+        self.len()
+    }
+
+    #[inline]
+    fn nth(&mut self, n: usize) -> Option<&'a mut [T]> {
+        let (start, overflow) = n.overflowing_mul(self.chunk_size);
+        if start >= self.v.len() || overflow {
+            self.v = &mut [];
+            None
+        } else {
+            let tmp = mem::replace(&mut self.v, &mut []);
+            let (_, snd) = tmp.split_at_mut(start);
+            self.v = snd;
+            self.next()
+        }
+    }
+
+    #[inline]
+    fn last(mut self) -> Option<Self::Item> {
+        self.next_back()
+    }
+
+    #[doc(hidden)]
+    unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item {
+        let start = idx * self.chunk_size;
+        // SAFETY: see comments for `ChunksMut::get_unchecked`.
+        unsafe { from_raw_parts_mut(self.v.as_mut_ptr().add(start), self.chunk_size) }
+    }
+}
+
+#[stable(feature = "chunks_exact", since = "1.31.0")]
+impl<'a, T> DoubleEndedIterator for ChunksExactMut<'a, T> {
+    #[inline]
+    fn next_back(&mut self) -> Option<&'a mut [T]> {
+        if self.v.len() < self.chunk_size {
+            None
+        } else {
+            let tmp = mem::replace(&mut self.v, &mut []);
+            let tmp_len = tmp.len();
+            let (head, tail) = tmp.split_at_mut(tmp_len - self.chunk_size);
+            self.v = head;
+            Some(tail)
+        }
+    }
+
+    #[inline]
+    fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
+        let len = self.len();
+        if n >= len {
+            self.v = &mut [];
+            None
+        } else {
+            let start = (len - 1 - n) * self.chunk_size;
+            let end = start + self.chunk_size;
+            let (temp, _tail) = mem::replace(&mut self.v, &mut []).split_at_mut(end);
+            let (head, nth_back) = temp.split_at_mut(start);
+            self.v = head;
+            Some(nth_back)
+        }
+    }
+}
+
+#[stable(feature = "chunks_exact", since = "1.31.0")]
+impl<T> ExactSizeIterator for ChunksExactMut<'_, T> {
+    fn is_empty(&self) -> bool {
+        self.v.is_empty()
+    }
+}
+
+#[unstable(feature = "trusted_len", issue = "37572")]
+unsafe impl<T> TrustedLen for ChunksExactMut<'_, T> {}
+
+#[stable(feature = "chunks_exact", since = "1.31.0")]
+impl<T> FusedIterator for ChunksExactMut<'_, T> {}
+
+#[doc(hidden)]
+#[unstable(feature = "trusted_random_access", issue = "none")]
+unsafe impl<'a, T> TrustedRandomAccess for ChunksExactMut<'a, T> {
+    fn may_have_side_effect() -> bool {
+        false
+    }
+}
+
+/// A windowed iterator over a slice in overlapping chunks (`N` elements at a
+/// time), starting at the beginning of the slice
+///
+/// This struct is created by the [`array_windows`] method on [slices].
+///
+/// [`array_windows`]: ../../std/primitive.slice.html#method.array_windows
+/// [slices]: ../../std/primitive.slice.html
+#[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]>,
+}
+
+#[unstable(feature = "array_windows", issue = "75027")]
+impl<'a, T, const N: usize> Iterator for ArrayWindows<'a, T, N> {
+    type Item = &'a [T; N];
+
+    #[inline]
+    fn next(&mut self) -> Option<Self::Item> {
+        if self.num == 0 {
+            return None;
+        }
+        // SAFETY:
+        // This is safe because it's indexing into a slice guaranteed to be length > N.
+        let ret = unsafe { &*self.slice_head.cast::<[T; N]>() };
+        // SAFETY: Guaranteed that there are at least 1 item remaining otherwise
+        // earlier branch would've been hit
+        self.slice_head = unsafe { self.slice_head.add(1) };
+
+        self.num -= 1;
+        Some(ret)
+    }
+
+    #[inline]
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        (self.num, Some(self.num))
+    }
+
+    #[inline]
+    fn count(self) -> usize {
+        self.num
+    }
+
+    #[inline]
+    fn nth(&mut self, n: usize) -> Option<Self::Item> {
+        if self.num <= n {
+            self.num = 0;
+            return None;
+        }
+        // SAFETY:
+        // This is safe because it's indexing into a slice guaranteed to be length > N.
+        let ret = unsafe { &*self.slice_head.add(n).cast::<[T; N]>() };
+        // SAFETY: Guaranteed that there are at least n items remaining
+        self.slice_head = unsafe { self.slice_head.add(n + 1) };
+
+        self.num -= n + 1;
+        Some(ret)
+    }
+
+    #[inline]
+    fn last(mut self) -> Option<Self::Item> {
+        self.nth(self.num.checked_sub(1)?)
+    }
+}
+
+#[unstable(feature = "array_windows", issue = "75027")]
+impl<'a, T, const N: usize> DoubleEndedIterator for ArrayWindows<'a, T, N> {
+    #[inline]
+    fn next_back(&mut self) -> Option<&'a [T; N]> {
+        if self.num == 0 {
+            return None;
+        }
+        // SAFETY: Guaranteed that there are n items remaining, n-1 for 0-indexing.
+        let ret = unsafe { &*self.slice_head.add(self.num - 1).cast::<[T; N]>() };
+        self.num -= 1;
+        Some(ret)
+    }
+
+    #[inline]
+    fn nth_back(&mut self, n: usize) -> Option<&'a [T; N]> {
+        if self.num <= n {
+            self.num = 0;
+            return None;
+        }
+        // SAFETY: Guaranteed that there are n items remaining, n-1 for 0-indexing.
+        let ret = unsafe { &*self.slice_head.add(self.num - (n + 1)).cast::<[T; N]>() };
+        self.num -= n + 1;
+        Some(ret)
+    }
+}
+
+#[unstable(feature = "array_windows", issue = "75027")]
+impl<T, const N: usize> ExactSizeIterator for ArrayWindows<'_, T, N> {
+    fn is_empty(&self) -> bool {
+        self.num == 0
+    }
+}
+
+/// An iterator over a slice in (non-overlapping) chunks (`N` elements at a
+/// time), starting at the beginning of the slice.
+///
+/// When the slice len is not evenly divided by the chunk size, the last
+/// up to `N-1` elements will be omitted but can be retrieved from
+/// the [`remainder`] function from the iterator.
+///
+/// This struct is created by the [`array_chunks`] method on [slices].
+///
+/// [`array_chunks`]: ../../std/primitive.slice.html#method.array_chunks
+/// [`remainder`]: ArrayChunks::remainder
+/// [slices]: ../../std/primitive.slice.html
+#[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],
+}
+
+impl<'a, T, const N: usize> ArrayChunks<'a, T, N> {
+    /// 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.
+    #[unstable(feature = "array_chunks", issue = "74985")]
+    pub fn remainder(&self) -> &'a [T] {
+        self.rem
+    }
+}
+
+// FIXME(#26925) Remove in favor of `#[derive(Clone)]`
+#[unstable(feature = "array_chunks", issue = "74985")]
+impl<T, const N: usize> Clone for ArrayChunks<'_, T, N> {
+    fn clone(&self) -> Self {
+        ArrayChunks { iter: self.iter.clone(), rem: self.rem }
+    }
+}
+
+#[unstable(feature = "array_chunks", issue = "74985")]
+impl<'a, T, const N: usize> Iterator for ArrayChunks<'a, T, N> {
+    type Item = &'a [T; N];
+
+    #[inline]
+    fn next(&mut self) -> Option<&'a [T; N]> {
+        self.iter.next()
+    }
+
+    #[inline]
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        self.iter.size_hint()
+    }
+
+    #[inline]
+    fn count(self) -> usize {
+        self.iter.count()
+    }
+
+    #[inline]
+    fn nth(&mut self, n: usize) -> Option<Self::Item> {
+        self.iter.nth(n)
+    }
+
+    #[inline]
+    fn last(self) -> Option<Self::Item> {
+        self.iter.last()
+    }
+
+    unsafe fn get_unchecked(&mut self, i: usize) -> &'a [T; N] {
+        // SAFETY: The safety guarantees of `get_unchecked` are transferred to
+        // the caller.
+        unsafe { self.iter.get_unchecked(i) }
+    }
+}
+
+#[unstable(feature = "array_chunks", issue = "74985")]
+impl<'a, T, const N: usize> DoubleEndedIterator for ArrayChunks<'a, T, N> {
+    #[inline]
+    fn next_back(&mut self) -> Option<&'a [T; N]> {
+        self.iter.next_back()
+    }
+
+    #[inline]
+    fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
+        self.iter.nth_back(n)
+    }
+}
+
+#[unstable(feature = "array_chunks", issue = "74985")]
+impl<T, const N: usize> ExactSizeIterator for ArrayChunks<'_, T, N> {
+    fn is_empty(&self) -> bool {
+        self.iter.is_empty()
+    }
+}
+
+#[unstable(feature = "trusted_len", issue = "37572")]
+unsafe impl<T, const N: usize> TrustedLen for ArrayChunks<'_, T, N> {}
+
+#[unstable(feature = "array_chunks", issue = "74985")]
+impl<T, const N: usize> FusedIterator for ArrayChunks<'_, T, N> {}
+
+#[doc(hidden)]
+#[unstable(feature = "array_chunks", issue = "74985")]
+unsafe impl<'a, T, const N: usize> TrustedRandomAccess for ArrayChunks<'a, T, N> {
+    fn may_have_side_effect() -> bool {
+        false
+    }
+}
+
+/// An iterator over a slice in (non-overlapping) mutable chunks (`N` elements
+/// at a time), starting at the beginning of the slice.
+///
+/// When the slice len is not evenly divided by the chunk size, the last
+/// up to `N-1` elements will be omitted but can be retrieved from
+/// the [`into_remainder`] function from the iterator.
+///
+/// This struct is created by the [`array_chunks_mut`] method on [slices].
+///
+/// [`array_chunks_mut`]: ../../std/primitive.slice.html#method.array_chunks_mut
+/// [`into_remainder`]: ../../std/slice/struct.ArrayChunksMut.html#method.into_remainder
+/// [slices]: ../../std/primitive.slice.html
+#[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],
+}
+
+impl<'a, T, const N: usize> ArrayChunksMut<'a, T, N> {
+    /// 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.
+    #[unstable(feature = "array_chunks", issue = "74985")]
+    pub fn into_remainder(self) -> &'a mut [T] {
+        self.rem
+    }
+}
+
+#[unstable(feature = "array_chunks", issue = "74985")]
+impl<'a, T, const N: usize> Iterator for ArrayChunksMut<'a, T, N> {
+    type Item = &'a mut [T; N];
+
+    #[inline]
+    fn next(&mut self) -> Option<&'a mut [T; N]> {
+        self.iter.next()
+    }
+
+    #[inline]
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        self.iter.size_hint()
+    }
+
+    #[inline]
+    fn count(self) -> usize {
+        self.iter.count()
+    }
+
+    #[inline]
+    fn nth(&mut self, n: usize) -> Option<Self::Item> {
+        self.iter.nth(n)
+    }
+
+    #[inline]
+    fn last(self) -> Option<Self::Item> {
+        self.iter.last()
+    }
+
+    unsafe fn get_unchecked(&mut self, i: usize) -> &'a mut [T; N] {
+        // SAFETY: The safety guarantees of `get_unchecked` are transferred to
+        // the caller.
+        unsafe { self.iter.get_unchecked(i) }
+    }
+}
+
+#[unstable(feature = "array_chunks", issue = "74985")]
+impl<'a, T, const N: usize> DoubleEndedIterator for ArrayChunksMut<'a, T, N> {
+    #[inline]
+    fn next_back(&mut self) -> Option<&'a mut [T; N]> {
+        self.iter.next_back()
+    }
+
+    #[inline]
+    fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
+        self.iter.nth_back(n)
+    }
+}
+
+#[unstable(feature = "array_chunks", issue = "74985")]
+impl<T, const N: usize> ExactSizeIterator for ArrayChunksMut<'_, T, N> {
+    fn is_empty(&self) -> bool {
+        self.iter.is_empty()
+    }
+}
+
+#[unstable(feature = "trusted_len", issue = "37572")]
+unsafe impl<T, const N: usize> TrustedLen for ArrayChunksMut<'_, T, N> {}
+
+#[unstable(feature = "array_chunks", issue = "74985")]
+impl<T, const N: usize> FusedIterator for ArrayChunksMut<'_, T, N> {}
+
+#[doc(hidden)]
+#[unstable(feature = "array_chunks", issue = "74985")]
+unsafe impl<'a, T, const N: usize> TrustedRandomAccess for ArrayChunksMut<'a, T, N> {
+    fn may_have_side_effect() -> bool {
+        false
+    }
+}
+
+/// An iterator over a slice in (non-overlapping) chunks (`chunk_size` elements at a
+/// time), starting at the end of the slice.
+///
+/// When the slice len is not evenly divided by the chunk size, the last slice
+/// of the iteration will be the remainder.
+///
+/// This struct is created by the [`rchunks`] method on [slices].
+///
+/// [`rchunks`]: ../../std/primitive.slice.html#method.rchunks
+/// [slices]: ../../std/primitive.slice.html
+#[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,
+}
+
+// FIXME(#26925) Remove in favor of `#[derive(Clone)]`
+#[stable(feature = "rchunks", since = "1.31.0")]
+impl<T> Clone for RChunks<'_, T> {
+    fn clone(&self) -> Self {
+        RChunks { v: self.v, chunk_size: self.chunk_size }
+    }
+}
+
+#[stable(feature = "rchunks", since = "1.31.0")]
+impl<'a, T> Iterator for RChunks<'a, T> {
+    type Item = &'a [T];
+
+    #[inline]
+    fn next(&mut self) -> Option<&'a [T]> {
+        if self.v.is_empty() {
+            None
+        } else {
+            let chunksz = cmp::min(self.v.len(), self.chunk_size);
+            let (fst, snd) = self.v.split_at(self.v.len() - chunksz);
+            self.v = fst;
+            Some(snd)
+        }
+    }
+
+    #[inline]
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        if self.v.is_empty() {
+            (0, Some(0))
+        } else {
+            let n = self.v.len() / self.chunk_size;
+            let rem = self.v.len() % self.chunk_size;
+            let n = if rem > 0 { n + 1 } else { n };
+            (n, Some(n))
+        }
+    }
+
+    #[inline]
+    fn count(self) -> usize {
+        self.len()
+    }
+
+    #[inline]
+    fn nth(&mut self, n: usize) -> Option<Self::Item> {
+        let (end, overflow) = n.overflowing_mul(self.chunk_size);
+        if end >= self.v.len() || overflow {
+            self.v = &[];
+            None
+        } else {
+            // Can't underflow because of the check above
+            let end = self.v.len() - end;
+            let start = match end.checked_sub(self.chunk_size) {
+                Some(sum) => sum,
+                None => 0,
+            };
+            let nth = &self.v[start..end];
+            self.v = &self.v[0..start];
+            Some(nth)
+        }
+    }
+
+    #[inline]
+    fn last(self) -> Option<Self::Item> {
+        if self.v.is_empty() {
+            None
+        } else {
+            let rem = self.v.len() % self.chunk_size;
+            let end = if rem == 0 { self.chunk_size } else { rem };
+            Some(&self.v[0..end])
+        }
+    }
+
+    #[doc(hidden)]
+    unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item {
+        let end = self.v.len() - idx * self.chunk_size;
+        let start = match end.checked_sub(self.chunk_size) {
+            None => 0,
+            Some(start) => start,
+        };
+        // SAFETY: mostly identical to `Chunks::get_unchecked`.
+        unsafe { from_raw_parts(self.v.as_ptr().add(start), end - start) }
+    }
+}
+
+#[stable(feature = "rchunks", since = "1.31.0")]
+impl<'a, T> DoubleEndedIterator for RChunks<'a, T> {
+    #[inline]
+    fn next_back(&mut self) -> Option<&'a [T]> {
+        if self.v.is_empty() {
+            None
+        } else {
+            let remainder = self.v.len() % self.chunk_size;
+            let chunksz = if remainder != 0 { remainder } else { self.chunk_size };
+            let (fst, snd) = self.v.split_at(chunksz);
+            self.v = snd;
+            Some(fst)
+        }
+    }
+
+    #[inline]
+    fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
+        let len = self.len();
+        if n >= len {
+            self.v = &[];
+            None
+        } else {
+            // can't underflow because `n < len`
+            let offset_from_end = (len - 1 - n) * self.chunk_size;
+            let end = self.v.len() - offset_from_end;
+            let start = end.saturating_sub(self.chunk_size);
+            let nth_back = &self.v[start..end];
+            self.v = &self.v[end..];
+            Some(nth_back)
+        }
+    }
+}
+
+#[stable(feature = "rchunks", since = "1.31.0")]
+impl<T> ExactSizeIterator for RChunks<'_, T> {}
+
+#[unstable(feature = "trusted_len", issue = "37572")]
+unsafe impl<T> TrustedLen for RChunks<'_, T> {}
+
+#[stable(feature = "rchunks", since = "1.31.0")]
+impl<T> FusedIterator for RChunks<'_, T> {}
+
+#[doc(hidden)]
+#[unstable(feature = "trusted_random_access", issue = "none")]
+unsafe impl<'a, T> TrustedRandomAccess for RChunks<'a, T> {
+    fn may_have_side_effect() -> bool {
+        false
+    }
+}
+
+/// An iterator over a slice in (non-overlapping) mutable chunks (`chunk_size`
+/// elements at a time), starting at the end of the slice.
+///
+/// When the slice len is not evenly divided by the chunk size, the last slice
+/// of the iteration will be the remainder.
+///
+/// This struct is created by the [`rchunks_mut`] method on [slices].
+///
+/// [`rchunks_mut`]: ../../std/primitive.slice.html#method.rchunks_mut
+/// [slices]: ../../std/primitive.slice.html
+#[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,
+}
+
+#[stable(feature = "rchunks", since = "1.31.0")]
+impl<'a, T> Iterator for RChunksMut<'a, T> {
+    type Item = &'a mut [T];
+
+    #[inline]
+    fn next(&mut self) -> Option<&'a mut [T]> {
+        if self.v.is_empty() {
+            None
+        } else {
+            let sz = cmp::min(self.v.len(), self.chunk_size);
+            let tmp = mem::replace(&mut self.v, &mut []);
+            let tmp_len = tmp.len();
+            let (head, tail) = tmp.split_at_mut(tmp_len - sz);
+            self.v = head;
+            Some(tail)
+        }
+    }
+
+    #[inline]
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        if self.v.is_empty() {
+            (0, Some(0))
+        } else {
+            let n = self.v.len() / self.chunk_size;
+            let rem = self.v.len() % self.chunk_size;
+            let n = if rem > 0 { n + 1 } else { n };
+            (n, Some(n))
+        }
+    }
+
+    #[inline]
+    fn count(self) -> usize {
+        self.len()
+    }
+
+    #[inline]
+    fn nth(&mut self, n: usize) -> Option<&'a mut [T]> {
+        let (end, overflow) = n.overflowing_mul(self.chunk_size);
+        if end >= self.v.len() || overflow {
+            self.v = &mut [];
+            None
+        } else {
+            // Can't underflow because of the check above
+            let end = self.v.len() - end;
+            let start = match end.checked_sub(self.chunk_size) {
+                Some(sum) => sum,
+                None => 0,
+            };
+            let tmp = mem::replace(&mut self.v, &mut []);
+            let (head, tail) = tmp.split_at_mut(start);
+            let (nth, _) = tail.split_at_mut(end - start);
+            self.v = head;
+            Some(nth)
+        }
+    }
+
+    #[inline]
+    fn last(self) -> Option<Self::Item> {
+        if self.v.is_empty() {
+            None
+        } else {
+            let rem = self.v.len() % self.chunk_size;
+            let end = if rem == 0 { self.chunk_size } else { rem };
+            Some(&mut self.v[0..end])
+        }
+    }
+
+    #[doc(hidden)]
+    unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item {
+        let end = self.v.len() - idx * self.chunk_size;
+        let start = match end.checked_sub(self.chunk_size) {
+            None => 0,
+            Some(start) => start,
+        };
+        // SAFETY: see comments for `RChunks::get_unchecked` and `ChunksMut::get_unchecked`
+        unsafe { from_raw_parts_mut(self.v.as_mut_ptr().add(start), end - start) }
+    }
+}
+
+#[stable(feature = "rchunks", since = "1.31.0")]
+impl<'a, T> DoubleEndedIterator for RChunksMut<'a, T> {
+    #[inline]
+    fn next_back(&mut self) -> Option<&'a mut [T]> {
+        if self.v.is_empty() {
+            None
+        } else {
+            let remainder = self.v.len() % self.chunk_size;
+            let sz = if remainder != 0 { remainder } else { self.chunk_size };
+            let tmp = mem::replace(&mut self.v, &mut []);
+            let (head, tail) = tmp.split_at_mut(sz);
+            self.v = tail;
+            Some(head)
+        }
+    }
+
+    #[inline]
+    fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
+        let len = self.len();
+        if n >= len {
+            self.v = &mut [];
+            None
+        } else {
+            // can't underflow because `n < len`
+            let offset_from_end = (len - 1 - n) * self.chunk_size;
+            let end = self.v.len() - offset_from_end;
+            let start = end.saturating_sub(self.chunk_size);
+            let (tmp, tail) = mem::replace(&mut self.v, &mut []).split_at_mut(end);
+            let (_, nth_back) = tmp.split_at_mut(start);
+            self.v = tail;
+            Some(nth_back)
+        }
+    }
+}
+
+#[stable(feature = "rchunks", since = "1.31.0")]
+impl<T> ExactSizeIterator for RChunksMut<'_, T> {}
+
+#[unstable(feature = "trusted_len", issue = "37572")]
+unsafe impl<T> TrustedLen for RChunksMut<'_, T> {}
+
+#[stable(feature = "rchunks", since = "1.31.0")]
+impl<T> FusedIterator for RChunksMut<'_, T> {}
+
+#[doc(hidden)]
+#[unstable(feature = "trusted_random_access", issue = "none")]
+unsafe impl<'a, T> TrustedRandomAccess for RChunksMut<'a, T> {
+    fn may_have_side_effect() -> bool {
+        false
+    }
+}
+
+/// An iterator over a slice in (non-overlapping) chunks (`chunk_size` elements at a
+/// time), starting at the end of the slice.
+///
+/// When the slice len is not evenly divided by the chunk size, the last
+/// up to `chunk_size-1` elements will be omitted but can be retrieved from
+/// the [`remainder`] function from the iterator.
+///
+/// This struct is created by the [`rchunks_exact`] method on [slices].
+///
+/// [`rchunks_exact`]: ../../std/primitive.slice.html#method.rchunks_exact
+/// [`remainder`]: ChunksExact::remainder
+/// [slices]: ../../std/primitive.slice.html
+#[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,
+}
+
+impl<'a, T> RChunksExact<'a, T> {
+    /// Returns the remainder of the original slice that is not going to be
+    /// returned by the iterator. The returned slice has at most `chunk_size-1`
+    /// elements.
+    #[stable(feature = "rchunks", since = "1.31.0")]
+    pub fn remainder(&self) -> &'a [T] {
+        self.rem
+    }
+}
+
+// FIXME(#26925) Remove in favor of `#[derive(Clone)]`
+#[stable(feature = "rchunks", since = "1.31.0")]
+impl<'a, T> Clone for RChunksExact<'a, T> {
+    fn clone(&self) -> RChunksExact<'a, T> {
+        RChunksExact { v: self.v, rem: self.rem, chunk_size: self.chunk_size }
+    }
+}
+
+#[stable(feature = "rchunks", since = "1.31.0")]
+impl<'a, T> Iterator for RChunksExact<'a, T> {
+    type Item = &'a [T];
+
+    #[inline]
+    fn next(&mut self) -> Option<&'a [T]> {
+        if self.v.len() < self.chunk_size {
+            None
+        } else {
+            let (fst, snd) = self.v.split_at(self.v.len() - self.chunk_size);
+            self.v = fst;
+            Some(snd)
+        }
+    }
+
+    #[inline]
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        let n = self.v.len() / self.chunk_size;
+        (n, Some(n))
+    }
+
+    #[inline]
+    fn count(self) -> usize {
+        self.len()
+    }
+
+    #[inline]
+    fn nth(&mut self, n: usize) -> Option<Self::Item> {
+        let (end, overflow) = n.overflowing_mul(self.chunk_size);
+        if end >= self.v.len() || overflow {
+            self.v = &[];
+            None
+        } else {
+            let (fst, _) = self.v.split_at(self.v.len() - end);
+            self.v = fst;
+            self.next()
+        }
+    }
+
+    #[inline]
+    fn last(mut self) -> Option<Self::Item> {
+        self.next_back()
+    }
+
+    #[doc(hidden)]
+    unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item {
+        let end = self.v.len() - idx * self.chunk_size;
+        let start = end - self.chunk_size;
+        // SAFETY:
+        // SAFETY: mostmy identical to `Chunks::get_unchecked`.
+        unsafe { from_raw_parts(self.v.as_ptr().add(start), self.chunk_size) }
+    }
+}
+
+#[stable(feature = "rchunks", since = "1.31.0")]
+impl<'a, T> DoubleEndedIterator for RChunksExact<'a, T> {
+    #[inline]
+    fn next_back(&mut self) -> Option<&'a [T]> {
+        if self.v.len() < self.chunk_size {
+            None
+        } else {
+            let (fst, snd) = self.v.split_at(self.chunk_size);
+            self.v = snd;
+            Some(fst)
+        }
+    }
+
+    #[inline]
+    fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
+        let len = self.len();
+        if n >= len {
+            self.v = &[];
+            None
+        } else {
+            // now that we know that `n` corresponds to a chunk,
+            // none of these operations can underflow/overflow
+            let offset = (len - n) * self.chunk_size;
+            let start = self.v.len() - offset;
+            let end = start + self.chunk_size;
+            let nth_back = &self.v[start..end];
+            self.v = &self.v[end..];
+            Some(nth_back)
+        }
+    }
+}
+
+#[stable(feature = "rchunks", since = "1.31.0")]
+impl<'a, T> ExactSizeIterator for RChunksExact<'a, T> {
+    fn is_empty(&self) -> bool {
+        self.v.is_empty()
+    }
+}
+
+#[unstable(feature = "trusted_len", issue = "37572")]
+unsafe impl<T> TrustedLen for RChunksExact<'_, T> {}
+
+#[stable(feature = "rchunks", since = "1.31.0")]
+impl<T> FusedIterator for RChunksExact<'_, T> {}
+
+#[doc(hidden)]
+#[unstable(feature = "trusted_random_access", issue = "none")]
+unsafe impl<'a, T> TrustedRandomAccess for RChunksExact<'a, T> {
+    fn may_have_side_effect() -> bool {
+        false
+    }
+}
+
+/// An iterator over a slice in (non-overlapping) mutable chunks (`chunk_size`
+/// elements at a time), starting at the end of the slice.
+///
+/// When the slice len is not evenly divided by the chunk size, the last up to
+/// `chunk_size-1` elements will be omitted but can be retrieved from the
+/// [`into_remainder`] function from the iterator.
+///
+/// This struct is created by the [`rchunks_exact_mut`] method on [slices].
+///
+/// [`rchunks_exact_mut`]: ../../std/primitive.slice.html#method.rchunks_exact_mut
+/// [`into_remainder`]: ChunksExactMut::into_remainder
+/// [slices]: ../../std/primitive.slice.html
+#[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,
+}
+
+impl<'a, T> RChunksExactMut<'a, T> {
+    /// Returns the remainder of the original slice that is not going to be
+    /// returned by the iterator. The returned slice has at most `chunk_size-1`
+    /// elements.
+    #[stable(feature = "rchunks", since = "1.31.0")]
+    pub fn into_remainder(self) -> &'a mut [T] {
+        self.rem
+    }
+}
+
+#[stable(feature = "rchunks", since = "1.31.0")]
+impl<'a, T> Iterator for RChunksExactMut<'a, T> {
+    type Item = &'a mut [T];
+
+    #[inline]
+    fn next(&mut self) -> Option<&'a mut [T]> {
+        if self.v.len() < self.chunk_size {
+            None
+        } else {
+            let tmp = mem::replace(&mut self.v, &mut []);
+            let tmp_len = tmp.len();
+            let (head, tail) = tmp.split_at_mut(tmp_len - self.chunk_size);
+            self.v = head;
+            Some(tail)
+        }
+    }
+
+    #[inline]
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        let n = self.v.len() / self.chunk_size;
+        (n, Some(n))
+    }
+
+    #[inline]
+    fn count(self) -> usize {
+        self.len()
+    }
+
+    #[inline]
+    fn nth(&mut self, n: usize) -> Option<&'a mut [T]> {
+        let (end, overflow) = n.overflowing_mul(self.chunk_size);
+        if end >= self.v.len() || overflow {
+            self.v = &mut [];
+            None
+        } else {
+            let tmp = mem::replace(&mut self.v, &mut []);
+            let tmp_len = tmp.len();
+            let (fst, _) = tmp.split_at_mut(tmp_len - end);
+            self.v = fst;
+            self.next()
+        }
+    }
+
+    #[inline]
+    fn last(mut self) -> Option<Self::Item> {
+        self.next_back()
+    }
+
+    #[doc(hidden)]
+    unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item {
+        let end = self.v.len() - idx * self.chunk_size;
+        let start = end - self.chunk_size;
+        // SAFETY: see comments for `RChunksMut::get_unchecked`.
+        unsafe { from_raw_parts_mut(self.v.as_mut_ptr().add(start), self.chunk_size) }
+    }
+}
+
+#[stable(feature = "rchunks", since = "1.31.0")]
+impl<'a, T> DoubleEndedIterator for RChunksExactMut<'a, T> {
+    #[inline]
+    fn next_back(&mut self) -> Option<&'a mut [T]> {
+        if self.v.len() < self.chunk_size {
+            None
+        } else {
+            let tmp = mem::replace(&mut self.v, &mut []);
+            let (head, tail) = tmp.split_at_mut(self.chunk_size);
+            self.v = tail;
+            Some(head)
+        }
+    }
+
+    #[inline]
+    fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
+        let len = self.len();
+        if n >= len {
+            self.v = &mut [];
+            None
+        } else {
+            // now that we know that `n` corresponds to a chunk,
+            // none of these operations can underflow/overflow
+            let offset = (len - n) * self.chunk_size;
+            let start = self.v.len() - offset;
+            let end = start + self.chunk_size;
+            let (tmp, tail) = mem::replace(&mut self.v, &mut []).split_at_mut(end);
+            let (_, nth_back) = tmp.split_at_mut(start);
+            self.v = tail;
+            Some(nth_back)
+        }
+    }
+}
+
+#[stable(feature = "rchunks", since = "1.31.0")]
+impl<T> ExactSizeIterator for RChunksExactMut<'_, T> {
+    fn is_empty(&self) -> bool {
+        self.v.is_empty()
+    }
+}
+
+#[unstable(feature = "trusted_len", issue = "37572")]
+unsafe impl<T> TrustedLen for RChunksExactMut<'_, T> {}
+
+#[stable(feature = "rchunks", since = "1.31.0")]
+impl<T> FusedIterator for RChunksExactMut<'_, T> {}
+
+#[doc(hidden)]
+#[unstable(feature = "trusted_random_access", issue = "none")]
+unsafe impl<'a, T> TrustedRandomAccess for RChunksExactMut<'a, T> {
+    fn may_have_side_effect() -> bool {
+        false
+    }
+}
+
+#[doc(hidden)]
+#[unstable(feature = "trusted_random_access", issue = "none")]
+unsafe impl<'a, T> TrustedRandomAccess for Iter<'a, T> {
+    fn may_have_side_effect() -> bool {
+        false
+    }
+}
+
+#[doc(hidden)]
+#[unstable(feature = "trusted_random_access", issue = "none")]
+unsafe impl<'a, T> TrustedRandomAccess for IterMut<'a, T> {
+    fn may_have_side_effect() -> bool {
+        false
+    }
+}
diff --git a/library/core/src/slice/iter/macros.rs b/library/core/src/slice/iter/macros.rs
new file mode 100644 (file)
index 0000000..9fcc7a7
--- /dev/null
@@ -0,0 +1,407 @@
+//! Macros used by iterators of slice.
+
+// Inlining is_empty and len makes a huge performance difference
+macro_rules! is_empty {
+    // The way we encode the length of a ZST iterator, this works both for ZST
+    // and non-ZST.
+    ($self: ident) => {
+        $self.ptr.as_ptr() as *const T == $self.end
+    };
+}
+
+// To get rid of some bounds checks (see `position`), we compute the length in a somewhat
+// unexpected way. (Tested by `codegen/slice-position-bounds-check`.)
+macro_rules! len {
+    ($self: ident) => {{
+        #![allow(unused_unsafe)] // we're sometimes used within an unsafe block
+
+        let start = $self.ptr;
+        let size = size_from_ptr(start.as_ptr());
+        if size == 0 {
+            // This _cannot_ use `unchecked_sub` because we depend on wrapping
+            // to represent the length of long ZST slice iterators.
+            ($self.end as usize).wrapping_sub(start.as_ptr() as usize)
+        } else {
+            // We know that `start <= end`, so can do better than `offset_from`,
+            // which needs to deal in signed.  By setting appropriate flags here
+            // we can tell LLVM this, which helps it remove bounds checks.
+            // SAFETY: By the type invariant, `start <= end`
+            let diff = unsafe { unchecked_sub($self.end as usize, start.as_ptr() as usize) };
+            // By also telling LLVM that the pointers are apart by an exact
+            // multiple of the type size, it can optimize `len() == 0` down to
+            // `start == end` instead of `(end - start) < size`.
+            // SAFETY: By the type invariant, the pointers are aligned so the
+            //         distance between them must be a multiple of pointee size
+            unsafe { exact_div(diff, size) }
+        }
+    }};
+}
+
+// The shared definition of the `Iter` and `IterMut` iterators
+macro_rules! iterator {
+    (
+        struct $name:ident -> $ptr:ty,
+        $elem:ty,
+        $raw_mut:tt,
+        {$( $mut_:tt )?},
+        {$($extra:tt)*}
+    ) => {
+        // Returns the first element and moves the start of the iterator forwards by 1.
+        // Greatly improves performance compared to an inlined function. The iterator
+        // must not be empty.
+        macro_rules! next_unchecked {
+            ($self: ident) => {& $( $mut_ )? *$self.post_inc_start(1)}
+        }
+
+        // Returns the last element and moves the end of the iterator backwards by 1.
+        // Greatly improves performance compared to an inlined function. The iterator
+        // must not be empty.
+        macro_rules! next_back_unchecked {
+            ($self: ident) => {& $( $mut_ )? *$self.pre_dec_end(1)}
+        }
+
+        // Shrinks the iterator when T is a ZST, by moving the end of the iterator
+        // backwards by `n`. `n` must not exceed `self.len()`.
+        macro_rules! zst_shrink {
+            ($self: ident, $n: ident) => {
+                $self.end = ($self.end as * $raw_mut u8).wrapping_offset(-$n) as * $raw_mut T;
+            }
+        }
+
+        impl<'a, T> $name<'a, T> {
+            // Helper function for creating a slice from the iterator.
+            #[inline(always)]
+            fn make_slice(&self) -> &'a [T] {
+                // SAFETY: the iterator was created from a slice with pointer
+                // `self.ptr` and length `len!(self)`. This guarantees that all
+                // the prerequisites for `from_raw_parts` are fulfilled.
+                unsafe { from_raw_parts(self.ptr.as_ptr(), len!(self)) }
+            }
+
+            // Helper function for moving the start of the iterator forwards by `offset` elements,
+            // returning the old start.
+            // Unsafe because the offset must not exceed `self.len()`.
+            #[inline(always)]
+            unsafe fn post_inc_start(&mut self, offset: isize) -> * $raw_mut T {
+                if mem::size_of::<T>() == 0 {
+                    zst_shrink!(self, offset);
+                    self.ptr.as_ptr()
+                } else {
+                    let old = self.ptr.as_ptr();
+                    // SAFETY: the caller guarantees that `offset` doesn't exceed `self.len()`,
+                    // so this new pointer is inside `self` and thus guaranteed to be non-null.
+                    self.ptr = unsafe { NonNull::new_unchecked(self.ptr.as_ptr().offset(offset)) };
+                    old
+                }
+            }
+
+            // Helper function for moving the end of the iterator backwards by `offset` elements,
+            // returning the new end.
+            // Unsafe because the offset must not exceed `self.len()`.
+            #[inline(always)]
+            unsafe fn pre_dec_end(&mut self, offset: isize) -> * $raw_mut T {
+                if mem::size_of::<T>() == 0 {
+                    zst_shrink!(self, offset);
+                    self.ptr.as_ptr()
+                } else {
+                    // SAFETY: the caller guarantees that `offset` doesn't exceed `self.len()`,
+                    // which is guaranteed to not overflow an `isize`. Also, the resulting pointer
+                    // is in bounds of `slice`, which fulfills the other requirements for `offset`.
+                    self.end = unsafe { self.end.offset(-offset) };
+                    self.end
+                }
+            }
+        }
+
+        #[stable(feature = "rust1", since = "1.0.0")]
+        impl<T> ExactSizeIterator for $name<'_, T> {
+            #[inline(always)]
+            fn len(&self) -> usize {
+                len!(self)
+            }
+
+            #[inline(always)]
+            fn is_empty(&self) -> bool {
+                is_empty!(self)
+            }
+        }
+
+        #[stable(feature = "rust1", since = "1.0.0")]
+        impl<'a, T> Iterator for $name<'a, T> {
+            type Item = $elem;
+
+            #[inline]
+            fn next(&mut self) -> Option<$elem> {
+                // could be implemented with slices, but this avoids bounds checks
+
+                // SAFETY: `assume` calls are safe since a slice's start pointer
+                // must be non-null, and slices over non-ZSTs must also have a
+                // non-null end pointer. The call to `next_unchecked!` is safe
+                // since we check if the iterator is empty first.
+                unsafe {
+                    assume(!self.ptr.as_ptr().is_null());
+                    if mem::size_of::<T>() != 0 {
+                        assume(!self.end.is_null());
+                    }
+                    if is_empty!(self) {
+                        None
+                    } else {
+                        Some(next_unchecked!(self))
+                    }
+                }
+            }
+
+            #[inline]
+            fn size_hint(&self) -> (usize, Option<usize>) {
+                let exact = len!(self);
+                (exact, Some(exact))
+            }
+
+            #[inline]
+            fn count(self) -> usize {
+                len!(self)
+            }
+
+            #[inline]
+            fn nth(&mut self, n: usize) -> Option<$elem> {
+                if n >= len!(self) {
+                    // This iterator is now empty.
+                    if mem::size_of::<T>() == 0 {
+                        // We have to do it this way as `ptr` may never be 0, but `end`
+                        // could be (due to wrapping).
+                        self.end = self.ptr.as_ptr();
+                    } else {
+                        // SAFETY: end can't be 0 if T isn't ZST because ptr isn't 0 and end >= ptr
+                        unsafe {
+                            self.ptr = NonNull::new_unchecked(self.end as *mut T);
+                        }
+                    }
+                    return None;
+                }
+                // SAFETY: We are in bounds. `post_inc_start` does the right thing even for ZSTs.
+                unsafe {
+                    self.post_inc_start(n as isize);
+                    Some(next_unchecked!(self))
+                }
+            }
+
+            #[inline]
+            fn last(mut self) -> Option<$elem> {
+                self.next_back()
+            }
+
+            // We override the default implementation, which uses `try_fold`,
+            // because this simple implementation generates less LLVM IR and is
+            // faster to compile.
+            #[inline]
+            fn for_each<F>(mut self, mut f: F)
+            where
+                Self: Sized,
+                F: FnMut(Self::Item),
+            {
+                while let Some(x) = self.next() {
+                    f(x);
+                }
+            }
+
+            // We override the default implementation, which uses `try_fold`,
+            // because this simple implementation generates less LLVM IR and is
+            // faster to compile.
+            #[inline]
+            fn all<F>(&mut self, mut f: F) -> bool
+            where
+                Self: Sized,
+                F: FnMut(Self::Item) -> bool,
+            {
+                while let Some(x) = self.next() {
+                    if !f(x) {
+                        return false;
+                    }
+                }
+                true
+            }
+
+            // We override the default implementation, which uses `try_fold`,
+            // because this simple implementation generates less LLVM IR and is
+            // faster to compile.
+            #[inline]
+            fn any<F>(&mut self, mut f: F) -> bool
+            where
+                Self: Sized,
+                F: FnMut(Self::Item) -> bool,
+            {
+                while let Some(x) = self.next() {
+                    if f(x) {
+                        return true;
+                    }
+                }
+                false
+            }
+
+            // We override the default implementation, which uses `try_fold`,
+            // because this simple implementation generates less LLVM IR and is
+            // faster to compile.
+            #[inline]
+            fn find<P>(&mut self, mut predicate: P) -> Option<Self::Item>
+            where
+                Self: Sized,
+                P: FnMut(&Self::Item) -> bool,
+            {
+                while let Some(x) = self.next() {
+                    if predicate(&x) {
+                        return Some(x);
+                    }
+                }
+                None
+            }
+
+            // We override the default implementation, which uses `try_fold`,
+            // because this simple implementation generates less LLVM IR and is
+            // faster to compile.
+            #[inline]
+            fn find_map<B, F>(&mut self, mut f: F) -> Option<B>
+            where
+                Self: Sized,
+                F: FnMut(Self::Item) -> Option<B>,
+            {
+                while let Some(x) = self.next() {
+                    if let Some(y) = f(x) {
+                        return Some(y);
+                    }
+                }
+                None
+            }
+
+            // We override the default implementation, which uses `try_fold`,
+            // because this simple implementation generates less LLVM IR and is
+            // faster to compile. Also, the `assume` avoids a bounds check.
+            #[inline]
+            #[rustc_inherit_overflow_checks]
+            fn position<P>(&mut self, mut predicate: P) -> Option<usize> where
+                Self: Sized,
+                P: FnMut(Self::Item) -> bool,
+            {
+                let n = len!(self);
+                let mut i = 0;
+                while let Some(x) = self.next() {
+                    if predicate(x) {
+                        // SAFETY: we are guaranteed to be in bounds by the loop invariant:
+                        // when `i >= n`, `self.next()` returns `None` and the loop breaks.
+                        unsafe { assume(i < n) };
+                        return Some(i);
+                    }
+                    i += 1;
+                }
+                None
+            }
+
+            // We override the default implementation, which uses `try_fold`,
+            // because this simple implementation generates less LLVM IR and is
+            // faster to compile. Also, the `assume` avoids a bounds check.
+            #[inline]
+            fn rposition<P>(&mut self, mut predicate: P) -> Option<usize> where
+                P: FnMut(Self::Item) -> bool,
+                Self: Sized + ExactSizeIterator + DoubleEndedIterator
+            {
+                let n = len!(self);
+                let mut i = n;
+                while let Some(x) = self.next_back() {
+                    i -= 1;
+                    if predicate(x) {
+                        // SAFETY: `i` must be lower than `n` since it starts at `n`
+                        // and is only decreasing.
+                        unsafe { assume(i < n) };
+                        return Some(i);
+                    }
+                }
+                None
+            }
+
+            #[doc(hidden)]
+            unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item {
+                // SAFETY: the caller must guarantee that `i` is in bounds of
+                // the underlying slice, so `i` cannot overflow an `isize`, and
+                // the returned references is guaranteed to refer to an element
+                // of the slice and thus guaranteed to be valid.
+                //
+                // Also note that the caller also guarantees that we're never
+                // called with the same index again, and that no other methods
+                // that will access this subslice are called, so it is valid
+                // for the returned reference to be mutable in the case of
+                // `IterMut`
+                unsafe { & $( $mut_ )? * self.ptr.as_ptr().add(idx) }
+            }
+
+            $($extra)*
+        }
+
+        #[stable(feature = "rust1", since = "1.0.0")]
+        impl<'a, T> DoubleEndedIterator for $name<'a, T> {
+            #[inline]
+            fn next_back(&mut self) -> Option<$elem> {
+                // could be implemented with slices, but this avoids bounds checks
+
+                // SAFETY: `assume` calls are safe since a slice's start pointer must be non-null,
+                // and slices over non-ZSTs must also have a non-null end pointer.
+                // The call to `next_back_unchecked!` is safe since we check if the iterator is
+                // empty first.
+                unsafe {
+                    assume(!self.ptr.as_ptr().is_null());
+                    if mem::size_of::<T>() != 0 {
+                        assume(!self.end.is_null());
+                    }
+                    if is_empty!(self) {
+                        None
+                    } else {
+                        Some(next_back_unchecked!(self))
+                    }
+                }
+            }
+
+            #[inline]
+            fn nth_back(&mut self, n: usize) -> Option<$elem> {
+                if n >= len!(self) {
+                    // This iterator is now empty.
+                    self.end = self.ptr.as_ptr();
+                    return None;
+                }
+                // SAFETY: We are in bounds. `pre_dec_end` does the right thing even for ZSTs.
+                unsafe {
+                    self.pre_dec_end(n as isize);
+                    Some(next_back_unchecked!(self))
+                }
+            }
+        }
+
+        #[stable(feature = "fused", since = "1.26.0")]
+        impl<T> FusedIterator for $name<'_, T> {}
+
+        #[unstable(feature = "trusted_len", issue = "37572")]
+        unsafe impl<T> TrustedLen for $name<'_, T> {}
+    }
+}
+
+macro_rules! forward_iterator {
+    ($name:ident: $elem:ident, $iter_of:ty) => {
+        #[stable(feature = "rust1", since = "1.0.0")]
+        impl<'a, $elem, P> Iterator for $name<'a, $elem, P>
+        where
+            P: FnMut(&T) -> bool,
+        {
+            type Item = $iter_of;
+
+            #[inline]
+            fn next(&mut self) -> Option<$iter_of> {
+                self.inner.next()
+            }
+
+            #[inline]
+            fn size_hint(&self) -> (usize, Option<usize>) {
+                self.inner.size_hint()
+            }
+        }
+
+        #[stable(feature = "fused", since = "1.26.0")]
+        impl<'a, $elem, P> FusedIterator for $name<'a, $elem, P> where P: FnMut(&T) -> bool {}
+    };
+}
index 4c027b23584bf7cd6c2102fbe5c3c0f2ceefce96..8e9d1eb98a86b08130ea21fc972cf63d719c8f73 100644 (file)
@@ -8,28 +8,11 @@
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
-// How this module is organized.
-//
-// The library infrastructure for slices is fairly messy. There's
-// a lot of stuff defined here. Let's keep it clean.
-//
-// The layout of this file is thus:
-//
-// * Inherent methods. This is where most of the slice API resides.
-// * Implementations of a few common traits with important slice ops.
-// * Definitions of a bunch of iterators.
-// * Free functions.
-// * The `raw` and `bytes` submodules.
-// * Boilerplate trait implementations.
-
-use crate::cmp;
 use crate::cmp::Ordering::{self, Equal, Greater, Less};
-use crate::fmt;
-use crate::intrinsics::{assume, exact_div, is_aligned_and_not_null, unchecked_sub};
-use crate::iter::*;
-use crate::marker::{self, Copy, Send, Sized, Sync};
+use crate::intrinsics::assume;
+use crate::marker::{self, Copy};
 use crate::mem;
-use crate::ops::{self, Bound, FnMut, Range, RangeBounds};
+use crate::ops::{FnMut, Range, RangeBounds};
 use crate::option::Option;
 use crate::option::Option::{None, Some};
 use crate::ptr::{self, NonNull};
 /// Pure rust memchr implementation, taken from rust-memchr
 pub mod memchr;
 
+mod ascii;
+mod cmp;
+mod index;
+mod iter;
+mod raw;
 mod rotate;
 mod sort;
 
-//
-// Extension traits
-//
+use iter::GenericSplitN;
+
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use iter::{Chunks, ChunksMut, Windows};
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use iter::{Iter, IterMut};
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use iter::{RSplitN, RSplitNMut, Split, SplitMut, SplitN, SplitNMut};
+
+#[stable(feature = "slice_rsplit", since = "1.27.0")]
+pub use iter::{RSplit, RSplitMut};
+
+#[stable(feature = "chunks_exact", since = "1.31.0")]
+pub use iter::{ChunksExact, ChunksExactMut};
+
+#[stable(feature = "rchunks", since = "1.31.0")]
+pub use iter::{RChunks, RChunksExact, RChunksExactMut, RChunksMut};
+
+#[unstable(feature = "array_chunks", issue = "74985")]
+pub use iter::{ArrayChunks, ArrayChunksMut};
+
+#[unstable(feature = "array_windows", issue = "75027")]
+pub use iter::ArrayWindows;
+
+#[unstable(feature = "split_inclusive", issue = "72360")]
+pub use iter::{SplitInclusive, SplitInclusiveMut};
+
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use raw::{from_raw_parts, from_raw_parts_mut};
+
+#[stable(feature = "from_ref", since = "1.28.0")]
+pub use raw::{from_mut, from_ref};
+
+// This function is public only because there is no other way to unit test heapsort.
+#[unstable(feature = "sort_internals", reason = "internal to sort module", issue = "none")]
+pub use sort::heapsort;
+
+#[stable(feature = "slice_get_slice", since = "1.28.0")]
+pub use index::SliceIndex;
+
+#[unstable(feature = "slice_check_range", issue = "76393")]
+pub use index::check_range;
 
 #[lang = "slice"]
 #[cfg(not(test))]
@@ -354,79 +381,6 @@ pub unsafe fn get_unchecked_mut<I>(&mut self, index: I) -> &mut I::Output
         unsafe { &mut *index.get_unchecked_mut(self) }
     }
 
-    /// Converts a range over this slice to [`Range`].
-    ///
-    /// The returned range is safe to pass to [`get_unchecked`] and [`get_unchecked_mut`].
-    ///
-    /// [`get_unchecked`]: #method.get_unchecked
-    /// [`get_unchecked_mut`]: #method.get_unchecked_mut
-    ///
-    /// # Panics
-    ///
-    /// Panics if the range is out of bounds.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(slice_check_range)]
-    ///
-    /// let v = [10, 40, 30];
-    /// assert_eq!(1..2, v.check_range(1..2));
-    /// assert_eq!(0..2, v.check_range(..2));
-    /// assert_eq!(1..3, v.check_range(1..));
-    /// ```
-    ///
-    /// Panics when [`Index::index`] would panic:
-    ///
-    /// ```should_panic
-    /// #![feature(slice_check_range)]
-    ///
-    /// [10, 40, 30].check_range(2..1);
-    /// ```
-    ///
-    /// ```should_panic
-    /// #![feature(slice_check_range)]
-    ///
-    /// [10, 40, 30].check_range(1..4);
-    /// ```
-    ///
-    /// ```should_panic
-    /// #![feature(slice_check_range)]
-    ///
-    /// [10, 40, 30].check_range(1..=usize::MAX);
-    /// ```
-    ///
-    /// [`Index::index`]: ops::Index::index
-    #[track_caller]
-    #[unstable(feature = "slice_check_range", issue = "76393")]
-    pub fn check_range<R: RangeBounds<usize>>(&self, range: R) -> Range<usize> {
-        let start = match range.start_bound() {
-            Bound::Included(&start) => start,
-            Bound::Excluded(start) => {
-                start.checked_add(1).unwrap_or_else(|| slice_start_index_overflow_fail())
-            }
-            Bound::Unbounded => 0,
-        };
-
-        let len = self.len();
-        let end = match range.end_bound() {
-            Bound::Included(end) => {
-                end.checked_add(1).unwrap_or_else(|| slice_end_index_overflow_fail())
-            }
-            Bound::Excluded(&end) => end,
-            Bound::Unbounded => len,
-        };
-
-        if start > end {
-            slice_index_order_fail(start, end);
-        }
-        if end > len {
-            slice_end_index_len_fail(end, len);
-        }
-
-        Range { start, end }
-    }
-
     /// Returns a raw pointer to the slice's buffer.
     ///
     /// The caller must ensure that the slice outlives the pointer this
@@ -1075,6 +1029,40 @@ pub fn array_chunks_mut<const N: usize>(&mut self) -> ArrayChunksMut<'_, T, N> {
         }
     }
 
+    /// Returns an iterator over overlapping windows of `N` elements of  a slice,
+    /// starting at the beginning of the slice.
+    ///
+    /// This is the const generic equivalent of [`windows`].
+    ///
+    /// If `N` is smaller than the size of the array, it will return no windows.
+    ///
+    /// # Panics
+    ///
+    /// Panics if `N` is 0. This check will most probably get changed to a compile time
+    /// error before this method gets stabilized.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(array_windows)]
+    /// let slice = [0, 1, 2, 3];
+    /// let mut iter = slice.array_windows();
+    /// assert_eq!(iter.next().unwrap(), &[0, 1]);
+    /// assert_eq!(iter.next().unwrap(), &[1, 2]);
+    /// assert_eq!(iter.next().unwrap(), &[2, 3]);
+    /// assert!(iter.next().is_none());
+    /// ```
+    ///
+    /// [`windows`]: #method.windows
+    #[unstable(feature = "array_windows", issue = "75027")]
+    #[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 }
+    }
+
     /// Returns an iterator over `chunk_size` elements of the slice at a time, starting at the end
     /// of the slice.
     ///
@@ -1734,7 +1722,7 @@ pub fn contains(&self, x: &T) -> bool
     where
         T: PartialEq,
     {
-        x.slice_contains(self)
+        cmp::SliceContains::slice_contains(x, self)
     }
 
     /// Returns `true` if `needle` is a prefix of the slice.
@@ -2770,7 +2758,7 @@ pub fn copy_within<R: RangeBounds<usize>>(&mut self, src: R, dest: usize)
     where
         T: Copy,
     {
-        let Range { start: src_start, end: src_end } = self.check_range(src);
+        let Range { start: src_start, end: src_end } = check_range(self.len(), src);
         let count = src_end - src_start;
         assert!(dest <= self.len() - count, "dest is out of bounds");
         // SAFETY: the conditions for `ptr::copy` have all been checked above,
@@ -3158,619 +3146,11 @@ pub fn partition_point<P>(&self, mut pred: P) -> usize
     }
 }
 
-#[lang = "slice_u8"]
-#[cfg(not(test))]
-impl [u8] {
-    /// Checks if all bytes in this slice are within the ASCII range.
-    #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
-    #[inline]
-    pub fn is_ascii(&self) -> bool {
-        is_ascii(self)
-    }
-
-    /// Checks that two slices are an ASCII case-insensitive match.
-    ///
-    /// Same as `to_ascii_lowercase(a) == to_ascii_lowercase(b)`,
-    /// but without allocating and copying temporaries.
-    #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
-    #[inline]
-    pub fn eq_ignore_ascii_case(&self, other: &[u8]) -> bool {
-        self.len() == other.len() && self.iter().zip(other).all(|(a, b)| a.eq_ignore_ascii_case(b))
-    }
-
-    /// Converts this slice to its ASCII upper case equivalent in-place.
-    ///
-    /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z',
-    /// but non-ASCII letters are unchanged.
-    ///
-    /// To return a new uppercased value without modifying the existing one, use
-    /// [`to_ascii_uppercase`].
-    ///
-    /// [`to_ascii_uppercase`]: #method.to_ascii_uppercase
-    #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
-    #[inline]
-    pub fn make_ascii_uppercase(&mut self) {
-        for byte in self {
-            byte.make_ascii_uppercase();
-        }
-    }
-
-    /// Converts this slice to its ASCII lower case equivalent in-place.
-    ///
-    /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z',
-    /// but non-ASCII letters are unchanged.
-    ///
-    /// To return a new lowercased value without modifying the existing one, use
-    /// [`to_ascii_lowercase`].
-    ///
-    /// [`to_ascii_lowercase`]: #method.to_ascii_lowercase
-    #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
-    #[inline]
-    pub fn make_ascii_lowercase(&mut self) {
-        for byte in self {
-            byte.make_ascii_lowercase();
-        }
-    }
-}
-
-/// Returns `true` if any byte in the word `v` is nonascii (>= 128). Snarfed
-/// from `../str/mod.rs`, which does something similar for utf8 validation.
-#[inline]
-fn contains_nonascii(v: usize) -> bool {
-    const NONASCII_MASK: usize = 0x80808080_80808080u64 as usize;
-    (NONASCII_MASK & v) != 0
-}
-
-/// Optimized ASCII test that will use usize-at-a-time operations instead of
-/// byte-at-a-time operations (when possible).
-///
-/// The algorithm we use here is pretty simple. If `s` is too short, we just
-/// check each byte and be done with it. Otherwise:
-///
-/// - Read the first word with an unaligned load.
-/// - Align the pointer, read subsequent words until end with aligned loads.
-/// - Read the last `usize` from `s` with an unaligned load.
-///
-/// If any of these loads produces something for which `contains_nonascii`
-/// (above) returns true, then we know the answer is false.
-#[inline]
-fn is_ascii(s: &[u8]) -> bool {
-    const USIZE_SIZE: usize = mem::size_of::<usize>();
-
-    let len = s.len();
-    let align_offset = s.as_ptr().align_offset(USIZE_SIZE);
-
-    // If we wouldn't gain anything from the word-at-a-time implementation, fall
-    // back to a scalar loop.
-    //
-    // We also do this for architectures where `size_of::<usize>()` isn't
-    // sufficient alignment for `usize`, because it's a weird edge case.
-    if len < USIZE_SIZE || len < align_offset || USIZE_SIZE < mem::align_of::<usize>() {
-        return s.iter().all(|b| b.is_ascii());
-    }
-
-    // We always read the first word unaligned, which means `align_offset` is
-    // 0, we'd read the same value again for the aligned read.
-    let offset_to_aligned = if align_offset == 0 { USIZE_SIZE } else { align_offset };
-
-    let start = s.as_ptr();
-    // SAFETY: We verify `len < USIZE_SIZE` above.
-    let first_word = unsafe { (start as *const usize).read_unaligned() };
-
-    if contains_nonascii(first_word) {
-        return false;
-    }
-    // We checked this above, somewhat implicitly. Note that `offset_to_aligned`
-    // is either `align_offset` or `USIZE_SIZE`, both of are explicitly checked
-    // above.
-    debug_assert!(offset_to_aligned <= len);
-
-    // SAFETY: word_ptr is the (properly aligned) usize ptr we use to read the
-    // middle chunk of the slice.
-    let mut word_ptr = unsafe { start.add(offset_to_aligned) as *const usize };
-
-    // `byte_pos` is the byte index of `word_ptr`, used for loop end checks.
-    let mut byte_pos = offset_to_aligned;
-
-    // Paranoia check about alignment, since we're about to do a bunch of
-    // unaligned loads. In practice this should be impossible barring a bug in
-    // `align_offset` though.
-    debug_assert_eq!((word_ptr as usize) % mem::align_of::<usize>(), 0);
-
-    // Read subsequent words until the last aligned word, excluding the last
-    // aligned word by itself to be done in tail check later, to ensure that
-    // tail is always one `usize` at most to extra branch `byte_pos == len`.
-    while byte_pos < len - USIZE_SIZE {
-        debug_assert!(
-            // Sanity check that the read is in bounds
-            (word_ptr as usize + USIZE_SIZE) <= (start.wrapping_add(len) as usize) &&
-            // And that our assumptions about `byte_pos` hold.
-            (word_ptr as usize) - (start as usize) == byte_pos
-        );
-
-        // SAFETY: We know `word_ptr` is properly aligned (because of
-        // `align_offset`), and we know that we have enough bytes between `word_ptr` and the end
-        let word = unsafe { word_ptr.read() };
-        if contains_nonascii(word) {
-            return false;
-        }
-
-        byte_pos += USIZE_SIZE;
-        // SAFETY: We know that `byte_pos <= len - USIZE_SIZE`, which means that
-        // after this `add`, `word_ptr` will be at most one-past-the-end.
-        word_ptr = unsafe { word_ptr.add(1) };
-    }
-
-    // Sanity check to ensure there really is only one `usize` left. This should
-    // be guaranteed by our loop condition.
-    debug_assert!(byte_pos <= len && len - byte_pos <= USIZE_SIZE);
-
-    // SAFETY: This relies on `len >= USIZE_SIZE`, which we check at the start.
-    let last_word = unsafe { (start.add(len - USIZE_SIZE) as *const usize).read_unaligned() };
-
-    !contains_nonascii(last_word)
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T, I> ops::Index<I> for [T]
-where
-    I: SliceIndex<[T]>,
-{
-    type Output = I::Output;
-
-    #[inline]
-    fn index(&self, index: I) -> &I::Output {
-        index.index(self)
-    }
-}
-
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T, I> ops::IndexMut<I> for [T]
-where
-    I: SliceIndex<[T]>,
-{
-    #[inline]
-    fn index_mut(&mut self, index: I) -> &mut I::Output {
-        index.index_mut(self)
-    }
-}
-
-#[inline(never)]
-#[cold]
-#[track_caller]
-fn slice_start_index_len_fail(index: usize, len: usize) -> ! {
-    panic!("range start index {} out of range for slice of length {}", index, len);
-}
-
-#[inline(never)]
-#[cold]
-#[track_caller]
-fn slice_end_index_len_fail(index: usize, len: usize) -> ! {
-    panic!("range end index {} out of range for slice of length {}", index, len);
-}
-
-#[inline(never)]
-#[cold]
-#[track_caller]
-fn slice_index_order_fail(index: usize, end: usize) -> ! {
-    panic!("slice index starts at {} but ends at {}", index, end);
-}
-
-#[inline(never)]
-#[cold]
-#[track_caller]
-fn slice_start_index_overflow_fail() -> ! {
-    panic!("attempted to index slice from after maximum usize");
-}
-
-#[inline(never)]
-#[cold]
-#[track_caller]
-fn slice_end_index_overflow_fail() -> ! {
-    panic!("attempted to index slice up to maximum usize");
-}
-
-mod private_slice_index {
-    use super::ops;
-    #[stable(feature = "slice_get_slice", since = "1.28.0")]
-    pub trait Sealed {}
-
-    #[stable(feature = "slice_get_slice", since = "1.28.0")]
-    impl Sealed for usize {}
-    #[stable(feature = "slice_get_slice", since = "1.28.0")]
-    impl Sealed for ops::Range<usize> {}
-    #[stable(feature = "slice_get_slice", since = "1.28.0")]
-    impl Sealed for ops::RangeTo<usize> {}
-    #[stable(feature = "slice_get_slice", since = "1.28.0")]
-    impl Sealed for ops::RangeFrom<usize> {}
-    #[stable(feature = "slice_get_slice", since = "1.28.0")]
-    impl Sealed for ops::RangeFull {}
-    #[stable(feature = "slice_get_slice", since = "1.28.0")]
-    impl Sealed for ops::RangeInclusive<usize> {}
-    #[stable(feature = "slice_get_slice", since = "1.28.0")]
-    impl Sealed for ops::RangeToInclusive<usize> {}
-}
-
-/// A helper trait used for indexing operations.
-///
-/// Implementations of this trait have to promise that if the argument
-/// to `get_(mut_)unchecked` is a safe reference, then so is the result.
-#[stable(feature = "slice_get_slice", since = "1.28.0")]
-#[rustc_on_unimplemented(
-    on(T = "str", label = "string indices are ranges of `usize`",),
-    on(
-        all(any(T = "str", T = "&str", T = "std::string::String"), _Self = "{integer}"),
-        note = "you can use `.chars().nth()` or `.bytes().nth()`\n\
-                for more information, see chapter 8 in The Book: \
-                <https://doc.rust-lang.org/book/ch08-02-strings.html#indexing-into-strings>"
-    ),
-    message = "the type `{T}` cannot be indexed by `{Self}`",
-    label = "slice indices are of type `usize` or ranges of `usize`"
-)]
-pub unsafe trait SliceIndex<T: ?Sized>: private_slice_index::Sealed {
-    /// The output type returned by methods.
-    #[stable(feature = "slice_get_slice", since = "1.28.0")]
-    type Output: ?Sized;
-
-    /// Returns a shared reference to the output at this location, if in
-    /// bounds.
-    #[unstable(feature = "slice_index_methods", issue = "none")]
-    fn get(self, slice: &T) -> Option<&Self::Output>;
-
-    /// Returns a mutable reference to the output at this location, if in
-    /// bounds.
-    #[unstable(feature = "slice_index_methods", issue = "none")]
-    fn get_mut(self, slice: &mut T) -> Option<&mut Self::Output>;
-
-    /// Returns a shared reference to the output at this location, without
-    /// performing any bounds checking.
-    /// Calling this method with an out-of-bounds index or a dangling `slice` pointer
-    /// is *[undefined behavior]* even if the resulting reference is not used.
-    ///
-    /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
-    #[unstable(feature = "slice_index_methods", issue = "none")]
-    unsafe fn get_unchecked(self, slice: *const T) -> *const Self::Output;
-
-    /// Returns a mutable reference to the output at this location, without
-    /// performing any bounds checking.
-    /// Calling this method with an out-of-bounds index or a dangling `slice` pointer
-    /// is *[undefined behavior]* even if the resulting reference is not used.
-    ///
-    /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
-    #[unstable(feature = "slice_index_methods", issue = "none")]
-    unsafe fn get_unchecked_mut(self, slice: *mut T) -> *mut Self::Output;
-
-    /// Returns a shared reference to the output at this location, panicking
-    /// if out of bounds.
-    #[unstable(feature = "slice_index_methods", issue = "none")]
-    #[track_caller]
-    fn index(self, slice: &T) -> &Self::Output;
-
-    /// Returns a mutable reference to the output at this location, panicking
-    /// if out of bounds.
-    #[unstable(feature = "slice_index_methods", issue = "none")]
-    #[track_caller]
-    fn index_mut(self, slice: &mut T) -> &mut Self::Output;
-}
-
-#[stable(feature = "slice_get_slice_impls", since = "1.15.0")]
-unsafe impl<T> SliceIndex<[T]> for usize {
-    type Output = T;
-
-    #[inline]
-    fn get(self, slice: &[T]) -> Option<&T> {
-        // SAFETY: `self` is checked to be in bounds.
-        if self < slice.len() { unsafe { Some(&*self.get_unchecked(slice)) } } else { None }
-    }
-
-    #[inline]
-    fn get_mut(self, slice: &mut [T]) -> Option<&mut T> {
-        // SAFETY: `self` is checked to be in bounds.
-        if self < slice.len() { unsafe { Some(&mut *self.get_unchecked_mut(slice)) } } else { None }
-    }
-
-    #[inline]
-    unsafe fn get_unchecked(self, slice: *const [T]) -> *const T {
-        // SAFETY: the caller guarantees that `slice` is not dangling, so it
-        // cannot be longer than `isize::MAX`. They also guarantee that
-        // `self` is in bounds of `slice` so `self` cannot overflow an `isize`,
-        // so the call to `add` is safe.
-        unsafe { slice.as_ptr().add(self) }
-    }
-
-    #[inline]
-    unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut T {
-        // SAFETY: see comments for `get_unchecked` above.
-        unsafe { slice.as_mut_ptr().add(self) }
-    }
-
-    #[inline]
-    fn index(self, slice: &[T]) -> &T {
-        // N.B., use intrinsic indexing
-        &(*slice)[self]
-    }
-
-    #[inline]
-    fn index_mut(self, slice: &mut [T]) -> &mut T {
-        // N.B., use intrinsic indexing
-        &mut (*slice)[self]
-    }
-}
-
-#[stable(feature = "slice_get_slice_impls", since = "1.15.0")]
-unsafe impl<T> SliceIndex<[T]> for ops::Range<usize> {
-    type Output = [T];
-
-    #[inline]
-    fn get(self, slice: &[T]) -> Option<&[T]> {
-        if self.start > self.end || self.end > slice.len() {
-            None
-        } else {
-            // SAFETY: `self` is checked to be valid and in bounds above.
-            unsafe { Some(&*self.get_unchecked(slice)) }
-        }
-    }
-
-    #[inline]
-    fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> {
-        if self.start > self.end || self.end > slice.len() {
-            None
-        } else {
-            // SAFETY: `self` is checked to be valid and in bounds above.
-            unsafe { Some(&mut *self.get_unchecked_mut(slice)) }
-        }
-    }
-
-    #[inline]
-    unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] {
-        // SAFETY: the caller guarantees that `slice` is not dangling, so it
-        // cannot be longer than `isize::MAX`. They also guarantee that
-        // `self` is in bounds of `slice` so `self` cannot overflow an `isize`,
-        // so the call to `add` is safe.
-        unsafe { ptr::slice_from_raw_parts(slice.as_ptr().add(self.start), self.end - self.start) }
-    }
-
-    #[inline]
-    unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] {
-        // SAFETY: see comments for `get_unchecked` above.
-        unsafe {
-            ptr::slice_from_raw_parts_mut(slice.as_mut_ptr().add(self.start), self.end - self.start)
-        }
-    }
-
-    #[inline]
-    fn index(self, slice: &[T]) -> &[T] {
-        if self.start > self.end {
-            slice_index_order_fail(self.start, self.end);
-        } else if self.end > slice.len() {
-            slice_end_index_len_fail(self.end, slice.len());
-        }
-        // SAFETY: `self` is checked to be valid and in bounds above.
-        unsafe { &*self.get_unchecked(slice) }
-    }
-
-    #[inline]
-    fn index_mut(self, slice: &mut [T]) -> &mut [T] {
-        if self.start > self.end {
-            slice_index_order_fail(self.start, self.end);
-        } else if self.end > slice.len() {
-            slice_end_index_len_fail(self.end, slice.len());
-        }
-        // SAFETY: `self` is checked to be valid and in bounds above.
-        unsafe { &mut *self.get_unchecked_mut(slice) }
-    }
-}
-
-#[stable(feature = "slice_get_slice_impls", since = "1.15.0")]
-unsafe impl<T> SliceIndex<[T]> for ops::RangeTo<usize> {
-    type Output = [T];
-
-    #[inline]
-    fn get(self, slice: &[T]) -> Option<&[T]> {
-        (0..self.end).get(slice)
-    }
-
-    #[inline]
-    fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> {
-        (0..self.end).get_mut(slice)
-    }
-
-    #[inline]
-    unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] {
-        // SAFETY: the caller has to uphold the safety contract for `get_unchecked`.
-        unsafe { (0..self.end).get_unchecked(slice) }
-    }
-
-    #[inline]
-    unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] {
-        // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`.
-        unsafe { (0..self.end).get_unchecked_mut(slice) }
-    }
-
-    #[inline]
-    fn index(self, slice: &[T]) -> &[T] {
-        (0..self.end).index(slice)
-    }
-
-    #[inline]
-    fn index_mut(self, slice: &mut [T]) -> &mut [T] {
-        (0..self.end).index_mut(slice)
-    }
-}
-
-#[stable(feature = "slice_get_slice_impls", since = "1.15.0")]
-unsafe impl<T> SliceIndex<[T]> for ops::RangeFrom<usize> {
-    type Output = [T];
-
-    #[inline]
-    fn get(self, slice: &[T]) -> Option<&[T]> {
-        (self.start..slice.len()).get(slice)
-    }
-
-    #[inline]
-    fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> {
-        (self.start..slice.len()).get_mut(slice)
-    }
-
-    #[inline]
-    unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] {
-        // SAFETY: the caller has to uphold the safety contract for `get_unchecked`.
-        unsafe { (self.start..slice.len()).get_unchecked(slice) }
-    }
-
-    #[inline]
-    unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] {
-        // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`.
-        unsafe { (self.start..slice.len()).get_unchecked_mut(slice) }
-    }
-
-    #[inline]
-    fn index(self, slice: &[T]) -> &[T] {
-        if self.start > slice.len() {
-            slice_start_index_len_fail(self.start, slice.len());
-        }
-        // SAFETY: `self` is checked to be valid and in bounds above.
-        unsafe { &*self.get_unchecked(slice) }
-    }
-
-    #[inline]
-    fn index_mut(self, slice: &mut [T]) -> &mut [T] {
-        if self.start > slice.len() {
-            slice_start_index_len_fail(self.start, slice.len());
-        }
-        // SAFETY: `self` is checked to be valid and in bounds above.
-        unsafe { &mut *self.get_unchecked_mut(slice) }
-    }
-}
-
-#[stable(feature = "slice_get_slice_impls", since = "1.15.0")]
-unsafe impl<T> SliceIndex<[T]> for ops::RangeFull {
-    type Output = [T];
-
-    #[inline]
-    fn get(self, slice: &[T]) -> Option<&[T]> {
-        Some(slice)
-    }
-
-    #[inline]
-    fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> {
-        Some(slice)
-    }
-
-    #[inline]
-    unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] {
-        slice
-    }
-
-    #[inline]
-    unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] {
-        slice
-    }
-
-    #[inline]
-    fn index(self, slice: &[T]) -> &[T] {
-        slice
-    }
-
-    #[inline]
-    fn index_mut(self, slice: &mut [T]) -> &mut [T] {
-        slice
-    }
-}
-
-#[stable(feature = "inclusive_range", since = "1.26.0")]
-unsafe impl<T> SliceIndex<[T]> for ops::RangeInclusive<usize> {
-    type Output = [T];
-
-    #[inline]
-    fn get(self, slice: &[T]) -> Option<&[T]> {
-        if *self.end() == usize::MAX { None } else { (*self.start()..self.end() + 1).get(slice) }
-    }
-
-    #[inline]
-    fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> {
-        if *self.end() == usize::MAX {
-            None
-        } else {
-            (*self.start()..self.end() + 1).get_mut(slice)
-        }
-    }
-
-    #[inline]
-    unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] {
-        // SAFETY: the caller has to uphold the safety contract for `get_unchecked`.
-        unsafe { (*self.start()..self.end() + 1).get_unchecked(slice) }
-    }
-
-    #[inline]
-    unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] {
-        // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`.
-        unsafe { (*self.start()..self.end() + 1).get_unchecked_mut(slice) }
-    }
-
-    #[inline]
-    fn index(self, slice: &[T]) -> &[T] {
-        if *self.end() == usize::MAX {
-            slice_end_index_overflow_fail();
-        }
-        (*self.start()..self.end() + 1).index(slice)
-    }
-
-    #[inline]
-    fn index_mut(self, slice: &mut [T]) -> &mut [T] {
-        if *self.end() == usize::MAX {
-            slice_end_index_overflow_fail();
-        }
-        (*self.start()..self.end() + 1).index_mut(slice)
-    }
-}
-
-#[stable(feature = "inclusive_range", since = "1.26.0")]
-unsafe impl<T> SliceIndex<[T]> for ops::RangeToInclusive<usize> {
-    type Output = [T];
-
-    #[inline]
-    fn get(self, slice: &[T]) -> Option<&[T]> {
-        (0..=self.end).get(slice)
-    }
-
-    #[inline]
-    fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> {
-        (0..=self.end).get_mut(slice)
-    }
-
-    #[inline]
-    unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] {
-        // SAFETY: the caller has to uphold the safety contract for `get_unchecked`.
-        unsafe { (0..=self.end).get_unchecked(slice) }
-    }
-
-    #[inline]
-    unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] {
-        // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`.
-        unsafe { (0..=self.end).get_unchecked_mut(slice) }
-    }
-
-    #[inline]
-    fn index(self, slice: &[T]) -> &[T] {
-        (0..=self.end).index(slice)
-    }
-
-    #[inline]
-    fn index_mut(self, slice: &mut [T]) -> &mut [T] {
-        (0..=self.end).index_mut(slice)
-    }
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Common traits
-////////////////////////////////////////////////////////////////////////////////
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T> Default for &[T] {
-    /// Creates an empty slice.
-    fn default() -> Self {
-        &[]
+impl<T> Default for &[T] {
+    /// Creates an empty slice.
+    fn default() -> Self {
+        &[]
     }
 }
 
@@ -3781,3338 +3161,3 @@ fn default() -> Self {
         &mut []
     }
 }
-
-//
-// Iterators
-//
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, T> IntoIterator for &'a [T] {
-    type Item = &'a T;
-    type IntoIter = Iter<'a, T>;
-
-    fn into_iter(self) -> Iter<'a, T> {
-        self.iter()
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, T> IntoIterator for &'a mut [T] {
-    type Item = &'a mut T;
-    type IntoIter = IterMut<'a, T>;
-
-    fn into_iter(self) -> IterMut<'a, T> {
-        self.iter_mut()
-    }
-}
-
-// Macro helper functions
-#[inline(always)]
-fn size_from_ptr<T>(_: *const T) -> usize {
-    mem::size_of::<T>()
-}
-
-// Inlining is_empty and len makes a huge performance difference
-macro_rules! is_empty {
-    // The way we encode the length of a ZST iterator, this works both for ZST
-    // and non-ZST.
-    ($self: ident) => {
-        $self.ptr.as_ptr() as *const T == $self.end
-    };
-}
-
-// To get rid of some bounds checks (see `position`), we compute the length in a somewhat
-// unexpected way. (Tested by `codegen/slice-position-bounds-check`.)
-macro_rules! len {
-    ($self: ident) => {{
-        #![allow(unused_unsafe)] // we're sometimes used within an unsafe block
-
-        let start = $self.ptr;
-        let size = size_from_ptr(start.as_ptr());
-        if size == 0 {
-            // This _cannot_ use `unchecked_sub` because we depend on wrapping
-            // to represent the length of long ZST slice iterators.
-            ($self.end as usize).wrapping_sub(start.as_ptr() as usize)
-        } else {
-            // We know that `start <= end`, so can do better than `offset_from`,
-            // which needs to deal in signed.  By setting appropriate flags here
-            // we can tell LLVM this, which helps it remove bounds checks.
-            // SAFETY: By the type invariant, `start <= end`
-            let diff = unsafe { unchecked_sub($self.end as usize, start.as_ptr() as usize) };
-            // By also telling LLVM that the pointers are apart by an exact
-            // multiple of the type size, it can optimize `len() == 0` down to
-            // `start == end` instead of `(end - start) < size`.
-            // SAFETY: By the type invariant, the pointers are aligned so the
-            //         distance between them must be a multiple of pointee size
-            unsafe { exact_div(diff, size) }
-        }
-    }};
-}
-
-// The shared definition of the `Iter` and `IterMut` iterators
-macro_rules! iterator {
-    (
-        struct $name:ident -> $ptr:ty,
-        $elem:ty,
-        $raw_mut:tt,
-        {$( $mut_:tt )?},
-        {$($extra:tt)*}
-    ) => {
-        // Returns the first element and moves the start of the iterator forwards by 1.
-        // Greatly improves performance compared to an inlined function. The iterator
-        // must not be empty.
-        macro_rules! next_unchecked {
-            ($self: ident) => {& $( $mut_ )? *$self.post_inc_start(1)}
-        }
-
-        // Returns the last element and moves the end of the iterator backwards by 1.
-        // Greatly improves performance compared to an inlined function. The iterator
-        // must not be empty.
-        macro_rules! next_back_unchecked {
-            ($self: ident) => {& $( $mut_ )? *$self.pre_dec_end(1)}
-        }
-
-        // Shrinks the iterator when T is a ZST, by moving the end of the iterator
-        // backwards by `n`. `n` must not exceed `self.len()`.
-        macro_rules! zst_shrink {
-            ($self: ident, $n: ident) => {
-                $self.end = ($self.end as * $raw_mut u8).wrapping_offset(-$n) as * $raw_mut T;
-            }
-        }
-
-        impl<'a, T> $name<'a, T> {
-            // Helper function for creating a slice from the iterator.
-            #[inline(always)]
-            fn make_slice(&self) -> &'a [T] {
-                // SAFETY: the iterator was created from a slice with pointer
-                // `self.ptr` and length `len!(self)`. This guarantees that all
-                // the prerequisites for `from_raw_parts` are fulfilled.
-                unsafe { from_raw_parts(self.ptr.as_ptr(), len!(self)) }
-            }
-
-            // Helper function for moving the start of the iterator forwards by `offset` elements,
-            // returning the old start.
-            // Unsafe because the offset must not exceed `self.len()`.
-            #[inline(always)]
-            unsafe fn post_inc_start(&mut self, offset: isize) -> * $raw_mut T {
-                if mem::size_of::<T>() == 0 {
-                    zst_shrink!(self, offset);
-                    self.ptr.as_ptr()
-                } else {
-                    let old = self.ptr.as_ptr();
-                    // SAFETY: the caller guarantees that `offset` doesn't exceed `self.len()`,
-                    // so this new pointer is inside `self` and thus guaranteed to be non-null.
-                    self.ptr = unsafe { NonNull::new_unchecked(self.ptr.as_ptr().offset(offset)) };
-                    old
-                }
-            }
-
-            // Helper function for moving the end of the iterator backwards by `offset` elements,
-            // returning the new end.
-            // Unsafe because the offset must not exceed `self.len()`.
-            #[inline(always)]
-            unsafe fn pre_dec_end(&mut self, offset: isize) -> * $raw_mut T {
-                if mem::size_of::<T>() == 0 {
-                    zst_shrink!(self, offset);
-                    self.ptr.as_ptr()
-                } else {
-                    // SAFETY: the caller guarantees that `offset` doesn't exceed `self.len()`,
-                    // which is guaranteed to not overflow an `isize`. Also, the resulting pointer
-                    // is in bounds of `slice`, which fulfills the other requirements for `offset`.
-                    self.end = unsafe { self.end.offset(-offset) };
-                    self.end
-                }
-            }
-        }
-
-        #[stable(feature = "rust1", since = "1.0.0")]
-        impl<T> ExactSizeIterator for $name<'_, T> {
-            #[inline(always)]
-            fn len(&self) -> usize {
-                len!(self)
-            }
-
-            #[inline(always)]
-            fn is_empty(&self) -> bool {
-                is_empty!(self)
-            }
-        }
-
-        #[stable(feature = "rust1", since = "1.0.0")]
-        impl<'a, T> Iterator for $name<'a, T> {
-            type Item = $elem;
-
-            #[inline]
-            fn next(&mut self) -> Option<$elem> {
-                // could be implemented with slices, but this avoids bounds checks
-
-                // SAFETY: `assume` calls are safe since a slice's start pointer
-                // must be non-null, and slices over non-ZSTs must also have a
-                // non-null end pointer. The call to `next_unchecked!` is safe
-                // since we check if the iterator is empty first.
-                unsafe {
-                    assume(!self.ptr.as_ptr().is_null());
-                    if mem::size_of::<T>() != 0 {
-                        assume(!self.end.is_null());
-                    }
-                    if is_empty!(self) {
-                        None
-                    } else {
-                        Some(next_unchecked!(self))
-                    }
-                }
-            }
-
-            #[inline]
-            fn size_hint(&self) -> (usize, Option<usize>) {
-                let exact = len!(self);
-                (exact, Some(exact))
-            }
-
-            #[inline]
-            fn count(self) -> usize {
-                len!(self)
-            }
-
-            #[inline]
-            fn nth(&mut self, n: usize) -> Option<$elem> {
-                if n >= len!(self) {
-                    // This iterator is now empty.
-                    if mem::size_of::<T>() == 0 {
-                        // We have to do it this way as `ptr` may never be 0, but `end`
-                        // could be (due to wrapping).
-                        self.end = self.ptr.as_ptr();
-                    } else {
-                        // SAFETY: end can't be 0 if T isn't ZST because ptr isn't 0 and end >= ptr
-                        unsafe {
-                            self.ptr = NonNull::new_unchecked(self.end as *mut T);
-                        }
-                    }
-                    return None;
-                }
-                // SAFETY: We are in bounds. `post_inc_start` does the right thing even for ZSTs.
-                unsafe {
-                    self.post_inc_start(n as isize);
-                    Some(next_unchecked!(self))
-                }
-            }
-
-            #[inline]
-            fn last(mut self) -> Option<$elem> {
-                self.next_back()
-            }
-
-            // We override the default implementation, which uses `try_fold`,
-            // because this simple implementation generates less LLVM IR and is
-            // faster to compile.
-            #[inline]
-            fn for_each<F>(mut self, mut f: F)
-            where
-                Self: Sized,
-                F: FnMut(Self::Item),
-            {
-                while let Some(x) = self.next() {
-                    f(x);
-                }
-            }
-
-            // We override the default implementation, which uses `try_fold`,
-            // because this simple implementation generates less LLVM IR and is
-            // faster to compile.
-            #[inline]
-            fn all<F>(&mut self, mut f: F) -> bool
-            where
-                Self: Sized,
-                F: FnMut(Self::Item) -> bool,
-            {
-                while let Some(x) = self.next() {
-                    if !f(x) {
-                        return false;
-                    }
-                }
-                true
-            }
-
-            // We override the default implementation, which uses `try_fold`,
-            // because this simple implementation generates less LLVM IR and is
-            // faster to compile.
-            #[inline]
-            fn any<F>(&mut self, mut f: F) -> bool
-            where
-                Self: Sized,
-                F: FnMut(Self::Item) -> bool,
-            {
-                while let Some(x) = self.next() {
-                    if f(x) {
-                        return true;
-                    }
-                }
-                false
-            }
-
-            // We override the default implementation, which uses `try_fold`,
-            // because this simple implementation generates less LLVM IR and is
-            // faster to compile.
-            #[inline]
-            fn find<P>(&mut self, mut predicate: P) -> Option<Self::Item>
-            where
-                Self: Sized,
-                P: FnMut(&Self::Item) -> bool,
-            {
-                while let Some(x) = self.next() {
-                    if predicate(&x) {
-                        return Some(x);
-                    }
-                }
-                None
-            }
-
-            // We override the default implementation, which uses `try_fold`,
-            // because this simple implementation generates less LLVM IR and is
-            // faster to compile.
-            #[inline]
-            fn find_map<B, F>(&mut self, mut f: F) -> Option<B>
-            where
-                Self: Sized,
-                F: FnMut(Self::Item) -> Option<B>,
-            {
-                while let Some(x) = self.next() {
-                    if let Some(y) = f(x) {
-                        return Some(y);
-                    }
-                }
-                None
-            }
-
-            // We override the default implementation, which uses `try_fold`,
-            // because this simple implementation generates less LLVM IR and is
-            // faster to compile. Also, the `assume` avoids a bounds check.
-            #[inline]
-            #[rustc_inherit_overflow_checks]
-            fn position<P>(&mut self, mut predicate: P) -> Option<usize> where
-                Self: Sized,
-                P: FnMut(Self::Item) -> bool,
-            {
-                let n = len!(self);
-                let mut i = 0;
-                while let Some(x) = self.next() {
-                    if predicate(x) {
-                        // SAFETY: we are guaranteed to be in bounds by the loop invariant:
-                        // when `i >= n`, `self.next()` returns `None` and the loop breaks.
-                        unsafe { assume(i < n) };
-                        return Some(i);
-                    }
-                    i += 1;
-                }
-                None
-            }
-
-            // We override the default implementation, which uses `try_fold`,
-            // because this simple implementation generates less LLVM IR and is
-            // faster to compile. Also, the `assume` avoids a bounds check.
-            #[inline]
-            fn rposition<P>(&mut self, mut predicate: P) -> Option<usize> where
-                P: FnMut(Self::Item) -> bool,
-                Self: Sized + ExactSizeIterator + DoubleEndedIterator
-            {
-                let n = len!(self);
-                let mut i = n;
-                while let Some(x) = self.next_back() {
-                    i -= 1;
-                    if predicate(x) {
-                        // SAFETY: `i` must be lower than `n` since it starts at `n`
-                        // and is only decreasing.
-                        unsafe { assume(i < n) };
-                        return Some(i);
-                    }
-                }
-                None
-            }
-
-            #[doc(hidden)]
-            unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item {
-                // SAFETY: the caller must guarantee that `i` is in bounds of
-                // the underlying slice, so `i` cannot overflow an `isize`, and
-                // the returned references is guaranteed to refer to an element
-                // of the slice and thus guaranteed to be valid.
-                //
-                // Also note that the caller also guarantees that we're never
-                // called with the same index again, and that no other methods
-                // that will access this subslice are called, so it is valid
-                // for the returned reference to be mutable in the case of
-                // `IterMut`
-                unsafe { & $( $mut_ )? * self.ptr.as_ptr().add(idx) }
-            }
-
-            $($extra)*
-        }
-
-        #[stable(feature = "rust1", since = "1.0.0")]
-        impl<'a, T> DoubleEndedIterator for $name<'a, T> {
-            #[inline]
-            fn next_back(&mut self) -> Option<$elem> {
-                // could be implemented with slices, but this avoids bounds checks
-
-                // SAFETY: `assume` calls are safe since a slice's start pointer must be non-null,
-                // and slices over non-ZSTs must also have a non-null end pointer.
-                // The call to `next_back_unchecked!` is safe since we check if the iterator is
-                // empty first.
-                unsafe {
-                    assume(!self.ptr.as_ptr().is_null());
-                    if mem::size_of::<T>() != 0 {
-                        assume(!self.end.is_null());
-                    }
-                    if is_empty!(self) {
-                        None
-                    } else {
-                        Some(next_back_unchecked!(self))
-                    }
-                }
-            }
-
-            #[inline]
-            fn nth_back(&mut self, n: usize) -> Option<$elem> {
-                if n >= len!(self) {
-                    // This iterator is now empty.
-                    self.end = self.ptr.as_ptr();
-                    return None;
-                }
-                // SAFETY: We are in bounds. `pre_dec_end` does the right thing even for ZSTs.
-                unsafe {
-                    self.pre_dec_end(n as isize);
-                    Some(next_back_unchecked!(self))
-                }
-            }
-        }
-
-        #[stable(feature = "fused", since = "1.26.0")]
-        impl<T> FusedIterator for $name<'_, T> {}
-
-        #[unstable(feature = "trusted_len", issue = "37572")]
-        unsafe impl<T> TrustedLen for $name<'_, T> {}
-    }
-}
-
-/// Immutable slice iterator
-///
-/// This struct is created by the [`iter`] method on [slices].
-///
-/// # Examples
-///
-/// Basic usage:
-///
-/// ```
-/// // First, we declare a type which has `iter` method to get the `Iter` struct (&[usize here]):
-/// let slice = &[1, 2, 3];
-///
-/// // Then, we iterate over it:
-/// for element in slice.iter() {
-///     println!("{}", element);
-/// }
-/// ```
-///
-/// [`iter`]: ../../std/primitive.slice.html#method.iter
-/// [slices]: ../../std/primitive.slice.html
-#[stable(feature = "rust1", since = "1.0.0")]
-pub struct Iter<'a, T: 'a> {
-    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.
-    _marker: marker::PhantomData<&'a T>,
-}
-
-#[stable(feature = "core_impl_debug", since = "1.9.0")]
-impl<T: fmt::Debug> fmt::Debug for Iter<'_, T> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.debug_tuple("Iter").field(&self.as_slice()).finish()
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-unsafe impl<T: Sync> Sync for Iter<'_, T> {}
-#[stable(feature = "rust1", since = "1.0.0")]
-unsafe impl<T: Sync> Send for Iter<'_, T> {}
-
-impl<'a, T> Iter<'a, T> {
-    /// Views the underlying data as a subslice of the original data.
-    ///
-    /// This has the same lifetime as the original slice, and so the
-    /// iterator can continue to be used while this exists.
-    ///
-    /// # Examples
-    ///
-    /// Basic usage:
-    ///
-    /// ```
-    /// // First, we declare a type which has the `iter` method to get the `Iter`
-    /// // struct (&[usize here]):
-    /// let slice = &[1, 2, 3];
-    ///
-    /// // Then, we get the iterator:
-    /// let mut iter = slice.iter();
-    /// // So if we print what `as_slice` method returns here, we have "[1, 2, 3]":
-    /// println!("{:?}", iter.as_slice());
-    ///
-    /// // Next, we move to the second element of the slice:
-    /// iter.next();
-    /// // Now `as_slice` returns "[2, 3]":
-    /// println!("{:?}", iter.as_slice());
-    /// ```
-    #[stable(feature = "iter_to_slice", since = "1.4.0")]
-    pub fn as_slice(&self) -> &'a [T] {
-        self.make_slice()
-    }
-}
-
-iterator! {struct Iter -> *const T, &'a T, const, {/* no mut */}, {
-    fn is_sorted_by<F>(self, mut compare: F) -> bool
-    where
-        Self: Sized,
-        F: FnMut(&Self::Item, &Self::Item) -> Option<Ordering>,
-    {
-        self.as_slice().windows(2).all(|w| {
-            compare(&&w[0], &&w[1]).map(|o| o != Ordering::Greater).unwrap_or(false)
-        })
-    }
-}}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T> Clone for Iter<'_, T> {
-    fn clone(&self) -> Self {
-        Iter { ptr: self.ptr, end: self.end, _marker: self._marker }
-    }
-}
-
-#[stable(feature = "slice_iter_as_ref", since = "1.13.0")]
-impl<T> AsRef<[T]> for Iter<'_, T> {
-    fn as_ref(&self) -> &[T] {
-        self.as_slice()
-    }
-}
-
-/// Mutable slice iterator.
-///
-/// This struct is created by the [`iter_mut`] method on [slices].
-///
-/// # Examples
-///
-/// Basic usage:
-///
-/// ```
-/// // First, we declare a type which has `iter_mut` method to get the `IterMut`
-/// // struct (&[usize here]):
-/// let mut slice = &mut [1, 2, 3];
-///
-/// // Then, we iterate over it and increment each element value:
-/// for element in slice.iter_mut() {
-///     *element += 1;
-/// }
-///
-/// // We now have "[2, 3, 4]":
-/// println!("{:?}", slice);
-/// ```
-///
-/// [`iter_mut`]: ../../std/primitive.slice.html#method.iter_mut
-/// [slices]: ../../std/primitive.slice.html
-#[stable(feature = "rust1", since = "1.0.0")]
-pub struct IterMut<'a, T: 'a> {
-    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.
-    _marker: marker::PhantomData<&'a mut T>,
-}
-
-#[stable(feature = "core_impl_debug", since = "1.9.0")]
-impl<T: fmt::Debug> fmt::Debug for IterMut<'_, T> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.debug_tuple("IterMut").field(&self.make_slice()).finish()
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-unsafe impl<T: Sync> Sync for IterMut<'_, T> {}
-#[stable(feature = "rust1", since = "1.0.0")]
-unsafe impl<T: Send> Send for IterMut<'_, T> {}
-
-impl<'a, T> IterMut<'a, T> {
-    /// Views the underlying data as a subslice of the original data.
-    ///
-    /// To avoid creating `&mut` references that alias, this is forced
-    /// to consume the iterator.
-    ///
-    /// # Examples
-    ///
-    /// Basic usage:
-    ///
-    /// ```
-    /// // First, we declare a type which has `iter_mut` method to get the `IterMut`
-    /// // struct (&[usize here]):
-    /// let mut slice = &mut [1, 2, 3];
-    ///
-    /// {
-    ///     // Then, we get the iterator:
-    ///     let mut iter = slice.iter_mut();
-    ///     // We move to next element:
-    ///     iter.next();
-    ///     // So if we print what `into_slice` method returns here, we have "[2, 3]":
-    ///     println!("{:?}", iter.into_slice());
-    /// }
-    ///
-    /// // Now let's modify a value of the slice:
-    /// {
-    ///     // First we get back the iterator:
-    ///     let mut iter = slice.iter_mut();
-    ///     // We change the value of the first element of the slice returned by the `next` method:
-    ///     *iter.next().unwrap() += 1;
-    /// }
-    /// // Now slice is "[2, 2, 3]":
-    /// println!("{:?}", slice);
-    /// ```
-    #[stable(feature = "iter_to_slice", since = "1.4.0")]
-    pub fn into_slice(self) -> &'a mut [T] {
-        // SAFETY: the iterator was created from a mutable slice with pointer
-        // `self.ptr` and length `len!(self)`. This guarantees that all the prerequisites
-        // for `from_raw_parts_mut` are fulfilled.
-        unsafe { from_raw_parts_mut(self.ptr.as_ptr(), len!(self)) }
-    }
-
-    /// Views the underlying data as a subslice of the original data.
-    ///
-    /// To avoid creating `&mut [T]` references that alias, the returned slice
-    /// borrows its lifetime from the iterator the method is applied on.
-    ///
-    /// # Examples
-    ///
-    /// Basic usage:
-    ///
-    /// ```
-    /// # #![feature(slice_iter_mut_as_slice)]
-    /// let mut slice: &mut [usize] = &mut [1, 2, 3];
-    ///
-    /// // First, we get the iterator:
-    /// let mut iter = slice.iter_mut();
-    /// // So if we check what the `as_slice` method returns here, we have "[1, 2, 3]":
-    /// assert_eq!(iter.as_slice(), &[1, 2, 3]);
-    ///
-    /// // Next, we move to the second element of the slice:
-    /// iter.next();
-    /// // Now `as_slice` returns "[2, 3]":
-    /// assert_eq!(iter.as_slice(), &[2, 3]);
-    /// ```
-    #[unstable(feature = "slice_iter_mut_as_slice", reason = "recently added", issue = "58957")]
-    pub fn as_slice(&self) -> &[T] {
-        self.make_slice()
-    }
-}
-
-iterator! {struct IterMut -> *mut T, &'a mut T, mut, {mut}, {}}
-
-/// An internal abstraction over the splitting iterators, so that
-/// splitn, splitn_mut etc can be implemented once.
-#[doc(hidden)]
-trait SplitIter: DoubleEndedIterator {
-    /// Marks the underlying iterator as complete, extracting the remaining
-    /// portion of the slice.
-    fn finish(&mut self) -> Option<Self::Item>;
-}
-
-/// An iterator over subslices separated by elements that match a predicate
-/// function.
-///
-/// This struct is created by the [`split`] method on [slices].
-///
-/// [`split`]: ../../std/primitive.slice.html#method.split
-/// [slices]: ../../std/primitive.slice.html
-#[stable(feature = "rust1", since = "1.0.0")]
-pub struct Split<'a, T: 'a, P>
-where
-    P: FnMut(&T) -> bool,
-{
-    v: &'a [T],
-    pred: P,
-    finished: bool,
-}
-
-#[stable(feature = "core_impl_debug", since = "1.9.0")]
-impl<T: fmt::Debug, P> fmt::Debug for Split<'_, T, P>
-where
-    P: FnMut(&T) -> bool,
-{
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.debug_struct("Split").field("v", &self.v).field("finished", &self.finished).finish()
-    }
-}
-
-// FIXME(#26925) Remove in favor of `#[derive(Clone)]`
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T, P> Clone for Split<'_, T, P>
-where
-    P: Clone + FnMut(&T) -> bool,
-{
-    fn clone(&self) -> Self {
-        Split { v: self.v, pred: self.pred.clone(), finished: self.finished }
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, T, P> Iterator for Split<'a, T, P>
-where
-    P: FnMut(&T) -> bool,
-{
-    type Item = &'a [T];
-
-    #[inline]
-    fn next(&mut self) -> Option<&'a [T]> {
-        if self.finished {
-            return None;
-        }
-
-        match self.v.iter().position(|x| (self.pred)(x)) {
-            None => self.finish(),
-            Some(idx) => {
-                let ret = Some(&self.v[..idx]);
-                self.v = &self.v[idx + 1..];
-                ret
-            }
-        }
-    }
-
-    #[inline]
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        if self.finished { (0, Some(0)) } else { (1, Some(self.v.len() + 1)) }
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, T, P> DoubleEndedIterator for Split<'a, T, P>
-where
-    P: FnMut(&T) -> bool,
-{
-    #[inline]
-    fn next_back(&mut self) -> Option<&'a [T]> {
-        if self.finished {
-            return None;
-        }
-
-        match self.v.iter().rposition(|x| (self.pred)(x)) {
-            None => self.finish(),
-            Some(idx) => {
-                let ret = Some(&self.v[idx + 1..]);
-                self.v = &self.v[..idx];
-                ret
-            }
-        }
-    }
-}
-
-impl<'a, T, P> SplitIter for Split<'a, T, P>
-where
-    P: FnMut(&T) -> bool,
-{
-    #[inline]
-    fn finish(&mut self) -> Option<&'a [T]> {
-        if self.finished {
-            None
-        } else {
-            self.finished = true;
-            Some(self.v)
-        }
-    }
-}
-
-#[stable(feature = "fused", since = "1.26.0")]
-impl<T, P> FusedIterator for Split<'_, T, P> where P: FnMut(&T) -> bool {}
-
-/// An iterator over subslices separated by elements that match a predicate
-/// function. Unlike `Split`, it contains the matched part as a terminator
-/// of the subslice.
-///
-/// This struct is created by the [`split_inclusive`] method on [slices].
-///
-/// [`split_inclusive`]: ../../std/primitive.slice.html#method.split_inclusive
-/// [slices]: ../../std/primitive.slice.html
-#[unstable(feature = "split_inclusive", issue = "72360")]
-pub struct SplitInclusive<'a, T: 'a, P>
-where
-    P: FnMut(&T) -> bool,
-{
-    v: &'a [T],
-    pred: P,
-    finished: bool,
-}
-
-#[unstable(feature = "split_inclusive", issue = "72360")]
-impl<T: fmt::Debug, P> fmt::Debug for SplitInclusive<'_, T, P>
-where
-    P: FnMut(&T) -> bool,
-{
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.debug_struct("SplitInclusive")
-            .field("v", &self.v)
-            .field("finished", &self.finished)
-            .finish()
-    }
-}
-
-// FIXME(#26925) Remove in favor of `#[derive(Clone)]`
-#[unstable(feature = "split_inclusive", issue = "72360")]
-impl<T, P> Clone for SplitInclusive<'_, T, P>
-where
-    P: Clone + FnMut(&T) -> bool,
-{
-    fn clone(&self) -> Self {
-        SplitInclusive { v: self.v, pred: self.pred.clone(), finished: self.finished }
-    }
-}
-
-#[unstable(feature = "split_inclusive", issue = "72360")]
-impl<'a, T, P> Iterator for SplitInclusive<'a, T, P>
-where
-    P: FnMut(&T) -> bool,
-{
-    type Item = &'a [T];
-
-    #[inline]
-    fn next(&mut self) -> Option<&'a [T]> {
-        if self.finished {
-            return None;
-        }
-
-        let idx =
-            self.v.iter().position(|x| (self.pred)(x)).map(|idx| idx + 1).unwrap_or(self.v.len());
-        if idx == self.v.len() {
-            self.finished = true;
-        }
-        let ret = Some(&self.v[..idx]);
-        self.v = &self.v[idx..];
-        ret
-    }
-
-    #[inline]
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        if self.finished { (0, Some(0)) } else { (1, Some(self.v.len() + 1)) }
-    }
-}
-
-#[unstable(feature = "split_inclusive", issue = "72360")]
-impl<'a, T, P> DoubleEndedIterator for SplitInclusive<'a, T, P>
-where
-    P: FnMut(&T) -> bool,
-{
-    #[inline]
-    fn next_back(&mut self) -> Option<&'a [T]> {
-        if self.finished {
-            return None;
-        }
-
-        // The last index of self.v is already checked and found to match
-        // by the last iteration, so we start searching a new match
-        // one index to the left.
-        let remainder = if self.v.is_empty() { &[] } else { &self.v[..(self.v.len() - 1)] };
-        let idx = remainder.iter().rposition(|x| (self.pred)(x)).map(|idx| idx + 1).unwrap_or(0);
-        if idx == 0 {
-            self.finished = true;
-        }
-        let ret = Some(&self.v[idx..]);
-        self.v = &self.v[..idx];
-        ret
-    }
-}
-
-#[unstable(feature = "split_inclusive", issue = "72360")]
-impl<T, P> FusedIterator for SplitInclusive<'_, T, P> where P: FnMut(&T) -> bool {}
-
-/// An iterator over the mutable subslices of the vector which are separated
-/// by elements that match `pred`.
-///
-/// This struct is created by the [`split_mut`] method on [slices].
-///
-/// [`split_mut`]: ../../std/primitive.slice.html#method.split_mut
-/// [slices]: ../../std/primitive.slice.html
-#[stable(feature = "rust1", since = "1.0.0")]
-pub struct SplitMut<'a, T: 'a, P>
-where
-    P: FnMut(&T) -> bool,
-{
-    v: &'a mut [T],
-    pred: P,
-    finished: bool,
-}
-
-#[stable(feature = "core_impl_debug", since = "1.9.0")]
-impl<T: fmt::Debug, P> fmt::Debug for SplitMut<'_, T, P>
-where
-    P: FnMut(&T) -> bool,
-{
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.debug_struct("SplitMut").field("v", &self.v).field("finished", &self.finished).finish()
-    }
-}
-
-impl<'a, T, P> SplitIter for SplitMut<'a, T, P>
-where
-    P: FnMut(&T) -> bool,
-{
-    #[inline]
-    fn finish(&mut self) -> Option<&'a mut [T]> {
-        if self.finished {
-            None
-        } else {
-            self.finished = true;
-            Some(mem::replace(&mut self.v, &mut []))
-        }
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, T, P> Iterator for SplitMut<'a, T, P>
-where
-    P: FnMut(&T) -> bool,
-{
-    type Item = &'a mut [T];
-
-    #[inline]
-    fn next(&mut self) -> Option<&'a mut [T]> {
-        if self.finished {
-            return None;
-        }
-
-        let idx_opt = {
-            // work around borrowck limitations
-            let pred = &mut self.pred;
-            self.v.iter().position(|x| (*pred)(x))
-        };
-        match idx_opt {
-            None => self.finish(),
-            Some(idx) => {
-                let tmp = mem::replace(&mut self.v, &mut []);
-                let (head, tail) = tmp.split_at_mut(idx);
-                self.v = &mut tail[1..];
-                Some(head)
-            }
-        }
-    }
-
-    #[inline]
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        if self.finished {
-            (0, Some(0))
-        } else {
-            // if the predicate doesn't match anything, we yield one slice
-            // if it matches every element, we yield len+1 empty slices.
-            (1, Some(self.v.len() + 1))
-        }
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, T, P> DoubleEndedIterator for SplitMut<'a, T, P>
-where
-    P: FnMut(&T) -> bool,
-{
-    #[inline]
-    fn next_back(&mut self) -> Option<&'a mut [T]> {
-        if self.finished {
-            return None;
-        }
-
-        let idx_opt = {
-            // work around borrowck limitations
-            let pred = &mut self.pred;
-            self.v.iter().rposition(|x| (*pred)(x))
-        };
-        match idx_opt {
-            None => self.finish(),
-            Some(idx) => {
-                let tmp = mem::replace(&mut self.v, &mut []);
-                let (head, tail) = tmp.split_at_mut(idx);
-                self.v = head;
-                Some(&mut tail[1..])
-            }
-        }
-    }
-}
-
-#[stable(feature = "fused", since = "1.26.0")]
-impl<T, P> FusedIterator for SplitMut<'_, T, P> where P: FnMut(&T) -> bool {}
-
-/// An iterator over the mutable subslices of the vector which are separated
-/// by elements that match `pred`. Unlike `SplitMut`, it contains the matched
-/// parts in the ends of the subslices.
-///
-/// This struct is created by the [`split_inclusive_mut`] method on [slices].
-///
-/// [`split_inclusive_mut`]: ../../std/primitive.slice.html#method.split_inclusive_mut
-/// [slices]: ../../std/primitive.slice.html
-#[unstable(feature = "split_inclusive", issue = "72360")]
-pub struct SplitInclusiveMut<'a, T: 'a, P>
-where
-    P: FnMut(&T) -> bool,
-{
-    v: &'a mut [T],
-    pred: P,
-    finished: bool,
-}
-
-#[unstable(feature = "split_inclusive", issue = "72360")]
-impl<T: fmt::Debug, P> fmt::Debug for SplitInclusiveMut<'_, T, P>
-where
-    P: FnMut(&T) -> bool,
-{
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.debug_struct("SplitInclusiveMut")
-            .field("v", &self.v)
-            .field("finished", &self.finished)
-            .finish()
-    }
-}
-
-#[unstable(feature = "split_inclusive", issue = "72360")]
-impl<'a, T, P> Iterator for SplitInclusiveMut<'a, T, P>
-where
-    P: FnMut(&T) -> bool,
-{
-    type Item = &'a mut [T];
-
-    #[inline]
-    fn next(&mut self) -> Option<&'a mut [T]> {
-        if self.finished {
-            return None;
-        }
-
-        let idx_opt = {
-            // work around borrowck limitations
-            let pred = &mut self.pred;
-            self.v.iter().position(|x| (*pred)(x))
-        };
-        let idx = idx_opt.map(|idx| idx + 1).unwrap_or(self.v.len());
-        if idx == self.v.len() {
-            self.finished = true;
-        }
-        let tmp = mem::replace(&mut self.v, &mut []);
-        let (head, tail) = tmp.split_at_mut(idx);
-        self.v = tail;
-        Some(head)
-    }
-
-    #[inline]
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        if self.finished {
-            (0, Some(0))
-        } else {
-            // if the predicate doesn't match anything, we yield one slice
-            // if it matches every element, we yield len+1 empty slices.
-            (1, Some(self.v.len() + 1))
-        }
-    }
-}
-
-#[unstable(feature = "split_inclusive", issue = "72360")]
-impl<'a, T, P> DoubleEndedIterator for SplitInclusiveMut<'a, T, P>
-where
-    P: FnMut(&T) -> bool,
-{
-    #[inline]
-    fn next_back(&mut self) -> Option<&'a mut [T]> {
-        if self.finished {
-            return None;
-        }
-
-        let idx_opt = if self.v.is_empty() {
-            None
-        } else {
-            // work around borrowck limitations
-            let pred = &mut self.pred;
-
-            // The last index of self.v is already checked and found to match
-            // by the last iteration, so we start searching a new match
-            // one index to the left.
-            let remainder = &self.v[..(self.v.len() - 1)];
-            remainder.iter().rposition(|x| (*pred)(x))
-        };
-        let idx = idx_opt.map(|idx| idx + 1).unwrap_or(0);
-        if idx == 0 {
-            self.finished = true;
-        }
-        let tmp = mem::replace(&mut self.v, &mut []);
-        let (head, tail) = tmp.split_at_mut(idx);
-        self.v = head;
-        Some(tail)
-    }
-}
-
-#[unstable(feature = "split_inclusive", issue = "72360")]
-impl<T, P> FusedIterator for SplitInclusiveMut<'_, T, P> where P: FnMut(&T) -> bool {}
-
-/// An iterator over subslices separated by elements that match a predicate
-/// function, starting from the end of the slice.
-///
-/// This struct is created by the [`rsplit`] method on [slices].
-///
-/// [`rsplit`]: ../../std/primitive.slice.html#method.rsplit
-/// [slices]: ../../std/primitive.slice.html
-#[stable(feature = "slice_rsplit", since = "1.27.0")]
-#[derive(Clone)] // Is this correct, or does it incorrectly require `T: Clone`?
-pub struct RSplit<'a, T: 'a, P>
-where
-    P: FnMut(&T) -> bool,
-{
-    inner: Split<'a, T, P>,
-}
-
-#[stable(feature = "slice_rsplit", since = "1.27.0")]
-impl<T: fmt::Debug, P> fmt::Debug for RSplit<'_, T, P>
-where
-    P: FnMut(&T) -> bool,
-{
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.debug_struct("RSplit")
-            .field("v", &self.inner.v)
-            .field("finished", &self.inner.finished)
-            .finish()
-    }
-}
-
-#[stable(feature = "slice_rsplit", since = "1.27.0")]
-impl<'a, T, P> Iterator for RSplit<'a, T, P>
-where
-    P: FnMut(&T) -> bool,
-{
-    type Item = &'a [T];
-
-    #[inline]
-    fn next(&mut self) -> Option<&'a [T]> {
-        self.inner.next_back()
-    }
-
-    #[inline]
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        self.inner.size_hint()
-    }
-}
-
-#[stable(feature = "slice_rsplit", since = "1.27.0")]
-impl<'a, T, P> DoubleEndedIterator for RSplit<'a, T, P>
-where
-    P: FnMut(&T) -> bool,
-{
-    #[inline]
-    fn next_back(&mut self) -> Option<&'a [T]> {
-        self.inner.next()
-    }
-}
-
-#[stable(feature = "slice_rsplit", since = "1.27.0")]
-impl<'a, T, P> SplitIter for RSplit<'a, T, P>
-where
-    P: FnMut(&T) -> bool,
-{
-    #[inline]
-    fn finish(&mut self) -> Option<&'a [T]> {
-        self.inner.finish()
-    }
-}
-
-#[stable(feature = "slice_rsplit", since = "1.27.0")]
-impl<T, P> FusedIterator for RSplit<'_, T, P> where P: FnMut(&T) -> bool {}
-
-/// An iterator over the subslices of the vector which are separated
-/// by elements that match `pred`, starting from the end of the slice.
-///
-/// This struct is created by the [`rsplit_mut`] method on [slices].
-///
-/// [`rsplit_mut`]: ../../std/primitive.slice.html#method.rsplit_mut
-/// [slices]: ../../std/primitive.slice.html
-#[stable(feature = "slice_rsplit", since = "1.27.0")]
-pub struct RSplitMut<'a, T: 'a, P>
-where
-    P: FnMut(&T) -> bool,
-{
-    inner: SplitMut<'a, T, P>,
-}
-
-#[stable(feature = "slice_rsplit", since = "1.27.0")]
-impl<T: fmt::Debug, P> fmt::Debug for RSplitMut<'_, T, P>
-where
-    P: FnMut(&T) -> bool,
-{
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.debug_struct("RSplitMut")
-            .field("v", &self.inner.v)
-            .field("finished", &self.inner.finished)
-            .finish()
-    }
-}
-
-#[stable(feature = "slice_rsplit", since = "1.27.0")]
-impl<'a, T, P> SplitIter for RSplitMut<'a, T, P>
-where
-    P: FnMut(&T) -> bool,
-{
-    #[inline]
-    fn finish(&mut self) -> Option<&'a mut [T]> {
-        self.inner.finish()
-    }
-}
-
-#[stable(feature = "slice_rsplit", since = "1.27.0")]
-impl<'a, T, P> Iterator for RSplitMut<'a, T, P>
-where
-    P: FnMut(&T) -> bool,
-{
-    type Item = &'a mut [T];
-
-    #[inline]
-    fn next(&mut self) -> Option<&'a mut [T]> {
-        self.inner.next_back()
-    }
-
-    #[inline]
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        self.inner.size_hint()
-    }
-}
-
-#[stable(feature = "slice_rsplit", since = "1.27.0")]
-impl<'a, T, P> DoubleEndedIterator for RSplitMut<'a, T, P>
-where
-    P: FnMut(&T) -> bool,
-{
-    #[inline]
-    fn next_back(&mut self) -> Option<&'a mut [T]> {
-        self.inner.next()
-    }
-}
-
-#[stable(feature = "slice_rsplit", since = "1.27.0")]
-impl<T, P> FusedIterator for RSplitMut<'_, T, P> where P: FnMut(&T) -> bool {}
-
-/// An private iterator over subslices separated by elements that
-/// match a predicate function, splitting at most a fixed number of
-/// times.
-#[derive(Debug)]
-struct GenericSplitN<I> {
-    iter: I,
-    count: usize,
-}
-
-impl<T, I: SplitIter<Item = T>> Iterator for GenericSplitN<I> {
-    type Item = T;
-
-    #[inline]
-    fn next(&mut self) -> Option<T> {
-        match self.count {
-            0 => None,
-            1 => {
-                self.count -= 1;
-                self.iter.finish()
-            }
-            _ => {
-                self.count -= 1;
-                self.iter.next()
-            }
-        }
-    }
-
-    #[inline]
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        let (lower, upper_opt) = self.iter.size_hint();
-        (lower, upper_opt.map(|upper| cmp::min(self.count, upper)))
-    }
-}
-
-/// An iterator over subslices separated by elements that match a predicate
-/// function, limited to a given number of splits.
-///
-/// This struct is created by the [`splitn`] method on [slices].
-///
-/// [`splitn`]: ../../std/primitive.slice.html#method.splitn
-/// [slices]: ../../std/primitive.slice.html
-#[stable(feature = "rust1", since = "1.0.0")]
-pub struct SplitN<'a, T: 'a, P>
-where
-    P: FnMut(&T) -> bool,
-{
-    inner: GenericSplitN<Split<'a, T, P>>,
-}
-
-#[stable(feature = "core_impl_debug", since = "1.9.0")]
-impl<T: fmt::Debug, P> fmt::Debug for SplitN<'_, T, P>
-where
-    P: FnMut(&T) -> bool,
-{
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.debug_struct("SplitN").field("inner", &self.inner).finish()
-    }
-}
-
-/// An iterator over subslices separated by elements that match a
-/// predicate function, limited to a given number of splits, starting
-/// from the end of the slice.
-///
-/// This struct is created by the [`rsplitn`] method on [slices].
-///
-/// [`rsplitn`]: ../../std/primitive.slice.html#method.rsplitn
-/// [slices]: ../../std/primitive.slice.html
-#[stable(feature = "rust1", since = "1.0.0")]
-pub struct RSplitN<'a, T: 'a, P>
-where
-    P: FnMut(&T) -> bool,
-{
-    inner: GenericSplitN<RSplit<'a, T, P>>,
-}
-
-#[stable(feature = "core_impl_debug", since = "1.9.0")]
-impl<T: fmt::Debug, P> fmt::Debug for RSplitN<'_, T, P>
-where
-    P: FnMut(&T) -> bool,
-{
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.debug_struct("RSplitN").field("inner", &self.inner).finish()
-    }
-}
-
-/// An iterator over subslices separated by elements that match a predicate
-/// function, limited to a given number of splits.
-///
-/// This struct is created by the [`splitn_mut`] method on [slices].
-///
-/// [`splitn_mut`]: ../../std/primitive.slice.html#method.splitn_mut
-/// [slices]: ../../std/primitive.slice.html
-#[stable(feature = "rust1", since = "1.0.0")]
-pub struct SplitNMut<'a, T: 'a, P>
-where
-    P: FnMut(&T) -> bool,
-{
-    inner: GenericSplitN<SplitMut<'a, T, P>>,
-}
-
-#[stable(feature = "core_impl_debug", since = "1.9.0")]
-impl<T: fmt::Debug, P> fmt::Debug for SplitNMut<'_, T, P>
-where
-    P: FnMut(&T) -> bool,
-{
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.debug_struct("SplitNMut").field("inner", &self.inner).finish()
-    }
-}
-
-/// An iterator over subslices separated by elements that match a
-/// predicate function, limited to a given number of splits, starting
-/// from the end of the slice.
-///
-/// This struct is created by the [`rsplitn_mut`] method on [slices].
-///
-/// [`rsplitn_mut`]: ../../std/primitive.slice.html#method.rsplitn_mut
-/// [slices]: ../../std/primitive.slice.html
-#[stable(feature = "rust1", since = "1.0.0")]
-pub struct RSplitNMut<'a, T: 'a, P>
-where
-    P: FnMut(&T) -> bool,
-{
-    inner: GenericSplitN<RSplitMut<'a, T, P>>,
-}
-
-#[stable(feature = "core_impl_debug", since = "1.9.0")]
-impl<T: fmt::Debug, P> fmt::Debug for RSplitNMut<'_, T, P>
-where
-    P: FnMut(&T) -> bool,
-{
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.debug_struct("RSplitNMut").field("inner", &self.inner).finish()
-    }
-}
-
-macro_rules! forward_iterator {
-    ($name:ident: $elem:ident, $iter_of:ty) => {
-        #[stable(feature = "rust1", since = "1.0.0")]
-        impl<'a, $elem, P> Iterator for $name<'a, $elem, P>
-        where
-            P: FnMut(&T) -> bool,
-        {
-            type Item = $iter_of;
-
-            #[inline]
-            fn next(&mut self) -> Option<$iter_of> {
-                self.inner.next()
-            }
-
-            #[inline]
-            fn size_hint(&self) -> (usize, Option<usize>) {
-                self.inner.size_hint()
-            }
-        }
-
-        #[stable(feature = "fused", since = "1.26.0")]
-        impl<'a, $elem, P> FusedIterator for $name<'a, $elem, P> where P: FnMut(&T) -> bool {}
-    };
-}
-
-forward_iterator! { SplitN: T, &'a [T] }
-forward_iterator! { RSplitN: T, &'a [T] }
-forward_iterator! { SplitNMut: T, &'a mut [T] }
-forward_iterator! { RSplitNMut: T, &'a mut [T] }
-
-/// An iterator over overlapping subslices of length `size`.
-///
-/// This struct is created by the [`windows`] method on [slices].
-///
-/// [`windows`]: ../../std/primitive.slice.html#method.windows
-/// [slices]: ../../std/primitive.slice.html
-#[derive(Debug)]
-#[stable(feature = "rust1", since = "1.0.0")]
-pub struct Windows<'a, T: 'a> {
-    v: &'a [T],
-    size: usize,
-}
-
-// FIXME(#26925) Remove in favor of `#[derive(Clone)]`
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T> Clone for Windows<'_, T> {
-    fn clone(&self) -> Self {
-        Windows { v: self.v, size: self.size }
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, T> Iterator for Windows<'a, T> {
-    type Item = &'a [T];
-
-    #[inline]
-    fn next(&mut self) -> Option<&'a [T]> {
-        if self.size > self.v.len() {
-            None
-        } else {
-            let ret = Some(&self.v[..self.size]);
-            self.v = &self.v[1..];
-            ret
-        }
-    }
-
-    #[inline]
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        if self.size > self.v.len() {
-            (0, Some(0))
-        } else {
-            let size = self.v.len() - self.size + 1;
-            (size, Some(size))
-        }
-    }
-
-    #[inline]
-    fn count(self) -> usize {
-        self.len()
-    }
-
-    #[inline]
-    fn nth(&mut self, n: usize) -> Option<Self::Item> {
-        let (end, overflow) = self.size.overflowing_add(n);
-        if end > self.v.len() || overflow {
-            self.v = &[];
-            None
-        } else {
-            let nth = &self.v[n..end];
-            self.v = &self.v[n + 1..];
-            Some(nth)
-        }
-    }
-
-    #[inline]
-    fn last(self) -> Option<Self::Item> {
-        if self.size > self.v.len() {
-            None
-        } else {
-            let start = self.v.len() - self.size;
-            Some(&self.v[start..])
-        }
-    }
-
-    #[doc(hidden)]
-    unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item {
-        // SAFETY: since the caller guarantees that `i` is in bounds,
-        // which means that `i` cannot overflow an `isize`, and the
-        // slice created by `from_raw_parts` is a subslice of `self.v`
-        // thus is guaranteed to be valid for the lifetime `'a` of `self.v`.
-        unsafe { from_raw_parts(self.v.as_ptr().add(idx), self.size) }
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, T> DoubleEndedIterator for Windows<'a, T> {
-    #[inline]
-    fn next_back(&mut self) -> Option<&'a [T]> {
-        if self.size > self.v.len() {
-            None
-        } else {
-            let ret = Some(&self.v[self.v.len() - self.size..]);
-            self.v = &self.v[..self.v.len() - 1];
-            ret
-        }
-    }
-
-    #[inline]
-    fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
-        let (end, overflow) = self.v.len().overflowing_sub(n);
-        if end < self.size || overflow {
-            self.v = &[];
-            None
-        } else {
-            let ret = &self.v[end - self.size..end];
-            self.v = &self.v[..end - 1];
-            Some(ret)
-        }
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T> ExactSizeIterator for Windows<'_, T> {}
-
-#[unstable(feature = "trusted_len", issue = "37572")]
-unsafe impl<T> TrustedLen for Windows<'_, T> {}
-
-#[stable(feature = "fused", since = "1.26.0")]
-impl<T> FusedIterator for Windows<'_, T> {}
-
-#[doc(hidden)]
-#[unstable(feature = "trusted_random_access", issue = "none")]
-unsafe impl<'a, T> TrustedRandomAccess for Windows<'a, T> {
-    fn may_have_side_effect() -> bool {
-        false
-    }
-}
-
-/// An iterator over a slice in (non-overlapping) chunks (`chunk_size` elements at a
-/// time), starting at the beginning of the slice.
-///
-/// When the slice len is not evenly divided by the chunk size, the last slice
-/// of the iteration will be the remainder.
-///
-/// This struct is created by the [`chunks`] method on [slices].
-///
-/// [`chunks`]: ../../std/primitive.slice.html#method.chunks
-/// [slices]: ../../std/primitive.slice.html
-#[derive(Debug)]
-#[stable(feature = "rust1", since = "1.0.0")]
-pub struct Chunks<'a, T: 'a> {
-    v: &'a [T],
-    chunk_size: usize,
-}
-
-// FIXME(#26925) Remove in favor of `#[derive(Clone)]`
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T> Clone for Chunks<'_, T> {
-    fn clone(&self) -> Self {
-        Chunks { v: self.v, chunk_size: self.chunk_size }
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, T> Iterator for Chunks<'a, T> {
-    type Item = &'a [T];
-
-    #[inline]
-    fn next(&mut self) -> Option<&'a [T]> {
-        if self.v.is_empty() {
-            None
-        } else {
-            let chunksz = cmp::min(self.v.len(), self.chunk_size);
-            let (fst, snd) = self.v.split_at(chunksz);
-            self.v = snd;
-            Some(fst)
-        }
-    }
-
-    #[inline]
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        if self.v.is_empty() {
-            (0, Some(0))
-        } else {
-            let n = self.v.len() / self.chunk_size;
-            let rem = self.v.len() % self.chunk_size;
-            let n = if rem > 0 { n + 1 } else { n };
-            (n, Some(n))
-        }
-    }
-
-    #[inline]
-    fn count(self) -> usize {
-        self.len()
-    }
-
-    #[inline]
-    fn nth(&mut self, n: usize) -> Option<Self::Item> {
-        let (start, overflow) = n.overflowing_mul(self.chunk_size);
-        if start >= self.v.len() || overflow {
-            self.v = &[];
-            None
-        } else {
-            let end = match start.checked_add(self.chunk_size) {
-                Some(sum) => cmp::min(self.v.len(), sum),
-                None => self.v.len(),
-            };
-            let nth = &self.v[start..end];
-            self.v = &self.v[end..];
-            Some(nth)
-        }
-    }
-
-    #[inline]
-    fn last(self) -> Option<Self::Item> {
-        if self.v.is_empty() {
-            None
-        } else {
-            let start = (self.v.len() - 1) / self.chunk_size * self.chunk_size;
-            Some(&self.v[start..])
-        }
-    }
-
-    #[doc(hidden)]
-    unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item {
-        let start = idx * self.chunk_size;
-        let end = match start.checked_add(self.chunk_size) {
-            None => self.v.len(),
-            Some(end) => cmp::min(end, self.v.len()),
-        };
-        // SAFETY: the caller guarantees that `i` is in bounds,
-        // which means that `start` must be in bounds of the
-        // underlying `self.v` slice, and we made sure that `end`
-        // is also in bounds of `self.v`. Thus, `start` cannot overflow
-        // an `isize`, and the slice constructed by `from_raw_parts`
-        // is a subslice of `self.v` which is guaranteed to be valid
-        // for the lifetime `'a` of `self.v`.
-        unsafe { from_raw_parts(self.v.as_ptr().add(start), end - start) }
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, T> DoubleEndedIterator for Chunks<'a, T> {
-    #[inline]
-    fn next_back(&mut self) -> Option<&'a [T]> {
-        if self.v.is_empty() {
-            None
-        } else {
-            let remainder = self.v.len() % self.chunk_size;
-            let chunksz = if remainder != 0 { remainder } else { self.chunk_size };
-            let (fst, snd) = self.v.split_at(self.v.len() - chunksz);
-            self.v = fst;
-            Some(snd)
-        }
-    }
-
-    #[inline]
-    fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
-        let len = self.len();
-        if n >= len {
-            self.v = &[];
-            None
-        } else {
-            let start = (len - 1 - n) * self.chunk_size;
-            let end = match start.checked_add(self.chunk_size) {
-                Some(res) => cmp::min(res, self.v.len()),
-                None => self.v.len(),
-            };
-            let nth_back = &self.v[start..end];
-            self.v = &self.v[..start];
-            Some(nth_back)
-        }
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T> ExactSizeIterator for Chunks<'_, T> {}
-
-#[unstable(feature = "trusted_len", issue = "37572")]
-unsafe impl<T> TrustedLen for Chunks<'_, T> {}
-
-#[stable(feature = "fused", since = "1.26.0")]
-impl<T> FusedIterator for Chunks<'_, T> {}
-
-#[doc(hidden)]
-#[unstable(feature = "trusted_random_access", issue = "none")]
-unsafe impl<'a, T> TrustedRandomAccess for Chunks<'a, T> {
-    fn may_have_side_effect() -> bool {
-        false
-    }
-}
-
-/// An iterator over a slice in (non-overlapping) mutable chunks (`chunk_size`
-/// elements at a time), starting at the beginning of the slice.
-///
-/// When the slice len is not evenly divided by the chunk size, the last slice
-/// of the iteration will be the remainder.
-///
-/// This struct is created by the [`chunks_mut`] method on [slices].
-///
-/// [`chunks_mut`]: ../../std/primitive.slice.html#method.chunks_mut
-/// [slices]: ../../std/primitive.slice.html
-#[derive(Debug)]
-#[stable(feature = "rust1", since = "1.0.0")]
-pub struct ChunksMut<'a, T: 'a> {
-    v: &'a mut [T],
-    chunk_size: usize,
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, T> Iterator for ChunksMut<'a, T> {
-    type Item = &'a mut [T];
-
-    #[inline]
-    fn next(&mut self) -> Option<&'a mut [T]> {
-        if self.v.is_empty() {
-            None
-        } else {
-            let sz = cmp::min(self.v.len(), self.chunk_size);
-            let tmp = mem::replace(&mut self.v, &mut []);
-            let (head, tail) = tmp.split_at_mut(sz);
-            self.v = tail;
-            Some(head)
-        }
-    }
-
-    #[inline]
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        if self.v.is_empty() {
-            (0, Some(0))
-        } else {
-            let n = self.v.len() / self.chunk_size;
-            let rem = self.v.len() % self.chunk_size;
-            let n = if rem > 0 { n + 1 } else { n };
-            (n, Some(n))
-        }
-    }
-
-    #[inline]
-    fn count(self) -> usize {
-        self.len()
-    }
-
-    #[inline]
-    fn nth(&mut self, n: usize) -> Option<&'a mut [T]> {
-        let (start, overflow) = n.overflowing_mul(self.chunk_size);
-        if start >= self.v.len() || overflow {
-            self.v = &mut [];
-            None
-        } else {
-            let end = match start.checked_add(self.chunk_size) {
-                Some(sum) => cmp::min(self.v.len(), sum),
-                None => self.v.len(),
-            };
-            let tmp = mem::replace(&mut self.v, &mut []);
-            let (head, tail) = tmp.split_at_mut(end);
-            let (_, nth) = head.split_at_mut(start);
-            self.v = tail;
-            Some(nth)
-        }
-    }
-
-    #[inline]
-    fn last(self) -> Option<Self::Item> {
-        if self.v.is_empty() {
-            None
-        } else {
-            let start = (self.v.len() - 1) / self.chunk_size * self.chunk_size;
-            Some(&mut self.v[start..])
-        }
-    }
-
-    #[doc(hidden)]
-    unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item {
-        let start = idx * self.chunk_size;
-        let end = match start.checked_add(self.chunk_size) {
-            None => self.v.len(),
-            Some(end) => cmp::min(end, self.v.len()),
-        };
-        // SAFETY: see comments for `Chunks::get_unchecked`.
-        //
-        // Also note that the caller also guarantees that we're never called
-        // with the same index again, and that no other methods that will
-        // access this subslice are called, so it is valid for the returned
-        // slice to be mutable.
-        unsafe { from_raw_parts_mut(self.v.as_mut_ptr().add(start), end - start) }
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, T> DoubleEndedIterator for ChunksMut<'a, T> {
-    #[inline]
-    fn next_back(&mut self) -> Option<&'a mut [T]> {
-        if self.v.is_empty() {
-            None
-        } else {
-            let remainder = self.v.len() % self.chunk_size;
-            let sz = if remainder != 0 { remainder } else { self.chunk_size };
-            let tmp = mem::replace(&mut self.v, &mut []);
-            let tmp_len = tmp.len();
-            let (head, tail) = tmp.split_at_mut(tmp_len - sz);
-            self.v = head;
-            Some(tail)
-        }
-    }
-
-    #[inline]
-    fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
-        let len = self.len();
-        if n >= len {
-            self.v = &mut [];
-            None
-        } else {
-            let start = (len - 1 - n) * self.chunk_size;
-            let end = match start.checked_add(self.chunk_size) {
-                Some(res) => cmp::min(res, self.v.len()),
-                None => self.v.len(),
-            };
-            let (temp, _tail) = mem::replace(&mut self.v, &mut []).split_at_mut(end);
-            let (head, nth_back) = temp.split_at_mut(start);
-            self.v = head;
-            Some(nth_back)
-        }
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T> ExactSizeIterator for ChunksMut<'_, T> {}
-
-#[unstable(feature = "trusted_len", issue = "37572")]
-unsafe impl<T> TrustedLen for ChunksMut<'_, T> {}
-
-#[stable(feature = "fused", since = "1.26.0")]
-impl<T> FusedIterator for ChunksMut<'_, T> {}
-
-#[doc(hidden)]
-#[unstable(feature = "trusted_random_access", issue = "none")]
-unsafe impl<'a, T> TrustedRandomAccess for ChunksMut<'a, T> {
-    fn may_have_side_effect() -> bool {
-        false
-    }
-}
-
-/// An iterator over a slice in (non-overlapping) chunks (`chunk_size` elements at a
-/// time), starting at the beginning of the slice.
-///
-/// When the slice len is not evenly divided by the chunk size, the last
-/// up to `chunk_size-1` elements will be omitted but can be retrieved from
-/// the [`remainder`] function from the iterator.
-///
-/// This struct is created by the [`chunks_exact`] method on [slices].
-///
-/// [`chunks_exact`]: ../../std/primitive.slice.html#method.chunks_exact
-/// [`remainder`]: ChunksExact::remainder
-/// [slices]: ../../std/primitive.slice.html
-#[derive(Debug)]
-#[stable(feature = "chunks_exact", since = "1.31.0")]
-pub struct ChunksExact<'a, T: 'a> {
-    v: &'a [T],
-    rem: &'a [T],
-    chunk_size: usize,
-}
-
-impl<'a, T> ChunksExact<'a, T> {
-    /// Returns the remainder of the original slice that is not going to be
-    /// returned by the iterator. The returned slice has at most `chunk_size-1`
-    /// elements.
-    #[stable(feature = "chunks_exact", since = "1.31.0")]
-    pub fn remainder(&self) -> &'a [T] {
-        self.rem
-    }
-}
-
-// FIXME(#26925) Remove in favor of `#[derive(Clone)]`
-#[stable(feature = "chunks_exact", since = "1.31.0")]
-impl<T> Clone for ChunksExact<'_, T> {
-    fn clone(&self) -> Self {
-        ChunksExact { v: self.v, rem: self.rem, chunk_size: self.chunk_size }
-    }
-}
-
-#[stable(feature = "chunks_exact", since = "1.31.0")]
-impl<'a, T> Iterator for ChunksExact<'a, T> {
-    type Item = &'a [T];
-
-    #[inline]
-    fn next(&mut self) -> Option<&'a [T]> {
-        if self.v.len() < self.chunk_size {
-            None
-        } else {
-            let (fst, snd) = self.v.split_at(self.chunk_size);
-            self.v = snd;
-            Some(fst)
-        }
-    }
-
-    #[inline]
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        let n = self.v.len() / self.chunk_size;
-        (n, Some(n))
-    }
-
-    #[inline]
-    fn count(self) -> usize {
-        self.len()
-    }
-
-    #[inline]
-    fn nth(&mut self, n: usize) -> Option<Self::Item> {
-        let (start, overflow) = n.overflowing_mul(self.chunk_size);
-        if start >= self.v.len() || overflow {
-            self.v = &[];
-            None
-        } else {
-            let (_, snd) = self.v.split_at(start);
-            self.v = snd;
-            self.next()
-        }
-    }
-
-    #[inline]
-    fn last(mut self) -> Option<Self::Item> {
-        self.next_back()
-    }
-
-    #[doc(hidden)]
-    unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item {
-        let start = idx * self.chunk_size;
-        // SAFETY: mostly identical to `Chunks::get_unchecked`.
-        unsafe { from_raw_parts(self.v.as_ptr().add(start), self.chunk_size) }
-    }
-}
-
-#[stable(feature = "chunks_exact", since = "1.31.0")]
-impl<'a, T> DoubleEndedIterator for ChunksExact<'a, T> {
-    #[inline]
-    fn next_back(&mut self) -> Option<&'a [T]> {
-        if self.v.len() < self.chunk_size {
-            None
-        } else {
-            let (fst, snd) = self.v.split_at(self.v.len() - self.chunk_size);
-            self.v = fst;
-            Some(snd)
-        }
-    }
-
-    #[inline]
-    fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
-        let len = self.len();
-        if n >= len {
-            self.v = &[];
-            None
-        } else {
-            let start = (len - 1 - n) * self.chunk_size;
-            let end = start + self.chunk_size;
-            let nth_back = &self.v[start..end];
-            self.v = &self.v[..start];
-            Some(nth_back)
-        }
-    }
-}
-
-#[stable(feature = "chunks_exact", since = "1.31.0")]
-impl<T> ExactSizeIterator for ChunksExact<'_, T> {
-    fn is_empty(&self) -> bool {
-        self.v.is_empty()
-    }
-}
-
-#[unstable(feature = "trusted_len", issue = "37572")]
-unsafe impl<T> TrustedLen for ChunksExact<'_, T> {}
-
-#[stable(feature = "chunks_exact", since = "1.31.0")]
-impl<T> FusedIterator for ChunksExact<'_, T> {}
-
-#[doc(hidden)]
-#[unstable(feature = "trusted_random_access", issue = "none")]
-unsafe impl<'a, T> TrustedRandomAccess for ChunksExact<'a, T> {
-    fn may_have_side_effect() -> bool {
-        false
-    }
-}
-
-/// An iterator over a slice in (non-overlapping) mutable chunks (`chunk_size`
-/// elements at a time), starting at the beginning of the slice.
-///
-/// When the slice len is not evenly divided by the chunk size, the last up to
-/// `chunk_size-1` elements will be omitted but can be retrieved from the
-/// [`into_remainder`] function from the iterator.
-///
-/// This struct is created by the [`chunks_exact_mut`] method on [slices].
-///
-/// [`chunks_exact_mut`]: ../../std/primitive.slice.html#method.chunks_exact_mut
-/// [`into_remainder`]: ChunksExactMut::into_remainder
-/// [slices]: ../../std/primitive.slice.html
-#[derive(Debug)]
-#[stable(feature = "chunks_exact", since = "1.31.0")]
-pub struct ChunksExactMut<'a, T: 'a> {
-    v: &'a mut [T],
-    rem: &'a mut [T],
-    chunk_size: usize,
-}
-
-impl<'a, T> ChunksExactMut<'a, T> {
-    /// Returns the remainder of the original slice that is not going to be
-    /// returned by the iterator. The returned slice has at most `chunk_size-1`
-    /// elements.
-    #[stable(feature = "chunks_exact", since = "1.31.0")]
-    pub fn into_remainder(self) -> &'a mut [T] {
-        self.rem
-    }
-}
-
-#[stable(feature = "chunks_exact", since = "1.31.0")]
-impl<'a, T> Iterator for ChunksExactMut<'a, T> {
-    type Item = &'a mut [T];
-
-    #[inline]
-    fn next(&mut self) -> Option<&'a mut [T]> {
-        if self.v.len() < self.chunk_size {
-            None
-        } else {
-            let tmp = mem::replace(&mut self.v, &mut []);
-            let (head, tail) = tmp.split_at_mut(self.chunk_size);
-            self.v = tail;
-            Some(head)
-        }
-    }
-
-    #[inline]
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        let n = self.v.len() / self.chunk_size;
-        (n, Some(n))
-    }
-
-    #[inline]
-    fn count(self) -> usize {
-        self.len()
-    }
-
-    #[inline]
-    fn nth(&mut self, n: usize) -> Option<&'a mut [T]> {
-        let (start, overflow) = n.overflowing_mul(self.chunk_size);
-        if start >= self.v.len() || overflow {
-            self.v = &mut [];
-            None
-        } else {
-            let tmp = mem::replace(&mut self.v, &mut []);
-            let (_, snd) = tmp.split_at_mut(start);
-            self.v = snd;
-            self.next()
-        }
-    }
-
-    #[inline]
-    fn last(mut self) -> Option<Self::Item> {
-        self.next_back()
-    }
-
-    #[doc(hidden)]
-    unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item {
-        let start = idx * self.chunk_size;
-        // SAFETY: see comments for `ChunksMut::get_unchecked`.
-        unsafe { from_raw_parts_mut(self.v.as_mut_ptr().add(start), self.chunk_size) }
-    }
-}
-
-#[stable(feature = "chunks_exact", since = "1.31.0")]
-impl<'a, T> DoubleEndedIterator for ChunksExactMut<'a, T> {
-    #[inline]
-    fn next_back(&mut self) -> Option<&'a mut [T]> {
-        if self.v.len() < self.chunk_size {
-            None
-        } else {
-            let tmp = mem::replace(&mut self.v, &mut []);
-            let tmp_len = tmp.len();
-            let (head, tail) = tmp.split_at_mut(tmp_len - self.chunk_size);
-            self.v = head;
-            Some(tail)
-        }
-    }
-
-    #[inline]
-    fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
-        let len = self.len();
-        if n >= len {
-            self.v = &mut [];
-            None
-        } else {
-            let start = (len - 1 - n) * self.chunk_size;
-            let end = start + self.chunk_size;
-            let (temp, _tail) = mem::replace(&mut self.v, &mut []).split_at_mut(end);
-            let (head, nth_back) = temp.split_at_mut(start);
-            self.v = head;
-            Some(nth_back)
-        }
-    }
-}
-
-#[stable(feature = "chunks_exact", since = "1.31.0")]
-impl<T> ExactSizeIterator for ChunksExactMut<'_, T> {
-    fn is_empty(&self) -> bool {
-        self.v.is_empty()
-    }
-}
-
-#[unstable(feature = "trusted_len", issue = "37572")]
-unsafe impl<T> TrustedLen for ChunksExactMut<'_, T> {}
-
-#[stable(feature = "chunks_exact", since = "1.31.0")]
-impl<T> FusedIterator for ChunksExactMut<'_, T> {}
-
-#[doc(hidden)]
-#[unstable(feature = "trusted_random_access", issue = "none")]
-unsafe impl<'a, T> TrustedRandomAccess for ChunksExactMut<'a, T> {
-    fn may_have_side_effect() -> bool {
-        false
-    }
-}
-
-/// An iterator over a slice in (non-overlapping) chunks (`N` elements at a
-/// time), starting at the beginning of the slice.
-///
-/// When the slice len is not evenly divided by the chunk size, the last
-/// up to `N-1` elements will be omitted but can be retrieved from
-/// the [`remainder`] function from the iterator.
-///
-/// This struct is created by the [`array_chunks`] method on [slices].
-///
-/// [`array_chunks`]: ../../std/primitive.slice.html#method.array_chunks
-/// [`remainder`]: ArrayChunks::remainder
-/// [slices]: ../../std/primitive.slice.html
-#[derive(Debug)]
-#[unstable(feature = "array_chunks", issue = "74985")]
-pub struct ArrayChunks<'a, T: 'a, const N: usize> {
-    iter: Iter<'a, [T; N]>,
-    rem: &'a [T],
-}
-
-impl<'a, T, const N: usize> ArrayChunks<'a, T, N> {
-    /// 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.
-    #[unstable(feature = "array_chunks", issue = "74985")]
-    pub fn remainder(&self) -> &'a [T] {
-        self.rem
-    }
-}
-
-// FIXME(#26925) Remove in favor of `#[derive(Clone)]`
-#[unstable(feature = "array_chunks", issue = "74985")]
-impl<T, const N: usize> Clone for ArrayChunks<'_, T, N> {
-    fn clone(&self) -> Self {
-        ArrayChunks { iter: self.iter.clone(), rem: self.rem }
-    }
-}
-
-#[unstable(feature = "array_chunks", issue = "74985")]
-impl<'a, T, const N: usize> Iterator for ArrayChunks<'a, T, N> {
-    type Item = &'a [T; N];
-
-    #[inline]
-    fn next(&mut self) -> Option<&'a [T; N]> {
-        self.iter.next()
-    }
-
-    #[inline]
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        self.iter.size_hint()
-    }
-
-    #[inline]
-    fn count(self) -> usize {
-        self.iter.count()
-    }
-
-    #[inline]
-    fn nth(&mut self, n: usize) -> Option<Self::Item> {
-        self.iter.nth(n)
-    }
-
-    #[inline]
-    fn last(self) -> Option<Self::Item> {
-        self.iter.last()
-    }
-
-    unsafe fn get_unchecked(&mut self, i: usize) -> &'a [T; N] {
-        // SAFETY: The safety guarantees of `get_unchecked` are transferred to
-        // the caller.
-        unsafe { self.iter.get_unchecked(i) }
-    }
-}
-
-#[unstable(feature = "array_chunks", issue = "74985")]
-impl<'a, T, const N: usize> DoubleEndedIterator for ArrayChunks<'a, T, N> {
-    #[inline]
-    fn next_back(&mut self) -> Option<&'a [T; N]> {
-        self.iter.next_back()
-    }
-
-    #[inline]
-    fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
-        self.iter.nth_back(n)
-    }
-}
-
-#[unstable(feature = "array_chunks", issue = "74985")]
-impl<T, const N: usize> ExactSizeIterator for ArrayChunks<'_, T, N> {
-    fn is_empty(&self) -> bool {
-        self.iter.is_empty()
-    }
-}
-
-#[unstable(feature = "trusted_len", issue = "37572")]
-unsafe impl<T, const N: usize> TrustedLen for ArrayChunks<'_, T, N> {}
-
-#[unstable(feature = "array_chunks", issue = "74985")]
-impl<T, const N: usize> FusedIterator for ArrayChunks<'_, T, N> {}
-
-#[doc(hidden)]
-#[unstable(feature = "array_chunks", issue = "74985")]
-unsafe impl<'a, T, const N: usize> TrustedRandomAccess for ArrayChunks<'a, T, N> {
-    fn may_have_side_effect() -> bool {
-        false
-    }
-}
-
-/// An iterator over a slice in (non-overlapping) mutable chunks (`N` elements
-/// at a time), starting at the beginning of the slice.
-///
-/// When the slice len is not evenly divided by the chunk size, the last
-/// up to `N-1` elements will be omitted but can be retrieved from
-/// the [`into_remainder`] function from the iterator.
-///
-/// This struct is created by the [`array_chunks_mut`] method on [slices].
-///
-/// [`array_chunks_mut`]: ../../std/primitive.slice.html#method.array_chunks_mut
-/// [`into_remainder`]: ../../std/slice/struct.ArrayChunksMut.html#method.into_remainder
-/// [slices]: ../../std/primitive.slice.html
-#[derive(Debug)]
-#[unstable(feature = "array_chunks", issue = "74985")]
-pub struct ArrayChunksMut<'a, T: 'a, const N: usize> {
-    iter: IterMut<'a, [T; N]>,
-    rem: &'a mut [T],
-}
-
-impl<'a, T, const N: usize> ArrayChunksMut<'a, T, N> {
-    /// 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.
-    #[unstable(feature = "array_chunks", issue = "74985")]
-    pub fn into_remainder(self) -> &'a mut [T] {
-        self.rem
-    }
-}
-
-#[unstable(feature = "array_chunks", issue = "74985")]
-impl<'a, T, const N: usize> Iterator for ArrayChunksMut<'a, T, N> {
-    type Item = &'a mut [T; N];
-
-    #[inline]
-    fn next(&mut self) -> Option<&'a mut [T; N]> {
-        self.iter.next()
-    }
-
-    #[inline]
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        self.iter.size_hint()
-    }
-
-    #[inline]
-    fn count(self) -> usize {
-        self.iter.count()
-    }
-
-    #[inline]
-    fn nth(&mut self, n: usize) -> Option<Self::Item> {
-        self.iter.nth(n)
-    }
-
-    #[inline]
-    fn last(self) -> Option<Self::Item> {
-        self.iter.last()
-    }
-
-    unsafe fn get_unchecked(&mut self, i: usize) -> &'a mut [T; N] {
-        // SAFETY: The safety guarantees of `get_unchecked` are transferred to
-        // the caller.
-        unsafe { self.iter.get_unchecked(i) }
-    }
-}
-
-#[unstable(feature = "array_chunks", issue = "74985")]
-impl<'a, T, const N: usize> DoubleEndedIterator for ArrayChunksMut<'a, T, N> {
-    #[inline]
-    fn next_back(&mut self) -> Option<&'a mut [T; N]> {
-        self.iter.next_back()
-    }
-
-    #[inline]
-    fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
-        self.iter.nth_back(n)
-    }
-}
-
-#[unstable(feature = "array_chunks", issue = "74985")]
-impl<T, const N: usize> ExactSizeIterator for ArrayChunksMut<'_, T, N> {
-    fn is_empty(&self) -> bool {
-        self.iter.is_empty()
-    }
-}
-
-#[unstable(feature = "trusted_len", issue = "37572")]
-unsafe impl<T, const N: usize> TrustedLen for ArrayChunksMut<'_, T, N> {}
-
-#[unstable(feature = "array_chunks", issue = "74985")]
-impl<T, const N: usize> FusedIterator for ArrayChunksMut<'_, T, N> {}
-
-#[doc(hidden)]
-#[unstable(feature = "array_chunks", issue = "74985")]
-unsafe impl<'a, T, const N: usize> TrustedRandomAccess for ArrayChunksMut<'a, T, N> {
-    fn may_have_side_effect() -> bool {
-        false
-    }
-}
-
-/// An iterator over a slice in (non-overlapping) chunks (`chunk_size` elements at a
-/// time), starting at the end of the slice.
-///
-/// When the slice len is not evenly divided by the chunk size, the last slice
-/// of the iteration will be the remainder.
-///
-/// This struct is created by the [`rchunks`] method on [slices].
-///
-/// [`rchunks`]: ../../std/primitive.slice.html#method.rchunks
-/// [slices]: ../../std/primitive.slice.html
-#[derive(Debug)]
-#[stable(feature = "rchunks", since = "1.31.0")]
-pub struct RChunks<'a, T: 'a> {
-    v: &'a [T],
-    chunk_size: usize,
-}
-
-// FIXME(#26925) Remove in favor of `#[derive(Clone)]`
-#[stable(feature = "rchunks", since = "1.31.0")]
-impl<T> Clone for RChunks<'_, T> {
-    fn clone(&self) -> Self {
-        RChunks { v: self.v, chunk_size: self.chunk_size }
-    }
-}
-
-#[stable(feature = "rchunks", since = "1.31.0")]
-impl<'a, T> Iterator for RChunks<'a, T> {
-    type Item = &'a [T];
-
-    #[inline]
-    fn next(&mut self) -> Option<&'a [T]> {
-        if self.v.is_empty() {
-            None
-        } else {
-            let chunksz = cmp::min(self.v.len(), self.chunk_size);
-            let (fst, snd) = self.v.split_at(self.v.len() - chunksz);
-            self.v = fst;
-            Some(snd)
-        }
-    }
-
-    #[inline]
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        if self.v.is_empty() {
-            (0, Some(0))
-        } else {
-            let n = self.v.len() / self.chunk_size;
-            let rem = self.v.len() % self.chunk_size;
-            let n = if rem > 0 { n + 1 } else { n };
-            (n, Some(n))
-        }
-    }
-
-    #[inline]
-    fn count(self) -> usize {
-        self.len()
-    }
-
-    #[inline]
-    fn nth(&mut self, n: usize) -> Option<Self::Item> {
-        let (end, overflow) = n.overflowing_mul(self.chunk_size);
-        if end >= self.v.len() || overflow {
-            self.v = &[];
-            None
-        } else {
-            // Can't underflow because of the check above
-            let end = self.v.len() - end;
-            let start = match end.checked_sub(self.chunk_size) {
-                Some(sum) => sum,
-                None => 0,
-            };
-            let nth = &self.v[start..end];
-            self.v = &self.v[0..start];
-            Some(nth)
-        }
-    }
-
-    #[inline]
-    fn last(self) -> Option<Self::Item> {
-        if self.v.is_empty() {
-            None
-        } else {
-            let rem = self.v.len() % self.chunk_size;
-            let end = if rem == 0 { self.chunk_size } else { rem };
-            Some(&self.v[0..end])
-        }
-    }
-
-    #[doc(hidden)]
-    unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item {
-        let end = self.v.len() - idx * self.chunk_size;
-        let start = match end.checked_sub(self.chunk_size) {
-            None => 0,
-            Some(start) => start,
-        };
-        // SAFETY: mostly identical to `Chunks::get_unchecked`.
-        unsafe { from_raw_parts(self.v.as_ptr().add(start), end - start) }
-    }
-}
-
-#[stable(feature = "rchunks", since = "1.31.0")]
-impl<'a, T> DoubleEndedIterator for RChunks<'a, T> {
-    #[inline]
-    fn next_back(&mut self) -> Option<&'a [T]> {
-        if self.v.is_empty() {
-            None
-        } else {
-            let remainder = self.v.len() % self.chunk_size;
-            let chunksz = if remainder != 0 { remainder } else { self.chunk_size };
-            let (fst, snd) = self.v.split_at(chunksz);
-            self.v = snd;
-            Some(fst)
-        }
-    }
-
-    #[inline]
-    fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
-        let len = self.len();
-        if n >= len {
-            self.v = &[];
-            None
-        } else {
-            // can't underflow because `n < len`
-            let offset_from_end = (len - 1 - n) * self.chunk_size;
-            let end = self.v.len() - offset_from_end;
-            let start = end.saturating_sub(self.chunk_size);
-            let nth_back = &self.v[start..end];
-            self.v = &self.v[end..];
-            Some(nth_back)
-        }
-    }
-}
-
-#[stable(feature = "rchunks", since = "1.31.0")]
-impl<T> ExactSizeIterator for RChunks<'_, T> {}
-
-#[unstable(feature = "trusted_len", issue = "37572")]
-unsafe impl<T> TrustedLen for RChunks<'_, T> {}
-
-#[stable(feature = "rchunks", since = "1.31.0")]
-impl<T> FusedIterator for RChunks<'_, T> {}
-
-#[doc(hidden)]
-#[unstable(feature = "trusted_random_access", issue = "none")]
-unsafe impl<'a, T> TrustedRandomAccess for RChunks<'a, T> {
-    fn may_have_side_effect() -> bool {
-        false
-    }
-}
-
-/// An iterator over a slice in (non-overlapping) mutable chunks (`chunk_size`
-/// elements at a time), starting at the end of the slice.
-///
-/// When the slice len is not evenly divided by the chunk size, the last slice
-/// of the iteration will be the remainder.
-///
-/// This struct is created by the [`rchunks_mut`] method on [slices].
-///
-/// [`rchunks_mut`]: ../../std/primitive.slice.html#method.rchunks_mut
-/// [slices]: ../../std/primitive.slice.html
-#[derive(Debug)]
-#[stable(feature = "rchunks", since = "1.31.0")]
-pub struct RChunksMut<'a, T: 'a> {
-    v: &'a mut [T],
-    chunk_size: usize,
-}
-
-#[stable(feature = "rchunks", since = "1.31.0")]
-impl<'a, T> Iterator for RChunksMut<'a, T> {
-    type Item = &'a mut [T];
-
-    #[inline]
-    fn next(&mut self) -> Option<&'a mut [T]> {
-        if self.v.is_empty() {
-            None
-        } else {
-            let sz = cmp::min(self.v.len(), self.chunk_size);
-            let tmp = mem::replace(&mut self.v, &mut []);
-            let tmp_len = tmp.len();
-            let (head, tail) = tmp.split_at_mut(tmp_len - sz);
-            self.v = head;
-            Some(tail)
-        }
-    }
-
-    #[inline]
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        if self.v.is_empty() {
-            (0, Some(0))
-        } else {
-            let n = self.v.len() / self.chunk_size;
-            let rem = self.v.len() % self.chunk_size;
-            let n = if rem > 0 { n + 1 } else { n };
-            (n, Some(n))
-        }
-    }
-
-    #[inline]
-    fn count(self) -> usize {
-        self.len()
-    }
-
-    #[inline]
-    fn nth(&mut self, n: usize) -> Option<&'a mut [T]> {
-        let (end, overflow) = n.overflowing_mul(self.chunk_size);
-        if end >= self.v.len() || overflow {
-            self.v = &mut [];
-            None
-        } else {
-            // Can't underflow because of the check above
-            let end = self.v.len() - end;
-            let start = match end.checked_sub(self.chunk_size) {
-                Some(sum) => sum,
-                None => 0,
-            };
-            let tmp = mem::replace(&mut self.v, &mut []);
-            let (head, tail) = tmp.split_at_mut(start);
-            let (nth, _) = tail.split_at_mut(end - start);
-            self.v = head;
-            Some(nth)
-        }
-    }
-
-    #[inline]
-    fn last(self) -> Option<Self::Item> {
-        if self.v.is_empty() {
-            None
-        } else {
-            let rem = self.v.len() % self.chunk_size;
-            let end = if rem == 0 { self.chunk_size } else { rem };
-            Some(&mut self.v[0..end])
-        }
-    }
-
-    #[doc(hidden)]
-    unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item {
-        let end = self.v.len() - idx * self.chunk_size;
-        let start = match end.checked_sub(self.chunk_size) {
-            None => 0,
-            Some(start) => start,
-        };
-        // SAFETY: see comments for `RChunks::get_unchecked` and `ChunksMut::get_unchecked`
-        unsafe { from_raw_parts_mut(self.v.as_mut_ptr().add(start), end - start) }
-    }
-}
-
-#[stable(feature = "rchunks", since = "1.31.0")]
-impl<'a, T> DoubleEndedIterator for RChunksMut<'a, T> {
-    #[inline]
-    fn next_back(&mut self) -> Option<&'a mut [T]> {
-        if self.v.is_empty() {
-            None
-        } else {
-            let remainder = self.v.len() % self.chunk_size;
-            let sz = if remainder != 0 { remainder } else { self.chunk_size };
-            let tmp = mem::replace(&mut self.v, &mut []);
-            let (head, tail) = tmp.split_at_mut(sz);
-            self.v = tail;
-            Some(head)
-        }
-    }
-
-    #[inline]
-    fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
-        let len = self.len();
-        if n >= len {
-            self.v = &mut [];
-            None
-        } else {
-            // can't underflow because `n < len`
-            let offset_from_end = (len - 1 - n) * self.chunk_size;
-            let end = self.v.len() - offset_from_end;
-            let start = end.saturating_sub(self.chunk_size);
-            let (tmp, tail) = mem::replace(&mut self.v, &mut []).split_at_mut(end);
-            let (_, nth_back) = tmp.split_at_mut(start);
-            self.v = tail;
-            Some(nth_back)
-        }
-    }
-}
-
-#[stable(feature = "rchunks", since = "1.31.0")]
-impl<T> ExactSizeIterator for RChunksMut<'_, T> {}
-
-#[unstable(feature = "trusted_len", issue = "37572")]
-unsafe impl<T> TrustedLen for RChunksMut<'_, T> {}
-
-#[stable(feature = "rchunks", since = "1.31.0")]
-impl<T> FusedIterator for RChunksMut<'_, T> {}
-
-#[doc(hidden)]
-#[unstable(feature = "trusted_random_access", issue = "none")]
-unsafe impl<'a, T> TrustedRandomAccess for RChunksMut<'a, T> {
-    fn may_have_side_effect() -> bool {
-        false
-    }
-}
-
-/// An iterator over a slice in (non-overlapping) chunks (`chunk_size` elements at a
-/// time), starting at the end of the slice.
-///
-/// When the slice len is not evenly divided by the chunk size, the last
-/// up to `chunk_size-1` elements will be omitted but can be retrieved from
-/// the [`remainder`] function from the iterator.
-///
-/// This struct is created by the [`rchunks_exact`] method on [slices].
-///
-/// [`rchunks_exact`]: ../../std/primitive.slice.html#method.rchunks_exact
-/// [`remainder`]: ChunksExact::remainder
-/// [slices]: ../../std/primitive.slice.html
-#[derive(Debug)]
-#[stable(feature = "rchunks", since = "1.31.0")]
-pub struct RChunksExact<'a, T: 'a> {
-    v: &'a [T],
-    rem: &'a [T],
-    chunk_size: usize,
-}
-
-impl<'a, T> RChunksExact<'a, T> {
-    /// Returns the remainder of the original slice that is not going to be
-    /// returned by the iterator. The returned slice has at most `chunk_size-1`
-    /// elements.
-    #[stable(feature = "rchunks", since = "1.31.0")]
-    pub fn remainder(&self) -> &'a [T] {
-        self.rem
-    }
-}
-
-// FIXME(#26925) Remove in favor of `#[derive(Clone)]`
-#[stable(feature = "rchunks", since = "1.31.0")]
-impl<'a, T> Clone for RChunksExact<'a, T> {
-    fn clone(&self) -> RChunksExact<'a, T> {
-        RChunksExact { v: self.v, rem: self.rem, chunk_size: self.chunk_size }
-    }
-}
-
-#[stable(feature = "rchunks", since = "1.31.0")]
-impl<'a, T> Iterator for RChunksExact<'a, T> {
-    type Item = &'a [T];
-
-    #[inline]
-    fn next(&mut self) -> Option<&'a [T]> {
-        if self.v.len() < self.chunk_size {
-            None
-        } else {
-            let (fst, snd) = self.v.split_at(self.v.len() - self.chunk_size);
-            self.v = fst;
-            Some(snd)
-        }
-    }
-
-    #[inline]
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        let n = self.v.len() / self.chunk_size;
-        (n, Some(n))
-    }
-
-    #[inline]
-    fn count(self) -> usize {
-        self.len()
-    }
-
-    #[inline]
-    fn nth(&mut self, n: usize) -> Option<Self::Item> {
-        let (end, overflow) = n.overflowing_mul(self.chunk_size);
-        if end >= self.v.len() || overflow {
-            self.v = &[];
-            None
-        } else {
-            let (fst, _) = self.v.split_at(self.v.len() - end);
-            self.v = fst;
-            self.next()
-        }
-    }
-
-    #[inline]
-    fn last(mut self) -> Option<Self::Item> {
-        self.next_back()
-    }
-
-    #[doc(hidden)]
-    unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item {
-        let end = self.v.len() - idx * self.chunk_size;
-        let start = end - self.chunk_size;
-        // SAFETY:
-        // SAFETY: mostmy identical to `Chunks::get_unchecked`.
-        unsafe { from_raw_parts(self.v.as_ptr().add(start), self.chunk_size) }
-    }
-}
-
-#[stable(feature = "rchunks", since = "1.31.0")]
-impl<'a, T> DoubleEndedIterator for RChunksExact<'a, T> {
-    #[inline]
-    fn next_back(&mut self) -> Option<&'a [T]> {
-        if self.v.len() < self.chunk_size {
-            None
-        } else {
-            let (fst, snd) = self.v.split_at(self.chunk_size);
-            self.v = snd;
-            Some(fst)
-        }
-    }
-
-    #[inline]
-    fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
-        let len = self.len();
-        if n >= len {
-            self.v = &[];
-            None
-        } else {
-            // now that we know that `n` corresponds to a chunk,
-            // none of these operations can underflow/overflow
-            let offset = (len - n) * self.chunk_size;
-            let start = self.v.len() - offset;
-            let end = start + self.chunk_size;
-            let nth_back = &self.v[start..end];
-            self.v = &self.v[end..];
-            Some(nth_back)
-        }
-    }
-}
-
-#[stable(feature = "rchunks", since = "1.31.0")]
-impl<'a, T> ExactSizeIterator for RChunksExact<'a, T> {
-    fn is_empty(&self) -> bool {
-        self.v.is_empty()
-    }
-}
-
-#[unstable(feature = "trusted_len", issue = "37572")]
-unsafe impl<T> TrustedLen for RChunksExact<'_, T> {}
-
-#[stable(feature = "rchunks", since = "1.31.0")]
-impl<T> FusedIterator for RChunksExact<'_, T> {}
-
-#[doc(hidden)]
-#[unstable(feature = "trusted_random_access", issue = "none")]
-unsafe impl<'a, T> TrustedRandomAccess for RChunksExact<'a, T> {
-    fn may_have_side_effect() -> bool {
-        false
-    }
-}
-
-/// An iterator over a slice in (non-overlapping) mutable chunks (`chunk_size`
-/// elements at a time), starting at the end of the slice.
-///
-/// When the slice len is not evenly divided by the chunk size, the last up to
-/// `chunk_size-1` elements will be omitted but can be retrieved from the
-/// [`into_remainder`] function from the iterator.
-///
-/// This struct is created by the [`rchunks_exact_mut`] method on [slices].
-///
-/// [`rchunks_exact_mut`]: ../../std/primitive.slice.html#method.rchunks_exact_mut
-/// [`into_remainder`]: ChunksExactMut::into_remainder
-/// [slices]: ../../std/primitive.slice.html
-#[derive(Debug)]
-#[stable(feature = "rchunks", since = "1.31.0")]
-pub struct RChunksExactMut<'a, T: 'a> {
-    v: &'a mut [T],
-    rem: &'a mut [T],
-    chunk_size: usize,
-}
-
-impl<'a, T> RChunksExactMut<'a, T> {
-    /// Returns the remainder of the original slice that is not going to be
-    /// returned by the iterator. The returned slice has at most `chunk_size-1`
-    /// elements.
-    #[stable(feature = "rchunks", since = "1.31.0")]
-    pub fn into_remainder(self) -> &'a mut [T] {
-        self.rem
-    }
-}
-
-#[stable(feature = "rchunks", since = "1.31.0")]
-impl<'a, T> Iterator for RChunksExactMut<'a, T> {
-    type Item = &'a mut [T];
-
-    #[inline]
-    fn next(&mut self) -> Option<&'a mut [T]> {
-        if self.v.len() < self.chunk_size {
-            None
-        } else {
-            let tmp = mem::replace(&mut self.v, &mut []);
-            let tmp_len = tmp.len();
-            let (head, tail) = tmp.split_at_mut(tmp_len - self.chunk_size);
-            self.v = head;
-            Some(tail)
-        }
-    }
-
-    #[inline]
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        let n = self.v.len() / self.chunk_size;
-        (n, Some(n))
-    }
-
-    #[inline]
-    fn count(self) -> usize {
-        self.len()
-    }
-
-    #[inline]
-    fn nth(&mut self, n: usize) -> Option<&'a mut [T]> {
-        let (end, overflow) = n.overflowing_mul(self.chunk_size);
-        if end >= self.v.len() || overflow {
-            self.v = &mut [];
-            None
-        } else {
-            let tmp = mem::replace(&mut self.v, &mut []);
-            let tmp_len = tmp.len();
-            let (fst, _) = tmp.split_at_mut(tmp_len - end);
-            self.v = fst;
-            self.next()
-        }
-    }
-
-    #[inline]
-    fn last(mut self) -> Option<Self::Item> {
-        self.next_back()
-    }
-
-    #[doc(hidden)]
-    unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item {
-        let end = self.v.len() - idx * self.chunk_size;
-        let start = end - self.chunk_size;
-        // SAFETY: see comments for `RChunksMut::get_unchecked`.
-        unsafe { from_raw_parts_mut(self.v.as_mut_ptr().add(start), self.chunk_size) }
-    }
-}
-
-#[stable(feature = "rchunks", since = "1.31.0")]
-impl<'a, T> DoubleEndedIterator for RChunksExactMut<'a, T> {
-    #[inline]
-    fn next_back(&mut self) -> Option<&'a mut [T]> {
-        if self.v.len() < self.chunk_size {
-            None
-        } else {
-            let tmp = mem::replace(&mut self.v, &mut []);
-            let (head, tail) = tmp.split_at_mut(self.chunk_size);
-            self.v = tail;
-            Some(head)
-        }
-    }
-
-    #[inline]
-    fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
-        let len = self.len();
-        if n >= len {
-            self.v = &mut [];
-            None
-        } else {
-            // now that we know that `n` corresponds to a chunk,
-            // none of these operations can underflow/overflow
-            let offset = (len - n) * self.chunk_size;
-            let start = self.v.len() - offset;
-            let end = start + self.chunk_size;
-            let (tmp, tail) = mem::replace(&mut self.v, &mut []).split_at_mut(end);
-            let (_, nth_back) = tmp.split_at_mut(start);
-            self.v = tail;
-            Some(nth_back)
-        }
-    }
-}
-
-#[stable(feature = "rchunks", since = "1.31.0")]
-impl<T> ExactSizeIterator for RChunksExactMut<'_, T> {
-    fn is_empty(&self) -> bool {
-        self.v.is_empty()
-    }
-}
-
-#[unstable(feature = "trusted_len", issue = "37572")]
-unsafe impl<T> TrustedLen for RChunksExactMut<'_, T> {}
-
-#[stable(feature = "rchunks", since = "1.31.0")]
-impl<T> FusedIterator for RChunksExactMut<'_, T> {}
-
-#[doc(hidden)]
-#[unstable(feature = "trusted_random_access", issue = "none")]
-unsafe impl<'a, T> TrustedRandomAccess for RChunksExactMut<'a, T> {
-    fn may_have_side_effect() -> bool {
-        false
-    }
-}
-
-//
-// Free functions
-//
-
-/// Forms a slice from a pointer and a length.
-///
-/// The `len` argument is the number of **elements**, not the number of bytes.
-///
-/// # Safety
-///
-/// Behavior is undefined if any of the following conditions are violated:
-///
-/// * `data` must be [valid] for reads for `len * mem::size_of::<T>()` many bytes,
-///   and it must be properly aligned. This means in particular:
-///
-///     * The entire memory range of this slice must be contained within a single allocated object!
-///       Slices can never span across multiple allocated objects. See [below](#incorrect-usage)
-///       for an example incorrectly not taking this into account.
-///     * `data` must be non-null and aligned even for zero-length slices. One
-///       reason for this is that enum layout optimizations may rely on references
-///       (including slices of any length) being aligned and non-null to distinguish
-///       them from other data. You can obtain a pointer that is usable as `data`
-///       for zero-length slices using [`NonNull::dangling()`].
-///
-/// * The memory referenced by the returned slice must not be mutated for the duration
-///   of lifetime `'a`, except inside an `UnsafeCell`.
-///
-/// * The total size `len * mem::size_of::<T>()` of the slice must be no larger than `isize::MAX`.
-///   See the safety documentation of [`pointer::offset`].
-///
-/// # Caveat
-///
-/// The lifetime for the returned slice is inferred from its usage. To
-/// prevent accidental misuse, it's suggested to tie the lifetime to whichever
-/// source lifetime is safe in the context, such as by providing a helper
-/// function taking the lifetime of a host value for the slice, or by explicit
-/// annotation.
-///
-/// # Examples
-///
-/// ```
-/// use std::slice;
-///
-/// // manifest a slice for a single element
-/// let x = 42;
-/// let ptr = &x as *const _;
-/// let slice = unsafe { slice::from_raw_parts(ptr, 1) };
-/// assert_eq!(slice[0], 42);
-/// ```
-///
-/// ### Incorrect usage
-///
-/// The following `join_slices` function is **unsound** ⚠️
-///
-/// ```rust,no_run
-/// use std::slice;
-///
-/// fn join_slices<'a, T>(fst: &'a [T], snd: &'a [T]) -> &'a [T] {
-///     let fst_end = fst.as_ptr().wrapping_add(fst.len());
-///     let snd_start = snd.as_ptr();
-///     assert_eq!(fst_end, snd_start, "Slices must be contiguous!");
-///     unsafe {
-///         // The assertion above ensures `fst` and `snd` are contiguous, but they might
-///         // still be contained within _different allocated objects_, in which case
-///         // creating this slice is undefined behavior.
-///         slice::from_raw_parts(fst.as_ptr(), fst.len() + snd.len())
-///     }
-/// }
-///
-/// fn main() {
-///     // `a` and `b` are different allocated objects...
-///     let a = 42;
-///     let b = 27;
-///     // ... which may nevertheless be laid out contiguously in memory: | a | b |
-///     let _ = join_slices(slice::from_ref(&a), slice::from_ref(&b)); // UB
-/// }
-/// ```
-///
-/// [valid]: ptr#safety
-/// [`NonNull::dangling()`]: ptr::NonNull::dangling
-/// [`pointer::offset`]: ../../std/primitive.pointer.html#method.offset
-#[inline]
-#[stable(feature = "rust1", since = "1.0.0")]
-pub unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] {
-    debug_assert!(is_aligned_and_not_null(data), "attempt to create unaligned or null slice");
-    debug_assert!(
-        mem::size_of::<T>().saturating_mul(len) <= isize::MAX as usize,
-        "attempt to create slice covering at least half the address space"
-    );
-    // SAFETY: the caller must uphold the safety contract for `from_raw_parts`.
-    unsafe { &*ptr::slice_from_raw_parts(data, len) }
-}
-
-/// Performs the same functionality as [`from_raw_parts`], except that a
-/// mutable slice is returned.
-///
-/// # Safety
-///
-/// Behavior is undefined if any of the following conditions are violated:
-///
-/// * `data` must be [valid] for boths reads and writes for `len * mem::size_of::<T>()` many bytes,
-///   and it must be properly aligned. This means in particular:
-///
-///     * The entire memory range of this slice must be contained within a single allocated object!
-///       Slices can never span across multiple allocated objects.
-///     * `data` must be non-null and aligned even for zero-length slices. One
-///       reason for this is that enum layout optimizations may rely on references
-///       (including slices of any length) being aligned and non-null to distinguish
-///       them from other data. You can obtain a pointer that is usable as `data`
-///       for zero-length slices using [`NonNull::dangling()`].
-///
-/// * The memory referenced by the returned slice must not be accessed through any other pointer
-///   (not derived from the return value) for the duration of lifetime `'a`.
-///   Both read and write accesses are forbidden.
-///
-/// * The total size `len * mem::size_of::<T>()` of the slice must be no larger than `isize::MAX`.
-///   See the safety documentation of [`pointer::offset`].
-///
-/// [valid]: ptr#safety
-/// [`NonNull::dangling()`]: ptr::NonNull::dangling
-/// [`pointer::offset`]: ../../std/primitive.pointer.html#method.offset
-#[inline]
-#[stable(feature = "rust1", since = "1.0.0")]
-pub unsafe fn from_raw_parts_mut<'a, T>(data: *mut T, len: usize) -> &'a mut [T] {
-    debug_assert!(is_aligned_and_not_null(data), "attempt to create unaligned or null slice");
-    debug_assert!(
-        mem::size_of::<T>().saturating_mul(len) <= isize::MAX as usize,
-        "attempt to create slice covering at least half the address space"
-    );
-    // SAFETY: the caller must uphold the safety contract for `from_raw_parts_mut`.
-    unsafe { &mut *ptr::slice_from_raw_parts_mut(data, len) }
-}
-
-/// Converts a reference to T into a slice of length 1 (without copying).
-#[stable(feature = "from_ref", since = "1.28.0")]
-pub fn from_ref<T>(s: &T) -> &[T] {
-    // SAFETY: a reference is guaranteed to be valid for reads. The returned
-    // reference cannot be mutated as it is an immutable reference.
-    // `mem::size_of::<T>()` cannot be larger than `isize::MAX`.
-    // Thus the call to `from_raw_parts` is safe.
-    unsafe { from_raw_parts(s, 1) }
-}
-
-/// Converts a reference to T into a slice of length 1 (without copying).
-#[stable(feature = "from_ref", since = "1.28.0")]
-pub fn from_mut<T>(s: &mut T) -> &mut [T] {
-    // SAFETY: a mutable reference is guaranteed to be valid for writes.
-    // The reference cannot be accessed by another pointer as it is an mutable reference.
-    // `mem::size_of::<T>()` cannot be larger than `isize::MAX`.
-    // Thus the call to `from_raw_parts_mut` is safe.
-    unsafe { from_raw_parts_mut(s, 1) }
-}
-
-// This function is public only because there is no other way to unit test heapsort.
-#[unstable(feature = "sort_internals", reason = "internal to sort module", issue = "none")]
-#[doc(hidden)]
-pub fn heapsort<T, F>(v: &mut [T], mut is_less: F)
-where
-    F: FnMut(&T, &T) -> bool,
-{
-    sort::heapsort(v, &mut is_less);
-}
-
-//
-// Comparison traits
-//
-
-extern "C" {
-    /// Calls implementation provided memcmp.
-    ///
-    /// Interprets the data as u8.
-    ///
-    /// Returns 0 for equal, < 0 for less than and > 0 for greater
-    /// than.
-    // FIXME(#32610): Return type should be c_int
-    fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32;
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<A, B> PartialEq<[B]> for [A]
-where
-    A: PartialEq<B>,
-{
-    fn eq(&self, other: &[B]) -> bool {
-        SlicePartialEq::equal(self, other)
-    }
-
-    fn ne(&self, other: &[B]) -> bool {
-        SlicePartialEq::not_equal(self, other)
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: Eq> Eq for [T] {}
-
-/// Implements comparison of vectors lexicographically.
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: Ord> Ord for [T] {
-    fn cmp(&self, other: &[T]) -> Ordering {
-        SliceOrd::compare(self, other)
-    }
-}
-
-/// Implements comparison of vectors lexicographically.
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: PartialOrd> PartialOrd for [T] {
-    fn partial_cmp(&self, other: &[T]) -> Option<Ordering> {
-        SlicePartialOrd::partial_compare(self, other)
-    }
-}
-
-#[doc(hidden)]
-// intermediate trait for specialization of slice's PartialEq
-trait SlicePartialEq<B> {
-    fn equal(&self, other: &[B]) -> bool;
-
-    fn not_equal(&self, other: &[B]) -> bool {
-        !self.equal(other)
-    }
-}
-
-// Generic slice equality
-impl<A, B> SlicePartialEq<B> for [A]
-where
-    A: PartialEq<B>,
-{
-    default fn equal(&self, other: &[B]) -> bool {
-        if self.len() != other.len() {
-            return false;
-        }
-
-        self.iter().zip(other.iter()).all(|(x, y)| x == y)
-    }
-}
-
-// Use an equal-pointer optimization when types are `Eq`
-// We can't make `A` and `B` the same type because `min_specialization` won't
-// allow it.
-impl<A, B> SlicePartialEq<B> for [A]
-where
-    A: MarkerEq<B>,
-{
-    default fn equal(&self, other: &[B]) -> bool {
-        if self.len() != other.len() {
-            return false;
-        }
-
-        // While performance would suffer if `guaranteed_eq` just returned `false`
-        // for all arguments, correctness and return value of this function are not affected.
-        if self.as_ptr().guaranteed_eq(other.as_ptr() as *const A) {
-            return true;
-        }
-
-        self.iter().zip(other.iter()).all(|(x, y)| x == y)
-    }
-}
-
-// Use memcmp for bytewise equality when the types allow
-impl<A, B> SlicePartialEq<B> for [A]
-where
-    A: BytewiseEquality<B>,
-{
-    fn equal(&self, other: &[B]) -> bool {
-        if self.len() != other.len() {
-            return false;
-        }
-
-        // While performance would suffer if `guaranteed_eq` just returned `false`
-        // for all arguments, correctness and return value of this function are not affected.
-        if self.as_ptr().guaranteed_eq(other.as_ptr() as *const A) {
-            return true;
-        }
-        // SAFETY: `self` and `other` are references and are thus guaranteed to be valid.
-        // The two slices have been checked to have the same size above.
-        unsafe {
-            let size = mem::size_of_val(self);
-            memcmp(self.as_ptr() as *const u8, other.as_ptr() as *const u8, size) == 0
-        }
-    }
-}
-
-#[doc(hidden)]
-// intermediate trait for specialization of slice's PartialOrd
-trait SlicePartialOrd: Sized {
-    fn partial_compare(left: &[Self], right: &[Self]) -> Option<Ordering>;
-}
-
-impl<A: PartialOrd> SlicePartialOrd for A {
-    default fn partial_compare(left: &[A], right: &[A]) -> Option<Ordering> {
-        let l = cmp::min(left.len(), right.len());
-
-        // Slice to the loop iteration range to enable bound check
-        // elimination in the compiler
-        let lhs = &left[..l];
-        let rhs = &right[..l];
-
-        for i in 0..l {
-            match lhs[i].partial_cmp(&rhs[i]) {
-                Some(Ordering::Equal) => (),
-                non_eq => return non_eq,
-            }
-        }
-
-        left.len().partial_cmp(&right.len())
-    }
-}
-
-// This is the impl that we would like to have. Unfortunately it's not sound.
-// See `partial_ord_slice.rs`.
-/*
-impl<A> SlicePartialOrd for A
-where
-    A: Ord,
-{
-    default fn partial_compare(left: &[A], right: &[A]) -> Option<Ordering> {
-        Some(SliceOrd::compare(left, right))
-    }
-}
-*/
-
-impl<A: AlwaysApplicableOrd> SlicePartialOrd for A {
-    fn partial_compare(left: &[A], right: &[A]) -> Option<Ordering> {
-        Some(SliceOrd::compare(left, right))
-    }
-}
-
-#[rustc_specialization_trait]
-trait AlwaysApplicableOrd: SliceOrd + Ord {}
-
-macro_rules! always_applicable_ord {
-    ($([$($p:tt)*] $t:ty,)*) => {
-        $(impl<$($p)*> AlwaysApplicableOrd for $t {})*
-    }
-}
-
-always_applicable_ord! {
-    [] u8, [] u16, [] u32, [] u64, [] u128, [] usize,
-    [] i8, [] i16, [] i32, [] i64, [] i128, [] isize,
-    [] bool, [] char,
-    [T: ?Sized] *const T, [T: ?Sized] *mut T,
-    [T: AlwaysApplicableOrd] &T,
-    [T: AlwaysApplicableOrd] &mut T,
-    [T: AlwaysApplicableOrd] Option<T>,
-}
-
-#[doc(hidden)]
-// intermediate trait for specialization of slice's Ord
-trait SliceOrd: Sized {
-    fn compare(left: &[Self], right: &[Self]) -> Ordering;
-}
-
-impl<A: Ord> SliceOrd for A {
-    default fn compare(left: &[Self], right: &[Self]) -> Ordering {
-        let l = cmp::min(left.len(), right.len());
-
-        // Slice to the loop iteration range to enable bound check
-        // elimination in the compiler
-        let lhs = &left[..l];
-        let rhs = &right[..l];
-
-        for i in 0..l {
-            match lhs[i].cmp(&rhs[i]) {
-                Ordering::Equal => (),
-                non_eq => return non_eq,
-            }
-        }
-
-        left.len().cmp(&right.len())
-    }
-}
-
-// memcmp compares a sequence of unsigned bytes lexicographically.
-// this matches the order we want for [u8], but no others (not even [i8]).
-impl SliceOrd for u8 {
-    #[inline]
-    fn compare(left: &[Self], right: &[Self]) -> Ordering {
-        let order =
-            // SAFETY: `left` and `right` are references and are thus guaranteed to be valid.
-            // We use the minimum of both lengths which guarantees that both regions are
-            // valid for reads in that interval.
-            unsafe { memcmp(left.as_ptr(), right.as_ptr(), cmp::min(left.len(), right.len())) };
-        if order == 0 {
-            left.len().cmp(&right.len())
-        } else if order < 0 {
-            Less
-        } else {
-            Greater
-        }
-    }
-}
-
-// Hack to allow specializing on `Eq` even though `Eq` has a method.
-#[rustc_unsafe_specialization_marker]
-trait MarkerEq<T>: PartialEq<T> {}
-
-impl<T: Eq> MarkerEq<T> for T {}
-
-#[doc(hidden)]
-/// Trait implemented for types that can be compared for equality using
-/// their bytewise representation
-#[rustc_specialization_trait]
-trait BytewiseEquality<T>: MarkerEq<T> + Copy {}
-
-macro_rules! impl_marker_for {
-    ($traitname:ident, $($ty:ty)*) => {
-        $(
-            impl $traitname<$ty> for $ty { }
-        )*
-    }
-}
-
-impl_marker_for!(BytewiseEquality,
-                 u8 i8 u16 i16 u32 i32 u64 i64 u128 i128 usize isize char bool);
-
-#[doc(hidden)]
-#[unstable(feature = "trusted_random_access", issue = "none")]
-unsafe impl<'a, T> TrustedRandomAccess for Iter<'a, T> {
-    fn may_have_side_effect() -> bool {
-        false
-    }
-}
-
-#[doc(hidden)]
-#[unstable(feature = "trusted_random_access", issue = "none")]
-unsafe impl<'a, T> TrustedRandomAccess for IterMut<'a, T> {
-    fn may_have_side_effect() -> bool {
-        false
-    }
-}
-
-trait SliceContains: Sized {
-    fn slice_contains(&self, x: &[Self]) -> bool;
-}
-
-impl<T> SliceContains for T
-where
-    T: PartialEq,
-{
-    default fn slice_contains(&self, x: &[Self]) -> bool {
-        x.iter().any(|y| *y == *self)
-    }
-}
-
-impl SliceContains for u8 {
-    fn slice_contains(&self, x: &[Self]) -> bool {
-        memchr::memchr(*self, x).is_some()
-    }
-}
-
-impl SliceContains for i8 {
-    fn slice_contains(&self, x: &[Self]) -> bool {
-        let byte = *self as u8;
-        // SAFETY: `i8` and `u8` have the same memory layout, thus casting `x.as_ptr()`
-        // as `*const u8` is safe. The `x.as_ptr()` comes from a reference and is thus guaranteed
-        // to be valid for reads for the length of the slice `x.len()`, which cannot be larger
-        // than `isize::MAX`. The returned slice is never mutated.
-        let bytes: &[u8] = unsafe { from_raw_parts(x.as_ptr() as *const u8, x.len()) };
-        memchr::memchr(byte, bytes).is_some()
-    }
-}
diff --git a/library/core/src/slice/raw.rs b/library/core/src/slice/raw.rs
new file mode 100644 (file)
index 0000000..a5811c5
--- /dev/null
@@ -0,0 +1,158 @@
+//! Free functions to create `&[T]` and `&mut [T]`.
+
+use crate::intrinsics::is_aligned_and_not_null;
+use crate::mem;
+use crate::ptr;
+
+/// Forms a slice from a pointer and a length.
+///
+/// The `len` argument is the number of **elements**, not the number of bytes.
+///
+/// # Safety
+///
+/// Behavior is undefined if any of the following conditions are violated:
+///
+/// * `data` must be [valid] for reads for `len * mem::size_of::<T>()` many bytes,
+///   and it must be properly aligned. This means in particular:
+///
+///     * The entire memory range of this slice must be contained within a single allocated object!
+///       Slices can never span across multiple allocated objects. See [below](#incorrect-usage)
+///       for an example incorrectly not taking this into account.
+///     * `data` must be non-null and aligned even for zero-length slices. One
+///       reason for this is that enum layout optimizations may rely on references
+///       (including slices of any length) being aligned and non-null to distinguish
+///       them from other data. You can obtain a pointer that is usable as `data`
+///       for zero-length slices using [`NonNull::dangling()`].
+///
+/// * `data` must point to `len` consecutive properly initialized values of type `T`.
+///
+/// * The memory referenced by the returned slice must not be mutated for the duration
+///   of lifetime `'a`, except inside an `UnsafeCell`.
+///
+/// * The total size `len * mem::size_of::<T>()` of the slice must be no larger than `isize::MAX`.
+///   See the safety documentation of [`pointer::offset`].
+///
+/// # Caveat
+///
+/// The lifetime for the returned slice is inferred from its usage. To
+/// prevent accidental misuse, it's suggested to tie the lifetime to whichever
+/// source lifetime is safe in the context, such as by providing a helper
+/// function taking the lifetime of a host value for the slice, or by explicit
+/// annotation.
+///
+/// # Examples
+///
+/// ```
+/// use std::slice;
+///
+/// // manifest a slice for a single element
+/// let x = 42;
+/// let ptr = &x as *const _;
+/// let slice = unsafe { slice::from_raw_parts(ptr, 1) };
+/// assert_eq!(slice[0], 42);
+/// ```
+///
+/// ### Incorrect usage
+///
+/// The following `join_slices` function is **unsound** ⚠️
+///
+/// ```rust,no_run
+/// use std::slice;
+///
+/// fn join_slices<'a, T>(fst: &'a [T], snd: &'a [T]) -> &'a [T] {
+///     let fst_end = fst.as_ptr().wrapping_add(fst.len());
+///     let snd_start = snd.as_ptr();
+///     assert_eq!(fst_end, snd_start, "Slices must be contiguous!");
+///     unsafe {
+///         // The assertion above ensures `fst` and `snd` are contiguous, but they might
+///         // still be contained within _different allocated objects_, in which case
+///         // creating this slice is undefined behavior.
+///         slice::from_raw_parts(fst.as_ptr(), fst.len() + snd.len())
+///     }
+/// }
+///
+/// fn main() {
+///     // `a` and `b` are different allocated objects...
+///     let a = 42;
+///     let b = 27;
+///     // ... which may nevertheless be laid out contiguously in memory: | a | b |
+///     let _ = join_slices(slice::from_ref(&a), slice::from_ref(&b)); // UB
+/// }
+/// ```
+///
+/// [valid]: ptr#safety
+/// [`NonNull::dangling()`]: ptr::NonNull::dangling
+/// [`pointer::offset`]: ../../std/primitive.pointer.html#method.offset
+#[inline]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] {
+    debug_assert!(is_aligned_and_not_null(data), "attempt to create unaligned or null slice");
+    debug_assert!(
+        mem::size_of::<T>().saturating_mul(len) <= isize::MAX as usize,
+        "attempt to create slice covering at least half the address space"
+    );
+    // SAFETY: the caller must uphold the safety contract for `from_raw_parts`.
+    unsafe { &*ptr::slice_from_raw_parts(data, len) }
+}
+
+/// Performs the same functionality as [`from_raw_parts`], except that a
+/// mutable slice is returned.
+///
+/// # Safety
+///
+/// Behavior is undefined if any of the following conditions are violated:
+///
+/// * `data` must be [valid] for boths reads and writes for `len * mem::size_of::<T>()` many bytes,
+///   and it must be properly aligned. This means in particular:
+///
+///     * The entire memory range of this slice must be contained within a single allocated object!
+///       Slices can never span across multiple allocated objects.
+///     * `data` must be non-null and aligned even for zero-length slices. One
+///       reason for this is that enum layout optimizations may rely on references
+///       (including slices of any length) being aligned and non-null to distinguish
+///       them from other data. You can obtain a pointer that is usable as `data`
+///       for zero-length slices using [`NonNull::dangling()`].
+///
+/// * `data` must point to `len` consecutive properly initialized values of type `T`.
+///
+/// * The memory referenced by the returned slice must not be accessed through any other pointer
+///   (not derived from the return value) for the duration of lifetime `'a`.
+///   Both read and write accesses are forbidden.
+///
+/// * The total size `len * mem::size_of::<T>()` of the slice must be no larger than `isize::MAX`.
+///   See the safety documentation of [`pointer::offset`].
+///
+/// [valid]: ptr#safety
+/// [`NonNull::dangling()`]: ptr::NonNull::dangling
+/// [`pointer::offset`]: ../../std/primitive.pointer.html#method.offset
+#[inline]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub unsafe fn from_raw_parts_mut<'a, T>(data: *mut T, len: usize) -> &'a mut [T] {
+    debug_assert!(is_aligned_and_not_null(data), "attempt to create unaligned or null slice");
+    debug_assert!(
+        mem::size_of::<T>().saturating_mul(len) <= isize::MAX as usize,
+        "attempt to create slice covering at least half the address space"
+    );
+    // SAFETY: the caller must uphold the safety contract for `from_raw_parts_mut`.
+    unsafe { &mut *ptr::slice_from_raw_parts_mut(data, len) }
+}
+
+/// Converts a reference to T into a slice of length 1 (without copying).
+#[stable(feature = "from_ref", since = "1.28.0")]
+pub fn from_ref<T>(s: &T) -> &[T] {
+    // SAFETY: a reference is guaranteed to be valid for reads. The returned
+    // reference cannot be mutated as it is an immutable reference.
+    // `mem::size_of::<T>()` cannot be larger than `isize::MAX`.
+    // Thus the call to `from_raw_parts` is safe.
+    unsafe { from_raw_parts(s, 1) }
+}
+
+/// Converts a reference to T into a slice of length 1 (without copying).
+#[stable(feature = "from_ref", since = "1.28.0")]
+pub fn from_mut<T>(s: &mut T) -> &mut [T] {
+    // SAFETY: a mutable reference is guaranteed to be valid for writes.
+    // The reference cannot be accessed by another pointer as it is an mutable reference.
+    // `mem::size_of::<T>()` cannot be larger than `isize::MAX`.
+    // Thus the call to `from_raw_parts_mut` is safe.
+    unsafe { from_raw_parts_mut(s, 1) }
+}
index 4a00124fcff3e764455d26116c251d3cee59b917..8c14651bd826cd4881f545a8d16d9446bf234037 100644 (file)
@@ -180,7 +180,8 @@ fn insertion_sort<T, F>(v: &mut [T], is_less: &mut F)
 
 /// Sorts `v` using heapsort, which guarantees *O*(*n* \* log(*n*)) worst-case.
 #[cold]
-pub fn heapsort<T, F>(v: &mut [T], is_less: &mut F)
+#[unstable(feature = "sort_internals", reason = "internal to sort module", issue = "none")]
+pub fn heapsort<T, F>(v: &mut [T], mut is_less: F)
 where
     F: FnMut(&T, &T) -> bool,
 {
index 38eabaaa396e0df3bea563d46b4d5f82ea01454c..9d74f537491b1d076967137cbfeee1cdbc7defdc 100644 (file)
 use crate::cell::UnsafeCell;
 use crate::fmt;
 use crate::intrinsics;
+use crate::mem::align_of;
 
 use crate::hint::spin_loop;
 
@@ -327,6 +328,27 @@ pub fn get_mut(&mut self) -> &mut bool {
         unsafe { &mut *(self.v.get() as *mut bool) }
     }
 
+    /// Get atomic access to a `&mut bool`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(atomic_from_mut)]
+    /// use std::sync::atomic::{AtomicBool, Ordering};
+    ///
+    /// let mut some_bool = true;
+    /// let a = AtomicBool::from_mut(&mut some_bool);
+    /// a.store(false, Ordering::Relaxed);
+    /// assert_eq!(some_bool, false);
+    /// ```
+    #[inline]
+    #[unstable(feature = "atomic_from_mut", issue = "76314")]
+    pub fn from_mut(v: &mut bool) -> &Self {
+        // SAFETY: the mutable reference guarantees unique ownership, and
+        // alignment of both `bool` and `Self` is 1.
+        unsafe { &*(v as *mut bool as *mut Self) }
+    }
+
     /// Consumes the atomic and returns the contained value.
     ///
     /// This is safe because passing `self` by value guarantees that no other threads are
@@ -820,6 +842,30 @@ pub fn get_mut(&mut self) -> &mut *mut T {
         unsafe { &mut *self.p.get() }
     }
 
+    /// Get atomic access to a pointer.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(atomic_from_mut)]
+    /// use std::sync::atomic::{AtomicPtr, Ordering};
+    ///
+    /// let mut some_ptr = &mut 123 as *mut i32;
+    /// let a = AtomicPtr::from_mut(&mut some_ptr);
+    /// a.store(&mut 456, Ordering::Relaxed);
+    /// assert_eq!(unsafe { *some_ptr }, 456);
+    /// ```
+    #[inline]
+    #[unstable(feature = "atomic_from_mut", issue = "76314")]
+    pub fn from_mut(v: &mut *mut T) -> &Self {
+        let [] = [(); align_of::<AtomicPtr<()>>() - align_of::<*mut ()>()];
+        // SAFETY:
+        //  - the mutable reference guarantees unique ownership.
+        //  - the alignment of `*mut T` and `Self` is the same on all platforms
+        //    supported by rust, as verified above.
+        unsafe { &*(v as *mut *mut T as *mut Self) }
+    }
+
     /// Consumes the atomic and returns the contained value.
     ///
     /// This is safe because passing `self` by value guarantees that no other threads are
@@ -1104,6 +1150,13 @@ fn from(p: *mut T) -> Self {
     }
 }
 
+#[allow(unused_macros)] // This macro ends up being unused on some architectures.
+macro_rules! if_not_8_bit {
+    (u8, $($tt:tt)*) => { "" };
+    (i8, $($tt:tt)*) => { "" };
+    ($_:ident, $($tt:tt)*) => { $($tt)* };
+}
+
 #[cfg(target_has_atomic_load_store = "8")]
 macro_rules! atomic_int {
     ($cfg_cas:meta,
@@ -1115,7 +1168,8 @@ macro_rules! atomic_int {
      $stable_nand:meta,
      $const_stable:meta,
      $stable_init_const:meta,
-     $s_int_type:expr, $int_ref:expr,
+     $(from_mut: cfg($from_mut_cfg:meta),)?
+     $s_int_type:literal, $int_ref:expr,
      $extra_feature:expr,
      $min_fn:ident, $max_fn:ident,
      $align:expr,
@@ -1226,6 +1280,45 @@ pub fn get_mut(&mut self) -> &mut $int_type {
                 }
             }
 
+            doc_comment! {
+                concat!("Get atomic access to a `&mut ", stringify!($int_type), "`.
+
+",
+if_not_8_bit! {
+    $int_type,
+    concat!(
+        "**Note:** This function is only available on targets where `",
+        stringify!($int_type), "` has an alignment of ", $align, " bytes."
+    )
+},
+"
+
+# Examples
+
+```
+#![feature(atomic_from_mut)]
+", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};
+
+let mut some_int = 123;
+let a = ", stringify!($atomic_type), "::from_mut(&mut some_int);
+a.store(100, Ordering::Relaxed);
+assert_eq!(some_int, 100);
+```
+                "),
+                #[inline]
+                $(#[cfg($from_mut_cfg)])?
+                #[unstable(feature = "atomic_from_mut", issue = "76314")]
+                pub fn from_mut(v: &mut $int_type) -> &Self {
+                    let [] = [(); align_of::<Self>() - align_of::<$int_type>()];
+                    // SAFETY:
+                    //  - the mutable reference guarantees unique ownership.
+                    //  - the alignment of `$int_type` and `Self` is the
+                    //    same on all platforms enabled by `$from_mut_cfg`
+                    //    as verified above.
+                    unsafe { &*(v as *mut $int_type as *mut Self) }
+                }
+            }
+
             doc_comment! {
                 concat!("Consumes the atomic and returns the contained value.
 
@@ -1984,6 +2077,7 @@ pub fn as_mut_ptr(&self) -> *mut $int_type {
     stable(feature = "integer_atomics_stable", since = "1.34.0"),
     rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
     unstable(feature = "integer_atomics", issue = "32976"),
+    from_mut: cfg(not(target_arch = "x86")),
     "i64", "../../../std/primitive.i64.html",
     "",
     atomic_min, atomic_max,
@@ -2002,6 +2096,7 @@ pub fn as_mut_ptr(&self) -> *mut $int_type {
     stable(feature = "integer_atomics_stable", since = "1.34.0"),
     rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
     unstable(feature = "integer_atomics", issue = "32976"),
+    from_mut: cfg(not(target_arch = "x86")),
     "u64", "../../../std/primitive.u64.html",
     "",
     atomic_umin, atomic_umax,
@@ -2020,6 +2115,7 @@ pub fn as_mut_ptr(&self) -> *mut $int_type {
     unstable(feature = "integer_atomics", issue = "32976"),
     rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
     unstable(feature = "integer_atomics", issue = "32976"),
+    from_mut: cfg(not(target_arch = "x86_64")),
     "i128", "../../../std/primitive.i128.html",
     "#![feature(integer_atomics)]\n\n",
     atomic_min, atomic_max,
@@ -2038,6 +2134,7 @@ pub fn as_mut_ptr(&self) -> *mut $int_type {
     unstable(feature = "integer_atomics", issue = "32976"),
     rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
     unstable(feature = "integer_atomics", issue = "32976"),
+    from_mut: cfg(not(target_arch = "x86_64")),
     "u128", "../../../std/primitive.u128.html",
     "#![feature(integer_atomics)]\n\n",
     atomic_umin, atomic_umax,
index 9383e7c45fa55b6c29b1ebd56346842b4b844b09..4e987a53b2cb236f12fd3618c80c579431bc56b5 100644 (file)
@@ -112,6 +112,14 @@ pub fn map_err<U, F>(self, f: F) -> Poll<Option<Result<T, U>>>
 
 #[stable(feature = "futures_api", since = "1.36.0")]
 impl<T> From<T> for Poll<T> {
+    /// Convert to a `Ready` variant.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// # use core::task::Poll;
+    /// assert_eq!(Poll::from(true), Poll::Ready(true));
+    /// ```
     fn from(t: T) -> Poll<T> {
         Poll::Ready(t)
     }
index f39781788d7c04e09a5da36744a9ab77e5b37553..6dc542dee58e65ff280a4c0b343aaea322457413 100644 (file)
@@ -693,7 +693,8 @@ pub const fn as_secs_f32(&self) -> f32 {
     /// ```
     #[stable(feature = "duration_float", since = "1.38.0")]
     #[inline]
-    pub fn from_secs_f64(secs: f64) -> Duration {
+    #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")]
+    pub const fn from_secs_f64(secs: f64) -> Duration {
         const MAX_NANOS_F64: f64 = ((u64::MAX as u128 + 1) * (NANOS_PER_SEC as u128)) as f64;
         let nanos = secs * (NANOS_PER_SEC as f64);
         if !nanos.is_finite() {
@@ -727,7 +728,8 @@ pub fn from_secs_f64(secs: f64) -> Duration {
     /// ```
     #[stable(feature = "duration_float", since = "1.38.0")]
     #[inline]
-    pub fn from_secs_f32(secs: f32) -> Duration {
+    #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")]
+    pub const fn from_secs_f32(secs: f32) -> Duration {
         const MAX_NANOS_F32: f32 = ((u64::MAX as u128 + 1) * (NANOS_PER_SEC as u128)) as f32;
         let nanos = secs * (NANOS_PER_SEC as f32);
         if !nanos.is_finite() {
@@ -761,7 +763,8 @@ pub fn from_secs_f32(secs: f32) -> Duration {
     /// ```
     #[stable(feature = "duration_float", since = "1.38.0")]
     #[inline]
-    pub fn mul_f64(self, rhs: f64) -> Duration {
+    #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")]
+    pub const fn mul_f64(self, rhs: f64) -> Duration {
         Duration::from_secs_f64(rhs * self.as_secs_f64())
     }
 
@@ -782,7 +785,8 @@ pub fn mul_f64(self, rhs: f64) -> Duration {
     /// ```
     #[stable(feature = "duration_float", since = "1.38.0")]
     #[inline]
-    pub fn mul_f32(self, rhs: f32) -> Duration {
+    #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")]
+    pub const fn mul_f32(self, rhs: f32) -> Duration {
         Duration::from_secs_f32(rhs * self.as_secs_f32())
     }
 
@@ -802,7 +806,8 @@ pub fn mul_f32(self, rhs: f32) -> Duration {
     /// ```
     #[stable(feature = "duration_float", since = "1.38.0")]
     #[inline]
-    pub fn div_f64(self, rhs: f64) -> Duration {
+    #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")]
+    pub const fn div_f64(self, rhs: f64) -> Duration {
         Duration::from_secs_f64(self.as_secs_f64() / rhs)
     }
 
@@ -824,7 +829,8 @@ pub fn div_f64(self, rhs: f64) -> Duration {
     /// ```
     #[stable(feature = "duration_float", since = "1.38.0")]
     #[inline]
-    pub fn div_f32(self, rhs: f32) -> Duration {
+    #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")]
+    pub const fn div_f32(self, rhs: f32) -> Duration {
         Duration::from_secs_f32(self.as_secs_f32() / rhs)
     }
 
index 4086917780fa4ae46ac17834567e5e34f6571fab..835289daf715adf936723f10b62f145248491640 100644 (file)
@@ -1,4 +1,7 @@
-use core::cmp::{self, Ordering::*};
+use core::cmp::{
+    self,
+    Ordering::{self, *},
+};
 
 #[test]
 fn test_int_totalord() {
@@ -116,3 +119,16 @@ fn eq(&self, other: &SketchyNum) -> bool {
     assert!(SketchyNum { num: 37 } == SketchyNum { num: 34 });
     assert!(SketchyNum { num: 25 } != SketchyNum { num: 57 });
 }
+
+#[test]
+fn ordering_const() {
+    // test that the methods of `Ordering` are usable in a const context
+
+    const ORDERING: Ordering = Greater;
+
+    const REVERSE: Ordering = ORDERING.reverse();
+    assert_eq!(REVERSE, Less);
+
+    const THEN: Ordering = Equal.then(ORDERING);
+    assert_eq!(THEN, Greater);
+}
index a2e294ace1860f2226350fb80c1df9fd2c647e82..a5b1b51e06c64ebea26e19a3d3b54a486d7579ac 100644 (file)
@@ -2,6 +2,7 @@
 #![feature(array_chunks)]
 #![feature(array_methods)]
 #![feature(array_map)]
+#![feature(array_windows)]
 #![feature(bool_to_option)]
 #![feature(bound_cloned)]
 #![feature(box_syntax)]
 #![feature(core_private_diy_float)]
 #![feature(debug_non_exhaustive)]
 #![feature(dec2flt)]
+#![feature(div_duration)]
+#![feature(duration_consts_2)]
 #![feature(duration_constants)]
 #![feature(duration_saturating_ops)]
+#![feature(duration_zero)]
 #![feature(exact_size_is_empty)]
 #![feature(fixed_size_array)]
 #![feature(flt2dec)]
index 39250ee84bce6d1f28485c052048f7d316205586..4acc760ffac9907e0d22509c140a679a82009572 100644 (file)
@@ -1 +1,30 @@
 int_module!(i32, i32);
+
+#[test]
+fn test_arith_operation() {
+    let a: isize = 10;
+    assert_eq!(a * (a - 1), 90);
+    let i32_a: isize = 10;
+    assert_eq!(i32_a, 10);
+    assert_eq!(i32_a - 10, 0);
+    assert_eq!(i32_a / 10, 1);
+    assert_eq!(i32_a - 20, -10);
+    assert_eq!(i32_a << 10, 10240);
+    assert_eq!(i32_a << 16, 655360);
+    assert_eq!(i32_a * 16, 160);
+    assert_eq!(i32_a * i32_a * i32_a, 1000);
+    assert_eq!(i32_a * i32_a * i32_a * i32_a, 10000);
+    assert_eq!(i32_a * i32_a / i32_a * i32_a, 100);
+    assert_eq!(i32_a * (i32_a - 1) << (2 + i32_a as usize), 368640);
+    let i32_b: isize = 0x10101010;
+    assert_eq!(i32_b + 1 - 1, i32_b);
+    assert_eq!(i32_b << 1, i32_b << 1);
+    assert_eq!(i32_b >> 1, i32_b >> 1);
+    assert_eq!(i32_b & i32_b << 1, 0);
+    assert_eq!(i32_b | i32_b << 1, 0x30303030);
+    let i32_c: isize = 0x10101010;
+    assert_eq!(
+        i32_c + i32_c * 2 / 3 * 2 + (i32_c - 7 % 3),
+        i32_c + i32_c * 2 / 3 * 2 + (i32_c - 7 % 3)
+    );
+}
index 9b31e532a6a9fc2f6d8f41d7f070faf0757c2463..9556d43f9d78b3e9864ca1a6d78d4479ff7fb318 100644 (file)
@@ -657,6 +657,55 @@ fn test_array_chunks_mut_zip() {
     assert_eq!(v1, [13, 14, 19, 20, 4]);
 }
 
+#[test]
+fn test_array_windows_infer() {
+    let v: &[i32] = &[0, 1, 0, 1];
+    assert_eq!(v.array_windows::<2>().count(), 3);
+    let c = v.array_windows();
+    for &[a, b] in c {
+        assert_eq!(a + b, 1);
+    }
+
+    let v2: &[i32] = &[0, 1, 2, 3, 4, 5, 6];
+    let total = v2.array_windows().map(|&[a, b, c]| a + b + c).sum::<i32>();
+    assert_eq!(total, 3 + 6 + 9 + 12 + 15);
+}
+
+#[test]
+fn test_array_windows_count() {
+    let v: &[i32] = &[0, 1, 2, 3, 4, 5];
+    let c = v.array_windows::<3>();
+    assert_eq!(c.count(), 4);
+
+    let v2: &[i32] = &[0, 1, 2, 3, 4];
+    let c2 = v2.array_windows::<6>();
+    assert_eq!(c2.count(), 0);
+
+    let v3: &[i32] = &[];
+    let c3 = v3.array_windows::<2>();
+    assert_eq!(c3.count(), 0);
+}
+
+#[test]
+fn test_array_windows_nth() {
+    let v: &[i32] = &[0, 1, 2, 3, 4, 5];
+    let snd = v.array_windows::<4>().nth(1);
+    assert_eq!(snd, Some(&[1, 2, 3, 4]));
+    let mut arr_windows = v.array_windows::<2>();
+    assert_ne!(arr_windows.nth(0), arr_windows.nth(0));
+    let last = v.array_windows::<3>().last();
+    assert_eq!(last, Some(&[3, 4, 5]));
+}
+
+#[test]
+fn test_array_windows_nth_back() {
+    let v: &[i32] = &[0, 1, 2, 3, 4, 5];
+    let snd = v.array_windows::<4>().nth_back(1);
+    assert_eq!(snd, Some(&[1, 2, 3, 4]));
+    let mut arr_windows = v.array_windows::<2>();
+    assert_ne!(arr_windows.nth_back(0), arr_windows.nth_back(0));
+}
+
 #[test]
 fn test_rchunks_count() {
     let v: &[i32] = &[0, 1, 2, 3, 4, 5];
index 4f90eb63b0472393c2d8e7beeaef66b9f56d0cdb..7c43885040b3e3fde6fdad5eca2dca12eb6d2189 100644 (file)
@@ -321,3 +321,104 @@ fn debug_formatting_precision_high() {
     assert_eq!(format!("{:.10?}", Duration::new(4, 001_000_000)), "4.0010000000s");
     assert_eq!(format!("{:.20?}", Duration::new(4, 001_000_000)), "4.00100000000000000000s");
 }
+
+#[test]
+fn duration_const() {
+    // test that the methods of `Duration` are usable in a const context
+
+    const DURATION: Duration = Duration::new(0, 123_456_789);
+
+    const SUB_SEC_MILLIS: u32 = DURATION.subsec_millis();
+    assert_eq!(SUB_SEC_MILLIS, 123);
+
+    const SUB_SEC_MICROS: u32 = DURATION.subsec_micros();
+    assert_eq!(SUB_SEC_MICROS, 123_456);
+
+    const SUB_SEC_NANOS: u32 = DURATION.subsec_nanos();
+    assert_eq!(SUB_SEC_NANOS, 123_456_789);
+
+    const ZERO: Duration = Duration::zero();
+    assert_eq!(ZERO, Duration::new(0, 0));
+
+    const IS_ZERO: bool = ZERO.is_zero();
+    assert!(IS_ZERO);
+
+    const ONE: Duration = Duration::new(1, 0);
+
+    const SECONDS: u64 = ONE.as_secs();
+    assert_eq!(SECONDS, 1);
+
+    const FROM_SECONDS: Duration = Duration::from_secs(1);
+    assert_eq!(FROM_SECONDS, ONE);
+
+    const SECONDS_F32: f32 = ONE.as_secs_f32();
+    assert_eq!(SECONDS_F32, 1.0);
+
+    const FROM_SECONDS_F32: Duration = Duration::from_secs_f32(1.0);
+    assert_eq!(FROM_SECONDS_F32, ONE);
+
+    const SECONDS_F64: f64 = ONE.as_secs_f64();
+    assert_eq!(SECONDS_F64, 1.0);
+
+    const FROM_SECONDS_F64: Duration = Duration::from_secs_f64(1.0);
+    assert_eq!(FROM_SECONDS_F64, ONE);
+
+    const MILLIS: u128 = ONE.as_millis();
+    assert_eq!(MILLIS, 1_000);
+
+    const FROM_MILLIS: Duration = Duration::from_millis(1_000);
+    assert_eq!(FROM_MILLIS, ONE);
+
+    const MICROS: u128 = ONE.as_micros();
+    assert_eq!(MICROS, 1_000_000);
+
+    const FROM_MICROS: Duration = Duration::from_micros(1_000_000);
+    assert_eq!(FROM_MICROS, ONE);
+
+    const NANOS: u128 = ONE.as_nanos();
+    assert_eq!(NANOS, 1_000_000_000);
+
+    const FROM_NANOS: Duration = Duration::from_nanos(1_000_000_000);
+    assert_eq!(FROM_NANOS, ONE);
+
+    const MAX: Duration = Duration::new(u64::MAX, 999_999_999);
+
+    const CHECKED_ADD: Option<Duration> = MAX.checked_add(ONE);
+    assert_eq!(CHECKED_ADD, None);
+
+    const CHECKED_SUB: Option<Duration> = ZERO.checked_sub(ONE);
+    assert_eq!(CHECKED_SUB, None);
+
+    const CHECKED_MUL: Option<Duration> = ONE.checked_mul(1);
+    assert_eq!(CHECKED_MUL, Some(ONE));
+
+    const MUL_F32: Duration = ONE.mul_f32(1.0);
+    assert_eq!(MUL_F32, ONE);
+
+    const MUL_F64: Duration = ONE.mul_f64(1.0);
+    assert_eq!(MUL_F64, ONE);
+
+    const CHECKED_DIV: Option<Duration> = ONE.checked_div(1);
+    assert_eq!(CHECKED_DIV, Some(ONE));
+
+    const DIV_F32: Duration = ONE.div_f32(1.0);
+    assert_eq!(DIV_F32, ONE);
+
+    const DIV_F64: Duration = ONE.div_f64(1.0);
+    assert_eq!(DIV_F64, ONE);
+
+    const DIV_DURATION_F32: f32 = ONE.div_duration_f32(ONE);
+    assert_eq!(DIV_DURATION_F32, 1.0);
+
+    const DIV_DURATION_F64: f64 = ONE.div_duration_f64(ONE);
+    assert_eq!(DIV_DURATION_F64, 1.0);
+
+    const SATURATING_ADD: Duration = MAX.saturating_add(ONE);
+    assert_eq!(SATURATING_ADD, MAX);
+
+    const SATURATING_SUB: Duration = ZERO.saturating_sub(ONE);
+    assert_eq!(SATURATING_SUB, ZERO);
+
+    const SATURATING_MUL: Duration = MAX.saturating_mul(2);
+    assert_eq!(SATURATING_MUL, MAX);
+}
index 091e2091fb09576c37a259d3a8a408583aef9298..e0095e64faf312502398333fc434f609b437ef8e 100644 (file)
@@ -7,7 +7,7 @@
     cell::{Cell, UnsafeCell},
     fmt,
     marker::PhantomData,
-    mem::{self, MaybeUninit},
+    mem::MaybeUninit,
     ops::{Deref, Drop},
     panic::{RefUnwindSafe, UnwindSafe},
     sync::Once,
@@ -316,13 +316,7 @@ pub fn get_or_try_init<F, E>(&self, f: F) -> Result<&T, E>
     /// ```
     #[unstable(feature = "once_cell", issue = "74465")]
     pub fn into_inner(mut self) -> Option<T> {
-        // SAFETY: Safe because we immediately free `self` without dropping
-        let inner = unsafe { self.take_inner() };
-
-        // Don't drop this `SyncOnceCell`. We just moved out one of the fields, but didn't set
-        // the state to uninitialized.
-        mem::forget(self);
-        inner
+        self.take()
     }
 
     /// Takes the value out of this `SyncOnceCell`, moving it back to an uninitialized state.
@@ -348,22 +342,12 @@ pub fn into_inner(mut self) -> Option<T> {
     /// ```
     #[unstable(feature = "once_cell", issue = "74465")]
     pub fn take(&mut self) -> Option<T> {
-        mem::take(self).into_inner()
-    }
-
-    /// Takes the wrapped value out of a `SyncOnceCell`.
-    /// Afterwards the cell is no longer initialized.
-    ///
-    /// Safety: The cell must now be free'd WITHOUT dropping. No other usages of the cell
-    /// are valid. Only used by `into_inner` and `drop`.
-    unsafe fn take_inner(&mut self) -> Option<T> {
-        // The mutable reference guarantees there are no other threads that can observe us
-        // taking out the wrapped value.
-        // Right after this function `self` is supposed to be freed, so it makes little sense
-        // to atomically set the state to uninitialized.
         if self.is_initialized() {
-            let value = mem::replace(&mut self.value, UnsafeCell::new(MaybeUninit::uninit()));
-            Some(value.into_inner().assume_init())
+            self.once = Once::new();
+            // SAFETY: `self.value` is initialized and contains a valid `T`.
+            // `self.once` is reset, so `is_initialized()` will be false again
+            // which prevents the value from being read twice.
+            unsafe { Some((&mut *self.value.get()).assume_init_read()) }
         } else {
             None
         }
@@ -416,9 +400,12 @@ unsafe fn get_unchecked_mut(&mut self) -> &mut T {
 
 unsafe impl<#[may_dangle] T> Drop for SyncOnceCell<T> {
     fn drop(&mut self) {
-        // SAFETY: The cell is being dropped, so it can't be accessed again.
-        // We also don't touch the `T`, which validates our usage of #[may_dangle].
-        unsafe { self.take_inner() };
+        if self.is_initialized() {
+            // Safety: The cell is initialized and being dropped, so it can't
+            // be accessed again. We also don't touch the `T` other than
+            // dropping it, which validates our usage of #[may_dangle].
+            unsafe { (&mut *self.value.get()).assume_init_drop() };
+        }
     }
 }
 
index 307e222f713b7cbdee1ab746e0df5aba82807a35..b834361b750ebb2027fd70f912febcfd5239651f 100644 (file)
 #![feature(core_intrinsics)]
 #![feature(custom_test_frameworks)]
 #![feature(decl_macro)]
-#![feature(doc_alias)]
+#![cfg_attr(bootstrap, feature(doc_alias))]
 #![feature(doc_cfg)]
 #![feature(doc_keyword)]
 #![feature(doc_masked)]
index d1960a049d9062cb01e32b642b2a88e66cfda7fb..00e2dbc9c1dbf33e5d3c7c94c36edf4b6635f762 100644 (file)
@@ -95,6 +95,7 @@
 //! [`Read`]: io::Read
 
 #![stable(feature = "process", since = "1.0.0")]
+#![deny(unsafe_op_in_unsafe_fn)]
 
 #[cfg(all(test, not(any(target_os = "cloudabi", target_os = "emscripten", target_env = "sgx"))))]
 mod tests;
@@ -321,7 +322,8 @@ fn is_read_vectored(&self) -> bool {
 
     #[inline]
     unsafe fn initializer(&self) -> Initializer {
-        Initializer::nop()
+        // SAFETY: Read is guaranteed to work on uninitialized memory
+        unsafe { Initializer::nop() }
     }
 }
 
@@ -381,7 +383,8 @@ fn is_read_vectored(&self) -> bool {
 
     #[inline]
     unsafe fn initializer(&self) -> Initializer {
-        Initializer::nop()
+        // SAFETY: Read is guaranteed to work on uninitialized memory
+        unsafe { Initializer::nop() }
     }
 }
 
index 8fed369bffc27dd6ee5003c8e0c408e3c1a20225..29ae338cb2ec74bab242190b78187c63d1388e87 100644 (file)
@@ -191,6 +191,7 @@ struct WaiterQueue<'a> {
 
 impl Once {
     /// Creates a new `Once` value.
+    #[inline]
     #[stable(feature = "once_new", since = "1.2.0")]
     #[rustc_const_stable(feature = "const_once_new", since = "1.32.0")]
     pub const fn new() -> Once {
diff --git a/library/std/src/sys/sgx/fs.rs b/library/std/src/sys/sgx/fs.rs
deleted file mode 100644 (file)
index ecb5b51..0000000
+++ /dev/null
@@ -1,308 +0,0 @@
-use crate::ffi::OsString;
-use crate::fmt;
-use crate::hash::{Hash, Hasher};
-use crate::io::{self, IoSlice, IoSliceMut, SeekFrom};
-use crate::path::{Path, PathBuf};
-use crate::sys::time::SystemTime;
-use crate::sys::{unsupported, Void};
-
-pub struct File(Void);
-
-pub struct FileAttr(Void);
-
-pub struct ReadDir(Void);
-
-pub struct DirEntry(Void);
-
-#[derive(Clone, Debug)]
-pub struct OpenOptions {}
-
-pub struct FilePermissions(Void);
-
-pub struct FileType(Void);
-
-#[derive(Debug)]
-pub struct DirBuilder {}
-
-impl FileAttr {
-    pub fn size(&self) -> u64 {
-        match self.0 {}
-    }
-
-    pub fn perm(&self) -> FilePermissions {
-        match self.0 {}
-    }
-
-    pub fn file_type(&self) -> FileType {
-        match self.0 {}
-    }
-
-    pub fn modified(&self) -> io::Result<SystemTime> {
-        match self.0 {}
-    }
-
-    pub fn accessed(&self) -> io::Result<SystemTime> {
-        match self.0 {}
-    }
-
-    pub fn created(&self) -> io::Result<SystemTime> {
-        match self.0 {}
-    }
-}
-
-impl Clone for FileAttr {
-    fn clone(&self) -> FileAttr {
-        match self.0 {}
-    }
-}
-
-impl FilePermissions {
-    pub fn readonly(&self) -> bool {
-        match self.0 {}
-    }
-
-    pub fn set_readonly(&mut self, _readonly: bool) {
-        match self.0 {}
-    }
-}
-
-impl Clone for FilePermissions {
-    fn clone(&self) -> FilePermissions {
-        match self.0 {}
-    }
-}
-
-impl PartialEq for FilePermissions {
-    fn eq(&self, _other: &FilePermissions) -> bool {
-        match self.0 {}
-    }
-}
-
-impl Eq for FilePermissions {}
-
-impl fmt::Debug for FilePermissions {
-    fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match self.0 {}
-    }
-}
-
-impl FileType {
-    pub fn is_dir(&self) -> bool {
-        match self.0 {}
-    }
-
-    pub fn is_file(&self) -> bool {
-        match self.0 {}
-    }
-
-    pub fn is_symlink(&self) -> bool {
-        match self.0 {}
-    }
-}
-
-impl Clone for FileType {
-    fn clone(&self) -> FileType {
-        match self.0 {}
-    }
-}
-
-impl Copy for FileType {}
-
-impl PartialEq for FileType {
-    fn eq(&self, _other: &FileType) -> bool {
-        match self.0 {}
-    }
-}
-
-impl Eq for FileType {}
-
-impl Hash for FileType {
-    fn hash<H: Hasher>(&self, _h: &mut H) {
-        match self.0 {}
-    }
-}
-
-impl fmt::Debug for FileType {
-    fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match self.0 {}
-    }
-}
-
-impl fmt::Debug for ReadDir {
-    fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match self.0 {}
-    }
-}
-
-impl Iterator for ReadDir {
-    type Item = io::Result<DirEntry>;
-
-    fn next(&mut self) -> Option<io::Result<DirEntry>> {
-        match self.0 {}
-    }
-}
-
-impl DirEntry {
-    pub fn path(&self) -> PathBuf {
-        match self.0 {}
-    }
-
-    pub fn file_name(&self) -> OsString {
-        match self.0 {}
-    }
-
-    pub fn metadata(&self) -> io::Result<FileAttr> {
-        match self.0 {}
-    }
-
-    pub fn file_type(&self) -> io::Result<FileType> {
-        match self.0 {}
-    }
-}
-
-impl OpenOptions {
-    pub fn new() -> OpenOptions {
-        OpenOptions {}
-    }
-
-    pub fn read(&mut self, _read: bool) {}
-    pub fn write(&mut self, _write: bool) {}
-    pub fn append(&mut self, _append: bool) {}
-    pub fn truncate(&mut self, _truncate: bool) {}
-    pub fn create(&mut self, _create: bool) {}
-    pub fn create_new(&mut self, _create_new: bool) {}
-}
-
-impl File {
-    pub fn open(_path: &Path, _opts: &OpenOptions) -> io::Result<File> {
-        unsupported()
-    }
-
-    pub fn file_attr(&self) -> io::Result<FileAttr> {
-        match self.0 {}
-    }
-
-    pub fn fsync(&self) -> io::Result<()> {
-        match self.0 {}
-    }
-
-    pub fn datasync(&self) -> io::Result<()> {
-        match self.0 {}
-    }
-
-    pub fn truncate(&self, _size: u64) -> io::Result<()> {
-        match self.0 {}
-    }
-
-    pub fn read(&self, _buf: &mut [u8]) -> io::Result<usize> {
-        match self.0 {}
-    }
-
-    pub fn read_vectored(&self, _bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
-        match self.0 {}
-    }
-
-    pub fn is_read_vectored(&self) -> bool {
-        match self.0 {}
-    }
-
-    pub fn write(&self, _buf: &[u8]) -> io::Result<usize> {
-        match self.0 {}
-    }
-
-    pub fn write_vectored(&self, _bufs: &[IoSlice<'_>]) -> io::Result<usize> {
-        match self.0 {}
-    }
-
-    pub fn is_write_vectored(&self) -> bool {
-        match self.0 {}
-    }
-
-    pub fn flush(&self) -> io::Result<()> {
-        match self.0 {}
-    }
-
-    pub fn seek(&self, _pos: SeekFrom) -> io::Result<u64> {
-        match self.0 {}
-    }
-
-    pub fn duplicate(&self) -> io::Result<File> {
-        match self.0 {}
-    }
-
-    pub fn set_permissions(&self, _perm: FilePermissions) -> io::Result<()> {
-        match self.0 {}
-    }
-
-    pub fn diverge(&self) -> ! {
-        match self.0 {}
-    }
-}
-
-impl DirBuilder {
-    pub fn new() -> DirBuilder {
-        DirBuilder {}
-    }
-
-    pub fn mkdir(&self, _p: &Path) -> io::Result<()> {
-        unsupported()
-    }
-}
-
-impl fmt::Debug for File {
-    fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match self.0 {}
-    }
-}
-
-pub fn readdir(_p: &Path) -> io::Result<ReadDir> {
-    unsupported()
-}
-
-pub fn unlink(_p: &Path) -> io::Result<()> {
-    unsupported()
-}
-
-pub fn rename(_old: &Path, _new: &Path) -> io::Result<()> {
-    unsupported()
-}
-
-pub fn set_perm(_p: &Path, perm: FilePermissions) -> io::Result<()> {
-    match perm.0 {}
-}
-
-pub fn rmdir(_p: &Path) -> io::Result<()> {
-    unsupported()
-}
-
-pub fn remove_dir_all(_path: &Path) -> io::Result<()> {
-    unsupported()
-}
-
-pub fn readlink(_p: &Path) -> io::Result<PathBuf> {
-    unsupported()
-}
-
-pub fn symlink(_src: &Path, _dst: &Path) -> io::Result<()> {
-    unsupported()
-}
-
-pub fn link(_src: &Path, _dst: &Path) -> io::Result<()> {
-    unsupported()
-}
-
-pub fn stat(_p: &Path) -> io::Result<FileAttr> {
-    unsupported()
-}
-
-pub fn lstat(_p: &Path) -> io::Result<FileAttr> {
-    unsupported()
-}
-
-pub fn canonicalize(_p: &Path) -> io::Result<PathBuf> {
-    unsupported()
-}
-
-pub fn copy(_from: &Path, _to: &Path) -> io::Result<u64> {
-    unsupported()
-}
diff --git a/library/std/src/sys/sgx/io.rs b/library/std/src/sys/sgx/io.rs
deleted file mode 100644 (file)
index d5f475b..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-use crate::mem;
-
-#[derive(Copy, Clone)]
-pub struct IoSlice<'a>(&'a [u8]);
-
-impl<'a> IoSlice<'a> {
-    #[inline]
-    pub fn new(buf: &'a [u8]) -> IoSlice<'a> {
-        IoSlice(buf)
-    }
-
-    #[inline]
-    pub fn advance(&mut self, n: usize) {
-        self.0 = &self.0[n..]
-    }
-
-    #[inline]
-    pub fn as_slice(&self) -> &[u8] {
-        self.0
-    }
-}
-
-pub struct IoSliceMut<'a>(&'a mut [u8]);
-
-impl<'a> IoSliceMut<'a> {
-    #[inline]
-    pub fn new(buf: &'a mut [u8]) -> IoSliceMut<'a> {
-        IoSliceMut(buf)
-    }
-
-    #[inline]
-    pub fn advance(&mut self, n: usize) {
-        let slice = mem::replace(&mut self.0, &mut []);
-        let (_, remaining) = slice.split_at_mut(n);
-        self.0 = remaining;
-    }
-
-    #[inline]
-    pub fn as_slice(&self) -> &[u8] {
-        self.0
-    }
-
-    #[inline]
-    pub fn as_mut_slice(&mut self) -> &mut [u8] {
-        self.0
-    }
-}
index 1d32eb25424345578d63d378ad1fa3c9d463f4db..1abd91e75e8c40d9e3a472efce09e3e075b01367 100644 (file)
 pub mod env;
 pub mod ext;
 pub mod fd;
+#[path = "../unsupported/fs.rs"]
 pub mod fs;
+#[path = "../unsupported/io.rs"]
 pub mod io;
 pub mod memchr;
 pub mod mutex;
 pub mod net;
 pub mod os;
 pub mod path;
+#[path = "../unsupported/pipe.rs"]
 pub mod pipe;
+#[path = "../unsupported/process.rs"]
 pub mod process;
 pub mod rwlock;
 pub mod stack_overflow;
diff --git a/library/std/src/sys/sgx/pipe.rs b/library/std/src/sys/sgx/pipe.rs
deleted file mode 100644 (file)
index 10d0925..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-use crate::io::{self, IoSlice, IoSliceMut};
-use crate::sys::Void;
-
-pub struct AnonPipe(Void);
-
-impl AnonPipe {
-    pub fn read(&self, _buf: &mut [u8]) -> io::Result<usize> {
-        match self.0 {}
-    }
-
-    pub fn read_vectored(&self, _bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
-        match self.0 {}
-    }
-
-    pub fn is_read_vectored(&self) -> bool {
-        match self.0 {}
-    }
-
-    pub fn write(&self, _buf: &[u8]) -> io::Result<usize> {
-        match self.0 {}
-    }
-
-    pub fn write_vectored(&self, _bufs: &[IoSlice<'_>]) -> io::Result<usize> {
-        match self.0 {}
-    }
-
-    pub fn is_write_vectored(&self) -> bool {
-        match self.0 {}
-    }
-
-    pub fn diverge(&self) -> ! {
-        match self.0 {}
-    }
-}
-
-pub fn read2(p1: AnonPipe, _v1: &mut Vec<u8>, _p2: AnonPipe, _v2: &mut Vec<u8>) -> io::Result<()> {
-    match p1.0 {}
-}
diff --git a/library/std/src/sys/sgx/process.rs b/library/std/src/sys/sgx/process.rs
deleted file mode 100644 (file)
index 4702e5c..0000000
+++ /dev/null
@@ -1,149 +0,0 @@
-use crate::ffi::OsStr;
-use crate::fmt;
-use crate::io;
-use crate::sys::fs::File;
-use crate::sys::pipe::AnonPipe;
-use crate::sys::{unsupported, Void};
-use crate::sys_common::process::CommandEnv;
-
-pub use crate::ffi::OsString as EnvKey;
-
-////////////////////////////////////////////////////////////////////////////////
-// Command
-////////////////////////////////////////////////////////////////////////////////
-
-pub struct Command {
-    env: CommandEnv,
-}
-
-// passed back to std::process with the pipes connected to the child, if any
-// were requested
-pub struct StdioPipes {
-    pub stdin: Option<AnonPipe>,
-    pub stdout: Option<AnonPipe>,
-    pub stderr: Option<AnonPipe>,
-}
-
-pub enum Stdio {
-    Inherit,
-    Null,
-    MakePipe,
-}
-
-impl Command {
-    pub fn new(_program: &OsStr) -> Command {
-        Command { env: Default::default() }
-    }
-
-    pub fn arg(&mut self, _arg: &OsStr) {}
-
-    pub fn env_mut(&mut self) -> &mut CommandEnv {
-        &mut self.env
-    }
-
-    pub fn cwd(&mut self, _dir: &OsStr) {}
-
-    pub fn stdin(&mut self, _stdin: Stdio) {}
-
-    pub fn stdout(&mut self, _stdout: Stdio) {}
-
-    pub fn stderr(&mut self, _stderr: Stdio) {}
-
-    pub fn spawn(
-        &mut self,
-        _default: Stdio,
-        _needs_stdin: bool,
-    ) -> io::Result<(Process, StdioPipes)> {
-        unsupported()
-    }
-}
-
-impl From<AnonPipe> for Stdio {
-    fn from(pipe: AnonPipe) -> Stdio {
-        pipe.diverge()
-    }
-}
-
-impl From<File> for Stdio {
-    fn from(file: File) -> Stdio {
-        file.diverge()
-    }
-}
-
-impl fmt::Debug for Command {
-    fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        Ok(())
-    }
-}
-
-pub struct ExitStatus(Void);
-
-impl ExitStatus {
-    pub fn success(&self) -> bool {
-        match self.0 {}
-    }
-
-    pub fn code(&self) -> Option<i32> {
-        match self.0 {}
-    }
-}
-
-impl Clone for ExitStatus {
-    fn clone(&self) -> ExitStatus {
-        match self.0 {}
-    }
-}
-
-impl Copy for ExitStatus {}
-
-impl PartialEq for ExitStatus {
-    fn eq(&self, _other: &ExitStatus) -> bool {
-        match self.0 {}
-    }
-}
-
-impl Eq for ExitStatus {}
-
-impl fmt::Debug for ExitStatus {
-    fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match self.0 {}
-    }
-}
-
-impl fmt::Display for ExitStatus {
-    fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match self.0 {}
-    }
-}
-
-#[derive(PartialEq, Eq, Clone, Copy, Debug)]
-pub struct ExitCode(bool);
-
-impl ExitCode {
-    pub const SUCCESS: ExitCode = ExitCode(false);
-    pub const FAILURE: ExitCode = ExitCode(true);
-
-    pub fn as_i32(&self) -> i32 {
-        self.0 as i32
-    }
-}
-
-pub struct Process(Void);
-
-impl Process {
-    pub fn id(&self) -> u32 {
-        match self.0 {}
-    }
-
-    pub fn kill(&mut self) -> io::Result<()> {
-        match self.0 {}
-    }
-
-    pub fn wait(&mut self) -> io::Result<ExitStatus> {
-        match self.0 {}
-    }
-
-    pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
-        match self.0 {}
-    }
-}
index 05b36c633f8618e4a50e7a764ad1f11ab0b507a0..17c9e72ee39fa2ed2b2e690f01d80dcd855a28e2 100644 (file)
@@ -1,14 +1,12 @@
 use super::*;
-use crate::mem::{self, MaybeUninit};
-use core::array::FixedSizeArray;
 
-// Verify that the bytes of initialized RWLock are the same as in
-// libunwind. If they change, `src/UnwindRustSgx.h` in libunwind needs to
-// be changed too.
+// Verify that the byte pattern libunwind uses to initialize an RWLock is
+// equivalent to the value of RWLock::new(). If the value changes,
+// `src/UnwindRustSgx.h` in libunwind needs to be changed too.
 #[test]
 fn test_c_rwlock_initializer() {
     #[rustfmt::skip]
-    const RWLOCK_INIT: &[u8] = &[
+    const C_RWLOCK_INIT: &[u8] = &[
         /* 0x00 */ 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
         /* 0x10 */ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
         /* 0x20 */ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
@@ -20,24 +18,14 @@ fn test_c_rwlock_initializer() {
         /* 0x80 */ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
     ];
 
-    #[inline(never)]
-    fn zero_stack() {
-        test::black_box(MaybeUninit::<[RWLock; 16]>::zeroed());
-    }
-
-    #[inline(never)]
-    unsafe fn rwlock_new(init: &mut MaybeUninit<RWLock>) {
-        init.write(RWLock::new());
-    }
+    // For the test to work, we need the padding/unused bytes in RWLock to be
+    // initialized as 0. In practice, this is the case with statics.
+    static RUST_RWLOCK_INIT: RWLock = RWLock::new();
 
     unsafe {
-        // try hard to make sure that the padding/unused bytes in RWLock
-        // get initialized as 0. If the assertion below fails, that might
-        // just be an issue with the test code and not with the value of
-        // RWLOCK_INIT.
-        zero_stack();
-        let mut init = MaybeUninit::<RWLock>::zeroed();
-        rwlock_new(&mut init);
-        assert_eq!(mem::transmute::<_, [u8; 144]>(init.assume_init()).as_slice(), RWLOCK_INIT)
+        // If the assertion fails, that not necessarily an issue with the value
+        // of C_RWLOCK_INIT. It might just be an issue with the way padding
+        // bytes are initialized in the test code.
+        assert_eq!(&crate::mem::transmute_copy::<_, [u8; 144]>(&RUST_RWLOCK_INIT), C_RWLOCK_INIT);
     };
 }
index 8e193935460eb1f450ccb1cd9fd9ffcfb9ac66f3..964abe8b8c9ea86ffe714811e897110ab488c083 100644 (file)
@@ -52,46 +52,48 @@ unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut
     }
 }
 
-#[cfg(any(
-    target_os = "android",
-    target_os = "illumos",
-    target_os = "redox",
-    target_os = "solaris"
-))]
-#[inline]
-unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {
-    // On android we currently target API level 9 which unfortunately
-    // doesn't have the `posix_memalign` API used below. Instead we use
-    // `memalign`, but this unfortunately has the property on some systems
-    // where the memory returned cannot be deallocated by `free`!
-    //
-    // Upon closer inspection, however, this appears to work just fine with
-    // Android, so for this platform we should be fine to call `memalign`
-    // (which is present in API level 9). Some helpful references could
-    // possibly be chromium using memalign [1], attempts at documenting that
-    // memalign + free is ok [2] [3], or the current source of chromium
-    // which still uses memalign on android [4].
-    //
-    // [1]: https://codereview.chromium.org/10796020/
-    // [2]: https://code.google.com/p/android/issues/detail?id=35391
-    // [3]: https://bugs.chromium.org/p/chromium/issues/detail?id=138579
-    // [4]: https://chromium.googlesource.com/chromium/src/base/+/master/
-    //                                       /memory/aligned_memory.cc
-    libc::memalign(layout.align(), layout.size()) as *mut u8
-}
-
-#[cfg(not(any(
-    target_os = "android",
-    target_os = "illumos",
-    target_os = "redox",
-    target_os = "solaris"
-)))]
-#[inline]
-unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {
-    let mut out = ptr::null_mut();
-    // posix_memalign requires that the alignment be a multiple of `sizeof(void*)`.
-    // Since these are all powers of 2, we can just use max.
-    let align = layout.align().max(crate::mem::size_of::<usize>());
-    let ret = libc::posix_memalign(&mut out, align, layout.size());
-    if ret != 0 { ptr::null_mut() } else { out as *mut u8 }
+cfg_if::cfg_if! {
+    if #[cfg(any(
+        target_os = "android",
+        target_os = "illumos",
+        target_os = "redox",
+        target_os = "solaris"
+    ))] {
+        #[inline]
+        unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {
+            // On android we currently target API level 9 which unfortunately
+            // doesn't have the `posix_memalign` API used below. Instead we use
+            // `memalign`, but this unfortunately has the property on some systems
+            // where the memory returned cannot be deallocated by `free`!
+            //
+            // Upon closer inspection, however, this appears to work just fine with
+            // Android, so for this platform we should be fine to call `memalign`
+            // (which is present in API level 9). Some helpful references could
+            // possibly be chromium using memalign [1], attempts at documenting that
+            // memalign + free is ok [2] [3], or the current source of chromium
+            // which still uses memalign on android [4].
+            //
+            // [1]: https://codereview.chromium.org/10796020/
+            // [2]: https://code.google.com/p/android/issues/detail?id=35391
+            // [3]: https://bugs.chromium.org/p/chromium/issues/detail?id=138579
+            // [4]: https://chromium.googlesource.com/chromium/src/base/+/master/
+            //                                       /memory/aligned_memory.cc
+            libc::memalign(layout.align(), layout.size()) as *mut u8
+        }
+    } else if #[cfg(target_os = "wasi")] {
+        #[inline]
+        unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {
+            libc::aligned_alloc(layout.align(), layout.size()) as *mut u8
+        }
+    } else {
+        #[inline]
+        unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {
+            let mut out = ptr::null_mut();
+            // posix_memalign requires that the alignment be a multiple of `sizeof(void*)`.
+            // Since these are all powers of 2, we can just use max.
+            let align = layout.align().max(crate::mem::size_of::<usize>());
+            let ret = libc::posix_memalign(&mut out, align, layout.size());
+            if ret != 0 { ptr::null_mut() } else { out as *mut u8 }
+        }
+    }
 }
index 487ac266ee9cdbc71547f0f6f922a8b5760de475..4b9f4ceb29c490f857eccb729d26289eb8dbb69d 100644 (file)
@@ -836,15 +836,6 @@ fn ino(&self) -> u64 {
 ///
 /// The `dst` path will be a symbolic link pointing to the `src` path.
 ///
-/// # Note
-///
-/// On Windows, you must specify whether a symbolic link points to a file
-/// or directory. Use `os::windows::fs::symlink_file` to create a
-/// symbolic link to a file, or `os::windows::fs::symlink_dir` to create a
-/// symbolic link to a directory. Additionally, the process must have
-/// `SeCreateSymbolicLinkPrivilege` in order to be able to create a
-/// symbolic link.
-///
 /// # Examples
 ///
 /// ```no_run
index cbdb1c10049843176570375450c45c0d2b53d4a7..f43546880983ab3c18ad3da2f66d9eadb9c80aad 100644 (file)
 pub mod raw;
 pub mod thread;
 
+#[unstable(feature = "peer_credentials_unix_socket", issue = "42839", reason = "unstable")]
+#[cfg(any(
+    target_os = "android",
+    target_os = "linux",
+    target_os = "dragonfly",
+    target_os = "freebsd",
+    target_os = "ios",
+    target_os = "macos",
+    target_os = "openbsd"
+))]
+pub mod ucred;
+
 /// A prelude for conveniently writing platform-specific code.
 ///
 /// Includes all extension traits, and some important type definitions.
index 320378e30ccb10524303a8225b8df87924770c85..f3da8f9f584884ed0111c8163c415d0726dc6c22 100644 (file)
@@ -30,6 +30,29 @@ mod libc {
 use crate::sys_common::{self, AsInner, FromInner, IntoInner};
 use crate::time::Duration;
 
+#[cfg(any(
+    target_os = "android",
+    target_os = "linux",
+    target_os = "dragonfly",
+    target_os = "freebsd",
+    target_os = "ios",
+    target_os = "macos",
+    target_os = "openbsd"
+))]
+use crate::os::unix::ucred;
+
+#[unstable(feature = "peer_credentials_unix_socket", issue = "42839", reason = "unstable")]
+#[cfg(any(
+    target_os = "android",
+    target_os = "linux",
+    target_os = "dragonfly",
+    target_os = "freebsd",
+    target_os = "ios",
+    target_os = "macos",
+    target_os = "openbsd"
+))]
+pub use ucred::UCred;
+
 #[cfg(any(
     target_os = "linux",
     target_os = "android",
@@ -405,6 +428,34 @@ pub fn peer_addr(&self) -> io::Result<SocketAddr> {
         SocketAddr::new(|addr, len| unsafe { libc::getpeername(*self.0.as_inner(), addr, len) })
     }
 
+    /// Gets the peer credentials for this Unix domain socket.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// #![feature(peer_credentials_unix_socket)]
+    /// use std::os::unix::net::UnixStream;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let socket = UnixStream::connect("/tmp/sock")?;
+    ///     let peer_cred = socket.peer_cred().expect("Couldn't get peer credentials");
+    ///     Ok(())
+    /// }
+    /// ```
+    #[unstable(feature = "peer_credentials_unix_socket", issue = "42839", reason = "unstable")]
+    #[cfg(any(
+        target_os = "android",
+        target_os = "linux",
+        target_os = "dragonfly",
+        target_os = "freebsd",
+        target_os = "ios",
+        target_os = "macos",
+        target_os = "openbsd"
+    ))]
+    pub fn peer_cred(&self) -> io::Result<UCred> {
+        ucred::peer_cred(self)
+    }
+
     /// Sets the read timeout for the socket.
     ///
     /// If the provided value is [`None`], then [`read`] calls will block
diff --git a/library/std/src/sys/unix/ext/ucred.rs b/library/std/src/sys/unix/ext/ucred.rs
new file mode 100644 (file)
index 0000000..ed7516c
--- /dev/null
@@ -0,0 +1,97 @@
+//! Unix peer credentials.
+
+// NOTE: Code in this file is heavily based on work done in PR 13 from the tokio-uds repository on
+//       GitHub.
+//
+//       For reference, the link is here: https://github.com/tokio-rs/tokio-uds/pull/13
+//       Credit to Martin Habovštiak (GitHub username Kixunil) and contributors for this work.
+
+use libc::{gid_t, pid_t, uid_t};
+
+/// Credentials for a UNIX process for credentials passing.
+#[unstable(feature = "peer_credentials_unix_socket", issue = "42839", reason = "unstable")]
+#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
+pub struct UCred {
+    /// The UID part of the peer credential. This is the effective UID of the process at the domain
+    /// socket's endpoint.
+    pub uid: uid_t,
+    /// The GID part of the peer credential. This is the effective GID of the process at the domain
+    /// socket's endpoint.
+    pub gid: gid_t,
+    /// The PID part of the peer credential. This field is optional because the PID part of the
+    /// peer credentials is not supported on every platform. On platforms where the mechanism to
+    /// discover the PID exists, this field will be populated to the PID of the process at the
+    /// domain socket's endpoint. Otherwise, it will be set to None.
+    pub pid: Option<pid_t>,
+}
+
+#[cfg(any(target_os = "android", target_os = "linux"))]
+pub use self::impl_linux::peer_cred;
+
+#[cfg(any(
+    target_os = "dragonfly",
+    target_os = "freebsd",
+    target_os = "ios",
+    target_os = "macos",
+    target_os = "openbsd"
+))]
+pub use self::impl_bsd::peer_cred;
+
+#[cfg(any(target_os = "linux", target_os = "android"))]
+pub mod impl_linux {
+    use super::UCred;
+    use crate::os::unix::io::AsRawFd;
+    use crate::os::unix::net::UnixStream;
+    use crate::{io, mem};
+    use libc::{c_void, getsockopt, socklen_t, ucred, SOL_SOCKET, SO_PEERCRED};
+
+    pub fn peer_cred(socket: &UnixStream) -> io::Result<UCred> {
+        let ucred_size = mem::size_of::<ucred>();
+
+        // Trivial sanity checks.
+        assert!(mem::size_of::<u32>() <= mem::size_of::<usize>());
+        assert!(ucred_size <= u32::MAX as usize);
+
+        let mut ucred_size = ucred_size as socklen_t;
+        let mut ucred: ucred = ucred { pid: 1, uid: 1, gid: 1 };
+
+        unsafe {
+            let ret = getsockopt(
+                socket.as_raw_fd(),
+                SOL_SOCKET,
+                SO_PEERCRED,
+                &mut ucred as *mut ucred as *mut c_void,
+                &mut ucred_size,
+            );
+
+            if ret == 0 && ucred_size as usize == mem::size_of::<ucred>() {
+                Ok(UCred { uid: ucred.uid, gid: ucred.gid, pid: Some(ucred.pid) })
+            } else {
+                Err(io::Error::last_os_error())
+            }
+        }
+    }
+}
+
+#[cfg(any(
+    target_os = "dragonfly",
+    target_os = "macos",
+    target_os = "ios",
+    target_os = "freebsd",
+    target_os = "openbsd"
+))]
+pub mod impl_bsd {
+    use super::UCred;
+    use crate::io;
+    use crate::os::unix::io::AsRawFd;
+    use crate::os::unix::net::UnixStream;
+
+    pub fn peer_cred(socket: &UnixStream) -> io::Result<UCred> {
+        let mut cred = UCred { uid: 1, gid: 1, pid: None };
+        unsafe {
+            let ret = libc::getpeereid(socket.as_raw_fd(), &mut cred.uid, &mut cred.gid);
+
+            if ret == 0 { Ok(cred) } else { Err(io::Error::last_os_error()) }
+        }
+    }
+}
diff --git a/library/std/src/sys/unix/ext/ucred/tests.rs b/library/std/src/sys/unix/ext/ucred/tests.rs
new file mode 100644 (file)
index 0000000..451b534
--- /dev/null
@@ -0,0 +1,25 @@
+use crate::os::unix::net::UnixStream;
+use libc::{getegid, geteuid};
+
+#[test]
+#[cfg(any(
+    target_os = "android",
+    target_os = "linux",
+    target_os = "dragonfly",
+    target_os = "freebsd",
+    target_os = "ios",
+    target_os = "macos",
+    target_os = "openbsd"
+))]
+fn test_socket_pair() {
+    // Create two connected sockets and get their peer credentials. They should be equal.
+    let (sock_a, sock_b) = UnixStream::pair().unwrap();
+    let (cred_a, cred_b) = (sock_a.peer_cred().unwrap(), sock_b.peer_cred().unwrap());
+    assert_eq!(cred_a, cred_b);
+
+    // Check that the UID and GIDs match up.
+    let uid = unsafe { geteuid() };
+    let gid = unsafe { getegid() };
+    assert_eq!(cred_a.uid, uid);
+    assert_eq!(cred_a.gid, gid);
+}
index ecb5b51cccdcd965d85e9ee8e22ecb878d876719..faa53b6a74422ddff884dec7a850c37252798d58 100644 (file)
@@ -233,10 +233,6 @@ pub fn duplicate(&self) -> io::Result<File> {
     pub fn set_permissions(&self, _perm: FilePermissions) -> io::Result<()> {
         match self.0 {}
     }
-
-    pub fn diverge(&self) -> ! {
-        match self.0 {}
-    }
 }
 
 impl DirBuilder {
index 87f655eecd54e74a33bde42e0b88d1a85a144d19..8ba870c5dbc14cecba6f52158fae1d49a799ea8e 100644 (file)
@@ -8,6 +8,7 @@
 pub mod mutex;
 pub mod net;
 pub mod os;
+#[path = "../unix/path.rs"]
 pub mod path;
 pub mod pipe;
 pub mod process;
diff --git a/library/std/src/sys/unsupported/path.rs b/library/std/src/sys/unsupported/path.rs
deleted file mode 100644 (file)
index 840a7ae..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-use crate::ffi::OsStr;
-use crate::path::Prefix;
-
-#[inline]
-pub fn is_sep_byte(b: u8) -> bool {
-    b == b'/'
-}
-
-#[inline]
-pub fn is_verbatim_sep(b: u8) -> bool {
-    b == b'/'
-}
-
-pub fn parse_prefix(_: &OsStr) -> Option<Prefix<'_>> {
-    None
-}
-
-pub const MAIN_SEP_STR: &str = "/";
-pub const MAIN_SEP: char = '/';
index 4702e5c549228ea27e5c59777cb707b34ea5d248..7156c9ab92f2b6af3da9699a3618f76275280af1 100644 (file)
@@ -65,8 +65,8 @@ fn from(pipe: AnonPipe) -> Stdio {
 }
 
 impl From<File> for Stdio {
-    fn from(file: File) -> Stdio {
-        file.diverge()
+    fn from(_file: File) -> Stdio {
+        panic!("unsupported")
     }
 }
 
index 9b4c64bdb6d84daaefde02a8edc10608c4391205..68dc21b806c0fd70cb0be6555939bf9dc8b3a3bb 100644 (file)
@@ -774,15 +774,6 @@ fn ino(&self) -> u64 {
 ///
 /// The `dst` path will be a symbolic link pointing to the `src` path.
 ///
-/// # Note
-///
-/// On Windows, you must specify whether a symbolic link points to a file
-/// or directory.  Use `os::windows::fs::symlink_file` to create a
-/// symbolic link to a file, or `os::windows::fs::symlink_dir` to create a
-/// symbolic link to a directory.  Additionally, the process must have
-/// `SeCreateSymbolicLinkPrivilege` in order to be able to create a
-/// symbolic link.
-///
 /// # Examples
 ///
 /// ```no_run
diff --git a/library/std/src/sys/wasi/alloc.rs b/library/std/src/sys/wasi/alloc.rs
deleted file mode 100644 (file)
index 4d0afe2..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-#![deny(unsafe_op_in_unsafe_fn)]
-
-use crate::alloc::{GlobalAlloc, Layout, System};
-use crate::ptr;
-use crate::sys_common::alloc::{realloc_fallback, MIN_ALIGN};
-
-// SAFETY: All methods implemented follow the contract rules defined
-// in `GlobalAlloc`.
-#[stable(feature = "alloc_system_type", since = "1.28.0")]
-unsafe impl GlobalAlloc for System {
-    #[inline]
-    unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
-        if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() {
-            // SAFETY: `libc::malloc` is guaranteed to be safe, it will allocate
-            // `layout.size()` bytes of memory and return a pointer to it
-            unsafe { libc::malloc(layout.size()) as *mut u8 }
-        } else {
-            // SAFETY: `libc::aligned_alloc` is guaranteed to be safe if
-            // `layout.size()` is a multiple of `layout.align()`. This
-            // constraint can be satisfied if `pad_to_align` is called,
-            // which creates a layout by rounding the size of this layout up
-            // to a multiple of the layout's alignment
-            let aligned_layout = layout.pad_to_align();
-            unsafe { libc::aligned_alloc(aligned_layout.align(), aligned_layout.size()) as *mut u8 }
-        }
-    }
-
-    #[inline]
-    unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
-        if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() {
-            // SAFETY: `libc::calloc` is safe as long that `layout.size() * 1`
-            // would not result in integer overflow which cannot happen,
-            // multiplying by one never overflows
-            unsafe { libc::calloc(layout.size(), 1) as *mut u8 }
-        } else {
-            // SAFETY: The safety contract for `alloc` must be upheld by the caller
-            let ptr = unsafe { self.alloc(layout.clone()) };
-            if !ptr.is_null() {
-                // SAFETY: in the case of the `ptr` being not null
-                // it will be properly aligned and a valid ptr
-                // which satisfies `ptr::write_bytes` safety constrains
-                unsafe { ptr::write_bytes(ptr, 0, layout.size()) };
-            }
-            ptr
-        }
-    }
-
-    #[inline]
-    unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
-        // SAFETY: `libc::free` is guaranteed to be safe if `ptr` is allocated
-        // by this allocator or if `ptr` is NULL
-        unsafe { libc::free(ptr as *mut libc::c_void) }
-    }
-
-    #[inline]
-    unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
-        if layout.align() <= MIN_ALIGN && layout.align() <= new_size {
-            // SAFETY: `libc::realloc` is safe if `ptr` is allocated by this
-            // allocator or NULL
-            // - If `new_size` is 0 and `ptr` is not NULL, it will act as `libc::free`
-            // - If `new_size` is not 0 and `ptr` is NULL, it will act as `libc::malloc`
-            // - Else, it will resize the block accordingly
-            unsafe { libc::realloc(ptr as *mut libc::c_void, new_size) as *mut u8 }
-        } else {
-            // SAFETY: The safety contract for `realloc_fallback` must be upheld by the caller
-            unsafe { realloc_fallback(self, ptr, layout, new_size) }
-        }
-    }
-}
index 2704ff484f9911c920329e86ebdb21dbeaf9372e..a7a4407ac38e281fb4ac716d2f8e75679c0d26af 100644 (file)
@@ -17,6 +17,7 @@
 use crate::io as std_io;
 use crate::mem;
 
+#[path = "../unix/alloc.rs"]
 pub mod alloc;
 pub mod args;
 #[path = "../unsupported/cmath.rs"]
 pub mod os;
 pub use crate::sys_common::os_str_bytes as os_str;
 pub mod ext;
+#[path = "../unix/path.rs"]
 pub mod path;
+#[path = "../unsupported/pipe.rs"]
 pub mod pipe;
+#[path = "../unsupported/process.rs"]
 pub mod process;
 #[path = "../unsupported/rwlock.rs"]
 pub mod rwlock;
diff --git a/library/std/src/sys/wasi/path.rs b/library/std/src/sys/wasi/path.rs
deleted file mode 100644 (file)
index 840a7ae..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-use crate::ffi::OsStr;
-use crate::path::Prefix;
-
-#[inline]
-pub fn is_sep_byte(b: u8) -> bool {
-    b == b'/'
-}
-
-#[inline]
-pub fn is_verbatim_sep(b: u8) -> bool {
-    b == b'/'
-}
-
-pub fn parse_prefix(_: &OsStr) -> Option<Prefix<'_>> {
-    None
-}
-
-pub const MAIN_SEP_STR: &str = "/";
-pub const MAIN_SEP: char = '/';
diff --git a/library/std/src/sys/wasi/pipe.rs b/library/std/src/sys/wasi/pipe.rs
deleted file mode 100644 (file)
index 180fc11..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-#![deny(unsafe_op_in_unsafe_fn)]
-
-use crate::io::{self, IoSlice, IoSliceMut};
-use crate::sys::Void;
-
-pub struct AnonPipe(Void);
-
-impl AnonPipe {
-    pub fn read(&self, _buf: &mut [u8]) -> io::Result<usize> {
-        match self.0 {}
-    }
-
-    pub fn read_vectored(&self, _bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
-        match self.0 {}
-    }
-
-    pub fn is_read_vectored(&self) -> bool {
-        match self.0 {}
-    }
-
-    pub fn write(&self, _buf: &[u8]) -> io::Result<usize> {
-        match self.0 {}
-    }
-
-    pub fn write_vectored(&self, _bufs: &[IoSlice<'_>]) -> io::Result<usize> {
-        match self.0 {}
-    }
-
-    pub fn is_write_vectored(&self) -> bool {
-        match self.0 {}
-    }
-
-    pub fn diverge(&self) -> ! {
-        match self.0 {}
-    }
-}
-
-pub fn read2(p1: AnonPipe, _v1: &mut Vec<u8>, _p2: AnonPipe, _v2: &mut Vec<u8>) -> io::Result<()> {
-    match p1.0 {}
-}
diff --git a/library/std/src/sys/wasi/process.rs b/library/std/src/sys/wasi/process.rs
deleted file mode 100644 (file)
index c69d637..0000000
+++ /dev/null
@@ -1,151 +0,0 @@
-#![deny(unsafe_op_in_unsafe_fn)]
-
-use crate::ffi::OsStr;
-use crate::fmt;
-use crate::io;
-use crate::sys::fs::File;
-use crate::sys::pipe::AnonPipe;
-use crate::sys::{unsupported, Void};
-use crate::sys_common::process::CommandEnv;
-
-pub use crate::ffi::OsString as EnvKey;
-
-////////////////////////////////////////////////////////////////////////////////
-// Command
-////////////////////////////////////////////////////////////////////////////////
-
-pub struct Command {
-    env: CommandEnv,
-}
-
-// passed back to std::process with the pipes connected to the child, if any
-// were requested
-pub struct StdioPipes {
-    pub stdin: Option<AnonPipe>,
-    pub stdout: Option<AnonPipe>,
-    pub stderr: Option<AnonPipe>,
-}
-
-pub enum Stdio {
-    Inherit,
-    Null,
-    MakePipe,
-}
-
-impl Command {
-    pub fn new(_program: &OsStr) -> Command {
-        Command { env: Default::default() }
-    }
-
-    pub fn arg(&mut self, _arg: &OsStr) {}
-
-    pub fn env_mut(&mut self) -> &mut CommandEnv {
-        &mut self.env
-    }
-
-    pub fn cwd(&mut self, _dir: &OsStr) {}
-
-    pub fn stdin(&mut self, _stdin: Stdio) {}
-
-    pub fn stdout(&mut self, _stdout: Stdio) {}
-
-    pub fn stderr(&mut self, _stderr: Stdio) {}
-
-    pub fn spawn(
-        &mut self,
-        _default: Stdio,
-        _needs_stdin: bool,
-    ) -> io::Result<(Process, StdioPipes)> {
-        unsupported()
-    }
-}
-
-impl From<AnonPipe> for Stdio {
-    fn from(pipe: AnonPipe) -> Stdio {
-        pipe.diverge()
-    }
-}
-
-impl From<File> for Stdio {
-    fn from(_file: File) -> Stdio {
-        panic!("unsupported")
-    }
-}
-
-impl fmt::Debug for Command {
-    fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        Ok(())
-    }
-}
-
-pub struct ExitStatus(Void);
-
-impl ExitStatus {
-    pub fn success(&self) -> bool {
-        match self.0 {}
-    }
-
-    pub fn code(&self) -> Option<i32> {
-        match self.0 {}
-    }
-}
-
-impl Clone for ExitStatus {
-    fn clone(&self) -> ExitStatus {
-        match self.0 {}
-    }
-}
-
-impl Copy for ExitStatus {}
-
-impl PartialEq for ExitStatus {
-    fn eq(&self, _other: &ExitStatus) -> bool {
-        match self.0 {}
-    }
-}
-
-impl Eq for ExitStatus {}
-
-impl fmt::Debug for ExitStatus {
-    fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match self.0 {}
-    }
-}
-
-impl fmt::Display for ExitStatus {
-    fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match self.0 {}
-    }
-}
-
-#[derive(PartialEq, Eq, Clone, Copy, Debug)]
-pub struct ExitCode(bool);
-
-impl ExitCode {
-    pub const SUCCESS: ExitCode = ExitCode(false);
-    pub const FAILURE: ExitCode = ExitCode(true);
-
-    pub fn as_i32(&self) -> i32 {
-        self.0 as i32
-    }
-}
-
-pub struct Process(Void);
-
-impl Process {
-    pub fn id(&self) -> u32 {
-        match self.0 {}
-    }
-
-    pub fn kill(&mut self) -> io::Result<()> {
-        match self.0 {}
-    }
-
-    pub fn wait(&mut self) -> io::Result<ExitStatus> {
-        match self.0 {}
-    }
-
-    pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
-        match self.0 {}
-    }
-}
index 3de58904043573d4d4020021156e98c8d0383c12..2934ea59ab5ff687081f502df9e48417f7edea9d 100644 (file)
@@ -27,7 +27,7 @@
 pub mod net;
 #[path = "../unsupported/os.rs"]
 pub mod os;
-#[path = "../unsupported/path.rs"]
+#[path = "../unix/path.rs"]
 pub mod path;
 #[path = "../unsupported/pipe.rs"]
 pub mod pipe;
index 9d8c6f1815eeb38963decadd4bbb98d13a23a821..60a05dc5d545b74ea168a0a3c9d2b54251ead303 100644 (file)
@@ -424,10 +424,9 @@ pub unsafe fn get<F: FnOnce() -> T>(&self, init: F) -> Option<&'static T> {
         // thread_local's, or it is being recursively initialized.
         //
         // Macos: Inlining this function can cause two `tlv_get_addr` calls to
-        // be performed for every call to `Key::get`. The #[cold] hint makes
-        // that less likely.
+        // be performed for every call to `Key::get`.
         // LLVM issue: https://bugs.llvm.org/show_bug.cgi?id=41722
-        #[cold]
+        #[inline(never)]
         unsafe fn try_initialize<F: FnOnce() -> T>(&self, init: F) -> Option<&'static T> {
             if !mem::needs_drop::<T>() || self.try_register_dtor() {
                 Some(self.inner.initialize(init))
index 78891cdf292c23278ca8723bd543100249159604..718175b34a39e4e3d59b40e35930326edc515b87 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 78891cdf292c23278ca8723bd543100249159604
+Subproject commit 718175b34a39e4e3d59b40e35930326edc515b87
index 975b8be02c89831687ce21cad716007139ce5fcd..a69bd1cc3bc530f3d7f230d8232cfa2c51cd9837 100644 (file)
@@ -26,10 +26,10 @@ The script accepts commands, flags, and arguments to determine what to do:
 
   ```
   # build the whole compiler
-  ./x.py build
+  ./x.py build --stage 2
 
   # build the stage1 compiler
-  ./x.py build --stage 1
+  ./x.py build
 
   # build stage0 libstd
   ./x.py build --stage 0 library/std
@@ -43,8 +43,8 @@ The script accepts commands, flags, and arguments to determine what to do:
   that belong to stage n or earlier:
 
   ```
-  # keep old build products for stage 0 and build stage 1
-  ./x.py build --keep-stage 0 --stage 1
+  # build stage 1, keeping old build products for stage 0
+  ./x.py build --keep-stage 0
   ```
 
 * `test` - a command for executing unit tests. Like the `build` command this
@@ -123,24 +123,8 @@ that (b) leverage Rust as much as possible!
 
 ## Incremental builds
 
-You can configure rustbuild to use incremental compilation. Because
-incremental is new and evolving rapidly, if you want to use it, it is
-recommended that you replace the snapshot with a locally installed
-nightly build of rustc. You will want to keep this up to date.
-
-To follow this course of action, first thing you will want to do is to
-install a nightly, presumably using `rustup`. You will then want to
-configure your directory to use this build, like so:
-
-```sh
-# configure to use local rust instead of downloading a beta.
-# `--local-rust-root` is optional here. If elided, we will
-# use whatever rustc we find on your PATH.
-$ ./configure --local-rust-root=~/.cargo/ --enable-local-rebuild
-```
-
-After that, you can use the `--incremental` flag to actually do
-incremental builds:
+You can configure rustbuild to use incremental compilation with the
+`--incremental` flag:
 
 ```sh
 $ ./x.py build --incremental
@@ -150,9 +134,7 @@ The `--incremental` flag will store incremental compilation artifacts
 in `build/<host>/stage0-incremental`. Note that we only use incremental
 compilation for the stage0 -> stage1 compilation -- this is because
 the stage1 compiler is changing, and we don't try to cache and reuse
-incremental artifacts across different versions of the compiler. For
-this reason, `--incremental` defaults to `--stage 1` (though you can
-manually select a higher stage, if you prefer).
+incremental artifacts across different versions of the compiler.
 
 You can always drop the `--incremental` to build as normal (but you
 will still be using the local nightly as your bootstrap).
@@ -331,8 +313,8 @@ are:
   `Config` struct.
 * Adding a sanity check? Take a look at `bootstrap/sanity.rs`.
 
-If you have any questions feel free to reach out on `#infra` channel in the
-[Rust Discord server][rust-discord] or ask on internals.rust-lang.org. When
+If you have any questions feel free to reach out on the `#t-infra` channel in
+the [Rust Zulip server][rust-zulip] or ask on internals.rust-lang.org. When
 you encounter bugs, please file issues on the rust-lang/rust issue tracker.
 
-[rust-discord]: https://discord.gg/rust-lang
+[rust-zulip]: https://rust-lang.zulipchat.com/#narrow/stream/242791-t-infra
index 44a17f75451a92d520f2d822642769117647dc1c..5f78031e1c7cb29fbae6e44e874ab384afabde49 100644 (file)
@@ -429,6 +429,8 @@ class RustBuild(object):
             llvm_assertions = self.get_toml('assertions', 'llvm') == 'true'
             if self.program_out_of_date(self.llvm_stamp(), llvm_sha + str(llvm_assertions)):
                 self._download_ci_llvm(llvm_sha, llvm_assertions)
+                for binary in ["llvm-config", "FileCheck"]:
+                    self.fix_bin_or_dylib("{}/bin/{}".format(self.llvm_root(), binary))
                 with output(self.llvm_stamp()) as llvm_stamp:
                     llvm_stamp.write(self.date + llvm_sha + str(llvm_assertions))
 
index 0f18660c0e1092fd85876d89d4c1cbe23f64e262..140507eab66e66bf2786d2957638111e96e3d559 100644 (file)
@@ -526,23 +526,9 @@ pub fn get_help(build: &Build, subcommand: &str) -> Option<String> {
     }
 
     fn new_internal(build: &Build, kind: Kind, paths: Vec<PathBuf>) -> Builder<'_> {
-        let top_stage = if let Some(explicit_stage) = build.config.stage {
-            explicit_stage
-        } else {
-            // See https://github.com/rust-lang/compiler-team/issues/326
-            match kind {
-                Kind::Doc => 0,
-                Kind::Build | Kind::Test => 1,
-                Kind::Bench | Kind::Dist | Kind::Install => 2,
-                // These are all bootstrap tools, which don't depend on the compiler.
-                // The stage we pass shouldn't matter, but use 0 just in case.
-                Kind::Check | Kind::Clippy | Kind::Fix | Kind::Run | Kind::Format => 0,
-            }
-        };
-
         Builder {
             build,
-            top_stage,
+            top_stage: build.config.stage,
             kind,
             cache: Cache::new(),
             stack: RefCell::new(Vec::new()),
@@ -566,20 +552,7 @@ pub fn new(build: &Build) -> Builder<'_> {
             Subcommand::Format { .. } | Subcommand::Clean { .. } => panic!(),
         };
 
-        let this = Self::new_internal(build, kind, paths.to_owned());
-
-        // CI should always run stage 2 builds, unless it specifically states otherwise
-        #[cfg(not(test))]
-        if build.config.stage.is_none() && build.ci_env != crate::CiEnv::None {
-            match kind {
-                Kind::Test | Kind::Doc | Kind::Build | Kind::Bench | Kind::Dist | Kind::Install => {
-                    assert_eq!(this.top_stage, 2)
-                }
-                Kind::Check | Kind::Clippy | Kind::Fix | Kind::Run | Kind::Format => {}
-            }
-        }
-
-        this
+        Self::new_internal(build, kind, paths.to_owned())
     }
 
     pub fn execute_cli(&self) {
@@ -710,7 +683,7 @@ pub fn sysroot_libdir_relative(&self, compiler: Compiler) -> &Path {
 
     /// Adds the compiler's directory of dynamic libraries to `cmd`'s dynamic
     /// library lookup path.
-    pub fn add_rustc_lib_path(&self, compiler: Compiler, cmd: &mut Cargo) {
+    pub fn add_rustc_lib_path(&self, compiler: Compiler, cmd: &mut Command) {
         // Windows doesn't need dylib path munging because the dlls for the
         // compiler live next to the compiler and the system will find them
         // automatically.
@@ -718,7 +691,7 @@ pub fn add_rustc_lib_path(&self, compiler: Compiler, cmd: &mut Cargo) {
             return;
         }
 
-        add_dylib_path(vec![self.rustc_libdir(compiler)], &mut cmd.command);
+        add_dylib_path(vec![self.rustc_libdir(compiler)], cmd);
     }
 
     /// Gets a path to the compiler specified.
@@ -1515,6 +1488,10 @@ pub fn env(&mut self, key: impl AsRef<OsStr>, value: impl AsRef<OsStr>) -> &mut
         self.command.env(key.as_ref(), value.as_ref());
         self
     }
+
+    pub fn add_rustc_lib_path(&mut self, builder: &Builder<'_>, compiler: Compiler) {
+        builder.add_rustc_lib_path(compiler, &mut self.command);
+    }
 }
 
 impl From<Cargo> for Command {
index c6eac95c34507bcb8954be882db0060df40a2439..f96925f927086ad1e64c3902e7427288ccef655c 100644 (file)
@@ -2,8 +2,8 @@
 use crate::config::{Config, TargetSelection};
 use std::thread;
 
-fn configure(host: &[&str], target: &[&str]) -> Config {
-    let mut config = Config::default_opts();
+fn configure(cmd: &str, host: &[&str], target: &[&str]) -> Config {
+    let mut config = Config::parse(&[cmd.to_owned()]);
     // don't save toolstates
     config.save_toolstates = None;
     config.skip_only_host_steps = false;
@@ -42,7 +42,7 @@ mod defaults {
 
     #[test]
     fn build_default() {
-        let build = Build::new(configure(&[], &[]));
+        let build = Build::new(configure("build", &[], &[]));
         let mut builder = Builder::new(&build);
         builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Build), &[]);
 
@@ -70,7 +70,7 @@ fn build_default() {
 
     #[test]
     fn build_stage_0() {
-        let config = Config { stage: Some(0), ..configure(&[], &[]) };
+        let config = Config { stage: 0, ..configure("build", &[], &[]) };
         let build = Build::new(config);
         let mut builder = Builder::new(&build);
         builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Build), &[]);
@@ -92,7 +92,7 @@ fn build_stage_0() {
 
     #[test]
     fn doc_default() {
-        let mut config = configure(&[], &[]);
+        let mut config = configure("doc", &[], &[]);
         config.compiler_docs = true;
         config.cmd = Subcommand::Doc { paths: Vec::new(), open: false };
         let build = Build::new(config);
@@ -126,7 +126,7 @@ mod dist {
     use pretty_assertions::assert_eq;
 
     fn configure(host: &[&str], target: &[&str]) -> Config {
-        Config { stage: Some(2), ..super::configure(host, target) }
+        Config { stage: 2, ..super::configure("dist", host, target) }
     }
 
     #[test]
@@ -455,7 +455,7 @@ fn build_with_target_flag() {
     #[test]
     fn test_with_no_doc_stage0() {
         let mut config = configure(&[], &[]);
-        config.stage = Some(0);
+        config.stage = 0;
         config.cmd = Subcommand::Test {
             paths: vec!["library/std".into()],
             test_args: vec![],
index 7c8c729b5bfab56021247432c4dc0a1efd6280e3..30c9e012cd6f53d1ab6c91021a7d72b42d01ad17 100644 (file)
@@ -10,7 +10,6 @@
 use std::fmt;
 use std::fs;
 use std::path::{Path, PathBuf};
-use std::process;
 
 use crate::cache::{Interned, INTERNER};
 use crate::flags::Flags;
@@ -68,7 +67,7 @@ pub struct Config {
     pub skip_only_host_steps: bool,
 
     pub on_fail: Option<String>,
-    pub stage: Option<u32>,
+    pub stage: u32,
     pub keep_stage: Vec<u32>,
     pub src: PathBuf,
     pub jobs: Option<u32>,
@@ -313,6 +312,12 @@ struct Build {
     configure_args: Option<Vec<String>>,
     local_rebuild: Option<bool>,
     print_step_timings: Option<bool>,
+    doc_stage: Option<u32>,
+    build_stage: Option<u32>,
+    test_stage: Option<u32>,
+    install_stage: Option<u32>,
+    dist_stage: Option<u32>,
+    bench_stage: Option<u32>,
 }
 
 /// TOML representation of various global install decisions.
@@ -495,13 +500,11 @@ pub fn default_opts() -> Config {
 
     pub fn parse(args: &[String]) -> Config {
         let flags = Flags::parse(&args);
-        let file = flags.config.clone();
         let mut config = Config::default_opts();
         config.exclude = flags.exclude;
         config.rustc_error_format = flags.rustc_error_format;
         config.json_output = flags.json_output;
         config.on_fail = flags.on_fail;
-        config.stage = flags.stage;
         config.jobs = flags.jobs.map(threads_from_config);
         config.cmd = flags.cmd;
         config.incremental = flags.incremental;
@@ -518,8 +521,14 @@ pub fn parse(args: &[String]) -> Config {
             config.out = dir;
         }
 
-        let toml = file
+        #[cfg(test)]
+        let toml = TomlConfig::default();
+        #[cfg(not(test))]
+        let toml = flags
+            .config
             .map(|file| {
+                use std::process;
+
                 let contents = t!(fs::read_to_string(&file));
                 match toml::from_str(&contents) {
                     Ok(table) => table,
@@ -535,7 +544,7 @@ pub fn parse(args: &[String]) -> Config {
             })
             .unwrap_or_else(TomlConfig::default);
 
-        let build = toml.build.clone().unwrap_or_default();
+        let build = toml.build.unwrap_or_default();
 
         // If --target was specified but --host wasn't specified, don't run any host-only tests.
         let has_hosts = build.host.is_some() || flags.host.is_some();
@@ -579,6 +588,44 @@ pub fn parse(args: &[String]) -> Config {
         set(&mut config.configure_args, build.configure_args);
         set(&mut config.local_rebuild, build.local_rebuild);
         set(&mut config.print_step_timings, build.print_step_timings);
+
+        // See https://github.com/rust-lang/compiler-team/issues/326
+        config.stage = match config.cmd {
+            Subcommand::Doc { .. } => flags.stage.or(build.doc_stage).unwrap_or(0),
+            Subcommand::Build { .. } => flags.stage.or(build.build_stage).unwrap_or(1),
+            Subcommand::Test { .. } => flags.stage.or(build.test_stage).unwrap_or(1),
+            Subcommand::Bench { .. } => flags.stage.or(build.bench_stage).unwrap_or(2),
+            Subcommand::Dist { .. } => flags.stage.or(build.dist_stage).unwrap_or(2),
+            Subcommand::Install { .. } => flags.stage.or(build.install_stage).unwrap_or(2),
+            // These are all bootstrap tools, which don't depend on the compiler.
+            // The stage we pass shouldn't matter, but use 0 just in case.
+            Subcommand::Clean { .. }
+            | Subcommand::Check { .. }
+            | Subcommand::Clippy { .. }
+            | Subcommand::Fix { .. }
+            | Subcommand::Run { .. }
+            | Subcommand::Format { .. } => flags.stage.unwrap_or(0),
+        };
+
+        // CI should always run stage 2 builds, unless it specifically states otherwise
+        #[cfg(not(test))]
+        if flags.stage.is_none() && crate::CiEnv::current() != crate::CiEnv::None {
+            match config.cmd {
+                Subcommand::Test { .. }
+                | Subcommand::Doc { .. }
+                | Subcommand::Build { .. }
+                | Subcommand::Bench { .. }
+                | Subcommand::Dist { .. }
+                | Subcommand::Install { .. } => assert_eq!(config.stage, 2),
+                Subcommand::Clean { .. }
+                | Subcommand::Check { .. }
+                | Subcommand::Clippy { .. }
+                | Subcommand::Fix { .. }
+                | Subcommand::Run { .. }
+                | Subcommand::Format { .. } => {}
+            }
+        }
+
         config.verbose = cmp::max(config.verbose, flags.verbose);
 
         if let Some(ref install) = toml.install {
index d7f3a888edd899e5512ac4ab822a9964de73f308..f90e76a4f4ea68f8a8ee331a125bc9c5c0f56f3c 100644 (file)
@@ -66,7 +66,6 @@ fn run(self, builder: &Builder<'_>) {
     Nomicon, "src/doc/nomicon", "nomicon";
     Reference, "src/doc/reference", "reference";
     RustByExample, "src/doc/rust-by-example", "rust-by-example";
-    RustcBook, "src/doc/rustc", "rustc";
     RustdocBook, "src/doc/rustdoc", "rustdoc";
 );
 
@@ -718,3 +717,70 @@ fn symlink_dir_force(config: &Config, src: &Path, dst: &Path) -> io::Result<()>
 
     symlink_dir(config, src, dst)
 }
+
+#[derive(Ord, PartialOrd, Debug, Copy, Clone, Hash, PartialEq, Eq)]
+pub struct RustcBook {
+    pub compiler: Compiler,
+    pub target: TargetSelection,
+}
+
+impl Step for RustcBook {
+    type Output = ();
+    const DEFAULT: bool = true;
+    const ONLY_HOSTS: bool = true;
+
+    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
+        let builder = run.builder;
+        run.path("src/doc/rustc").default_condition(builder.config.docs)
+    }
+
+    fn make_run(run: RunConfig<'_>) {
+        run.builder.ensure(RustcBook {
+            compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build),
+            target: run.target,
+        });
+    }
+
+    /// Builds the rustc book.
+    ///
+    /// The lints are auto-generated by a tool, and then merged into the book
+    /// in the "md-doc" directory in the build output directory. Then
+    /// "rustbook" is used to convert it to HTML.
+    fn run(self, builder: &Builder<'_>) {
+        let out_base = builder.md_doc_out(self.target).join("rustc");
+        t!(fs::create_dir_all(&out_base));
+        let out_listing = out_base.join("src/lints");
+        builder.cp_r(&builder.src.join("src/doc/rustc"), &out_base);
+        builder.info(&format!("Generating lint docs ({})", self.target));
+        let rustc = builder.rustc(self.compiler);
+        // The tool runs `rustc` for extracting output examples, so it needs a
+        // functional sysroot.
+        builder.ensure(compile::Std { compiler: self.compiler, target: self.target });
+        let mut cmd = builder.tool_cmd(Tool::LintDocs);
+        cmd.arg("--src");
+        cmd.arg(builder.src.join("compiler"));
+        cmd.arg("--out");
+        cmd.arg(&out_listing);
+        cmd.arg("--rustc");
+        cmd.arg(rustc);
+        if builder.config.verbose() {
+            cmd.arg("--verbose");
+        }
+        // If the lib directories are in an unusual location (changed in
+        // config.toml), then this needs to explicitly update the dylib search
+        // path.
+        builder.add_rustc_lib_path(self.compiler, &mut cmd);
+        builder.run(&mut cmd);
+        // Run rustbook/mdbook to generate the HTML pages.
+        builder.ensure(RustbookSrc {
+            target: self.target,
+            name: INTERNER.intern_str("rustc"),
+            src: INTERNER.intern_path(out_base),
+        });
+        if is_explicit_request(builder, "src/doc/rustc") {
+            let out = builder.doc_out(self.target);
+            let index = out.join("rustc").join("index.html");
+            open(builder, &index);
+        }
+    }
+}
index 6cd850bc0bfaadfe8cc343f42ca86a8f0b811d2e..3829d47da335f005f0d46f5711bc68bcfc00776e 100644 (file)
@@ -129,6 +129,10 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
                 Err(m) => m,
             };
 
+        if builder.config.llvm_link_shared && target.contains("windows") {
+            panic!("shared linking to LLVM is not currently supported on Windows");
+        }
+
         builder.info(&format!("Building LLVM for {}", target));
         t!(stamp.remove());
         let _time = util::timeit(&builder);
index 045dda2d4cb4cbbc5da6631bda9dc4616e9c670f..ba5f75c49ac7769e2de63b3686afc88ec98ee89e 100644 (file)
@@ -270,7 +270,7 @@ fn run(self, builder: &Builder<'_>) {
             &[],
         );
 
-        builder.add_rustc_lib_path(compiler, &mut cargo);
+        cargo.add_rustc_lib_path(builder, compiler);
         cargo.arg("--").args(builder.config.cmd.test_args());
 
         if try_run(builder, &mut cargo.into()) {
@@ -328,7 +328,7 @@ fn run(self, builder: &Builder<'_>) {
         t!(fs::create_dir_all(&dir));
         cargo.env("RUSTFMT_TEST_DIR", dir);
 
-        builder.add_rustc_lib_path(compiler, &mut cargo);
+        cargo.add_rustc_lib_path(builder, compiler);
 
         if try_run(builder, &mut cargo.into()) {
             builder.save_toolstate("rustfmt", ToolState::TestPass);
@@ -449,7 +449,7 @@ fn run(self, builder: &Builder<'_>) {
 
             cargo.arg("--").args(builder.config.cmd.test_args());
 
-            builder.add_rustc_lib_path(compiler, &mut cargo);
+            cargo.add_rustc_lib_path(builder, compiler);
 
             if !try_run(builder, &mut cargo.into()) {
                 return;
@@ -554,7 +554,7 @@ fn run(self, builder: &Builder<'_>) {
 
         cargo.arg("--").args(builder.config.cmd.test_args());
 
-        builder.add_rustc_lib_path(compiler, &mut cargo);
+        cargo.add_rustc_lib_path(builder, compiler);
 
         builder.run(&mut cargo.into());
     }
index a607f0fe258d4cf257606ed5c17128abc2ef3a68..99e33e3b006fe89a2d2d02f41875ca10d0a31030 100644 (file)
@@ -367,6 +367,7 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
     RustInstaller, "src/tools/rust-installer", "fabricate", is_external_tool = true;
     RustdocTheme, "src/tools/rustdoc-themes", "rustdoc-themes";
     ExpandYamlAnchors, "src/tools/expand-yaml-anchors", "expand-yaml-anchors";
+    LintDocs, "src/tools/lint-docs", "lint-docs";
 );
 
 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, Ord, PartialOrd)]
diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/build-git.sh b/src/ci/docker/host-x86_64/dist-x86_64-linux/build-git.sh
deleted file mode 100755 (executable)
index 38fea2a..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-#!/usr/bin/env bash
-
-set -ex
-source shared.sh
-
-curl -L https://www.kernel.org/pub/software/scm/git/git-2.10.0.tar.gz | tar xzf -
-
-cd git-2.10.0
-make configure
-hide_output ./configure --prefix=/rustroot
-hide_output make -j10
-hide_output make install
-
-cd ..
-rm -rf git-2.10.0
diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/build-headers.sh b/src/ci/docker/host-x86_64/dist-x86_64-linux/build-headers.sh
deleted file mode 100755 (executable)
index b623e53..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-#!/usr/bin/env bash
-
-set -ex
-source shared.sh
-
-curl https://cdn.kernel.org/pub/linux/kernel/v3.x/linux-3.2.84.tar.xz | unxz | tar x
-
-cd linux-3.2.84
-hide_output make mrproper
-hide_output make INSTALL_HDR_PATH=dest headers_install
-
-find dest/include \( -name .install -o -name ..install.cmd \) -delete
-yes | cp -fr dest/include/* /usr/include
-
-cd ..
-rm -rf linux-3.2.84
diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/build-perl.sh b/src/ci/docker/host-x86_64/dist-x86_64-linux/build-perl.sh
deleted file mode 100755 (executable)
index a678d35..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-#!/usr/bin/env bash
-
-set -ex
-source shared.sh
-
-curl https://www.cpan.org/src/5.0/perl-5.28.0.tar.gz | \
-  tar xzf -
-
-cd perl-5.28.0
-
-# Gotta do some hackery to tell python about our custom OpenSSL build, but other
-# than that fairly normal.
-CC=gcc \
-CFLAGS='-I /rustroot/include -fgnu89-inline' \
-LDFLAGS='-L /rustroot/lib -L /rustroot/lib64' \
-    hide_output ./configure.gnu
-hide_output make -j10
-hide_output make install
-
-cd ..
-rm -rf perl-5.28.0
index 2109cdf4e86b7f42f58352957955897baceede46..f8d3bc8e8e5881be92e5346c6a682cfe260db10e 100644 (file)
@@ -130,9 +130,7 @@ x--expand-yaml-anchors--remove:
         uses: rust-lang/simpleinfra/github-actions/cancel-outdated-builds@master
         with:
           github_token: "${{ secrets.github_token }}"
-        # TODO: remove the condition on RUST_CI_TEMP_SKIP_CANCEL_OUTDATED once
-        # we remove the `auto-fallible` job.
-        if: success() && !env.SKIP_JOB && github.ref != 'refs/heads/try' && !env.RUST_CI_TEMP_SKIP_CANCEL_OUTDATED
+        if: success() && !env.SKIP_JOB && github.ref != 'refs/heads/try'
         <<: *step
 
       - name: collect CPU statistics
@@ -434,6 +432,78 @@ jobs:
               DEPLOY_TOOLSTATES_JSON: toolstates-linux.json
             <<: *job-linux-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
+              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
+              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
+
           ######################
           #  Windows Builders  #
           ######################
@@ -600,54 +670,6 @@ jobs:
           - name: aarch64-gnu
             <<: *job-aarch64-linux
 
-          ####################
-          #  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
-              RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
-              MACOSX_DEPLOYMENT_TARGET: 10.7
-              NO_LLVM_ASSERTIONS: 1
-              NO_DEBUG_ASSERTIONS: 1
-              DIST_REQUIRE_ALL_TOOLS: 1
-
-              # TODO: remove once we move this job away from auto-fallible.
-              # Also, remove the variable from the cancel-outdated-builds step
-              RUST_CI_TEMP_SKIP_CANCEL_OUTDATED: 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
-
-              # TODO: remove once we move this job away from auto-fallible.
-              # Also, remove the variable from the cancel-outdated-builds step
-              RUST_CI_TEMP_SKIP_CANCEL_OUTDATED: 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
-
-              # TODO: remove once we move this job away from auto-fallible.
-              # Also, remove the variable from the cancel-outdated-builds step
-              RUST_CI_TEMP_SKIP_CANCEL_OUTDATED: 1
-            <<: *job-macos-xl
-
   master:
     name: master
     runs-on: ubuntu-latest
index 5231aa2e7661979f0ff006deeb5093682900311e..c8faf1ec83179436d248f9b2701bd80c71a6b4e3 100755 (executable)
@@ -75,6 +75,13 @@ if [ "$DEPLOY$DEPLOY_ALT" = "1" ]; then
   RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set rust.remap-debuginfo"
   RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --debuginfo-level-std=1"
 
+  # If we're distributing binaries, we want a shared LLVM link. We're already
+  # going to link LLVM to the LLVM tools dynamically, so we need to ship a
+  # libLLVM library anyway.
+  if !isWindows; then
+    RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set llvm.link-shared=true"
+  fi
+
   if [ "$NO_LLVM_ASSERTIONS" = "1" ]; then
     RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --disable-llvm-assertions"
   elif [ "$DEPLOY_ALT" != "" ]; then
index 049e59b651722ab029e25365d6fc93e2c665cf57..44cf42ff0d71b3dcc3e73289e6099292992685f7 100644 (file)
@@ -14,14 +14,7 @@ $ rustc -D non-camel-case-types -D non-snake-case -D non-upper-case-globals
 
 Here's a list of each lint group, and the lints that they are made up of:
 
-| group               | description                                                   | lints                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
-|---------------------|---------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| nonstandard-style   | Violation of standard naming conventions                      | non-camel-case-types, non-snake-case, non-upper-case-globals                                                                                                                                                                                                                                                                                                                                                                                                                           |
-| warnings            | all lints that would be issuing warnings                      | all lints that would be issuing warnings                                                                                                                                                                                                                                                                                                                                                                                                                                               |
-| edition-2018        | Lints that will be turned into errors in Rust 2018            | tyvar-behind-raw-pointer                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
-| rust-2018-idioms    | Lints to nudge you toward idiomatic features of Rust 2018     | bare-trait-object, unreachable-pub                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
-| unused              | These lints detect things being declared but not used         | unused-imports, unused-variables, unused-assignments, dead-code, unused-mut, unreachable-code, unreachable-patterns, unused-must-use, unused-unsafe, path-statements, unused-attributes, unused-macros, unused-allocation, unused-doc-comment, unused-extern-crates, unused-features, unused-parens                                                                                                                                                                                    |
-| future-incompatible | Lints that detect code that has future-compatibility problems | private-in-public, pub-use-of-private-extern-crate, patterns-in-fns-without-body, safe-extern-statics, invalid-type-param-default, legacy-directory-ownership, legacy-imports, legacy-constructor-visibility, missing-fragment-specifier, illegal-floating-point-literal-pattern, anonymous-parameters, parenthesized-params-in-types-and-modules, late-bound-lifetime-arguments, safe-packed-borrows, tyvar-behind-raw-pointer, unstable-name-collision |
+{{groups-table}}
 
 Additionally, there's a `bad-style` lint group that's a deprecated alias for `nonstandard-style`.
 
index 9010d436eb5cfa6eac08b2915252459e8d26d78b..029c9edc1b5feacd086b118a981d8a30c4ec46d5 100644 (file)
@@ -26,3 +26,35 @@ warning: unused variable: `x`
 This is the `unused_variables` lint, and it tells you that you've introduced
 a variable that you don't use in your code. That's not *wrong*, so it's not
 an error, but it might be a bug, so you get a warning.
+
+## Future-incompatible lints
+
+Sometimes the compiler needs to be changed to fix an issue that can cause
+existing code to stop compiling. "Future-incompatible" lints are issued in
+these cases to give users of Rust a smooth transition to the new behavior.
+Initially, the compiler will continue to accept the problematic code and issue
+a warning. The warning has a description of the problem, a notice that this
+will become an error in the future, and a link to a tracking issue that
+provides detailed information and an opportunity for feedback. This gives
+users some time to fix the code to accommodate the change. After some time,
+the warning may become an error.
+
+The following is an example of what a future-incompatible looks like:
+
+```text
+warning: borrow of packed field is unsafe and requires unsafe function or block (error E0133)
+  --> lint_example.rs:11:13
+   |
+11 |     let y = &x.data.0;
+   |             ^^^^^^^^^
+   |
+   = note: `#[warn(safe_packed_borrows)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #46043 <https://github.com/rust-lang/rust/issues/46043>
+   = note: fields of packed structs might be misaligned: dereferencing a misaligned pointer or even just creating a misaligned reference is undefined behavior
+```
+
+For more information about the process and policy of future-incompatible
+changes, see [RFC 1589].
+
+[RFC 1589]: https://github.com/rust-lang/rfcs/blob/master/text/1589-rustc-bug-fix-procedure.md
index d2d8c471efc96d0b5989026083ca18f1c84a140d..95dd60bebfbad5a0b05703ca465e3730082d503d 100644 (file)
@@ -1,454 +1,3 @@
 # Allowed-by-default lints
 
-These lints are all set to the 'allow' level by default. As such, they won't show up
-unless you set them to a higher lint level with a flag or attribute.
-
-## anonymous-parameters
-
-This lint detects anonymous parameters. Some example code that triggers this lint:
-
-```rust
-trait Foo {
-    fn foo(usize);
-}
-```
-
-When set to 'deny', this will produce:
-
-```text
-error: use of deprecated anonymous parameter
- --> src/lib.rs:5:11
-  |
-5 |     fn foo(usize);
-  |           ^
-  |
-  = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-  = note: for more information, see issue #41686 <https://github.com/rust-lang/rust/issues/41686>
-```
-
-This syntax is mostly a historical accident, and can be worked around quite
-easily:
-
-```rust
-trait Foo {
-    fn foo(_: usize);
-}
-```
-
-## bare-trait-object
-
-This lint suggests using `dyn Trait` for trait objects. Some example code
-that triggers this lint:
-
-```rust
-#![feature(dyn_trait)]
-
-trait Trait { }
-
-fn takes_trait_object(_: Box<Trait>) {
-}
-```
-
-When set to 'deny', this will produce:
-
-```text
-error: trait objects without an explicit `dyn` are deprecated
- --> src/lib.rs:7:30
-  |
-7 | fn takes_trait_object(_: Box<Trait>) {
-  |                              ^^^^^ help: use `dyn`: `dyn Trait`
-  |
-```
-
-To fix it, do as the help message suggests:
-
-```rust
-#![feature(dyn_trait)]
-#![deny(bare_trait_objects)]
-
-trait Trait { }
-
-fn takes_trait_object(_: Box<dyn Trait>) {
-}
-```
-
-## box-pointers
-
-This lints use of the Box type. Some example code that triggers this lint:
-
-```rust
-struct Foo {
-    x: Box<isize>,
-}
-```
-
-When set to 'deny', this will produce:
-
-```text
-error: type uses owned (Box type) pointers: std::boxed::Box<isize>
- --> src/lib.rs:6:5
-  |
-6 |     x: Box<isize> //~ ERROR type uses owned
-  |     ^^^^^^^^^^^^^
-  |
-```
-
-This lint is mostly historical, and not particularly useful. `Box<T>` used to
-be built into the language, and the only way to do heap allocation. Today's
-Rust can call into other allocators, etc.
-
-## elided-lifetime-in-path
-
-This lint detects the use of hidden lifetime parameters. Some example code
-that triggers this lint:
-
-```rust
-struct Foo<'a> {
-    x: &'a u32
-}
-
-fn foo(x: &Foo) {
-}
-```
-
-When set to 'deny', this will produce:
-
-```text
-error: hidden lifetime parameters are deprecated, try `Foo<'_>`
- --> src/lib.rs:5:12
-  |
-5 | fn foo(x: &Foo) {
-  |            ^^^
-  |
-```
-
-Lifetime elision elides this lifetime, but that is being deprecated.
-
-## missing-copy-implementations
-
-This lint detects potentially-forgotten implementations of `Copy`. Some
-example code that triggers this lint:
-
-```rust
-pub struct Foo {
-    pub field: i32
-}
-```
-
-When set to 'deny', this will produce:
-
-```text
-error: type could implement `Copy`; consider adding `impl Copy`
- --> src/main.rs:3:1
-  |
-3 | / pub struct Foo { //~ ERROR type could implement `Copy`; consider adding `impl Copy`
-4 | |     pub field: i32
-5 | | }
-  | |_^
-  |
-```
-
-You can fix the lint by deriving `Copy`.
-
-This lint is set to 'allow' because this code isn't bad; it's common to write
-newtypes like this specifically so that a `Copy` type is no longer `Copy`.
-
-## missing-debug-implementations
-
-This lint detects missing implementations of `fmt::Debug`. Some example code
-that triggers this lint:
-
-```rust
-pub struct Foo;
-```
-
-When set to 'deny', this will produce:
-
-```text
-error: type does not implement `fmt::Debug`; consider adding `#[derive(Debug)]` or a manual implementation
- --> src/main.rs:3:1
-  |
-3 | pub struct Foo;
-  | ^^^^^^^^^^^^^^^
-  |
-```
-
-You can fix the lint by deriving `Debug`.
-
-## missing-docs
-
-This lint detects missing documentation for public items. Some example code
-that triggers this lint:
-
-```rust
-pub fn foo() {}
-```
-
-When set to 'deny', this will produce:
-
-```text
-error: missing documentation for crate
- --> src/main.rs:1:1
-  |
-1 | / #![deny(missing_docs)]
-2 | |
-3 | | pub fn foo() {}
-4 | |
-5 | | fn main() {}
-  | |____________^
-  |
-
-error: missing documentation for a function
- --> src/main.rs:3:1
-  |
-3 | pub fn foo() {}
-  | ^^^^^^^^^^^^
-
-```
-
-To fix the lint, add documentation to all items.
-
-## single-use-lifetimes
-
-This lint detects lifetimes that are only used once. Some example code that
-triggers this lint:
-
-```rust
-struct Foo<'x> {
-    x: &'x u32
-}
-```
-
-When set to 'deny', this will produce:
-
-```text
-error: lifetime name `'x` only used once
- --> src/main.rs:3:12
-  |
-3 | struct Foo<'x> {
-  |            ^^
-  |
-```
-
-## trivial-casts
-
-This lint detects trivial casts which could be replaced with coercion, which may require
-type ascription or a temporary variable. Some example code
-that triggers this lint:
-
-```rust
-let x: &u32 = &42;
-let _ = x as *const u32;
-```
-
-When set to 'deny', this will produce:
-
-```text
-error: trivial cast: `&u32` as `*const u32`. Cast can be replaced by coercion, this might require type ascription or a temporary variable
- --> src/main.rs:5:13
-  |
-5 |     let _ = x as *const u32;
-  |             ^^^^^^^^^^^^^^^
-  |
-note: lint level defined here
- --> src/main.rs:1:9
-  |
-1 | #![deny(trivial_casts)]
-  |         ^^^^^^^^^^^^^
-```
-
-## trivial-numeric-casts
-
-This lint detects trivial casts of numeric types which could be removed. Some
-example code that triggers this lint:
-
-```rust
-let x = 42i32 as i32;
-```
-
-When set to 'deny', this will produce:
-
-```text
-error: trivial numeric cast: `i32` as `i32`. Cast can be replaced by coercion, this might require type ascription or a temporary variable
- --> src/main.rs:4:13
-  |
-4 |     let x = 42i32 as i32;
-  |             ^^^^^^^^^^^^
-  |
-```
-
-## unreachable-pub
-
-This lint triggers for `pub` items not reachable from the crate root. Some
-example code that triggers this lint:
-
-```rust
-mod foo {
-    pub mod bar {
-        
-    }
-}
-```
-
-When set to 'deny', this will produce:
-
-```text
-error: unreachable `pub` item
- --> src/main.rs:4:5
-  |
-4 |     pub mod bar {
-  |     ---^^^^^^^^
-  |     |
-  |     help: consider restricting its visibility: `pub(crate)`
-  |
-```
-
-## unsafe-code
-
-This lint catches usage of `unsafe` code. Some example code that triggers this lint:
-
-```rust
-fn main() {
-    unsafe {
-
-    }
-}
-```
-
-When set to 'deny', this will produce:
-
-```text
-error: usage of an `unsafe` block
- --> src/main.rs:4:5
-  |
-4 | /     unsafe {
-5 | |         
-6 | |     }
-  | |_____^
-  |
-```
-
-## unstable-features
-
-This lint is deprecated and no longer used.
-
-## unused-extern-crates
-
-This lint guards against `extern crate` items that are never used. Some
-example code that triggers this lint:
-
-```rust,ignore
-extern crate semver;
-```
-
-When set to 'deny', this will produce:
-
-```text
-error: unused extern crate
- --> src/main.rs:3:1
-  |
-3 | extern crate semver;
-  | ^^^^^^^^^^^^^^^^^^^^
-  |
-```
-
-## unused-import-braces
-
-This lint catches unnecessary braces around an imported item. Some example
-code that triggers this lint:
-
-```rust
-use test::{A};
-
-pub mod test {
-    pub struct A;
-}
-# fn main() {}
-```
-
-When set to 'deny', this will produce:
-
-```text
-error: braces around A is unnecessary
- --> src/main.rs:3:1
-  |
-3 | use test::{A};
-  | ^^^^^^^^^^^^^^
-  |
-```
-
-To fix it, `use test::A;`
-
-## unused-qualifications
-
-This lint detects unnecessarily qualified names. Some example code that triggers this lint:
-
-```rust
-mod foo {
-    pub fn bar() {}
-}
-
-fn main() {
-    use foo::bar;
-    foo::bar();
-}
-```
-
-When set to 'deny', this will produce:
-
-```text
-error: unnecessary qualification
- --> src/main.rs:9:5
-  |
-9 |     foo::bar();
-  |     ^^^^^^^^
-  |
-```
-
-You can call `bar()` directly, without the `foo::`.
-
-## unused-results
-
-This lint checks for the unused result of an expression in a statement. Some
-example code that triggers this lint:
-
-```rust,no_run
-fn foo<T>() -> T { panic!() }
-
-fn main() {
-    foo::<usize>();
-}
-```
-
-When set to 'deny', this will produce:
-
-```text
-error: unused result
- --> src/main.rs:6:5
-  |
-6 |     foo::<usize>();
-  |     ^^^^^^^^^^^^^^^
-  |
-```
-
-## variant-size-differences
-
-This lint detects enums with widely varying variant sizes. Some example code that triggers this lint:
-
-```rust
-enum En {
-    V0(u8),
-    VBig([u8; 1024]),
-}
-```
-
-When set to 'deny', this will produce:
-
-```text
-error: enum variant is more than three times larger (1024 bytes) than the next largest
- --> src/main.rs:5:5
-  |
-5 |     VBig([u8; 1024]),   //~ ERROR variant is more than three times larger
-  |     ^^^^^^^^^^^^^^^^
-  |
-```
+This file is auto-generated by the lint-docs script.
index 55714f8f4548b8b221bcf951012685a6c562cc76..3c1452d64676c68936711da2ed3b2e550c22123f 100644 (file)
@@ -1,203 +1,3 @@
 # Deny-by-default lints
 
-These lints are all set to the 'deny' level by default.
-
-## exceeding-bitshifts
-
-This lint detects that a shift exceeds the type's number of bits. Some
-example code that triggers this lint:
-
-```rust,ignore
-1_i32 << 32;
-```
-
-This will produce:
-
-```text
-error: bitshift exceeds the type's number of bits
- --> src/main.rs:2:5
-  |
-2 |     1_i32 << 32;
-  |     ^^^^^^^^^^^
-  |
-```
-
-## invalid-type-param-default
-
-This lint detects type parameter default erroneously allowed in invalid location. Some
-example code that triggers this lint:
-
-```rust,ignore
-fn foo<T=i32>(t: T) {}
-```
-
-This will produce:
-
-```text
-error: defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions.
- --> src/main.rs:4:8
-  |
-4 | fn foo<T=i32>(t: T) {}
-  |        ^
-  |
-  = note: `#[deny(invalid_type_param_default)]` on by default
-  = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-  = note: for more information, see issue #36887 <https://github.com/rust-lang/rust/issues/36887>
-```
-
-## mutable-transmutes
-
-This lint catches transmuting from `&T` to `&mut T` because it is undefined
-behavior. Some example code that triggers this lint:
-
-```rust,ignore
-unsafe {
-    let y = std::mem::transmute::<&i32, &mut i32>(&5);
-}
-```
-
-This will produce:
-
-```text
-error: mutating transmuted &mut T from &T may cause undefined behavior, consider instead using an UnsafeCell
- --> src/main.rs:3:17
-  |
-3 |         let y = std::mem::transmute::<&i32, &mut i32>(&5);
-  |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-  |
-```
-
-
-## no-mangle-const-items
-
-This lint detects any `const` items with the `#[no_mangle]` attribute.
-Constants do not have their symbols exported, and therefore, this probably
-means you meant to use a `static`, not a `const`. Some example code that
-triggers this lint:
-
-```rust,ignore
-#[no_mangle]
-const FOO: i32 = 5;
-```
-
-This will produce:
-
-```text
-error: const items should never be `#[no_mangle]`
- --> src/main.rs:3:1
-  |
-3 | const FOO: i32 = 5;
-  | -----^^^^^^^^^^^^^^
-  | |
-  | help: try a static value: `pub static`
-  |
-```
-
-## overflowing-literals
-
-This lint detects literal out of range for its type. Some
-example code that triggers this lint:
-
-```rust,compile_fail
-let x: u8 = 1000;
-```
-
-This will produce:
-
-```text
-error: literal out of range for u8
- --> src/main.rs:2:17
-  |
-2 |     let x: u8 = 1000;
-  |                 ^^^^
-  |
-```
-
-## patterns-in-fns-without-body
-
-This lint detects patterns in functions without body were that were
-previously erroneously allowed. Some example code that triggers this lint:
-
-```rust,compile_fail
-trait Trait {
-    fn foo(mut arg: u8);
-}
-```
-
-This will produce:
-
-```text
-warning: patterns aren't allowed in methods without bodies
- --> src/main.rs:2:12
-  |
-2 |     fn foo(mut arg: u8);
-  |            ^^^^^^^
-  |
-  = note: `#[warn(patterns_in_fns_without_body)]` on by default
-  = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-  = note: for more information, see issue #35203 <https://github.com/rust-lang/rust/issues/35203>
-```
-
-To fix this, remove the pattern; it can be used in the implementation without
-being used in the definition. That is:
-
-```rust
-trait Trait {
-    fn foo(arg: u8);
-}
-
-impl Trait for i32 {
-    fn foo(mut arg: u8) {
-
-    }
-}
-```
-
-## pub-use-of-private-extern-crate
-
-This lint detects a specific situation of re-exporting a private `extern crate`;
-
-## unknown-crate-types
-
-This lint detects an unknown crate type found in a `#[crate_type]` directive. Some
-example code that triggers this lint:
-
-```rust,ignore
-#![crate_type="lol"]
-```
-
-This will produce:
-
-```text
-error: invalid `crate_type` value
- --> src/lib.rs:1:1
-  |
-1 | #![crate_type="lol"]
-  | ^^^^^^^^^^^^^^^^^^^^
-  |
-```
-
-## const-err
-
-This lint detects expressions that will always panic at runtime and would be an
-error in a `const` context.
-
-```rust,ignore
-let _ = [0; 4][4];
-```
-
-This will produce:
-
-```text
-error: index out of bounds: the len is 4 but the index is 4
- --> src/lib.rs:1:9
-  |
-1 | let _ = [0; 4][4];
-  |         ^^^^^^^^^
-  |
-```
-
-## order-dependent-trait-objects
-
-This lint detects a trait coherency violation that would allow creating two
-trait impls for the same dynamic trait object involving marker traits.
+This file is auto-generated by the lint-docs script.
index 386f6008d06aad0b1b15741662ec43fad2529cf4..eebc022a82bf8298c0cf1459a9e4c675751d5027 100644 (file)
@@ -1,903 +1,3 @@
 # Warn-by-default lints
 
-These lints are all set to the 'warn' level by default.
-
-## const-err
-
-This lint detects an erroneous expression while doing constant evaluation. Some
-example code that triggers this lint:
-
-```rust,ignore
-let b = 200u8 + 200u8;
-```
-
-This will produce:
-
-```text
-warning: attempt to add with overflow
- --> src/main.rs:2:9
-  |
-2 | let b = 200u8 + 200u8;
-  |         ^^^^^^^^^^^^^
-  |
-```
-
-## dead-code
-
-This lint detects unused, unexported items. Some
-example code that triggers this lint:
-
-```rust
-fn foo() {}
-```
-
-This will produce:
-
-```text
-warning: function is never used: `foo`
- --> src/lib.rs:2:1
-  |
-2 | fn foo() {}
-  | ^^^^^^^^
-  |
-```
-
-## deprecated
-
-This lint detects use of deprecated items. Some
-example code that triggers this lint:
-
-```rust
-#[deprecated]
-fn foo() {}
-
-fn bar() {
-    foo();
-}
-```
-
-This will produce:
-
-```text
-warning: use of deprecated item 'foo'
- --> src/lib.rs:7:5
-  |
-7 |     foo();
-  |     ^^^
-  |
-```
-
-## illegal-floating-point-literal-pattern
-
-This lint detects floating-point literals used in patterns. Some example code
-that triggers this lint:
-
-```rust
-let x = 42.0;
-
-match x {
-    5.0 => {},
-    _ => {},
-}
-```
-
-This will produce:
-
-```text
-warning: floating-point literals cannot be used in patterns
- --> src/main.rs:4:9
-  |
-4 |         5.0 => {},
-  |         ^^^
-  |
-  = note: `#[warn(illegal_floating_point_literal_pattern)]` on by default
-  = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-  = note: for more information, see issue #41620 <https://github.com/rust-lang/rust/issues/41620>
-```
-
-## improper-ctypes
-
-This lint detects proper use of libc types in foreign modules. Some
-example code that triggers this lint:
-
-```rust
-extern "C" {
-    static STATIC: String;
-}
-```
-
-This will produce:
-
-```text
-warning: found struct without foreign-function-safe representation annotation in foreign module, consider adding a `#[repr(C)]` attribute to the type
- --> src/main.rs:2:20
-  |
-2 |     static STATIC: String;
-  |                    ^^^^^^
-  |
-```
-
-## late-bound-lifetime-arguments
-
-This lint detects generic lifetime arguments in path segments with
-late bound lifetime parameters. Some example code that triggers this lint:
-
-```rust
-struct S;
-
-impl S {
-    fn late<'a, 'b>(self, _: &'a u8, _: &'b u8) {}
-}
-
-fn main() {
-    S.late::<'static>(&0, &0);
-}
-```
-
-This will produce:
-
-```text
-warning: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
- --> src/main.rs:8:14
-  |
-4 |     fn late<'a, 'b>(self, _: &'a u8, _: &'b u8) {}
-  |             -- the late bound lifetime parameter is introduced here
-...
-8 |     S.late::<'static>(&0, &0);
-  |              ^^^^^^^
-  |
-  = note: `#[warn(late_bound_lifetime_arguments)]` on by default
-  = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-  = note: for more information, see issue #42868 <https://github.com/rust-lang/rust/issues/42868>
-```
-
-## non-camel-case-types
-
-This lint detects types, variants, traits and type parameters that don't have
-camel case names. Some example code that triggers this lint:
-
-```rust
-struct s;
-```
-
-This will produce:
-
-```text
-warning: type `s` should have a camel case name such as `S`
- --> src/main.rs:1:1
-  |
-1 | struct s;
-  | ^^^^^^^^^
-  |
-```
-
-## non-shorthand-field-patterns
-
-This lint detects using `Struct { x: x }` instead of `Struct { x }` in a pattern. Some
-example code that triggers this lint:
-
-```rust
-struct Point {
-    x: i32,
-    y: i32,
-}
-
-
-fn main() {
-    let p = Point {
-        x: 5,
-        y: 5,
-    };
-
-    match p {
-        Point { x: x, y: y } => (),
-    }
-}
-```
-
-This will produce:
-
-```text
-warning: the `x:` in this pattern is redundant
-  --> src/main.rs:14:17
-   |
-14 |         Point { x: x, y: y } => (),
-   |                 --^^
-   |                 |
-   |                 help: remove this
-   |
-
-warning: the `y:` in this pattern is redundant
-  --> src/main.rs:14:23
-   |
-14 |         Point { x: x, y: y } => (),
-   |                       --^^
-   |                       |
-   |                       help: remove this
-
-```
-
-## non-snake-case
-
-This lint detects variables, methods, functions, lifetime parameters and
-modules that don't have snake case names. Some example code that triggers
-this lint:
-
-```rust
-let X = 5;
-```
-
-This will produce:
-
-```text
-warning: variable `X` should have a snake case name such as `x`
- --> src/main.rs:2:9
-  |
-2 |     let X = 5;
-  |         ^
-  |
-```
-
-## non-upper-case-globals
-
-This lint detects static constants that don't have uppercase identifiers.
-Some example code that triggers this lint:
-
-```rust
-static x: i32 = 5;
-```
-
-This will produce:
-
-```text
-warning: static variable `x` should have an upper case name such as `X`
- --> src/main.rs:1:1
-  |
-1 | static x: i32 = 5;
-  | ^^^^^^^^^^^^^^^^^^
-  |
-```
-
-## no-mangle-generic-items
-
-This lint detects generic items must be mangled. Some
-example code that triggers this lint:
-
-```rust
-#[no_mangle]
-fn foo<T>(t: T) {
-
-}
-```
-
-This will produce:
-
-```text
-warning: functions generic over types must be mangled
- --> src/main.rs:2:1
-  |
-1 |   #[no_mangle]
-  |   ------------ help: remove this attribute
-2 | / fn foo<T>(t: T) {
-3 | |
-4 | | }
-  | |_^
-  |
-```
-
-## path-statements
-
-This lint detects path statements with no effect. Some example code that
-triggers this lint:
-
-```rust
-let x = 42;
-
-x;
-```
-
-This will produce:
-
-```text
-warning: path statement with no effect
- --> src/main.rs:3:5
-  |
-3 |     x;
-  |     ^^
-  |
-```
-
-## private-in-public
-
-This lint detects private items in public interfaces not caught by the old implementation. Some
-example code that triggers this lint:
-
-```rust,ignore
-pub trait Trait {
-    type A;
-}
-
-pub struct S;
-
-mod foo {
-    struct Z;
-
-    impl ::Trait for ::S {
-        type A = Z;
-    }
-}
-# fn main() {}
-```
-
-This will produce:
-
-```text
-error[E0446]: private type `foo::Z` in public interface
-  --> src/main.rs:11:9
-   |
-11 |         type A = Z;
-   |         ^^^^^^^^^^^ can't leak private type
-```
-
-## private-no-mangle-fns
-
-This lint detects functions marked `#[no_mangle]` that are also private.
-Given that private functions aren't exposed publicly, and `#[no_mangle]`
-controls the public symbol, this combination is erroneous. Some example code
-that triggers this lint:
-
-```rust
-#[no_mangle]
-fn foo() {}
-```
-
-This will produce:
-
-```text
-warning: function is marked `#[no_mangle]`, but not exported
- --> src/main.rs:2:1
-  |
-2 | fn foo() {}
-  | -^^^^^^^^^^
-  | |
-  | help: try making it public: `pub`
-  |
-```
-
-To fix this, either make it public or remove the `#[no_mangle]`.
-
-## private-no-mangle-statics
-
-This lint detects any statics marked `#[no_mangle]` that are private.
-Given that private statics aren't exposed publicly, and `#[no_mangle]`
-controls the public symbol, this combination is erroneous. Some example code
-that triggers this lint:
-
-```rust
-#[no_mangle]
-static X: i32 = 4;
-```
-
-This will produce:
-
-```text
-warning: static is marked `#[no_mangle]`, but not exported
- --> src/main.rs:2:1
-  |
-2 | static X: i32 = 4;
-  | -^^^^^^^^^^^^^^^^^
-  | |
-  | help: try making it public: `pub`
-  |
-```
-
-To fix this, either make it public or remove the `#[no_mangle]`.
-
-## renamed-and-removed-lints
-
-This lint detects lints that have been renamed or removed. Some
-example code that triggers this lint:
-
-```rust
-#![deny(raw_pointer_derive)]
-```
-
-This will produce:
-
-```text
-warning: lint raw_pointer_derive has been removed: using derive with raw pointers is ok
- --> src/main.rs:1:9
-  |
-1 | #![deny(raw_pointer_derive)]
-  |         ^^^^^^^^^^^^^^^^^^
-  |
-```
-
-To fix this, either remove the lint or use the new name.
-
-## safe-packed-borrows
-
-This lint detects borrowing a field in the interior of a packed structure
-with alignment other than 1. Some example code that triggers this lint:
-
-```rust
-#[repr(packed)]
-pub struct Unaligned<T>(pub T);
-
-pub struct Foo {
-    start: u8,
-    data: Unaligned<u32>,
-}
-
-fn main() {
-    let x = Foo { start: 0, data: Unaligned(1) };
-    let y = &x.data.0;
-}
-```
-
-This will produce:
-
-```text
-warning: borrow of packed field requires unsafe function or block (error E0133)
-  --> src/main.rs:11:13
-   |
-11 |     let y = &x.data.0;
-   |             ^^^^^^^^^
-   |
-   = note: `#[warn(safe_packed_borrows)]` on by default
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #46043 <https://github.com/rust-lang/rust/issues/46043>
-```
-
-## stable-features
-
-This lint detects a `#[feature]` attribute that's since been made stable. Some
-example code that triggers this lint:
-
-```rust
-#![feature(test_accepted_feature)]
-```
-
-This will produce:
-
-```text
-warning: this feature has been stable since 1.0.0. Attribute no longer needed
- --> src/main.rs:1:12
-  |
-1 | #![feature(test_accepted_feature)]
-  |            ^^^^^^^^^^^^^^^^^^^^^
-  |
-```
-
-To fix, simply remove the `#![feature]` attribute, as it's no longer needed.
-
-## type-alias-bounds
-
-This lint detects bounds in type aliases. These are not currently enforced.
-Some example code that triggers this lint:
-
-```rust
-#[allow(dead_code)]
-type SendVec<T: Send> = Vec<T>;
-```
-
-This will produce:
-
-```text
-warning: bounds on generic parameters are not enforced in type aliases
- --> src/lib.rs:2:17
-  |
-2 | type SendVec<T: Send> = Vec<T>;
-  |                 ^^^^
-  |
-  = note: `#[warn(type_alias_bounds)]` on by default
-  = help: the bound will not be checked when the type alias is used, and should be removed
-```
-
-## tyvar-behind-raw-pointer
-
-This lint detects raw pointer to an inference variable. Some
-example code that triggers this lint:
-
-```rust
-let data = std::ptr::null();
-let _ = &data as *const *const ();
-
-if data.is_null() {}
-```
-
-This will produce:
-
-```text
-warning: type annotations needed
- --> src/main.rs:4:13
-  |
-4 |     if data.is_null() {}
-  |             ^^^^^^^
-  |
-  = note: `#[warn(tyvar_behind_raw_pointer)]` on by default
-  = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
-  = note: for more information, see issue #46906 <https://github.com/rust-lang/rust/issues/46906>
-```
-
-## unconditional-recursion
-
-This lint detects functions that cannot return without calling themselves.
-Some example code that triggers this lint:
-
-```rust
-fn foo() {
-    foo();
-}
-```
-
-This will produce:
-
-```text
-warning: function cannot return without recursing
- --> src/main.rs:1:1
-  |
-1 | fn foo() {
-  | ^^^^^^^^ cannot return without recursing
-2 |     foo();
-  |     ----- recursive call site
-  |
-```
-
-## unknown-lints
-
-This lint detects unrecognized lint attribute. Some
-example code that triggers this lint:
-
-```rust,ignore
-#[allow(not_a_real_lint)]
-```
-
-This will produce:
-
-```text
-warning: unknown lint: `not_a_real_lint`
- --> src/main.rs:1:10
-  |
-1 | #![allow(not_a_real_lint)]
-  |          ^^^^^^^^^^^^^^^
-  |
-```
-
-## unreachable-code
-
-This lint detects unreachable code paths. Some example code that
-triggers this lint:
-
-```rust,no_run
-panic!("we never go past here!");
-
-let x = 5;
-```
-
-This will produce:
-
-```text
-warning: unreachable statement
- --> src/main.rs:4:5
-  |
-4 |     let x = 5;
-  |     ^^^^^^^^^^
-  |
-```
-
-## unreachable-patterns
-
-This lint detects unreachable patterns. Some
-example code that triggers this lint:
-
-```rust
-let x = 5;
-match x {
-    y => (),
-    5 => (),
-}
-```
-
-This will produce:
-
-```text
-warning: unreachable pattern
- --> src/main.rs:5:5
-  |
-5 |     5 => (),
-  |     ^
-  |
-```
-
-The `y` pattern will always match, so the five is impossible to reach.
-Remember, match arms match in order, you probably wanted to put the `5` case
-above the `y` case.
-
-## unstable-name-collision
-
-This lint detects that you've used a name that the standard library plans to
-add in the future, which means that your code may fail to compile without
-additional type annotations in the future. Either rename, or add those
-annotations now.
-
-## unused-allocation
-
-This lint detects unnecessary allocations that can be eliminated.
-
-## unused-assignments
-
-This lint detects assignments that will never be read. Some
-example code that triggers this lint:
-
-```rust
-let mut x = 5;
-x = 6;
-```
-
-This will produce:
-
-```text
-warning: value assigned to `x` is never read
- --> src/main.rs:4:5
-  |
-4 |     x = 6;
-  |     ^
-  |
-```
-
-## unused-attributes
-
-This lint detects attributes that were not used by the compiler. Some
-example code that triggers this lint:
-
-```rust
-#![macro_export]
-```
-
-This will produce:
-
-```text
-warning: unused attribute
- --> src/main.rs:1:1
-  |
-1 | #![macro_export]
-  | ^^^^^^^^^^^^^^^^
-  |
-```
-
-## unused-comparisons
-
-This lint detects comparisons made useless by limits of the types involved. Some
-example code that triggers this lint:
-
-```rust
-fn foo(x: u8) {
-    x >= 0;
-}
-```
-
-This will produce:
-
-```text
-warning: comparison is useless due to type limits
- --> src/main.rs:6:5
-  |
-6 |     x >= 0;
-  |     ^^^^^^
-  |
-```
-
-## unused-doc-comment
-
-This lint detects doc comments that aren't used by rustdoc. Some
-example code that triggers this lint:
-
-```rust
-/// docs for x
-let x = 12;
-```
-
-This will produce:
-
-```text
-warning: doc comment not used by rustdoc
- --> src/main.rs:2:5
-  |
-2 |     /// docs for x
-  |     ^^^^^^^^^^^^^^
-  |
-```
-
-## unused-features
-
-This lint detects unused or unknown features found in crate-level `#[feature]` directives.
-To fix this, simply remove the feature flag.
-
-## unused-imports
-
-This lint detects imports that are never used. Some
-example code that triggers this lint:
-
-```rust
-use std::collections::HashMap;
-```
-
-This will produce:
-
-```text
-warning: unused import: `std::collections::HashMap`
- --> src/main.rs:1:5
-  |
-1 | use std::collections::HashMap;
-  |     ^^^^^^^^^^^^^^^^^^^^^^^^^
-  |
-```
-
-## unused-macros
-
-This lint detects macros that were not used. Some example code that
-triggers this lint:
-
-```rust
-macro_rules! unused {
-    () => {};
-}
-
-fn main() {
-}
-```
-
-This will produce:
-
-```text
-warning: unused macro definition
- --> src/main.rs:1:1
-  |
-1 | / macro_rules! unused {
-2 | |     () => {};
-3 | | }
-  | |_^
-  |
-```
-
-## unused-must-use
-
-This lint detects unused result of a type flagged as `#[must_use]`. Some
-example code that triggers this lint:
-
-```rust
-fn returns_result() -> Result<(), ()> {
-    Ok(())
-}
-
-fn main() {
-    returns_result();
-}
-```
-
-This will produce:
-
-```text
-warning: unused `std::result::Result` that must be used
- --> src/main.rs:6:5
-  |
-6 |     returns_result();
-  |     ^^^^^^^^^^^^^^^^^
-  |
-```
-
-## unused-mut
-
-This lint detects mut variables which don't need to be mutable. Some
-example code that triggers this lint:
-
-```rust
-let mut x = 5;
-```
-
-This will produce:
-
-```text
-warning: variable does not need to be mutable
- --> src/main.rs:2:9
-  |
-2 |     let mut x = 5;
-  |         ----^
-  |         |
-  |         help: remove this `mut`
-  |
-```
-
-## unused-parens
-
-This lint detects `if`, `match`, `while` and `return` with parentheses; they
-do not need them. Some example code that triggers this lint:
-
-```rust
-if(true) {}
-```
-
-This will produce:
-
-```text
-warning: unnecessary parentheses around `if` condition
- --> src/main.rs:2:7
-  |
-2 |     if(true) {}
-  |       ^^^^^^ help: remove these parentheses
-  |
-```
-
-## unused-unsafe
-
-This lint detects unnecessary use of an `unsafe` block. Some
-example code that triggers this lint:
-
-```rust
-unsafe {}
-```
-
-This will produce:
-
-```text
-warning: unnecessary `unsafe` block
- --> src/main.rs:2:5
-  |
-2 |     unsafe {}
-  |     ^^^^^^ unnecessary `unsafe` block
-  |
-```
-
-## unused-variables
-
-This lint detects variables which are not used in any way. Some
-example code that triggers this lint:
-
-```rust
-let x = 5;
-```
-
-This will produce:
-
-```text
-warning: unused variable: `x`
- --> src/main.rs:2:9
-  |
-2 |     let x = 5;
-  |         ^ help: consider using `_x` instead
-  |
-```
-
-## warnings
-
-This lint is a bit special; by changing its level, you change every other warning
-that would produce a warning to whatever value you'd like:
-
-```rust
-#![deny(warnings)]
-```
-
-As such, you won't ever trigger this lint in your code directly.
-
-## while-true
-
-This lint detects `while true { }`. Some example code that triggers this
-lint:
-
-```rust,no_run
-while true {
-
-}
-```
-
-This will produce:
-
-```text
-warning: denote infinite loops with `loop { ... }`
- --> src/main.rs:2:5
-  |
-2 |     while true {
-  |     ^^^^^^^^^^ help: use `loop`
-  |
-```
+This file is auto-generated by the lint-docs script.
index 794eeafbbbff988c3053ca302d210f2b873c1db6..da27d2fbf99a3675c39b732e8462e03c85b5c51e 100644 (file)
@@ -195,6 +195,7 @@ target | std | host | notes
 `powerpc64-unknown-linux-musl` | ? |  |
 `powerpc64-wrs-vxworks` | ? |  |
 `powerpc64le-unknown-linux-musl` | ? |  |
+`riscv32gc-unknown-linux-gnu` |   |   | RISC-V Linux (kernel 5.4, glibc 2.33)
 `sparc-unknown-linux-gnu` | ✓ |  | 32-bit SPARC Linux
 `sparc64-unknown-netbsd` | ✓ | ✓ | NetBSD/sparc64
 `sparc64-unknown-openbsd` | ? |  |
index 7c12d23e6495c381bc6fcfdb5b59a09852c1c5d6..c9a0dff5ab30327bb6e9f9031ee12ff3669b86f5 100644 (file)
@@ -32,3 +32,17 @@ pub struct UnixToken;
 
 Here, the respective tokens can only be used by dependent crates on their respective platforms, but
 they will both appear in documentation.
+
+## Add aliases for an item in documentation search
+
+This feature allows you to add alias(es) to an item when using the `rustdoc` search through the
+`doc(alias)` attribute. Example:
+
+```rust,no_run
+#[doc(alias = "x")]
+#[doc(alias = "big")]
+pub struct BigX;
+```
+
+Then, when looking for it through the `rustdoc` search, if you enter "x" or
+"big", search will show the `BigX` struct first.
index 8e2869fef553e101824af966fd97609c140f4839..ce292c60460cc87cdcf67724cf71343baf44c8db 100644 (file)
@@ -49,6 +49,30 @@ warning: missing documentation for a function
    | ^^^^^^^^^^^^^^^^^^^^^
 ```
 
+## missing_crate_level_docs
+
+This lint is **allowed by default**. It detects if there is no documentation
+at the crate root. For example:
+
+```rust
+#![warn(missing_crate_level_docs)]
+```
+
+This will generate the following warning:
+
+```text
+warning: no documentation found for this crate's top-level module
+  |
+  = help: The following guide may be of use:
+          https://doc.rust-lang.org/nightly/rustdoc/how-to-write-documentation.html
+```
+
+This is currently "allow" by default, but it is intended to make this a
+warning in the future. This is intended as a means to introduce new users on
+*how* to document their crate by pointing them to some instructions on how to
+get started, without providing overwhelming warnings like `missing_docs`
+might.
+
 ## missing_doc_code_examples
 
 This lint is **allowed by default** and is **nightly-only**. It detects when a documentation block
@@ -117,3 +141,37 @@ warning: Documentation test in private item
  8 | |     /// ```
    | |___________^
 ```
+
+## invalid_codeblock_attributes
+
+This lint **warns by default**. It detects code block attributes in
+documentation examples that have potentially mis-typed values. For example:
+
+```rust
+/// Example.
+///
+/// ```should-panic
+/// assert_eq!(1, 2);
+/// ```
+pub fn foo() {}
+```
+
+Which will give:
+
+```text
+warning: unknown attribute `should-panic`. Did you mean `should_panic`?
+ --> src/lib.rs:1:1
+  |
+1 | / /// Example.
+2 | | ///
+3 | | /// ```should-panic
+4 | | /// assert_eq!(1, 2);
+5 | | /// ```
+  | |_______^
+  |
+  = note: `#[warn(invalid_codeblock_attributes)]` on by default
+  = help: the code block will either not be tested if not marked as a rust one or won't fail if it doesn't panic when running
+```
+
+In the example above, the correct form is `should_panic`. This helps detect
+typo mistakes for some common attributes.
index 2f49fc8a41552293af6078f04a9d493996fe3bca..cd8edbcd1a4ba0e16a5bf8916eed72627854b4b8 100644 (file)
@@ -207,22 +207,6 @@ issue][issue-include].
 [unstable-include]: ../unstable-book/language-features/external-doc.html
 [issue-include]: https://github.com/rust-lang/rust/issues/44732
 
-### Add aliases for an item in documentation search
-
-This feature allows you to add alias(es) to an item when using the `rustdoc` search through the
-`doc(alias)` attribute. Example:
-
-```rust,no_run
-#![feature(doc_alias)]
-
-#[doc(alias = "x")]
-#[doc(alias = "big")]
-pub struct BigX;
-```
-
-Then, when looking for it through the `rustdoc` search, if you enter "x" or
-"big", search will show the `BigX` struct first.
-
 ## Unstable command-line arguments
 
 These features are enabled by passing a command-line flag to Rustdoc, but the flags in question are
diff --git a/src/doc/unstable-book/src/language-features/doc-alias.md b/src/doc/unstable-book/src/language-features/doc-alias.md
deleted file mode 100644 (file)
index 647ac0c..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-# `doc_alias`
-
-The tracking issue for this feature is: [#50146]
-
-[#50146]: https://github.com/rust-lang/rust/issues/50146
-
-------------------------
-
-You can add alias(es) to an item when using the `rustdoc` search through the
-`doc(alias)` attribute. Example:
-
-```rust,no_run
-#![feature(doc_alias)]
-
-#[doc(alias = "x")]
-#[doc(alias = "big")]
-pub struct BigX;
-```
-
-Then, when looking for it through the `rustdoc` search, if you enter "x" or
-"big", search will show the `BigX` struct first.
-
-Note that this feature is currently hidden behind the `feature(doc_alias)` gate.
index 28a5fe31fc4b5f328e0be7dc72cf3a7e09a54d80..df113f0f1613c3fd33d37a13ae1fa9fb992350b7 100644 (file)
@@ -345,6 +345,25 @@ The `h` modifier will emit the register name for the high byte of that register
 
 If you use a smaller data type (e.g. `u16`) with an operand and forget the use template modifiers, the compiler will emit a warning and suggest the correct modifier to use.
 
+## Memory address operands
+
+Sometimes assembly instructions require operands passed via memory addresses/memory locations.
+You have to manually use the memory address syntax specified by the respectively architectures.
+For example, in x86/x86_64 and intel assembly syntax, you should wrap inputs/outputs in `[]`
+to indicate they are memory operands:
+
+```rust,allow_fail
+# #![feature(asm, llvm_asm)]
+# fn load_fpu_control_word(control: u16) {
+unsafe {
+    asm!("fldcw [{}]", in(reg) &control, options(nostack));
+
+    // Previously this would have been written with the deprecated `llvm_asm!` like this
+    llvm_asm!("fldcw $0" :: "m" (control) :: "volatile");
+}
+# }
+```
+
 ## Options
 
 By default, an inline assembly block is treated the same way as an external FFI function call with a custom calling convention: it may read/write memory, have observable side effects, etc. However in many cases, it is desirable to give the compiler more information about what the assembly code is actually doing so that it can optimize better.
index da01d9228f14e0ff12177e7694205a4f9a6ed095..a2f029db2916551e68afe12b388612747ce573b0 100644 (file)
@@ -159,12 +159,12 @@ specify some extra info about the inline assembly:
 
 Current valid options are:
 
-1. *volatile* - specifying this is analogous to
+1. `volatile` - specifying this is analogous to
    `__asm__ __volatile__ (...)` in gcc/clang.
-2. *alignstack* - certain instructions expect the stack to be
+2. `alignstack` - certain instructions expect the stack to be
    aligned a certain way (i.e. SSE) and specifying this indicates to
    the compiler to insert its usual stack alignment code
-3. *intel* - use intel syntax instead of the default AT&T.
+3. `intel` - use intel syntax instead of the default AT&T.
 
 ```rust
 # #![feature(llvm_asm)]
index 90d2a18ea58198a7bb15231ff64f154c56e78230..a40a44fe27da3edb9aace137a22d08ed93c4239a 100644 (file)
@@ -8,7 +8,7 @@ edition = "2018"
 path = "lib.rs"
 
 [dependencies]
-pulldown-cmark = { version = "0.7", default-features = false }
+pulldown-cmark = { version = "0.8", default-features = false }
 minifier = "0.0.33"
 rayon = { version = "0.3.0", package = "rustc-rayon" }
 serde = { version = "1.0", features = ["derive"] }
index 50cb987cf0870d9b0bb98989941245ca342b5c57..f8987c6beca33966aa0e3594d10d905f22d21412 100644 (file)
@@ -337,18 +337,13 @@ pub fn build_impl(
     // reachable in rustdoc generated documentation
     if !did.is_local() {
         if let Some(traitref) = associated_trait {
-            if !cx.renderinfo.borrow().access_levels.is_public(traitref.def_id) {
+            let did = traitref.def_id;
+            if !cx.renderinfo.borrow().access_levels.is_public(did) {
                 return;
             }
-        }
 
-        // Skip foreign unstable traits from lists of trait implementations and
-        // such. This helps prevent dependencies of the standard library, for
-        // example, from getting documented as "traits `u32` implements" which
-        // isn't really too helpful.
-        if let Some(trait_did) = associated_trait {
-            if let Some(stab) = cx.tcx.lookup_stability(trait_did.def_id) {
-                if stab.level.is_unstable() {
+            if let Some(stab) = tcx.lookup_stability(did) {
+                if stab.level.is_unstable() && stab.feature == sym::rustc_private {
                     return;
                 }
             }
@@ -372,6 +367,12 @@ pub fn build_impl(
             if !cx.renderinfo.borrow().access_levels.is_public(did) {
                 return;
             }
+
+            if let Some(stab) = tcx.lookup_stability(did) {
+                if stab.level.is_unstable() && stab.feature == sym::rustc_private {
+                    return;
+                }
+            }
         }
     }
 
index 6a75a9bfb74d7d5a3999a0ebc69703feef4ee159..46ba14aa67e60d7fb35ffd59ce961ec71d569451 100644 (file)
@@ -840,7 +840,7 @@ fn clean(&self, cx: &DocContext<'_>) -> Generics {
         let mut where_predicates =
             where_predicates.into_iter().flat_map(|p| p.clean(cx)).collect::<Vec<_>>();
 
-        // Type parameters and have a Sized bound by default unless removed with
+        // Type parameters have a Sized bound by default unless removed with
         // ?Sized. Scan through the predicates and mark any type parameter with
         // a Sized bound, removing the bounds as we find them.
         //
index c577b771d6094815f0cae32d256965e7cf013965..58b76d24a5bdbb94405ed4fe6e4bf62b4ae08d9c 100644 (file)
@@ -601,7 +601,7 @@ pub fn register_res(cx: &DocContext<'_>, res: Res) -> DefId {
         },
         Res::Def(DefKind::TraitAlias, i) => (i, TypeKind::TraitAlias),
         Res::SelfTy(Some(def_id), _) => (def_id, TypeKind::Trait),
-        Res::SelfTy(_, Some(impl_def_id)) => return impl_def_id,
+        Res::SelfTy(_, Some((impl_def_id, _))) => return impl_def_id,
         _ => return res.def_id(),
     };
     if did.is_local() {
index a8c60e4a76df4d8d38c315eb0c7e51af64ad1ff1..6c0f1c02ac6da77d48c602932c30957d4742b8ff 100644 (file)
@@ -27,7 +27,6 @@
 use rustc_span::edition::Edition;
 use rustc_span::Span;
 use std::borrow::Cow;
-use std::cell::RefCell;
 use std::collections::VecDeque;
 use std::default::Default;
 use std::fmt::Write;
@@ -39,7 +38,7 @@
 use crate::html::highlight;
 use crate::html::toc::TocBuilder;
 
-use pulldown_cmark::{html, CodeBlockKind, CowStr, Event, Options, Parser, Tag};
+use pulldown_cmark::{html, BrokenLink, CodeBlockKind, CowStr, Event, Options, Parser, Tag};
 
 #[cfg(test)]
 mod tests;
@@ -931,15 +930,17 @@ pub fn into_string(self) -> String {
         if md.is_empty() {
             return String::new();
         }
-        let replacer = |_: &str, s: &str| {
-            if let Some(link) = links.iter().find(|link| &*link.original_text == s) {
-                Some((link.href.clone(), link.new_text.clone()))
+        let mut replacer = |broken_link: BrokenLink<'_>| {
+            if let Some(link) =
+                links.iter().find(|link| &*link.original_text == broken_link.reference)
+            {
+                Some((link.href.as_str().into(), link.new_text.as_str().into()))
             } else {
                 None
             }
         };
 
-        let p = Parser::new_with_broken_link_callback(md, opts(), Some(&replacer));
+        let p = Parser::new_with_broken_link_callback(md, opts(), Some(&mut replacer));
 
         let mut s = String::with_capacity(md.len() * 3 / 2);
 
@@ -1009,9 +1010,11 @@ pub fn into_string(self) -> String {
             return String::new();
         }
 
-        let replacer = |_: &str, s: &str| {
-            if let Some(link) = links.iter().find(|link| &*link.original_text == s) {
-                Some((link.href.clone(), link.new_text.clone()))
+        let mut replacer = |broken_link: BrokenLink<'_>| {
+            if let Some(link) =
+                links.iter().find(|link| &*link.original_text == broken_link.reference)
+            {
+                Some((link.href.as_str().into(), link.new_text.as_str().into()))
             } else {
                 None
             }
@@ -1020,7 +1023,7 @@ pub fn into_string(self) -> String {
         let p = Parser::new_with_broken_link_callback(
             md,
             Options::ENABLE_STRIKETHROUGH,
-            Some(&replacer),
+            Some(&mut replacer),
         );
 
         let mut s = String::new();
@@ -1067,7 +1070,7 @@ pub fn markdown_links(md: &str) -> Vec<(String, Option<Range<usize>>)> {
     }
 
     let mut links = vec![];
-    let shortcut_links = RefCell::new(vec![]);
+    let mut shortcut_links = vec![];
 
     {
         let locate = |s: &str| unsafe {
@@ -1084,11 +1087,13 @@ pub fn markdown_links(md: &str) -> Vec<(String, Option<Range<usize>>)> {
             }
         };
 
-        let push = |_: &str, s: &str| {
-            shortcut_links.borrow_mut().push((s.to_owned(), locate(s)));
+        let mut push = |link: BrokenLink<'_>| {
+            // FIXME: use `link.span` instead of `locate`
+            // (doing it now includes the `[]` as well as the text)
+            shortcut_links.push((link.reference.to_owned(), locate(link.reference)));
             None
         };
-        let p = Parser::new_with_broken_link_callback(md, opts(), Some(&push));
+        let p = Parser::new_with_broken_link_callback(md, opts(), Some(&mut push));
 
         // There's no need to thread an IdMap through to here because
         // the IDs generated aren't going to be emitted anywhere.
@@ -1106,8 +1111,7 @@ pub fn markdown_links(md: &str) -> Vec<(String, Option<Range<usize>>)> {
         }
     }
 
-    let mut shortcut_links = shortcut_links.into_inner();
-    links.extend(shortcut_links.drain(..));
+    links.append(&mut shortcut_links);
 
     links
 }
index 5780610c862102347179867fc2d6afcdaa89f46f..5a9eeec4dfec334566f2fa407431dad8f77e7667 100644 (file)
@@ -217,7 +217,7 @@ fn variant_field(
                 let kind = if let Some(intermediate) = self.check_full_res(
                     TypeNS,
                     &intermediate_path,
-                    Some(module_id),
+                    module_id,
                     current_item,
                     extra_fragment,
                 ) {
@@ -235,7 +235,7 @@ fn variant_field(
     fn macro_resolve(
         &self,
         path_str: &'a str,
-        parent_id: Option<DefId>,
+        module_id: DefId,
     ) -> Result<Res, ResolutionFailure<'a>> {
         let cx = self.cx;
         let path = ast::Path::from_ident(Ident::from_str(path_str));
@@ -254,20 +254,15 @@ fn macro_resolve(
             if let Some(res) = resolver.all_macros().get(&Symbol::intern(path_str)) {
                 return Some(Ok(res.map_id(|_| panic!("unexpected id"))));
             }
-            if let Some(module_id) = parent_id {
-                debug!("resolving {} as a macro in the module {:?}", path_str, module_id);
-                if let Ok((_, res)) =
-                    resolver.resolve_str_path_error(DUMMY_SP, path_str, MacroNS, module_id)
-                {
-                    // don't resolve builtins like `#[derive]`
-                    if let Res::Def(..) = res {
-                        let res = res.map_id(|_| panic!("unexpected node_id"));
-                        return Some(Ok(res));
-                    }
+            debug!("resolving {} as a macro in the module {:?}", path_str, module_id);
+            if let Ok((_, res)) =
+                resolver.resolve_str_path_error(DUMMY_SP, path_str, MacroNS, module_id)
+            {
+                // don't resolve builtins like `#[derive]`
+                if let Res::Def(..) = res {
+                    let res = res.map_id(|_| panic!("unexpected node_id"));
+                    return Some(Ok(res));
                 }
-            } else {
-                debug!("attempting to resolve item without parent module: {}", path_str);
-                return Some(Err(ResolutionFailure::NoParentItem));
             }
             None
         })
@@ -275,7 +270,7 @@ fn macro_resolve(
         .unwrap_or_else(|| {
             let mut split = path_str.rsplitn(2, "::");
             if let Some((parent, base)) = split.next().and_then(|x| Some((split.next()?, x))) {
-                if let Some(res) = self.check_full_res(TypeNS, parent, parent_id, &None, &None) {
+                if let Some(res) = self.check_full_res(TypeNS, parent, module_id, &None, &None) {
                     return Err(if matches!(res, Res::PrimTy(_)) {
                         ResolutionFailure::NoPrimitiveAssocItem {
                             res,
@@ -287,12 +282,10 @@ fn macro_resolve(
                     });
                 }
             }
-            Err(ResolutionFailure::NotInScope {
-                module_id: parent_id.expect("already saw `Some` when resolving as a macro"),
-                name: path_str.into(),
-            })
+            Err(ResolutionFailure::NotInScope { module_id, name: path_str.into() })
         })
     }
+
     /// Resolves a string as a path within a particular namespace. Also returns an optional
     /// URL fragment in the case of variants and methods.
     fn resolve<'path>(
@@ -300,293 +293,271 @@ fn resolve<'path>(
         path_str: &'path str,
         ns: Namespace,
         current_item: &Option<String>,
-        parent_id: Option<DefId>,
+        module_id: DefId,
         extra_fragment: &Option<String>,
     ) -> Result<(Res, Option<String>), ErrorKind<'path>> {
         let cx = self.cx;
 
-        // In case we're in a module, try to resolve the relative path.
-        if let Some(module_id) = parent_id {
-            let result = cx.enter_resolver(|resolver| {
-                resolver.resolve_str_path_error(DUMMY_SP, &path_str, ns, module_id)
-            });
-            debug!("{} resolved to {:?} in namespace {:?}", path_str, result, ns);
-            let result = match result {
-                Ok((_, Res::Err)) => Err(()),
-                x => x,
-            };
+        let result = cx.enter_resolver(|resolver| {
+            resolver.resolve_str_path_error(DUMMY_SP, &path_str, ns, module_id)
+        });
+        debug!("{} resolved to {:?} in namespace {:?}", path_str, result, ns);
+        let result = match result {
+            Ok((_, Res::Err)) => Err(()),
+            x => x,
+        };
 
-            if let Ok((_, res)) = result {
-                let res = res.map_id(|_| panic!("unexpected node_id"));
-                // In case this is a trait item, skip the
-                // early return and try looking for the trait.
-                let value = match res {
-                    Res::Def(DefKind::AssocFn | DefKind::AssocConst, _) => true,
-                    Res::Def(DefKind::AssocTy, _) => false,
-                    Res::Def(DefKind::Variant, _) => {
-                        return handle_variant(cx, res, extra_fragment);
-                    }
-                    // Not a trait item; just return what we found.
-                    Res::PrimTy(..) => {
-                        if extra_fragment.is_some() {
-                            return Err(ErrorKind::AnchorFailure(
-                                AnchorFailure::RustdocAnchorConflict(res),
-                            ));
-                        }
-                        return Ok((res, Some(path_str.to_owned())));
-                    }
-                    Res::Def(DefKind::Mod, _) => {
-                        return Ok((res, extra_fragment.clone()));
-                    }
-                    _ => {
-                        return Ok((res, extra_fragment.clone()));
+        if let Ok((_, res)) = result {
+            let res = res.map_id(|_| panic!("unexpected node_id"));
+            // In case this is a trait item, skip the
+            // early return and try looking for the trait.
+            let value = match res {
+                Res::Def(DefKind::AssocFn | DefKind::AssocConst, _) => true,
+                Res::Def(DefKind::AssocTy, _) => false,
+                Res::Def(DefKind::Variant, _) => {
+                    return handle_variant(cx, res, extra_fragment);
+                }
+                // Not a trait item; just return what we found.
+                Res::PrimTy(..) => {
+                    if extra_fragment.is_some() {
+                        return Err(ErrorKind::AnchorFailure(
+                            AnchorFailure::RustdocAnchorConflict(res),
+                        ));
                     }
-                };
-
-                if value != (ns == ValueNS) {
-                    return Err(ResolutionFailure::WrongNamespace(res, ns).into());
+                    return Ok((res, Some(path_str.to_owned())));
+                }
+                Res::Def(DefKind::Mod, _) => {
+                    return Ok((res, extra_fragment.clone()));
                 }
-            } else if let Some((path, prim)) = is_primitive(path_str, ns) {
-                if extra_fragment.is_some() {
-                    return Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict(
-                        prim,
-                    )));
+                _ => {
+                    return Ok((res, extra_fragment.clone()));
                 }
-                return Ok((prim, Some(path.to_owned())));
+            };
+
+            if value != (ns == ValueNS) {
+                return Err(ResolutionFailure::WrongNamespace(res, ns).into());
             }
+        } else if let Some((path, prim)) = is_primitive(path_str, ns) {
+            if extra_fragment.is_some() {
+                return Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict(prim)));
+            }
+            return Ok((prim, Some(path.to_owned())));
+        }
 
-            // Try looking for methods and associated items.
-            let mut split = path_str.rsplitn(2, "::");
-            // this can be an `unwrap()` because we ensure the link is never empty
-            let item_name = Symbol::intern(split.next().unwrap());
-            let path_root = split
-                .next()
-                .map(|f| {
-                    if f == "self" || f == "Self" {
-                        if let Some(name) = current_item.as_ref() {
-                            return name.clone();
-                        }
-                    }
-                    f.to_owned()
-                })
-                // If there's no `::`, it's not an associated item.
-                // So we can be sure that `rustc_resolve` was accurate when it said it wasn't resolved.
-                .ok_or_else(|| {
-                    debug!("found no `::`, assumming {} was correctly not in scope", item_name);
-                    ResolutionFailure::NotInScope { module_id, name: item_name.to_string().into() }
-                })?;
-
-            if let Some((path, prim)) = is_primitive(&path_root, TypeNS) {
-                let impls = primitive_impl(cx, &path)
-                    .ok_or_else(|| ResolutionFailure::NoPrimitiveImpl(prim, path_root.into()))?;
-                for &impl_ in impls {
-                    let link = cx
-                        .tcx
-                        .associated_items(impl_)
-                        .find_by_name_and_namespace(
-                            cx.tcx,
-                            Ident::with_dummy_span(item_name),
-                            ns,
-                            impl_,
-                        )
-                        .map(|item| match item.kind {
-                            ty::AssocKind::Fn => "method",
-                            ty::AssocKind::Const => "associatedconstant",
-                            ty::AssocKind::Type => "associatedtype",
-                        })
-                        .map(|out| (prim, Some(format!("{}#{}.{}", path, out, item_name))));
-                    if let Some(link) = link {
-                        return Ok(link);
+        // Try looking for methods and associated items.
+        let mut split = path_str.rsplitn(2, "::");
+        // this can be an `unwrap()` because we ensure the link is never empty
+        let item_name = Symbol::intern(split.next().unwrap());
+        let path_root = split
+            .next()
+            .map(|f| {
+                if f == "self" || f == "Self" {
+                    if let Some(name) = current_item.as_ref() {
+                        return name.clone();
                     }
                 }
-                debug!(
-                    "returning primitive error for {}::{} in {} namespace",
-                    path,
-                    item_name,
-                    ns.descr()
-                );
-                return Err(ResolutionFailure::NoPrimitiveAssocItem {
-                    res: prim,
-                    prim_name: path,
-                    assoc_item: item_name,
+                f.to_owned()
+            })
+            // If there's no `::`, it's not an associated item.
+            // So we can be sure that `rustc_resolve` was accurate when it said it wasn't resolved.
+            .ok_or_else(|| {
+                debug!("found no `::`, assumming {} was correctly not in scope", item_name);
+                ResolutionFailure::NotInScope { module_id, name: item_name.to_string().into() }
+            })?;
+
+        if let Some((path, prim)) = is_primitive(&path_root, TypeNS) {
+            let impls = primitive_impl(cx, &path)
+                .ok_or_else(|| ResolutionFailure::NoPrimitiveImpl(prim, path_root.into()))?;
+            for &impl_ in impls {
+                let link = cx
+                    .tcx
+                    .associated_items(impl_)
+                    .find_by_name_and_namespace(
+                        cx.tcx,
+                        Ident::with_dummy_span(item_name),
+                        ns,
+                        impl_,
+                    )
+                    .map(|item| match item.kind {
+                        ty::AssocKind::Fn => "method",
+                        ty::AssocKind::Const => "associatedconstant",
+                        ty::AssocKind::Type => "associatedtype",
+                    })
+                    .map(|out| (prim, Some(format!("{}#{}.{}", path, out, item_name))));
+                if let Some(link) = link {
+                    return Ok(link);
                 }
-                .into());
             }
+            debug!(
+                "returning primitive error for {}::{} in {} namespace",
+                path,
+                item_name,
+                ns.descr()
+            );
+            return Err(ResolutionFailure::NoPrimitiveAssocItem {
+                res: prim,
+                prim_name: path,
+                assoc_item: item_name,
+            }
+            .into());
+        }
 
-            let ty_res = cx
-                .enter_resolver(|resolver| {
-                    // only types can have associated items
-                    resolver.resolve_str_path_error(DUMMY_SP, &path_root, TypeNS, module_id)
-                })
-                .map(|(_, res)| res);
-            let ty_res = match ty_res {
-                Err(()) | Ok(Res::Err) => {
-                    return if ns == Namespace::ValueNS {
-                        self.variant_field(path_str, current_item, module_id, extra_fragment)
-                    } else {
-                        // See if it only broke because of the namespace.
-                        let kind = cx.enter_resolver(|resolver| {
-                            // NOTE: this doesn't use `check_full_res` because we explicitly want to ignore `TypeNS` (we already checked it)
-                            for &ns in &[MacroNS, ValueNS] {
-                                match resolver
-                                    .resolve_str_path_error(DUMMY_SP, &path_root, ns, module_id)
-                                {
-                                    Ok((_, Res::Err)) | Err(()) => {}
-                                    Ok((_, res)) => {
-                                        let res = res.map_id(|_| panic!("unexpected node_id"));
-                                        return ResolutionFailure::CannotHaveAssociatedItems(
-                                            res, ns,
-                                        );
-                                    }
+        let ty_res = cx
+            .enter_resolver(|resolver| {
+                // only types can have associated items
+                resolver.resolve_str_path_error(DUMMY_SP, &path_root, TypeNS, module_id)
+            })
+            .map(|(_, res)| res);
+        let ty_res = match ty_res {
+            Err(()) | Ok(Res::Err) => {
+                return if ns == Namespace::ValueNS {
+                    self.variant_field(path_str, current_item, module_id, extra_fragment)
+                } else {
+                    // See if it only broke because of the namespace.
+                    let kind = cx.enter_resolver(|resolver| {
+                        // NOTE: this doesn't use `check_full_res` because we explicitly want to ignore `TypeNS` (we already checked it)
+                        for &ns in &[MacroNS, ValueNS] {
+                            match resolver
+                                .resolve_str_path_error(DUMMY_SP, &path_root, ns, module_id)
+                            {
+                                Ok((_, Res::Err)) | Err(()) => {}
+                                Ok((_, res)) => {
+                                    let res = res.map_id(|_| panic!("unexpected node_id"));
+                                    return ResolutionFailure::CannotHaveAssociatedItems(res, ns);
                                 }
                             }
-                            ResolutionFailure::NotInScope { module_id, name: path_root.into() }
-                        });
-                        Err(kind.into())
-                    };
-                }
-                Ok(res) => res,
-            };
-            let ty_res = ty_res.map_id(|_| panic!("unexpected node_id"));
-            let res = match ty_res {
-                Res::Def(
-                    DefKind::Struct | DefKind::Union | DefKind::Enum | DefKind::TyAlias,
-                    did,
-                ) => {
-                    debug!("looking for associated item named {} for item {:?}", item_name, did);
-                    // Checks if item_name belongs to `impl SomeItem`
-                    let assoc_item = cx
-                        .tcx
-                        .inherent_impls(did)
-                        .iter()
-                        .flat_map(|&imp| {
-                            cx.tcx.associated_items(imp).find_by_name_and_namespace(
-                                cx.tcx,
-                                Ident::with_dummy_span(item_name),
-                                ns,
-                                imp,
-                            )
-                        })
-                        .map(|item| (item.kind, item.def_id))
-                        // There should only ever be one associated item that matches from any inherent impl
-                        .next()
-                        // Check if item_name belongs to `impl SomeTrait for SomeItem`
-                        // This gives precedence to `impl SomeItem`:
-                        // Although having both would be ambiguous, use impl version for compat. sake.
-                        // To handle that properly resolve() would have to support
-                        // something like [`ambi_fn`](<SomeStruct as SomeTrait>::ambi_fn)
-                        .or_else(|| {
-                            let kind = resolve_associated_trait_item(
-                                did, module_id, item_name, ns, &self.cx,
-                            );
-                            debug!("got associated item kind {:?}", kind);
-                            kind
-                        });
-
-                    if let Some((kind, id)) = assoc_item {
-                        let out = match kind {
-                            ty::AssocKind::Fn => "method",
-                            ty::AssocKind::Const => "associatedconstant",
-                            ty::AssocKind::Type => "associatedtype",
-                        };
-                        Some(if extra_fragment.is_some() {
-                            Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict(
-                                ty_res,
-                            )))
-                        } else {
-                            // HACK(jynelson): `clean` expects the type, not the associated item.
-                            // but the disambiguator logic expects the associated item.
-                            // Store the kind in a side channel so that only the disambiguator logic looks at it.
-                            self.kind_side_channel.set(Some((kind.as_def_kind(), id)));
-                            Ok((ty_res, Some(format!("{}.{}", out, item_name))))
-                        })
-                    } else if ns == Namespace::ValueNS {
-                        debug!("looking for variants or fields named {} for {:?}", item_name, did);
-                        match cx.tcx.type_of(did).kind() {
-                            ty::Adt(def, _) => {
-                                let field = if def.is_enum() {
-                                    def.all_fields().find(|item| item.ident.name == item_name)
-                                } else {
-                                    def.non_enum_variant()
-                                        .fields
-                                        .iter()
-                                        .find(|item| item.ident.name == item_name)
-                                };
-                                field.map(|item| {
-                                    if extra_fragment.is_some() {
-                                        let res = Res::Def(
-                                            if def.is_enum() {
-                                                DefKind::Variant
-                                            } else {
-                                                DefKind::Field
-                                            },
-                                            item.did,
-                                        );
-                                        Err(ErrorKind::AnchorFailure(
-                                            AnchorFailure::RustdocAnchorConflict(res),
-                                        ))
-                                    } else {
-                                        Ok((
-                                            ty_res,
-                                            Some(format!(
-                                                "{}.{}",
-                                                if def.is_enum() {
-                                                    "variant"
-                                                } else {
-                                                    "structfield"
-                                                },
-                                                item.ident
-                                            )),
-                                        ))
-                                    }
-                                })
-                            }
-                            _ => None,
                         }
-                    } else {
-                        // We already know this isn't in ValueNS, so no need to check variant_field
-                        return Err(ResolutionFailure::NoAssocItem(ty_res, item_name).into());
-                    }
-                }
-                Res::Def(DefKind::Trait, did) => cx
+                        ResolutionFailure::NotInScope { module_id, name: path_root.into() }
+                    });
+                    Err(kind.into())
+                };
+            }
+            Ok(res) => res,
+        };
+        let ty_res = ty_res.map_id(|_| panic!("unexpected node_id"));
+        let res = match ty_res {
+            Res::Def(DefKind::Struct | DefKind::Union | DefKind::Enum | DefKind::TyAlias, did) => {
+                debug!("looking for associated item named {} for item {:?}", item_name, did);
+                // Checks if item_name belongs to `impl SomeItem`
+                let assoc_item = cx
                     .tcx
-                    .associated_items(did)
-                    .find_by_name_and_namespace(cx.tcx, Ident::with_dummy_span(item_name), ns, did)
-                    .map(|item| {
-                        let kind = match item.kind {
-                            ty::AssocKind::Const => "associatedconstant",
-                            ty::AssocKind::Type => "associatedtype",
-                            ty::AssocKind::Fn => {
-                                if item.defaultness.has_value() {
-                                    "method"
+                    .inherent_impls(did)
+                    .iter()
+                    .flat_map(|&imp| {
+                        cx.tcx.associated_items(imp).find_by_name_and_namespace(
+                            cx.tcx,
+                            Ident::with_dummy_span(item_name),
+                            ns,
+                            imp,
+                        )
+                    })
+                    .map(|item| (item.kind, item.def_id))
+                    // There should only ever be one associated item that matches from any inherent impl
+                    .next()
+                    // Check if item_name belongs to `impl SomeTrait for SomeItem`
+                    // This gives precedence to `impl SomeItem`:
+                    // Although having both would be ambiguous, use impl version for compat. sake.
+                    // To handle that properly resolve() would have to support
+                    // something like [`ambi_fn`](<SomeStruct as SomeTrait>::ambi_fn)
+                    .or_else(|| {
+                        let kind =
+                            resolve_associated_trait_item(did, module_id, item_name, ns, &self.cx);
+                        debug!("got associated item kind {:?}", kind);
+                        kind
+                    });
+
+                if let Some((kind, id)) = assoc_item {
+                    let out = match kind {
+                        ty::AssocKind::Fn => "method",
+                        ty::AssocKind::Const => "associatedconstant",
+                        ty::AssocKind::Type => "associatedtype",
+                    };
+                    Some(if extra_fragment.is_some() {
+                        Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict(ty_res)))
+                    } else {
+                        // HACK(jynelson): `clean` expects the type, not the associated item.
+                        // but the disambiguator logic expects the associated item.
+                        // Store the kind in a side channel so that only the disambiguator logic looks at it.
+                        self.kind_side_channel.set(Some((kind.as_def_kind(), id)));
+                        Ok((ty_res, Some(format!("{}.{}", out, item_name))))
+                    })
+                } else if ns == Namespace::ValueNS {
+                    debug!("looking for variants or fields named {} for {:?}", item_name, did);
+                    match cx.tcx.type_of(did).kind() {
+                        ty::Adt(def, _) => {
+                            let field = if def.is_enum() {
+                                def.all_fields().find(|item| item.ident.name == item_name)
+                            } else {
+                                def.non_enum_variant()
+                                    .fields
+                                    .iter()
+                                    .find(|item| item.ident.name == item_name)
+                            };
+                            field.map(|item| {
+                                if extra_fragment.is_some() {
+                                    let res = Res::Def(
+                                        if def.is_enum() {
+                                            DefKind::Variant
+                                        } else {
+                                            DefKind::Field
+                                        },
+                                        item.did,
+                                    );
+                                    Err(ErrorKind::AnchorFailure(
+                                        AnchorFailure::RustdocAnchorConflict(res),
+                                    ))
                                 } else {
-                                    "tymethod"
+                                    Ok((
+                                        ty_res,
+                                        Some(format!(
+                                            "{}.{}",
+                                            if def.is_enum() { "variant" } else { "structfield" },
+                                            item.ident
+                                        )),
+                                    ))
                                 }
-                            }
-                        };
-
-                        if extra_fragment.is_some() {
-                            Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict(
-                                ty_res,
-                            )))
-                        } else {
-                            let res = Res::Def(item.kind.as_def_kind(), item.def_id);
-                            Ok((res, Some(format!("{}.{}", kind, item_name))))
+                            })
                         }
-                    }),
-                _ => None,
-            };
-            res.unwrap_or_else(|| {
-                if ns == Namespace::ValueNS {
-                    self.variant_field(path_str, current_item, module_id, extra_fragment)
+                        _ => None,
+                    }
                 } else {
-                    Err(ResolutionFailure::NoAssocItem(ty_res, item_name).into())
+                    // We already know this isn't in ValueNS, so no need to check variant_field
+                    return Err(ResolutionFailure::NoAssocItem(ty_res, item_name).into());
                 }
-            })
-        } else {
-            debug!("attempting to resolve item without parent module: {}", path_str);
-            Err(ResolutionFailure::NoParentItem.into())
-        }
+            }
+            Res::Def(DefKind::Trait, did) => cx
+                .tcx
+                .associated_items(did)
+                .find_by_name_and_namespace(cx.tcx, Ident::with_dummy_span(item_name), ns, did)
+                .map(|item| {
+                    let kind = match item.kind {
+                        ty::AssocKind::Const => "associatedconstant",
+                        ty::AssocKind::Type => "associatedtype",
+                        ty::AssocKind::Fn => {
+                            if item.defaultness.has_value() {
+                                "method"
+                            } else {
+                                "tymethod"
+                            }
+                        }
+                    };
+
+                    if extra_fragment.is_some() {
+                        Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict(ty_res)))
+                    } else {
+                        let res = Res::Def(item.kind.as_def_kind(), item.def_id);
+                        Ok((res, Some(format!("{}.{}", kind, item_name))))
+                    }
+                }),
+            _ => None,
+        };
+        res.unwrap_or_else(|| {
+            if ns == Namespace::ValueNS {
+                self.variant_field(path_str, current_item, module_id, extra_fragment)
+            } else {
+                Err(ResolutionFailure::NoAssocItem(ty_res, item_name).into())
+            }
+        })
     }
 
     /// Used for reporting better errors.
@@ -599,7 +570,7 @@ fn check_full_res(
         &self,
         ns: Namespace,
         path_str: &str,
-        base_node: Option<DefId>,
+        module_id: DefId,
         current_item: &Option<String>,
         extra_fragment: &Option<String>,
     ) -> Option<Res> {
@@ -616,11 +587,11 @@ fn check_full_res(
         };
         // cannot be used for macro namespace
         let check_full_res = |this: &Self, ns| {
-            let result = this.resolve(path_str, ns, current_item, base_node, extra_fragment);
+            let result = this.resolve(path_str, ns, current_item, module_id, extra_fragment);
             check_full_res_inner(this, result.map(|(res, _)| res))
         };
         let check_full_res_macro = |this: &Self| {
-            let result = this.macro_resolve(path_str, base_node);
+            let result = this.macro_resolve(path_str, module_id);
             check_full_res_inner(this, result.map_err(ErrorKind::from))
         };
         match ns {
@@ -843,7 +814,6 @@ fn fold_item(&mut self, mut item: Item) -> Option<Item> {
             self.mod_ids.push(item.def_id);
         }
 
-        let cx = self.cx;
         let dox = item.attrs.collapsed_doc_value().unwrap_or_else(String::new);
         trace!("got documentation '{}'", dox);
 
@@ -885,377 +855,439 @@ fn fold_item(&mut self, mut item: Item) -> Option<Item> {
         });
 
         for (ori_link, link_range) in markdown_links(&dox) {
-            trace!("considering link '{}'", ori_link);
+            self.resolve_link(
+                &mut item,
+                &dox,
+                &current_item,
+                parent_node,
+                &parent_name,
+                ori_link,
+                link_range,
+            );
+        }
+
+        if item.is_mod() && !item.attrs.inner_docs {
+            self.mod_ids.push(item.def_id);
+        }
+
+        if item.is_mod() {
+            let ret = self.fold_item_recur(item);
+
+            self.mod_ids.pop();
 
-            // Bail early for real links.
-            if ori_link.contains('/') {
-                continue;
+            ret
+        } else {
+            self.fold_item_recur(item)
+        }
+    }
+}
+
+impl LinkCollector<'_, '_> {
+    fn resolve_link(
+        &self,
+        item: &mut Item,
+        dox: &str,
+        current_item: &Option<String>,
+        parent_node: Option<DefId>,
+        parent_name: &Option<String>,
+        ori_link: String,
+        link_range: Option<Range<usize>>,
+    ) {
+        trace!("considering link '{}'", ori_link);
+
+        // Bail early for real links.
+        if ori_link.contains('/') {
+            return;
+        }
+
+        // [] is mostly likely not supposed to be a link
+        if ori_link.is_empty() {
+            return;
+        }
+
+        let cx = self.cx;
+        let link = ori_link.replace("`", "");
+        let parts = link.split('#').collect::<Vec<_>>();
+        let (link, extra_fragment) = if parts.len() > 2 {
+            anchor_failure(cx, &item, &link, dox, link_range, AnchorFailure::MultipleAnchors);
+            return;
+        } else if parts.len() == 2 {
+            if parts[0].trim().is_empty() {
+                // This is an anchor to an element of the current page, nothing to do in here!
+                return;
             }
+            (parts[0], Some(parts[1].to_owned()))
+        } else {
+            (parts[0], None)
+        };
+        let resolved_self;
+        let link_text;
+        let mut path_str;
+        let disambiguator;
+        let (mut res, mut fragment) = {
+            path_str = if let Ok((d, path)) = Disambiguator::from_str(&link) {
+                disambiguator = Some(d);
+                path
+            } else {
+                disambiguator = None;
+                &link
+            }
+            .trim();
 
-            // [] is mostly likely not supposed to be a link
-            if ori_link.is_empty() {
-                continue;
+            if path_str.contains(|ch: char| !(ch.is_alphanumeric() || ch == ':' || ch == '_')) {
+                return;
             }
 
-            let link = ori_link.replace("`", "");
-            let parts = link.split('#').collect::<Vec<_>>();
-            let (link, extra_fragment) = if parts.len() > 2 {
-                anchor_failure(cx, &item, &link, &dox, link_range, AnchorFailure::MultipleAnchors);
-                continue;
-            } else if parts.len() == 2 {
-                if parts[0].trim().is_empty() {
-                    // This is an anchor to an element of the current page, nothing to do in here!
-                    continue;
-                }
-                (parts[0], Some(parts[1].to_owned()))
+            // We stripped `()` and `!` when parsing the disambiguator.
+            // Add them back to be displayed, but not prefix disambiguators.
+            link_text = disambiguator
+                .map(|d| d.display_for(path_str))
+                .unwrap_or_else(|| path_str.to_owned());
+
+            // In order to correctly resolve intra-doc-links we need to
+            // pick a base AST node to work from.  If the documentation for
+            // this module came from an inner comment (//!) then we anchor
+            // our name resolution *inside* the module.  If, on the other
+            // hand it was an outer comment (///) then we anchor the name
+            // resolution in the parent module on the basis that the names
+            // used are more likely to be intended to be parent names.  For
+            // this, we set base_node to None for inner comments since
+            // we've already pushed this node onto the resolution stack but
+            // for outer comments we explicitly try and resolve against the
+            // parent_node first.
+            let base_node = if item.is_mod() && item.attrs.inner_docs {
+                self.mod_ids.last().copied()
             } else {
-                (parts[0], None)
+                parent_node
             };
-            let resolved_self;
-            let link_text;
-            let mut path_str;
-            let disambiguator;
-            let (mut res, mut fragment) = {
-                path_str = if let Ok((d, path)) = Disambiguator::from_str(&link) {
-                    disambiguator = Some(d);
-                    path
-                } else {
-                    disambiguator = None;
-                    &link
-                }
-                .trim();
 
-                if path_str.contains(|ch: char| !(ch.is_alphanumeric() || ch == ':' || ch == '_')) {
-                    continue;
+            let module_id = if let Some(id) = base_node {
+                id
+            } else {
+                debug!("attempting to resolve item without parent module: {}", path_str);
+                let err_kind = ResolutionFailure::NoParentItem.into();
+                resolution_failure(
+                    self,
+                    &item,
+                    path_str,
+                    disambiguator,
+                    dox,
+                    link_range,
+                    smallvec![err_kind],
+                );
+                return;
+            };
+
+            // replace `Self` with suitable item's parent name
+            if path_str.starts_with("Self::") {
+                if let Some(ref name) = parent_name {
+                    resolved_self = format!("{}::{}", name, &path_str[6..]);
+                    path_str = &resolved_self;
                 }
+            }
 
-                // We stripped `()` and `!` when parsing the disambiguator.
-                // Add them back to be displayed, but not prefix disambiguators.
-                link_text = disambiguator
-                    .map(|d| d.display_for(path_str))
-                    .unwrap_or_else(|| path_str.to_owned());
-
-                // In order to correctly resolve intra-doc-links we need to
-                // pick a base AST node to work from.  If the documentation for
-                // this module came from an inner comment (//!) then we anchor
-                // our name resolution *inside* the module.  If, on the other
-                // hand it was an outer comment (///) then we anchor the name
-                // resolution in the parent module on the basis that the names
-                // used are more likely to be intended to be parent names.  For
-                // this, we set base_node to None for inner comments since
-                // we've already pushed this node onto the resolution stack but
-                // for outer comments we explicitly try and resolve against the
-                // parent_node first.
-                let base_node = if item.is_mod() && item.attrs.inner_docs {
-                    self.mod_ids.last().copied()
-                } else {
-                    parent_node
-                };
+            match self.resolve_with_disambiguator(
+                disambiguator,
+                item,
+                dox,
+                path_str,
+                current_item,
+                module_id,
+                extra_fragment,
+                &ori_link,
+                link_range.clone(),
+            ) {
+                Some(x) => x,
+                None => return,
+            }
+        };
 
-                // replace `Self` with suitable item's parent name
-                if path_str.starts_with("Self::") {
-                    if let Some(ref name) = parent_name {
-                        resolved_self = format!("{}::{}", name, &path_str[6..]);
-                        path_str = &resolved_self;
+        // Check for a primitive which might conflict with a module
+        // Report the ambiguity and require that the user specify which one they meant.
+        // FIXME: could there ever be a primitive not in the type namespace?
+        if matches!(
+            disambiguator,
+            None | Some(Disambiguator::Namespace(Namespace::TypeNS) | Disambiguator::Primitive)
+        ) && !matches!(res, Res::PrimTy(_))
+        {
+            if let Some((path, prim)) = is_primitive(path_str, TypeNS) {
+                // `prim@char`
+                if matches!(disambiguator, Some(Disambiguator::Primitive)) {
+                    if fragment.is_some() {
+                        anchor_failure(
+                            cx,
+                            &item,
+                            path_str,
+                            dox,
+                            link_range,
+                            AnchorFailure::RustdocAnchorConflict(prim),
+                        );
+                        return;
                     }
+                    res = prim;
+                    fragment = Some(path.to_owned());
+                } else {
+                    // `[char]` when a `char` module is in scope
+                    let candidates = vec![res, prim];
+                    ambiguity_error(cx, &item, path_str, dox, link_range, candidates);
+                    return;
                 }
+            }
+        }
 
-                match disambiguator.map(Disambiguator::ns) {
-                    Some(ns @ (ValueNS | TypeNS)) => {
-                        match self.resolve(path_str, ns, &current_item, base_node, &extra_fragment)
-                        {
-                            Ok(res) => res,
-                            Err(ErrorKind::Resolve(box mut kind)) => {
-                                // We only looked in one namespace. Try to give a better error if possible.
-                                if kind.full_res().is_none() {
-                                    let other_ns = if ns == ValueNS { TypeNS } else { ValueNS };
-                                    for &new_ns in &[other_ns, MacroNS] {
-                                        if let Some(res) = self.check_full_res(
-                                            new_ns,
-                                            path_str,
-                                            base_node,
-                                            &current_item,
-                                            &extra_fragment,
-                                        ) {
-                                            kind = ResolutionFailure::WrongNamespace(res, ns);
-                                            break;
-                                        }
-                                    }
-                                }
-                                resolution_failure(
-                                    self,
-                                    &item,
-                                    path_str,
-                                    disambiguator,
-                                    &dox,
-                                    link_range,
-                                    smallvec![kind],
-                                );
-                                // This could just be a normal link or a broken link
-                                // we could potentially check if something is
-                                // "intra-doc-link-like" and warn in that case.
-                                continue;
-                            }
-                            Err(ErrorKind::AnchorFailure(msg)) => {
-                                anchor_failure(cx, &item, &ori_link, &dox, link_range, msg);
-                                continue;
-                            }
-                        }
+        let report_mismatch = |specified: Disambiguator, resolved: Disambiguator| {
+            // The resolved item did not match the disambiguator; give a better error than 'not found'
+            let msg = format!("incompatible link kind for `{}`", path_str);
+            report_diagnostic(cx, &msg, &item, dox, &link_range, |diag, sp| {
+                let note = format!(
+                    "this link resolved to {} {}, which is not {} {}",
+                    resolved.article(),
+                    resolved.descr(),
+                    specified.article(),
+                    specified.descr()
+                );
+                diag.note(&note);
+                suggest_disambiguator(resolved, diag, path_str, dox, sp, &link_range);
+            });
+        };
+        if let Res::PrimTy(_) = res {
+            match disambiguator {
+                Some(Disambiguator::Primitive | Disambiguator::Namespace(_)) | None => {
+                    item.attrs.links.push(ItemLink {
+                        link: ori_link,
+                        link_text: path_str.to_owned(),
+                        did: None,
+                        fragment,
+                    });
+                }
+                Some(other) => {
+                    report_mismatch(other, Disambiguator::Primitive);
+                    return;
+                }
+            }
+        } else {
+            debug!("intra-doc link to {} resolved to {:?}", path_str, res);
+
+            // Disallow e.g. linking to enums with `struct@`
+            if let Res::Def(kind, _) = res {
+                debug!("saw kind {:?} with disambiguator {:?}", kind, disambiguator);
+                match (self.kind_side_channel.take().map(|(kind, _)| kind).unwrap_or(kind), disambiguator) {
+                    | (DefKind::Const | DefKind::ConstParam | DefKind::AssocConst | DefKind::AnonConst, Some(Disambiguator::Kind(DefKind::Const)))
+                    // NOTE: this allows 'method' to mean both normal functions and associated functions
+                    // This can't cause ambiguity because both are in the same namespace.
+                    | (DefKind::Fn | DefKind::AssocFn, Some(Disambiguator::Kind(DefKind::Fn)))
+                    // These are namespaces; allow anything in the namespace to match
+                    | (_, Some(Disambiguator::Namespace(_)))
+                    // If no disambiguator given, allow anything
+                    | (_, None)
+                    // All of these are valid, so do nothing
+                    => {}
+                    (actual, Some(Disambiguator::Kind(expected))) if actual == expected => {}
+                    (_, Some(specified @ Disambiguator::Kind(_) | specified @ Disambiguator::Primitive)) => {
+                        report_mismatch(specified, Disambiguator::Kind(kind));
+                        return;
                     }
-                    None => {
-                        // Try everything!
-                        let mut candidates = PerNS {
-                            macro_ns: self
-                                .macro_resolve(path_str, base_node)
-                                .map(|res| (res, extra_fragment.clone())),
-                            type_ns: match self.resolve(
-                                path_str,
-                                TypeNS,
-                                &current_item,
-                                base_node,
-                                &extra_fragment,
-                            ) {
-                                Ok(res) => {
-                                    debug!("got res in TypeNS: {:?}", res);
-                                    Ok(res)
-                                }
-                                Err(ErrorKind::AnchorFailure(msg)) => {
-                                    anchor_failure(cx, &item, &ori_link, &dox, link_range, msg);
-                                    continue;
-                                }
-                                Err(ErrorKind::Resolve(box kind)) => Err(kind),
-                            },
-                            value_ns: match self.resolve(
-                                path_str,
-                                ValueNS,
-                                &current_item,
-                                base_node,
-                                &extra_fragment,
-                            ) {
-                                Ok(res) => Ok(res),
-                                Err(ErrorKind::AnchorFailure(msg)) => {
-                                    anchor_failure(cx, &item, &ori_link, &dox, link_range, msg);
-                                    continue;
-                                }
-                                Err(ErrorKind::Resolve(box kind)) => Err(kind),
-                            }
-                            .and_then(|(res, fragment)| {
-                                // Constructors are picked up in the type namespace.
-                                match res {
-                                    Res::Def(DefKind::Ctor(..), _) | Res::SelfCtor(..) => {
-                                        Err(ResolutionFailure::WrongNamespace(res, TypeNS))
-                                    }
-                                    _ => match (fragment, extra_fragment) {
-                                        (Some(fragment), Some(_)) => {
-                                            // Shouldn't happen but who knows?
-                                            Ok((res, Some(fragment)))
-                                        }
-                                        (fragment, None) | (None, fragment) => Ok((res, fragment)),
-                                    },
-                                }
-                            }),
-                        };
+                }
+            }
 
-                        let len = candidates.iter().filter(|res| res.is_ok()).count();
+            // item can be non-local e.g. when using #[doc(primitive = "pointer")]
+            if let Some((src_id, dst_id)) = res
+                .opt_def_id()
+                .and_then(|def_id| def_id.as_local())
+                .and_then(|dst_id| item.def_id.as_local().map(|src_id| (src_id, dst_id)))
+            {
+                use rustc_hir::def_id::LOCAL_CRATE;
 
-                        if len == 0 {
-                            resolution_failure(
-                                self,
-                                &item,
-                                path_str,
-                                disambiguator,
-                                &dox,
-                                link_range,
-                                candidates.into_iter().filter_map(|res| res.err()).collect(),
-                            );
-                            // this could just be a normal link
-                            continue;
-                        }
+                let hir_src = self.cx.tcx.hir().local_def_id_to_hir_id(src_id);
+                let hir_dst = self.cx.tcx.hir().local_def_id_to_hir_id(dst_id);
 
-                        if len == 1 {
-                            candidates.into_iter().filter_map(|res| res.ok()).next().unwrap()
-                        } else if len == 2 && is_derive_trait_collision(&candidates) {
-                            candidates.type_ns.unwrap()
-                        } else {
-                            if is_derive_trait_collision(&candidates) {
-                                candidates.macro_ns = Err(ResolutionFailure::Dummy);
-                            }
-                            // If we're reporting an ambiguity, don't mention the namespaces that failed
-                            let candidates =
-                                candidates.map(|candidate| candidate.ok().map(|(res, _)| res));
-                            ambiguity_error(
-                                cx,
-                                &item,
-                                path_str,
-                                &dox,
-                                link_range,
-                                candidates.present_items().collect(),
-                            );
-                            continue;
-                        }
-                    }
-                    Some(MacroNS) => {
-                        match self.macro_resolve(path_str, base_node) {
-                            Ok(res) => (res, extra_fragment),
-                            Err(mut kind) => {
-                                // `macro_resolve` only looks in the macro namespace. Try to give a better error if possible.
-                                for &ns in &[TypeNS, ValueNS] {
-                                    if let Some(res) = self.check_full_res(
-                                        ns,
-                                        path_str,
-                                        base_node,
-                                        &current_item,
-                                        &extra_fragment,
-                                    ) {
-                                        kind = ResolutionFailure::WrongNamespace(res, MacroNS);
-                                        break;
-                                    }
-                                }
-                                resolution_failure(
-                                    self,
-                                    &item,
+                if self.cx.tcx.privacy_access_levels(LOCAL_CRATE).is_exported(hir_src)
+                    && !self.cx.tcx.privacy_access_levels(LOCAL_CRATE).is_exported(hir_dst)
+                {
+                    privacy_error(cx, &item, &path_str, dox, link_range);
+                    return;
+                }
+            }
+            let id = register_res(cx, res);
+            item.attrs.links.push(ItemLink { link: ori_link, link_text, did: Some(id), fragment });
+        }
+    }
+
+    fn resolve_with_disambiguator(
+        &self,
+        disambiguator: Option<Disambiguator>,
+        item: &mut Item,
+        dox: &str,
+        path_str: &str,
+        current_item: &Option<String>,
+        base_node: DefId,
+        extra_fragment: Option<String>,
+        ori_link: &str,
+        link_range: Option<Range<usize>>,
+    ) -> Option<(Res, Option<String>)> {
+        match disambiguator.map(Disambiguator::ns) {
+            Some(ns @ (ValueNS | TypeNS)) => {
+                match self.resolve(path_str, ns, &current_item, base_node, &extra_fragment) {
+                    Ok(res) => Some(res),
+                    Err(ErrorKind::Resolve(box mut kind)) => {
+                        // We only looked in one namespace. Try to give a better error if possible.
+                        if kind.full_res().is_none() {
+                            let other_ns = if ns == ValueNS { TypeNS } else { ValueNS };
+                            for &new_ns in &[other_ns, MacroNS] {
+                                if let Some(res) = self.check_full_res(
+                                    new_ns,
                                     path_str,
-                                    disambiguator,
-                                    &dox,
-                                    link_range,
-                                    smallvec![kind],
-                                );
-                                continue;
+                                    base_node,
+                                    &current_item,
+                                    &extra_fragment,
+                                ) {
+                                    kind = ResolutionFailure::WrongNamespace(res, ns);
+                                    break;
+                                }
                             }
                         }
+                        resolution_failure(
+                            self,
+                            &item,
+                            path_str,
+                            disambiguator,
+                            dox,
+                            link_range,
+                            smallvec![kind],
+                        );
+                        // This could just be a normal link or a broken link
+                        // we could potentially check if something is
+                        // "intra-doc-link-like" and warn in that case.
+                        return None;
                     }
-                }
-            };
-
-            // Check for a primitive which might conflict with a module
-            // Report the ambiguity and require that the user specify which one they meant.
-            // FIXME: could there ever be a primitive not in the type namespace?
-            if matches!(
-                disambiguator,
-                None | Some(Disambiguator::Namespace(Namespace::TypeNS) | Disambiguator::Primitive)
-            ) && !matches!(res, Res::PrimTy(_))
-            {
-                if let Some((path, prim)) = is_primitive(path_str, TypeNS) {
-                    // `prim@char`
-                    if matches!(disambiguator, Some(Disambiguator::Primitive)) {
-                        if fragment.is_some() {
-                            anchor_failure(
-                                cx,
-                                &item,
-                                path_str,
-                                &dox,
-                                link_range,
-                                AnchorFailure::RustdocAnchorConflict(prim),
-                            );
-                            continue;
-                        }
-                        res = prim;
-                        fragment = Some(path.to_owned());
-                    } else {
-                        // `[char]` when a `char` module is in scope
-                        let candidates = vec![res, prim];
-                        ambiguity_error(cx, &item, path_str, &dox, link_range, candidates);
-                        continue;
+                    Err(ErrorKind::AnchorFailure(msg)) => {
+                        anchor_failure(self.cx, &item, &ori_link, dox, link_range, msg);
+                        return None;
                     }
                 }
             }
+            None => {
+                // Try everything!
+                let mut candidates = PerNS {
+                    macro_ns: self
+                        .macro_resolve(path_str, base_node)
+                        .map(|res| (res, extra_fragment.clone())),
+                    type_ns: match self.resolve(
+                        path_str,
+                        TypeNS,
+                        &current_item,
+                        base_node,
+                        &extra_fragment,
+                    ) {
+                        Ok(res) => {
+                            debug!("got res in TypeNS: {:?}", res);
+                            Ok(res)
+                        }
+                        Err(ErrorKind::AnchorFailure(msg)) => {
+                            anchor_failure(self.cx, &item, ori_link, dox, link_range, msg);
+                            return None;
+                        }
+                        Err(ErrorKind::Resolve(box kind)) => Err(kind),
+                    },
+                    value_ns: match self.resolve(
+                        path_str,
+                        ValueNS,
+                        &current_item,
+                        base_node,
+                        &extra_fragment,
+                    ) {
+                        Ok(res) => Ok(res),
+                        Err(ErrorKind::AnchorFailure(msg)) => {
+                            anchor_failure(self.cx, &item, ori_link, dox, link_range, msg);
+                            return None;
+                        }
+                        Err(ErrorKind::Resolve(box kind)) => Err(kind),
+                    }
+                    .and_then(|(res, fragment)| {
+                        // Constructors are picked up in the type namespace.
+                        match res {
+                            Res::Def(DefKind::Ctor(..), _) | Res::SelfCtor(..) => {
+                                Err(ResolutionFailure::WrongNamespace(res, TypeNS))
+                            }
+                            _ => match (fragment, extra_fragment) {
+                                (Some(fragment), Some(_)) => {
+                                    // Shouldn't happen but who knows?
+                                    Ok((res, Some(fragment)))
+                                }
+                                (fragment, None) | (None, fragment) => Ok((res, fragment)),
+                            },
+                        }
+                    }),
+                };
 
-            let report_mismatch = |specified: Disambiguator, resolved: Disambiguator| {
-                // The resolved item did not match the disambiguator; give a better error than 'not found'
-                let msg = format!("incompatible link kind for `{}`", path_str);
-                report_diagnostic(cx, &msg, &item, &dox, &link_range, |diag, sp| {
-                    let note = format!(
-                        "this link resolved to {} {}, which is not {} {}",
-                        resolved.article(),
-                        resolved.descr(),
-                        specified.article(),
-                        specified.descr()
+                let len = candidates.iter().filter(|res| res.is_ok()).count();
+
+                if len == 0 {
+                    resolution_failure(
+                        self,
+                        &item,
+                        path_str,
+                        disambiguator,
+                        dox,
+                        link_range,
+                        candidates.into_iter().filter_map(|res| res.err()).collect(),
                     );
-                    diag.note(&note);
-                    suggest_disambiguator(resolved, diag, path_str, &dox, sp, &link_range);
-                });
-            };
-            if let Res::PrimTy(_) = res {
-                match disambiguator {
-                    Some(Disambiguator::Primitive | Disambiguator::Namespace(_)) | None => {
-                        item.attrs.links.push(ItemLink {
-                            link: ori_link,
-                            link_text: path_str.to_owned(),
-                            did: None,
-                            fragment,
-                        });
-                    }
-                    Some(other) => {
-                        report_mismatch(other, Disambiguator::Primitive);
-                        continue;
-                    }
+                    // this could just be a normal link
+                    return None;
                 }
-            } else {
-                debug!("intra-doc link to {} resolved to {:?}", path_str, res);
-
-                // Disallow e.g. linking to enums with `struct@`
-                if let Res::Def(kind, _) = res {
-                    debug!("saw kind {:?} with disambiguator {:?}", kind, disambiguator);
-                    match (self.kind_side_channel.take().map(|(kind, _)| kind).unwrap_or(kind), disambiguator) {
-                        | (DefKind::Const | DefKind::ConstParam | DefKind::AssocConst | DefKind::AnonConst, Some(Disambiguator::Kind(DefKind::Const)))
-                        // NOTE: this allows 'method' to mean both normal functions and associated functions
-                        // This can't cause ambiguity because both are in the same namespace.
-                        | (DefKind::Fn | DefKind::AssocFn, Some(Disambiguator::Kind(DefKind::Fn)))
-                        // These are namespaces; allow anything in the namespace to match
-                        | (_, Some(Disambiguator::Namespace(_)))
-                        // If no disambiguator given, allow anything
-                        | (_, None)
-                        // All of these are valid, so do nothing
-                        => {}
-                        (actual, Some(Disambiguator::Kind(expected))) if actual == expected => {}
-                        (_, Some(specified @ Disambiguator::Kind(_) | specified @ Disambiguator::Primitive)) => {
-                            report_mismatch(specified, Disambiguator::Kind(kind));
-                            continue;
-                        }
+
+                if len == 1 {
+                    Some(candidates.into_iter().filter_map(|res| res.ok()).next().unwrap())
+                } else if len == 2 && is_derive_trait_collision(&candidates) {
+                    Some(candidates.type_ns.unwrap())
+                } else {
+                    if is_derive_trait_collision(&candidates) {
+                        candidates.macro_ns = Err(ResolutionFailure::Dummy);
                     }
+                    // If we're reporting an ambiguity, don't mention the namespaces that failed
+                    let candidates = candidates.map(|candidate| candidate.ok().map(|(res, _)| res));
+                    ambiguity_error(
+                        self.cx,
+                        &item,
+                        path_str,
+                        dox,
+                        link_range,
+                        candidates.present_items().collect(),
+                    );
+                    return None;
                 }
-
-                // item can be non-local e.g. when using #[doc(primitive = "pointer")]
-                if let Some((src_id, dst_id)) = res
-                    .opt_def_id()
-                    .and_then(|def_id| def_id.as_local())
-                    .and_then(|dst_id| item.def_id.as_local().map(|src_id| (src_id, dst_id)))
-                {
-                    use rustc_hir::def_id::LOCAL_CRATE;
-
-                    let hir_src = self.cx.tcx.hir().local_def_id_to_hir_id(src_id);
-                    let hir_dst = self.cx.tcx.hir().local_def_id_to_hir_id(dst_id);
-
-                    if self.cx.tcx.privacy_access_levels(LOCAL_CRATE).is_exported(hir_src)
-                        && !self.cx.tcx.privacy_access_levels(LOCAL_CRATE).is_exported(hir_dst)
-                    {
-                        privacy_error(cx, &item, &path_str, &dox, link_range);
-                        continue;
+            }
+            Some(MacroNS) => {
+                match self.macro_resolve(path_str, base_node) {
+                    Ok(res) => Some((res, extra_fragment)),
+                    Err(mut kind) => {
+                        // `macro_resolve` only looks in the macro namespace. Try to give a better error if possible.
+                        for &ns in &[TypeNS, ValueNS] {
+                            if let Some(res) = self.check_full_res(
+                                ns,
+                                path_str,
+                                base_node,
+                                &current_item,
+                                &extra_fragment,
+                            ) {
+                                kind = ResolutionFailure::WrongNamespace(res, MacroNS);
+                                break;
+                            }
+                        }
+                        resolution_failure(
+                            self,
+                            &item,
+                            path_str,
+                            disambiguator,
+                            dox,
+                            link_range,
+                            smallvec![kind],
+                        );
+                        return None;
                     }
                 }
-                let id = register_res(cx, res);
-                item.attrs.links.push(ItemLink {
-                    link: ori_link,
-                    link_text,
-                    did: Some(id),
-                    fragment,
-                });
             }
         }
-
-        if item.is_mod() && !item.attrs.inner_docs {
-            self.mod_ids.push(item.def_id);
-        }
-
-        if item.is_mod() {
-            let ret = self.fold_item_recur(item);
-
-            self.mod_ids.pop();
-
-            ret
-        } else {
-            self.fold_item_recur(item)
-        }
     }
 }
 
@@ -1536,13 +1568,9 @@ fn resolution_failure(
                                 break;
                             }
                         };
-                        if let Some(res) = collector.check_full_res(
-                            TypeNS,
-                            &current,
-                            Some(*module_id),
-                            &None,
-                            &None,
-                        ) {
+                        if let Some(res) =
+                            collector.check_full_res(TypeNS, &current, *module_id, &None, &None)
+                        {
                             failure = ResolutionFailure::NoAssocItem(res, Symbol::intern(current));
                             break;
                         }
index cbbe86dc433f33456a7343750e21f044bbf51eda..78af9f9b8561a646ef1af4a7d2cbcf3b4e8a17bd 100644 (file)
@@ -8,7 +8,7 @@
 use crate::clean::*;
 use crate::core::DocContext;
 use crate::fold::DocFolder;
-use crate::html::markdown::{find_testable_code, ErrorCodes, LangString};
+use crate::html::markdown::{find_testable_code, ErrorCodes, Ignore, LangString};
 use rustc_session::lint;
 
 pub const CHECK_PRIVATE_ITEMS_DOC_TESTS: Pass = Pass {
@@ -48,15 +48,11 @@ pub(crate) struct Tests {
     pub(crate) found_tests: usize,
 }
 
-impl Tests {
-    pub(crate) fn new() -> Tests {
-        Tests { found_tests: 0 }
-    }
-}
-
 impl crate::doctest::Tester for Tests {
-    fn add_test(&mut self, _: String, _: LangString, _: usize) {
-        self.found_tests += 1;
+    fn add_test(&mut self, _: String, config: LangString, _: usize) {
+        if config.rust && config.ignore == Ignore::None {
+            self.found_tests += 1;
+        }
     }
 }
 
@@ -85,7 +81,7 @@ pub fn look_for_tests<'tcx>(cx: &DocContext<'tcx>, dox: &str, item: &Item) {
         }
     };
 
-    let mut tests = Tests::new();
+    let mut tests = Tests { found_tests: 0 };
 
     find_testable_code(&dox, &mut tests, ErrorCodes::No, false, None);
 
diff --git a/src/test/codegen/issue-73396-bounds-check-after-position.rs b/src/test/codegen/issue-73396-bounds-check-after-position.rs
new file mode 100644 (file)
index 0000000..e5f3ae4
--- /dev/null
@@ -0,0 +1,78 @@
+// min-llvm-version: 11.0.0
+// compile-flags: -O
+// ignore-debug: the debug assertions get in the way
+#![crate_type = "lib"]
+
+// Make sure no bounds checks are emitted when slicing or indexing
+// with an index from `position()` or `rposition()`.
+
+// CHECK-LABEL: @position_slice_to_no_bounds_check
+#[no_mangle]
+pub fn position_slice_to_no_bounds_check(s: &[u8]) -> &[u8] {
+    // CHECK-NOT: panic
+    // CHECK-NOT: slice_index_len_fail
+    if let Some(idx) = s.iter().position(|b| *b == b'\\') {
+        &s[..idx]
+    } else {
+        s
+    }
+}
+
+// CHECK-LABEL: @position_slice_from_no_bounds_check
+#[no_mangle]
+pub fn position_slice_from_no_bounds_check(s: &[u8]) -> &[u8] {
+    // CHECK-NOT: panic
+    // CHECK-NOT: slice_index_len_fail
+    if let Some(idx) = s.iter().position(|b| *b == b'\\') {
+        &s[idx..]
+    } else {
+        s
+    }
+}
+
+// CHECK-LABEL: @position_index_no_bounds_check
+#[no_mangle]
+pub fn position_index_no_bounds_check(s: &[u8]) -> u8 {
+    // CHECK-NOT: panic
+    // CHECK-NOT: slice_index_len_fail
+    if let Some(idx) = s.iter().position(|b| *b == b'\\') {
+        s[idx]
+    } else {
+        42
+    }
+}
+// CHECK-LABEL: @rposition_slice_to_no_bounds_check
+#[no_mangle]
+pub fn rposition_slice_to_no_bounds_check(s: &[u8]) -> &[u8] {
+    // CHECK-NOT: panic
+    // CHECK-NOT: slice_index_len_fail
+    if let Some(idx) = s.iter().rposition(|b| *b == b'\\') {
+        &s[..idx]
+    } else {
+        s
+    }
+}
+
+// CHECK-LABEL: @rposition_slice_from_no_bounds_check
+#[no_mangle]
+pub fn rposition_slice_from_no_bounds_check(s: &[u8]) -> &[u8] {
+    // CHECK-NOT: panic
+    // CHECK-NOT: slice_index_len_fail
+    if let Some(idx) = s.iter().rposition(|b| *b == b'\\') {
+        &s[idx..]
+    } else {
+        s
+    }
+}
+
+// CHECK-LABEL: @rposition_index_no_bounds_check
+#[no_mangle]
+pub fn rposition_index_no_bounds_check(s: &[u8]) -> u8 {
+    // CHECK-NOT: panic
+    // CHECK-NOT: slice_index_len_fail
+    if let Some(idx) = s.iter().rposition(|b| *b == b'\\') {
+        s[idx]
+    } else {
+        42
+    }
+}
index 9d490f047f7356a287bada5f72c01b8409c303f8..756f31315f18a982b3d9d9470a26cf594f480831 100644 (file)
@@ -22,9 +22,13 @@ fn bar() -> bool {
                                          // + literal: Const { ty: fn(i32, i32) -> bool {foo}, val: Value(Scalar(<ZST>)) }
         StorageLive(_2);                 // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:6
         _2 = _1;                         // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:6
+        StorageLive(_3);                 // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13
         _3 = const 1_i32;                // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13
+        StorageLive(_4);                 // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13
         _4 = const -1_i32;               // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13
         _0 = Eq(move _3, move _4);       // scope 2 at $DIR/inline-any-operand.rs:17:5: 17:11
+        StorageDead(_4);                 // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13
+        StorageDead(_3);                 // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13
         StorageDead(_2);                 // scope 1 at $DIR/inline-any-operand.rs:12:12: 12:13
         StorageDead(_1);                 // scope 0 at $DIR/inline-any-operand.rs:13:1: 13:2
         return;                          // scope 0 at $DIR/inline-any-operand.rs:13:2: 13:2
index b40a8047c4185fc9b427ece12cf19876b8c5a49f..6ecbd3022e389145b457df268bbb7d9c2cdee0ef 100644 (file)
@@ -30,9 +30,13 @@ fn foo(_1: T, _2: i32) -> i32 {
         _7 = _2;                         // scope 1 at $DIR/inline-closure.rs:12:10: 12:11
         (_5.0: i32) = move _6;           // scope 1 at $DIR/inline-closure.rs:12:5: 12:12
         (_5.1: i32) = move _7;           // scope 1 at $DIR/inline-closure.rs:12:5: 12:12
+        StorageLive(_8);                 // scope 1 at $DIR/inline-closure.rs:12:5: 12:12
         _8 = move (_5.0: i32);           // scope 1 at $DIR/inline-closure.rs:12:5: 12:12
+        StorageLive(_9);                 // scope 1 at $DIR/inline-closure.rs:12:5: 12:12
         _9 = move (_5.1: i32);           // scope 1 at $DIR/inline-closure.rs:12:5: 12:12
         _0 = _8;                         // scope 2 at $DIR/inline-closure.rs:11:22: 11:24
+        StorageDead(_9);                 // scope 1 at $DIR/inline-closure.rs:12:5: 12:12
+        StorageDead(_8);                 // scope 1 at $DIR/inline-closure.rs:12:5: 12:12
         StorageDead(_7);                 // scope 1 at $DIR/inline-closure.rs:12:11: 12:12
         StorageDead(_6);                 // scope 1 at $DIR/inline-closure.rs:12:11: 12:12
         StorageDead(_5);                 // scope 1 at $DIR/inline-closure.rs:12:11: 12:12
index f6dd7413640394762083bef4796d73391d0c6f33..7475be30c0dff8976c262be411a0bc58134a2190 100644 (file)
@@ -33,9 +33,13 @@ fn foo(_1: T, _2: &i32) -> i32 {
         _7 = &(*_2);                     // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:10: 16:11
         (_5.0: &i32) = move _6;          // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12
         (_5.1: &i32) = move _7;          // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12
+        StorageLive(_8);                 // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12
         _8 = move (_5.0: &i32);          // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12
+        StorageLive(_9);                 // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12
         _9 = move (_5.1: &i32);          // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12
         _0 = (*_8);                      // scope 3 at $DIR/inline-closure-borrows-arg.rs:14:9: 14:18
+        StorageDead(_9);                 // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12
+        StorageDead(_8);                 // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12
         StorageDead(_7);                 // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:11: 16:12
         StorageDead(_6);                 // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:11: 16:12
         StorageDead(_5);                 // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:11: 16:12
index e2b5d6567c29900602a8fb028df200c87f4f60e7..0258e3c2e4b380f8afaf4081272917bbe99eed83 100644 (file)
@@ -38,6 +38,7 @@ 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
@@ -47,6 +48,7 @@ fn foo(_1: T, _2: i32) -> (i32, T) {
         (_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
         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(_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 10ed13c9ff566c76d169649cc58949d7031dd442..8188740f8739bde325aea289b9119bcac222c35a 100644 (file)
@@ -1,7 +1,7 @@
 +-------------------------------------+------------+------------+------------+------------+
 | File                                | Documented | Percentage |   Examples | Percentage |
 +-------------------------------------+------------+------------+------------+------------+
-| ...tdoc-ui/coverage/doc-examples.rs |          4 |     100.0% |          2 |      50.0% |
+| ...tdoc-ui/coverage/doc-examples.rs |          4 |     100.0% |          1 |      25.0% |
 +-------------------------------------+------------+------------+------------+------------+
-| Total                               |          4 |     100.0% |          2 |      50.0% |
+| Total                               |          4 |     100.0% |          1 |      25.0% |
 +-------------------------------------+------------+------------+------------+------------+
diff --git a/src/test/rustdoc-ui/intra-link-double-anchor.rs b/src/test/rustdoc-ui/intra-link-double-anchor.rs
new file mode 100644 (file)
index 0000000..a01211c
--- /dev/null
@@ -0,0 +1,7 @@
+// check-pass
+
+// regression test for #73264
+// should only give one error
+/// docs [label][with#anchor#error]
+//~^ WARNING multiple anchors
+pub struct S;
diff --git a/src/test/rustdoc-ui/intra-link-double-anchor.stderr b/src/test/rustdoc-ui/intra-link-double-anchor.stderr
new file mode 100644 (file)
index 0000000..3282ec8
--- /dev/null
@@ -0,0 +1,10 @@
+warning: `with#anchor#error` contains multiple anchors
+  --> $DIR/intra-link-double-anchor.rs:5:18
+   |
+LL | /// docs [label][with#anchor#error]
+   |                  ^^^^^^^^^^^^^^^^^ contains invalid anchor
+   |
+   = note: `#[warn(broken_intra_doc_links)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/src/test/rustdoc-ui/private-doc-test.rs b/src/test/rustdoc-ui/private-doc-test.rs
new file mode 100644 (file)
index 0000000..379fa45
--- /dev/null
@@ -0,0 +1,12 @@
+// check-pass
+
+#![deny(private_doc_tests)]
+
+mod foo {
+    /// private doc test
+    ///
+    /// ```ignore (used for testing ignored doc tests)
+    /// assert!(false);
+    /// ```
+    fn bar() {}
+}
diff --git a/src/test/rustdoc/auxiliary/real_gimli.rs b/src/test/rustdoc/auxiliary/real_gimli.rs
new file mode 100644 (file)
index 0000000..80d5c4b
--- /dev/null
@@ -0,0 +1,13 @@
+// aux-build:realcore.rs
+
+#![crate_name = "real_gimli"]
+#![feature(staged_api, extremely_unstable)]
+#![unstable(feature = "rustc_private", issue = "none")]
+
+extern crate realcore;
+
+#[unstable(feature = "rustc_private", issue = "none")]
+pub struct EndianSlice;
+
+#[unstable(feature = "rustc_private", issue = "none")]
+impl realcore::Deref for EndianSlice {}
diff --git a/src/test/rustdoc/auxiliary/realcore.rs b/src/test/rustdoc/auxiliary/realcore.rs
new file mode 100644 (file)
index 0000000..e0a906d
--- /dev/null
@@ -0,0 +1,15 @@
+#![crate_name = "realcore"]
+#![feature(staged_api)]
+#![unstable(feature = "extremely_unstable", issue = "none")]
+
+#[unstable(feature = "extremely_unstable_foo", issue = "none")]
+pub struct Foo {}
+
+#[unstable(feature = "extremely_unstable_foo", issue = "none")]
+pub trait Join {}
+
+#[unstable(feature = "extremely_unstable_foo", issue = "none")]
+impl Join for Foo {}
+
+#[stable(feature = "faked_deref", since = "1.47.0")]
+pub trait Deref {}
diff --git a/src/test/rustdoc/issue-75588.rs b/src/test/rustdoc/issue-75588.rs
new file mode 100644 (file)
index 0000000..835ed02
--- /dev/null
@@ -0,0 +1,18 @@
+// ignore-tidy-linelength
+// aux-build:realcore.rs
+// aux-build:real_gimli.rs
+
+// Ensure unstably exported traits have their Implementors sections.
+
+#![crate_name = "foo"]
+#![feature(extremely_unstable_foo)]
+
+extern crate realcore;
+extern crate real_gimli;
+
+// issue #74672
+// @!has foo/trait.Deref.html '//*[@id="impl-Deref-for-EndianSlice"]//code' 'impl Deref for EndianSlice'
+pub use realcore::Deref;
+
+// @has foo/trait.Join.html '//*[@id="impl-Join-for-Foo"]//code' 'impl Join for Foo'
+pub use realcore::Join;
diff --git a/src/test/ui/const-generics/cannot-infer-const-args.full.stderr b/src/test/ui/const-generics/cannot-infer-const-args.full.stderr
deleted file mode 100644 (file)
index 0531397..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-error[E0282]: type annotations needed
-  --> $DIR/cannot-infer-const-args.rs:12:5
-   |
-LL |     foo();
-   |     ^^^
-   |
-   = note: unable to infer the value of a const parameter
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0282`.
diff --git a/src/test/ui/const-generics/cannot-infer-const-args.min.stderr b/src/test/ui/const-generics/cannot-infer-const-args.min.stderr
deleted file mode 100644 (file)
index 0531397..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-error[E0282]: type annotations needed
-  --> $DIR/cannot-infer-const-args.rs:12:5
-   |
-LL |     foo();
-   |     ^^^
-   |
-   = note: unable to infer the value of a const parameter
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0282`.
diff --git a/src/test/ui/const-generics/cannot-infer-const-args.rs b/src/test/ui/const-generics/cannot-infer-const-args.rs
deleted file mode 100644 (file)
index 2d74b47..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-// revisions: full min
-
-#![cfg_attr(full, feature(const_generics))]
-#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
-
-fn foo<const X: usize>() -> usize {
-    0
-}
-
-fn main() {
-    foo(); //~ ERROR type annotations needed
-}
diff --git a/src/test/ui/const-generics/infer/cannot-infer-const-args.full.stderr b/src/test/ui/const-generics/infer/cannot-infer-const-args.full.stderr
new file mode 100644 (file)
index 0000000..84e75cc
--- /dev/null
@@ -0,0 +1,11 @@
+error[E0282]: type annotations needed
+  --> $DIR/cannot-infer-const-args.rs:12:5
+   |
+LL |     foo();
+   |     ^^^
+   |
+   = note: cannot infer the value of the const parameter `X`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0282`.
diff --git a/src/test/ui/const-generics/infer/cannot-infer-const-args.min.stderr b/src/test/ui/const-generics/infer/cannot-infer-const-args.min.stderr
new file mode 100644 (file)
index 0000000..84e75cc
--- /dev/null
@@ -0,0 +1,11 @@
+error[E0282]: type annotations needed
+  --> $DIR/cannot-infer-const-args.rs:12:5
+   |
+LL |     foo();
+   |     ^^^
+   |
+   = note: cannot infer the value of the const parameter `X`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0282`.
diff --git a/src/test/ui/const-generics/infer/cannot-infer-const-args.rs b/src/test/ui/const-generics/infer/cannot-infer-const-args.rs
new file mode 100644 (file)
index 0000000..2d74b47
--- /dev/null
@@ -0,0 +1,13 @@
+// revisions: full min
+
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
+
+fn foo<const X: usize>() -> usize {
+    0
+}
+
+fn main() {
+    foo(); //~ ERROR type annotations needed
+}
diff --git a/src/test/ui/const-generics/infer/method-chain.full.stderr b/src/test/ui/const-generics/infer/method-chain.full.stderr
new file mode 100644 (file)
index 0000000..e65bc3f
--- /dev/null
@@ -0,0 +1,11 @@
+error[E0282]: type annotations needed
+  --> $DIR/method-chain.rs:21:33
+   |
+LL |     Foo.bar().bar().bar().bar().baz();
+   |                                 ^^^
+   |
+   = note: cannot infer the value of the const parameter `N`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0282`.
diff --git a/src/test/ui/const-generics/infer/method-chain.min.stderr b/src/test/ui/const-generics/infer/method-chain.min.stderr
new file mode 100644 (file)
index 0000000..e65bc3f
--- /dev/null
@@ -0,0 +1,11 @@
+error[E0282]: type annotations needed
+  --> $DIR/method-chain.rs:21:33
+   |
+LL |     Foo.bar().bar().bar().bar().baz();
+   |                                 ^^^
+   |
+   = note: cannot infer the value of the const parameter `N`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0282`.
diff --git a/src/test/ui/const-generics/infer/method-chain.rs b/src/test/ui/const-generics/infer/method-chain.rs
new file mode 100644 (file)
index 0000000..9389ca2
--- /dev/null
@@ -0,0 +1,22 @@
+// revisions: full min
+
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
+
+struct Foo;
+
+impl Foo {
+    fn bar(self) -> Foo {
+        Foo
+    }
+
+    fn baz<const N: usize>(self) -> Foo {
+        println!("baz: {}", N);
+        Foo
+    }
+}
+
+fn main() {
+    Foo.bar().bar().bar().bar().baz(); //~ ERROR type annotations needed
+}
diff --git a/src/test/ui/const-generics/infer/uninferred-consts.full.stderr b/src/test/ui/const-generics/infer/uninferred-consts.full.stderr
new file mode 100644 (file)
index 0000000..e47b6bd
--- /dev/null
@@ -0,0 +1,11 @@
+error[E0282]: type annotations needed
+  --> $DIR/uninferred-consts.rs:14:9
+   |
+LL |     Foo.foo();
+   |         ^^^
+   |
+   = note: cannot infer the value of the const parameter `N`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0282`.
diff --git a/src/test/ui/const-generics/infer/uninferred-consts.min.stderr b/src/test/ui/const-generics/infer/uninferred-consts.min.stderr
new file mode 100644 (file)
index 0000000..e47b6bd
--- /dev/null
@@ -0,0 +1,11 @@
+error[E0282]: type annotations needed
+  --> $DIR/uninferred-consts.rs:14:9
+   |
+LL |     Foo.foo();
+   |         ^^^
+   |
+   = note: cannot infer the value of the const parameter `N`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0282`.
diff --git a/src/test/ui/const-generics/infer/uninferred-consts.rs b/src/test/ui/const-generics/infer/uninferred-consts.rs
new file mode 100644 (file)
index 0000000..ec5b3ff
--- /dev/null
@@ -0,0 +1,16 @@
+// Test that we emit an error if we cannot properly infer a constant.
+// revisions: full min
+
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
+
+// taken from https://github.com/rust-lang/rust/issues/70507#issuecomment-615268893
+struct Foo;
+impl Foo {
+    fn foo<const N: usize>(self) {}
+}
+fn main() {
+    Foo.foo();
+    //~^ ERROR type annotations needed
+}
index 752df17aad61490d22b1e7ef60ca9bf2f7134ce5..8f794312834b244b9088e1f95b3a833d70fea403 100644 (file)
@@ -1,10 +1,14 @@
-error: generic parameters must not be used inside of non trivial constant values
+error: generic `Self` types are currently not permitted in anonymous constants
   --> $DIR/issue-62504.rs:19:25
    |
 LL |         ArrayHolder([0; Self::SIZE])
-   |                         ^^^^^^^^^^ non-trivial anonymous constants must not depend on the parameter `Self`
+   |                         ^^^^^^^^^^
    |
-   = help: it is currently only allowed to use either `Self` or `{ Self }` as generic constants
+note: not a concrete type
+  --> $DIR/issue-62504.rs:17:22
+   |
+LL | impl<const X: usize> ArrayHolder<X> {
+   |                      ^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
index b520dbe4e803bf2e6dd96776bddb944847fa17cd..015f170f00d1ce8ec797bf39c2dae9c69f1fbec8 100644 (file)
@@ -18,7 +18,7 @@ impl<const X: usize> ArrayHolder<X> {
     pub const fn new() -> Self {
         ArrayHolder([0; Self::SIZE])
         //[full]~^ ERROR constant expression depends on a generic parameter
-        //[min]~^^ ERROR generic parameters must not be used inside of non trivial constant values
+        //[min]~^^ ERROR generic `Self` types are currently
     }
 }
 
index 69fe0974a791a166040d65a526d756fad617d37c..07822f86f524b621e6c60f28ef5de0d35a88486e 100644 (file)
@@ -4,7 +4,7 @@ error: generic parameters must not be used inside of non trivial constant values
 LL | impl<T: Foo> MyTrait for T where Is<{T::VAL == 5}>: True {}
    |                                      ^^^^^^ non-trivial anonymous constants must not depend on the parameter `T`
    |
-   = help: it is currently only allowed to use either `T` or `{ T }` as generic constants
+   = note: type parameters are currently not permitted in anonymous constants
 
 error: generic parameters must not be used inside of non trivial constant values
   --> $DIR/issue-64494.rs:19:38
@@ -12,7 +12,7 @@ error: generic parameters must not be used inside of non trivial constant values
 LL | impl<T: Foo> MyTrait for T where Is<{T::VAL == 6}>: True {}
    |                                      ^^^^^^ non-trivial anonymous constants must not depend on the parameter `T`
    |
-   = help: it is currently only allowed to use either `T` or `{ T }` as generic constants
+   = note: type parameters are currently not permitted in anonymous constants
 
 error[E0119]: conflicting implementations of trait `MyTrait`:
   --> $DIR/issue-64494.rs:19:1
index 1254ee7239dc78877e4e205ad0a717ba89b0b270..68f1733decb93e03d1a455db3cae59714d522a8c 100644 (file)
@@ -4,7 +4,7 @@ error: generic parameters must not be used inside of non trivial constant values
 LL |         [0u8; mem::size_of::<Self::Associated>()];
    |                              ^^^^^^^^^^^^^^^^ non-trivial anonymous constants must not depend on the parameter `Self`
    |
-   = help: it is currently only allowed to use either `Self` or `{ Self }` as generic constants
+   = note: type parameters are currently not permitted in anonymous constants
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/const-generics/issues/issue-76701-ty-param-in-const.full.stderr b/src/test/ui/const-generics/issues/issue-76701-ty-param-in-const.full.stderr
new file mode 100644 (file)
index 0000000..089937e
--- /dev/null
@@ -0,0 +1,18 @@
+error: constant expression depends on a generic parameter
+  --> $DIR/issue-76701-ty-param-in-const.rs:6:21
+   |
+LL | fn ty_param<T>() -> [u8; std::mem::size_of::<T>()] {
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: this may fail depending on what value the parameter takes
+
+error: constant expression depends on a generic parameter
+  --> $DIR/issue-76701-ty-param-in-const.rs:12:37
+   |
+LL | fn const_param<const N: usize>() -> [u8; N + 1] {
+   |                                     ^^^^^^^^^^^
+   |
+   = note: this may fail depending on what value the parameter takes
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/const-generics/issues/issue-76701-ty-param-in-const.min.stderr b/src/test/ui/const-generics/issues/issue-76701-ty-param-in-const.min.stderr
new file mode 100644 (file)
index 0000000..a39495e
--- /dev/null
@@ -0,0 +1,18 @@
+error: generic parameters must not be used inside of non trivial constant values
+  --> $DIR/issue-76701-ty-param-in-const.rs:6:46
+   |
+LL | fn ty_param<T>() -> [u8; std::mem::size_of::<T>()] {
+   |                                              ^ non-trivial anonymous constants must not depend on the parameter `T`
+   |
+   = note: type parameters are currently not permitted in anonymous constants
+
+error: generic parameters must not be used inside of non trivial constant values
+  --> $DIR/issue-76701-ty-param-in-const.rs:12:42
+   |
+LL | fn const_param<const N: usize>() -> [u8; N + 1] {
+   |                                          ^ 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
+
diff --git a/src/test/ui/const-generics/issues/issue-76701-ty-param-in-const.rs b/src/test/ui/const-generics/issues/issue-76701-ty-param-in-const.rs
new file mode 100644 (file)
index 0000000..9252b59
--- /dev/null
@@ -0,0 +1,18 @@
+// revisions: full min
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
+
+fn ty_param<T>() -> [u8; std::mem::size_of::<T>()] {
+    //[full]~^ ERROR constant expression depends on a generic parameter
+    //[min]~^^ ERROR generic parameters must not be used inside of non trivial constant values
+    todo!()
+}
+
+fn const_param<const N: usize>() -> [u8; N + 1] {
+    //[full]~^ ERROR constant expression depends on a generic parameter
+    //[min]~^^ ERROR generic parameters must not be used inside of non trivial constant values
+    todo!()
+}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/min_const_generics/self-ty-in-const-1.rs b/src/test/ui/const-generics/min_const_generics/self-ty-in-const-1.rs
new file mode 100644 (file)
index 0000000..0973b37
--- /dev/null
@@ -0,0 +1,27 @@
+#![feature(min_const_generics)]
+
+trait Foo {
+    fn t1() -> [u8; std::mem::size_of::<Self>()]; //~ERROR generic parameters
+}
+
+struct Bar<T>(T);
+
+impl Bar<u8> {
+    fn t2() -> [u8; std::mem::size_of::<Self>()] { todo!() } // ok
+}
+
+impl<T> Bar<T> {
+    fn t3() -> [u8; std::mem::size_of::<Self>()] {} //~ERROR generic `Self`
+}
+
+trait Baz {
+    fn hey();
+}
+
+impl Baz for u16 {
+    fn hey() {
+        let _: [u8; std::mem::size_of::<Self>()]; // ok
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/min_const_generics/self-ty-in-const-1.stderr b/src/test/ui/const-generics/min_const_generics/self-ty-in-const-1.stderr
new file mode 100644 (file)
index 0000000..edb77a8
--- /dev/null
@@ -0,0 +1,22 @@
+error: generic parameters must not be used inside of non trivial constant values
+  --> $DIR/self-ty-in-const-1.rs:4:41
+   |
+LL |     fn t1() -> [u8; std::mem::size_of::<Self>()];
+   |                                         ^^^^ non-trivial anonymous constants must not depend on the parameter `Self`
+   |
+   = note: type parameters are currently not permitted in anonymous constants
+
+error: generic `Self` types are currently not permitted in anonymous constants
+  --> $DIR/self-ty-in-const-1.rs:14:41
+   |
+LL |     fn t3() -> [u8; std::mem::size_of::<Self>()] {}
+   |                                         ^^^^
+   |
+note: not a concrete type
+  --> $DIR/self-ty-in-const-1.rs:13:9
+   |
+LL | impl<T> Bar<T> {
+   |         ^^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/const-generics/min_const_generics/self-ty-in-const-2.rs b/src/test/ui/const-generics/min_const_generics/self-ty-in-const-2.rs
new file mode 100644 (file)
index 0000000..e7f80d5
--- /dev/null
@@ -0,0 +1,21 @@
+#![feature(min_const_generics)]
+
+struct Bar<T>(T);
+
+trait Baz {
+    fn hey();
+}
+
+impl Baz for u16 {
+    fn hey() {
+        let _: [u8; std::mem::size_of::<Self>()]; // ok
+    }
+}
+
+impl<T> Baz for Bar<T> {
+    fn hey() {
+        let _: [u8; std::mem::size_of::<Self>()]; //~ERROR generic `Self`
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/min_const_generics/self-ty-in-const-2.stderr b/src/test/ui/const-generics/min_const_generics/self-ty-in-const-2.stderr
new file mode 100644 (file)
index 0000000..9ac6410
--- /dev/null
@@ -0,0 +1,14 @@
+error: generic `Self` types are currently not permitted in anonymous constants
+  --> $DIR/self-ty-in-const-2.rs:17:41
+   |
+LL |         let _: [u8; std::mem::size_of::<Self>()];
+   |                                         ^^^^
+   |
+note: not a concrete type
+  --> $DIR/self-ty-in-const-2.rs:15:17
+   |
+LL | impl<T> Baz for Bar<T> {
+   |                 ^^^^^^
+
+error: aborting due to previous error
+
index 461822a96083b187a6fb2d7cd4abfbfeb2e277c2..e545ae8571f67d7ee7780bd20ddea1a02629f093 100644 (file)
@@ -12,7 +12,7 @@ error: generic parameters must not be used inside of non trivial constant values
 LL | struct Foo<T, U = [u8; std::mem::size_of::<T>()]>(T, U);
    |                                            ^ non-trivial anonymous constants must not depend on the parameter `T`
    |
-   = help: it is currently only allowed to use either `T` or `{ T }` as generic constants
+   = note: type parameters are currently not permitted in anonymous constants
 
 error: constant values inside of type parameter defaults must not depend on generic parameters
   --> $DIR/params-in-ct-in-ty-param-lazy-norm.rs:12:21
index 1d42afa3f8461de59044ed35380182c730f91b0a..f3b19109a7c80e14cd49faf608ae1cb7966f8802 100644 (file)
@@ -5,21 +5,21 @@
 #![cfg_attr(min, feature(min_const_generics))]
 
 trait SliceExt<T: Clone> {
-    fn array_windows<'a, const N: usize>(&'a self) -> ArrayWindows<'a, T, N>;
+    fn array_windows_example<'a, const N: usize>(&'a self) -> ArrayWindowsExample<'a, T, N>;
 }
 
 impl <T: Clone> SliceExt<T> for [T] {
-   fn array_windows<'a, const N: usize>(&'a self) -> ArrayWindows<'a, T, N> {
-       ArrayWindows{ idx: 0, slice: &self }
+   fn array_windows_example<'a, const N: usize>(&'a self) -> ArrayWindowsExample<'a, T, N> {
+       ArrayWindowsExample{ idx: 0, slice: &self }
    }
 }
 
-struct ArrayWindows<'a, T, const N: usize> {
+struct ArrayWindowsExample<'a, T, const N: usize> {
     slice: &'a [T],
     idx: usize,
 }
 
-impl <'a, T: Clone, const N: usize> Iterator for ArrayWindows<'a, T, N> {
+impl <'a, T: Clone, const N: usize> Iterator for ArrayWindowsExample<'a, T, N> {
     type Item = [T; N];
     fn next(&mut self) -> Option<Self::Item> {
         // Note: this is unsound for some `T` and not meant as an example
@@ -45,7 +45,7 @@ fn next(&mut self) -> Option<Self::Item> {
 fn main() {
     let v: Vec<usize> = vec![0; 100];
 
-    for array in v.as_slice().array_windows::<FOUR>() {
+    for array in v.as_slice().array_windows_example::<FOUR>() {
         assert_eq!(array, [0, 0, 0, 0])
     }
 }
diff --git a/src/test/ui/const-generics/uninferred-consts.full.stderr b/src/test/ui/const-generics/uninferred-consts.full.stderr
deleted file mode 100644 (file)
index 2c5af9e..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-error[E0282]: type annotations needed
-  --> $DIR/uninferred-consts.rs:14:5
-   |
-LL |     Foo.foo();
-   |     ^^^^^^^^^
-   |
-   = note: unable to infer the value of a const parameter
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0282`.
diff --git a/src/test/ui/const-generics/uninferred-consts.min.stderr b/src/test/ui/const-generics/uninferred-consts.min.stderr
deleted file mode 100644 (file)
index 2c5af9e..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-error[E0282]: type annotations needed
-  --> $DIR/uninferred-consts.rs:14:5
-   |
-LL |     Foo.foo();
-   |     ^^^^^^^^^
-   |
-   = note: unable to infer the value of a const parameter
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0282`.
diff --git a/src/test/ui/const-generics/uninferred-consts.rs b/src/test/ui/const-generics/uninferred-consts.rs
deleted file mode 100644 (file)
index ec5b3ff..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-// Test that we emit an error if we cannot properly infer a constant.
-// revisions: full min
-
-#![cfg_attr(full, feature(const_generics))]
-#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
-
-// taken from https://github.com/rust-lang/rust/issues/70507#issuecomment-615268893
-struct Foo;
-impl Foo {
-    fn foo<const N: usize>(self) {}
-}
-fn main() {
-    Foo.foo();
-    //~^ ERROR type annotations needed
-}
diff --git a/src/test/ui/consts/duration-consts-2.rs b/src/test/ui/consts/duration-consts-2.rs
deleted file mode 100644 (file)
index bc0969e..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-// run-pass
-
-#![feature(const_panic)]
-#![feature(duration_consts_2)]
-#![feature(div_duration)]
-#![feature(duration_saturating_ops)]
-
-use std::time::Duration;
-
-fn duration() {
-    const ZERO : Duration = Duration::new(0, 0);
-    assert_eq!(ZERO, Duration::from_secs(0));
-
-    const ONE : Duration = Duration::new(0, 1);
-    assert_eq!(ONE, Duration::from_nanos(1));
-
-    const MAX : Duration = Duration::new(u64::MAX, 1_000_000_000 - 1);
-
-    const MAX_CHECKED_ADD_ZERO : Option<Duration> = MAX.checked_add(ZERO);
-    assert_eq!(MAX_CHECKED_ADD_ZERO, Some(MAX));
-
-    const MAX_CHECKED_ADD_ONE : Option<Duration> = MAX.checked_add(ONE);
-    assert_eq!(MAX_CHECKED_ADD_ONE, None);
-
-    const ONE_CHECKED_SUB_ONE : Option<Duration> = ONE.checked_sub(ONE);
-    assert_eq!(ONE_CHECKED_SUB_ONE, Some(ZERO));
-
-    const ZERO_CHECKED_SUB_ONE : Option<Duration> = ZERO.checked_sub(ONE);
-    assert_eq!(ZERO_CHECKED_SUB_ONE, None);
-
-    const ONE_CHECKED_MUL_ONE : Option<Duration> = ONE.checked_mul(1);
-    assert_eq!(ONE_CHECKED_MUL_ONE, Some(ONE));
-
-    const MAX_CHECKED_MUL_TWO : Option<Duration> = MAX.checked_mul(2);
-    assert_eq!(MAX_CHECKED_MUL_TWO, None);
-
-    const ONE_CHECKED_DIV_ONE : Option<Duration> = ONE.checked_div(1);
-    assert_eq!(ONE_CHECKED_DIV_ONE, Some(ONE));
-
-    const ONE_CHECKED_DIV_ZERO : Option<Duration> = ONE.checked_div(0);
-    assert_eq!(ONE_CHECKED_DIV_ZERO, None);
-
-    const MAX_AS_F32 : f32 = MAX.as_secs_f32();
-    assert_eq!(MAX_AS_F32, 18446744000000000000.0_f32);
-
-    const MAX_AS_F64 : f64 = MAX.as_secs_f64();
-    assert_eq!(MAX_AS_F64, 18446744073709552000.0_f64);
-
-    const ONE_AS_F32 : f32 = ONE.div_duration_f32(ONE);
-    assert_eq!(ONE_AS_F32, 1.0_f32);
-
-    const ONE_AS_F64 : f64 = ONE.div_duration_f64(ONE);
-    assert_eq!(ONE_AS_F64, 1.0_f64);
-
-    const MAX_SATURATING_ADD_ONE : Duration = MAX.saturating_add(ONE);
-    assert_eq!(MAX_SATURATING_ADD_ONE, MAX);
-
-    const ZERO_SATURATING_SUB_ONE : Duration = ZERO.saturating_sub(ONE);
-    assert_eq!(ZERO_SATURATING_SUB_ONE, ZERO);
-
-    const MAX_SATURATING_MUL_TWO : Duration = MAX.saturating_mul(2);
-    assert_eq!(MAX_SATURATING_MUL_TWO, MAX);
-}
-
-fn main() {
-    duration();
-}
index e4e94bb9492371c811fb2a0ccc56fef040e673df..5497ba2e11f7325bbecaff305b7ef5ec3823aeae 100644 (file)
@@ -1,8 +1,29 @@
 fn main() {
     (0..13).collect<Vec<i32>>();
     //~^ ERROR comparison operators cannot be chained
+    //~| HELP use `::<...>` instead
     Vec<i32>::new();
     //~^ ERROR comparison operators cannot be chained
+    //~| HELP use `::<...>` instead
     (0..13).collect<Vec<i32>();
     //~^ ERROR comparison operators cannot be chained
+    //~| HELP use `::<...>` instead
+    let x = std::collections::HashMap<i128, i128>::new(); //~ ERROR expected one of
+    //~^ HELP use `::<...>` instead
+    let x: () = 42; //~ ERROR mismatched types
+    let x = {
+        std::collections::HashMap<i128, i128>::new() //~ ERROR expected one of
+        //~^ HELP use `::<...>` instead
+    };
+    let x: () = 42; //~ ERROR mismatched types
+    let x = {
+        std::collections::HashMap<i128, i128>::new(); //~ ERROR expected one of
+        //~^ HELP use `::<...>` instead
+        let x: () = 42; //~ ERROR mismatched types
+    };
+    {
+        std::collections::HashMap<i128, i128>::new(1, 2); //~ ERROR expected one of
+        //~^ HELP use `::<...>` instead
+        let x: () = 32; //~ ERROR mismatched types
+    };
 }
index 10972697f9fcdc7af0373f94d1493e80b785329e..184bcf0c74b1428cc1896e562a5a411c4d759743 100644 (file)
@@ -10,7 +10,7 @@ LL |     (0..13).collect::<Vec<i32>>();
    |                    ^^
 
 error: comparison operators cannot be chained
-  --> $DIR/issue-40396.rs:4:8
+  --> $DIR/issue-40396.rs:5:8
    |
 LL |     Vec<i32>::new();
    |        ^   ^
@@ -21,7 +21,7 @@ LL |     Vec::<i32>::new();
    |        ^^
 
 error: comparison operators cannot be chained
-  --> $DIR/issue-40396.rs:6:20
+  --> $DIR/issue-40396.rs:8:20
    |
 LL |     (0..13).collect<Vec<i32>();
    |                    ^   ^
@@ -31,5 +31,82 @@ help: use `::<...>` instead of `<...>` to specify type arguments
 LL |     (0..13).collect::<Vec<i32>();
    |                    ^^
 
-error: aborting due to 3 previous errors
+error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, or an operator, found `,`
+  --> $DIR/issue-40396.rs:11:43
+   |
+LL |     let x = std::collections::HashMap<i128, i128>::new();
+   |                                           ^ expected one of 7 possible tokens
+   |
+help: use `::<...>` instead of `<...>` to specify type arguments
+   |
+LL |     let x = std::collections::HashMap::<i128, i128>::new();
+   |                                      ^^
+
+error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `,`
+  --> $DIR/issue-40396.rs:15:39
+   |
+LL |         std::collections::HashMap<i128, i128>::new()
+   |                                       ^ expected one of 8 possible tokens
+   |
+help: use `::<...>` instead of `<...>` to specify type arguments
+   |
+LL |         std::collections::HashMap::<i128, i128>::new()
+   |                                  ^^
+
+error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `,`
+  --> $DIR/issue-40396.rs:20:39
+   |
+LL |         std::collections::HashMap<i128, i128>::new();
+   |                                       ^ expected one of 8 possible tokens
+   |
+help: use `::<...>` instead of `<...>` to specify type arguments
+   |
+LL |         std::collections::HashMap::<i128, i128>::new();
+   |                                  ^^
+
+error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `,`
+  --> $DIR/issue-40396.rs:25:39
+   |
+LL |         std::collections::HashMap<i128, i128>::new(1, 2);
+   |                                       ^ expected one of 8 possible tokens
+   |
+help: use `::<...>` instead of `<...>` to specify type arguments
+   |
+LL |         std::collections::HashMap::<i128, i128>::new(1, 2);
+   |                                  ^^
+
+error[E0308]: mismatched types
+  --> $DIR/issue-40396.rs:13:17
+   |
+LL |     let x: () = 42;
+   |            --   ^^ expected `()`, found integer
+   |            |
+   |            expected due to this
+
+error[E0308]: mismatched types
+  --> $DIR/issue-40396.rs:18:17
+   |
+LL |     let x: () = 42;
+   |            --   ^^ expected `()`, found integer
+   |            |
+   |            expected due to this
+
+error[E0308]: mismatched types
+  --> $DIR/issue-40396.rs:22:21
+   |
+LL |         let x: () = 42;
+   |                --   ^^ expected `()`, found integer
+   |                |
+   |                expected due to this
+
+error[E0308]: mismatched types
+  --> $DIR/issue-40396.rs:27:21
+   |
+LL |         let x: () = 32;
+   |                --   ^^ expected `()`, found integer
+   |                |
+   |                expected due to this
+
+error: aborting due to 11 previous errors
 
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/error-codes/E0027-teach.rs b/src/test/ui/error-codes/E0027-teach.rs
deleted file mode 100644 (file)
index 11402f0..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-// compile-flags: -Z teach
-
-struct Dog {
-    name: String,
-    age: u32,
-}
-
-fn main() {
-    let d = Dog { name: "Rusty".to_string(), age: 8 };
-
-    match d {
-        Dog { age: x } => {}
-        //~^ ERROR pattern does not mention field `name`
-    }
-}
diff --git a/src/test/ui/error-codes/E0027-teach.stderr b/src/test/ui/error-codes/E0027-teach.stderr
deleted file mode 100644 (file)
index aa4cb9d..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-error[E0027]: pattern does not mention field `name`
-  --> $DIR/E0027-teach.rs:12:9
-   |
-LL |         Dog { age: x } => {}
-   |         ^^^^^^^^^^^^^^ missing field `name`
-   |
-   = note: This error indicates that a pattern for a struct fails to specify a sub-pattern for every one of the struct's fields. Ensure that each field from the struct's definition is mentioned in the pattern, or use `..` to ignore unwanted fields.
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0027`.
index b8c6a2b7fcd700c1afcba7be15e02e7675b6779c..8d08e178934807125a85140a0807a5edc7123287 100644 (file)
@@ -7,7 +7,9 @@ fn main() {
     let d = Dog { name: "Rusty".to_string(), age: 8 };
 
     match d {
-        Dog { age: x } => {}
-        //~^ ERROR pattern does not mention field `name`
+        Dog { age: x } => {} //~ ERROR pattern does not mention field `name`
+    }
+    match d {
+        Dog {} => {} //~ ERROR pattern does not mention fields `name`, `age`
     }
 }
index 4f17bba6477a98498c92c51d47a9396436e5f147..c09f1ff1f2a8ce335d0e7314b9b699e72e028d7d 100644 (file)
@@ -3,7 +3,31 @@ error[E0027]: pattern does not mention field `name`
    |
 LL |         Dog { age: x } => {}
    |         ^^^^^^^^^^^^^^ missing field `name`
+   |
+help: include the missing field in the pattern
+   |
+LL |         Dog { age: x, name } => {}
+   |                     ^^^^^^
+help: if you don't care about this missing field, you can explicitely ignore it
+   |
+LL |         Dog { age: x, .. } => {}
+   |                     ^^^^
+
+error[E0027]: pattern does not mention fields `name`, `age`
+  --> $DIR/E0027.rs:13:9
+   |
+LL |         Dog {} => {}
+   |         ^^^^^^ missing fields `name`, `age`
+   |
+help: include the missing fields in the pattern
+   |
+LL |         Dog { name, age } => {}
+   |             ^^^^^^^^^^^^^
+help: if you don't care about these missing fields, you can explicitely ignore them
+   |
+LL |         Dog { .. } => {}
+   |             ^^^^^^
 
-error: aborting due to previous error
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0027`.
diff --git a/src/test/ui/feature-gates/feature-gate-doc_alias.rs b/src/test/ui/feature-gates/feature-gate-doc_alias.rs
deleted file mode 100644 (file)
index c957221..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-#[doc(alias = "foo")] //~ ERROR: `#[doc(alias)]` is experimental
-pub struct Foo;
-
-fn main() {}
diff --git a/src/test/ui/feature-gates/feature-gate-doc_alias.stderr b/src/test/ui/feature-gates/feature-gate-doc_alias.stderr
deleted file mode 100644 (file)
index f66d160..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-error[E0658]: `#[doc(alias)]` is experimental
-  --> $DIR/feature-gate-doc_alias.rs:1:1
-   |
-LL | #[doc(alias = "foo")]
-   | ^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #50146 <https://github.com/rust-lang/rust/issues/50146> for more information
-   = help: add `#![feature(doc_alias)]` to the crate attributes to enable
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0658`.
index 9667a9785dc63b0ef7c01ba9c211a9505aaad5a6..cdaa61ac323dd490fda9c16c930992a0f9487454 100644 (file)
@@ -23,7 +23,7 @@ LL |     0_u32
    = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
    = help: if the trait `Foo` were object safe, you could return a boxed trait object
    = note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
-   = help: alternatively, create a new `enum` with a variant for each returned type
+   = help: you could instead create a new `enum` with a variant for each returned type
 
 error[E0277]: cannot add `impl Foo` to `u32`
   --> $DIR/equality.rs:24:11
index dd4260fbe4f911b0cfc15f57e73b7958833146d0..66043267f91cd71979f72ae93fabbba300952e0c 100644 (file)
@@ -14,7 +14,7 @@ LL |     B
    = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
    = help: if the trait `NotObjectSafe` were object safe, you could return a boxed trait object
    = note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
-   = help: alternatively, create a new `enum` with a variant for each returned type
+   = help: you could instead create a new `enum` with a variant for each returned type
 
 error[E0308]: mismatched types
   --> $DIR/object-unsafe-trait-in-return-position-impl-trait.rs:43:5
@@ -30,9 +30,18 @@ LL |     B
    |
    = note: to return `impl Trait`, all returned values must be of the same type
    = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
-   = help: you can instead return a boxed trait object using `Box<dyn ObjectSafe>`
    = note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
-   = help: alternatively, create a new `enum` with a variant for each returned type
+   = help: you could instead create a new `enum` with a variant for each returned type
+help: you could change the return type to be a boxed trait object
+   |
+LL | fn cat() -> Box<dyn ObjectSafe> {
+   |             ^^^^^^^           ^
+help: if you change the return type to expect trait objects, box the returned expressions
+   |
+LL |         return Box::new(A);
+LL |     }
+LL |     Box::new(B)
+   |
 
 error: aborting due to 2 previous errors
 
index 1770d71e2e2fe6f12d2921aa17ce029995aa2e87..fb884e3129999c3246f085522ebc6e553705c25a 100644 (file)
@@ -149,7 +149,7 @@ error: function cannot return without recursing
 LL |     fn deref(&self) -> &Baz {
    |     ^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing
 LL |         self.as_ref()
-   |         ---- recursive call site
+   |         ------------- recursive call site
    |
    = help: a `loop` may express intention better if this is on purpose
 
diff --git a/src/test/ui/mir/issue-71793-inline-args-storage.rs b/src/test/ui/mir/issue-71793-inline-args-storage.rs
new file mode 100644 (file)
index 0000000..87b2806
--- /dev/null
@@ -0,0 +1,16 @@
+// Verifies that inliner emits StorageLive & StorageDead when introducing
+// temporaries for arguments, so that they don't become part of the generator.
+// Regression test for #71793.
+//
+// check-pass
+// edition:2018
+// compile-args: -Zmir-opt-level=2
+
+#![crate_type = "lib"]
+
+pub async fn connect() {}
+
+pub async fn connect_many() {
+    Vec::<String>::new().first().ok_or("").unwrap();
+    connect().await;
+}
diff --git a/src/test/ui/moves/move-deref-coercion.rs b/src/test/ui/moves/move-deref-coercion.rs
new file mode 100644 (file)
index 0000000..4115438
--- /dev/null
@@ -0,0 +1,33 @@
+use std::ops::Deref;
+
+struct NotCopy {
+    inner: bool
+}
+
+impl NotCopy {
+    fn inner_method(&self) {}
+}
+
+struct Foo {
+    first: NotCopy,
+    second: NotCopy
+}
+
+impl Deref for Foo {
+    type Target = NotCopy;
+    fn deref(&self) -> &NotCopy {
+        &self.second
+    }
+}
+
+fn use_field(val: Foo) {
+    let _val = val.first;
+    val.inner; //~ ERROR borrow of
+}
+
+fn use_method(val: Foo) {
+    let _val = val.first;
+    val.inner_method(); //~ ERROR borrow of
+}
+
+fn main() {}
diff --git a/src/test/ui/moves/move-deref-coercion.stderr b/src/test/ui/moves/move-deref-coercion.stderr
new file mode 100644 (file)
index 0000000..e3bdf6d
--- /dev/null
@@ -0,0 +1,35 @@
+error[E0382]: borrow of partially moved value: `val`
+  --> $DIR/move-deref-coercion.rs:25:5
+   |
+LL |     let _val = val.first;
+   |                --------- value partially moved here
+LL |     val.inner;
+   |     ^^^^^^^^^ value borrowed here after partial move
+   |
+   = note: partial move occurs because `val.first` has type `NotCopy`, which does not implement the `Copy` trait
+   = note: borrow occurs due to deref coercion to `NotCopy`
+note: deref defined here
+  --> $DIR/move-deref-coercion.rs:17:5
+   |
+LL |     type Target = NotCopy;
+   |     ^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0382]: borrow of partially moved value: `val`
+  --> $DIR/move-deref-coercion.rs:30:5
+   |
+LL |     let _val = val.first;
+   |                --------- value partially moved here
+LL |     val.inner_method();
+   |     ^^^^^^^^^^^^^^^^^^ value borrowed here after partial move
+   |
+   = note: partial move occurs because `val.first` has type `NotCopy`, which does not implement the `Copy` trait
+   = note: borrow occurs due to deref coercion to `NotCopy`
+note: deref defined here
+  --> $DIR/move-deref-coercion.rs:17:5
+   |
+LL |     type Target = NotCopy;
+   |     ^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0382`.
index 0081841fec0907c669f6840c513ed1790d17aa8d..37032e73f1900c2a21bdfc55821ea77ed476fb52 100644 (file)
@@ -1,5 +1,5 @@
 error[E0382]: borrow of moved value: `arc_v`
-  --> $DIR/no-capture-arc.rs:14:18
+  --> $DIR/no-capture-arc.rs:14:16
    |
 LL |     let arc_v = Arc::new(v);
    |         ----- move occurs because `arc_v` has type `Arc<Vec<i32>>`, which does not implement the `Copy` trait
@@ -10,7 +10,14 @@ LL |         assert_eq!((*arc_v)[3], 4);
    |                      ----- variable moved due to use in closure
 ...
 LL |     assert_eq!((*arc_v)[2], 3);
-   |                  ^^^^^ value borrowed here after move
+   |                ^^^^^^^^ value borrowed here after move
+   |
+   = note: borrow occurs due to deref coercion to `Vec<i32>`
+note: deref defined here
+  --> $SRC_DIR/alloc/src/sync.rs:LL:COL
+   |
+LL |     type Target = T;
+   |     ^^^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
index bb4e0871224a283bd8cc0ec38fdd92274686eade..6f37d4c9d869125a8ea59a314edebf5f1577efae 100644 (file)
@@ -1,5 +1,5 @@
 error[E0382]: borrow of moved value: `arc_v`
-  --> $DIR/no-reuse-move-arc.rs:12:18
+  --> $DIR/no-reuse-move-arc.rs:12:16
    |
 LL |     let arc_v = Arc::new(v);
    |         ----- move occurs because `arc_v` has type `Arc<Vec<i32>>`, which does not implement the `Copy` trait
@@ -10,7 +10,14 @@ LL |         assert_eq!((*arc_v)[3], 4);
    |                      ----- variable moved due to use in closure
 ...
 LL |     assert_eq!((*arc_v)[2], 3);
-   |                  ^^^^^ value borrowed here after move
+   |                ^^^^^^^^ value borrowed here after move
+   |
+   = note: borrow occurs due to deref coercion to `Vec<i32>`
+note: deref defined here
+  --> $SRC_DIR/alloc/src/sync.rs:LL:COL
+   |
+LL |     type Target = T;
+   |     ^^^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/numbers-arithmetic/arith-0.rs b/src/test/ui/numbers-arithmetic/arith-0.rs
deleted file mode 100644 (file)
index 7943cb9..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-// run-pass
-
-
-pub fn main() {
-    let a: isize = 10;
-    println!("{}", a);
-    assert_eq!(a * (a - 1), 90);
-}
diff --git a/src/test/ui/numbers-arithmetic/arith-1.rs b/src/test/ui/numbers-arithmetic/arith-1.rs
deleted file mode 100644 (file)
index c13c8d8..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-// run-pass
-
-
-pub fn main() {
-    let i32_a: isize = 10;
-    assert_eq!(i32_a, 10);
-    assert_eq!(i32_a - 10, 0);
-    assert_eq!(i32_a / 10, 1);
-    assert_eq!(i32_a - 20, -10);
-    assert_eq!(i32_a << 10, 10240);
-    assert_eq!(i32_a << 16, 655360);
-    assert_eq!(i32_a * 16, 160);
-    assert_eq!(i32_a * i32_a * i32_a, 1000);
-    assert_eq!(i32_a * i32_a * i32_a * i32_a, 10000);
-    assert_eq!(i32_a * i32_a / i32_a * i32_a, 100);
-    assert_eq!(i32_a * (i32_a - 1) << (2 + i32_a as usize), 368640);
-    let i32_b: isize = 0x10101010;
-    assert_eq!(i32_b + 1 - 1, i32_b);
-    assert_eq!(i32_b << 1, i32_b << 1);
-    assert_eq!(i32_b >> 1, i32_b >> 1);
-    assert_eq!(i32_b & i32_b << 1, 0);
-    println!("{}", i32_b | i32_b << 1);
-    assert_eq!(i32_b | i32_b << 1, 0x30303030);
-}
diff --git a/src/test/ui/numbers-arithmetic/arith-2.rs b/src/test/ui/numbers-arithmetic/arith-2.rs
deleted file mode 100644 (file)
index 46c2806..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-// run-pass
-
-
-
-pub fn main() {
-    let i32_c: isize = 0x10101010;
-    assert_eq!(i32_c + i32_c * 2 / 3 * 2 + (i32_c - 7 % 3),
-                 i32_c + i32_c * 2 / 3 * 2 + (i32_c - 7 % 3));
-}
diff --git a/src/test/ui/parser/issue-73568-lifetime-after-mut.rs b/src/test/ui/parser/issue-73568-lifetime-after-mut.rs
new file mode 100644 (file)
index 0000000..0b10a5f
--- /dev/null
@@ -0,0 +1,21 @@
+#![crate_type="lib"]
+fn x<'a>(x: &mut 'a i32){} //~ ERROR lifetime must precede `mut`
+
+macro_rules! mac {
+    ($lt:lifetime) => {
+        fn w<$lt>(w: &mut $lt i32) {}
+        //~^ ERROR lifetime must precede `mut`
+    }
+}
+
+mac!('a);
+
+// avoid false positives
+fn y<'a>(y: &mut 'a + Send) {
+    //~^ ERROR expected a path on the left-hand side of `+`, not `&mut 'a`
+    //~| WARNING trait objects without an explicit `dyn` are deprecated
+    //~| ERROR at least one trait is required for an object type
+    let z = y as &mut 'a + Send;
+    //~^ ERROR expected value, found trait `Send`
+    //~| WARNING trait objects without an explicit `dyn` are deprecated
+}
diff --git a/src/test/ui/parser/issue-73568-lifetime-after-mut.stderr b/src/test/ui/parser/issue-73568-lifetime-after-mut.stderr
new file mode 100644 (file)
index 0000000..abb64f7
--- /dev/null
@@ -0,0 +1,53 @@
+error: lifetime must precede `mut`
+  --> $DIR/issue-73568-lifetime-after-mut.rs:2:13
+   |
+LL | fn x<'a>(x: &mut 'a i32){}
+   |             ^^^^^^^ help: place the lifetime before `mut`: `&'a mut`
+
+error[E0178]: expected a path on the left-hand side of `+`, not `&mut 'a`
+  --> $DIR/issue-73568-lifetime-after-mut.rs:14:13
+   |
+LL | fn y<'a>(y: &mut 'a + Send) {
+   |             ^^^^^^^^^^^^^^ help: try adding parentheses: `&mut ('a + Send)`
+
+error: lifetime must precede `mut`
+  --> $DIR/issue-73568-lifetime-after-mut.rs:6:22
+   |
+LL |         fn w<$lt>(w: &mut $lt i32) {}
+   |                      ^^^^^^^^ help: place the lifetime before `mut`: `&$lt mut`
+...
+LL | mac!('a);
+   | --------- in this macro invocation
+   |
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0423]: expected value, found trait `Send`
+  --> $DIR/issue-73568-lifetime-after-mut.rs:18:28
+   |
+LL |     let z = y as &mut 'a + Send;
+   |                            ^^^^ not a value
+
+warning: trait objects without an explicit `dyn` are deprecated
+  --> $DIR/issue-73568-lifetime-after-mut.rs:14:18
+   |
+LL | fn y<'a>(y: &mut 'a + Send) {
+   |                  ^^ help: use `dyn`: `dyn 'a`
+   |
+   = note: `#[warn(bare_trait_objects)]` on by default
+
+warning: trait objects without an explicit `dyn` are deprecated
+  --> $DIR/issue-73568-lifetime-after-mut.rs:18:23
+   |
+LL |     let z = y as &mut 'a + Send;
+   |                       ^^ help: use `dyn`: `dyn 'a`
+
+error[E0224]: at least one trait is required for an object type
+  --> $DIR/issue-73568-lifetime-after-mut.rs:14:18
+   |
+LL | fn y<'a>(y: &mut 'a + Send) {
+   |                  ^^
+
+error: aborting due to 5 previous errors; 2 warnings emitted
+
+Some errors have detailed explanations: E0178, E0224, E0423.
+For more information about an error, try `rustc --explain E0178`.
index a80e5df1a26a2057c00adf868a00be3ec94a476a..fa7664a83eee073f7588794011a8f5f73f336117 100644 (file)
@@ -2,16 +2,14 @@ fn foo() -> impl std::fmt::Display {
     if false {
         return 0i32;
     }
-    1u32
-    //~^ ERROR mismatched types
+    1u32 //~ ERROR mismatched types
 }
 
 fn bar() -> impl std::fmt::Display {
     if false {
         return 0i32;
     } else {
-        return 1u32;
-        //~^ ERROR mismatched types
+        return 1u32; //~ ERROR mismatched types
     }
 }
 
@@ -19,8 +17,7 @@ fn baz() -> impl std::fmt::Display {
     if false {
         return 0i32;
     } else {
-        1u32
-        //~^ ERROR mismatched types
+        1u32 //~ ERROR mismatched types
     }
 }
 
@@ -28,22 +25,19 @@ fn qux() -> impl std::fmt::Display {
     if false {
         0i32
     } else {
-        1u32
-        //~^ ERROR `if` and `else` have incompatible types
+        1u32 //~ ERROR `if` and `else` have incompatible types
     }
 }
 
 fn bat() -> impl std::fmt::Display {
     match 13 {
         0 => return 0i32,
-        _ => 1u32,
-        //~^ ERROR mismatched types
+        _ => 1u32, //~ ERROR mismatched types
     }
 }
 
 fn can() -> impl std::fmt::Display {
-    match 13 {
-    //~^ ERROR mismatched types
+    match 13 { //~ ERROR mismatched types
         0 => return 0i32,
         1 => 1u32,
         _ => 2u32,
@@ -51,15 +45,57 @@ fn can() -> impl std::fmt::Display {
 }
 
 fn cat() -> impl std::fmt::Display {
+    match 13 {
+        0 => {
+            return 0i32;
+        }
+        _ => {
+            1u32 //~ ERROR mismatched types
+        }
+    }
+}
+
+fn dog() -> impl std::fmt::Display {
+    match 13 {
+        0 => 0i32,
+        1 => 1u32, //~ ERROR `match` arms have incompatible types
+        _ => 2u32,
+    }
+}
+
+fn hat() -> dyn std::fmt::Display { //~ ERROR return type cannot have an unboxed trait object
     match 13 {
         0 => {
             return 0i32;
         }
         _ => {
             1u32
-            //~^ ERROR mismatched types
         }
     }
 }
 
+fn pug() -> dyn std::fmt::Display { //~ ERROR return type cannot have an unboxed trait object
+    match 13 {
+        0 => 0i32,
+        1 => 1u32, //~ ERROR `match` arms have incompatible types
+        _ => 2u32,
+    }
+}
+
+fn man() -> dyn std::fmt::Display { //~ ERROR return type cannot have an unboxed trait object
+    if false {
+        0i32
+    } else {
+        1u32 //~ ERROR `if` and `else` have incompatible types
+    }
+}
+
+fn apt() -> impl std::fmt::Display {
+    if let Some(42) = Some(42) {
+        0i32
+    } else {
+        1u32 //~ ERROR `if` and `else` have incompatible types
+    }
+}
+
 fn main() {}
index b663cccbeef0f192da5e7d6b530a45f3bd974925..eb4dc45c8a9320e136428e8b6699a3e560de9ef9 100644 (file)
@@ -12,12 +12,21 @@ LL |     1u32
    |
    = note: to return `impl Trait`, all returned values must be of the same type
    = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
-   = help: you can instead return a boxed trait object using `Box<dyn std::fmt::Display>`
    = note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
-   = help: alternatively, create a new `enum` with a variant for each returned type
+   = help: you could instead create a new `enum` with a variant for each returned type
+help: you could change the return type to be a boxed trait object
+   |
+LL | fn foo() -> Box<dyn std::fmt::Display> {
+   |             ^^^^^^^                  ^
+help: if you change the return type to expect trait objects, box the returned expressions
+   |
+LL |         return Box::new(0i32);
+LL |     }
+LL |     Box::new(1u32)
+   |
 
 error[E0308]: mismatched types
-  --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:13:16
+  --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:12:16
    |
 LL | fn bar() -> impl std::fmt::Display {
    |             ---------------------- expected because this return type...
@@ -30,12 +39,21 @@ LL |         return 1u32;
    |
    = note: to return `impl Trait`, all returned values must be of the same type
    = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
-   = help: you can instead return a boxed trait object using `Box<dyn std::fmt::Display>`
    = note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
-   = help: alternatively, create a new `enum` with a variant for each returned type
+   = help: you could instead create a new `enum` with a variant for each returned type
+help: you could change the return type to be a boxed trait object
+   |
+LL | fn bar() -> Box<dyn std::fmt::Display> {
+   |             ^^^^^^^                  ^
+help: if you change the return type to expect trait objects, box the returned expressions
+   |
+LL |         return Box::new(0i32);
+LL |     } else {
+LL |         return Box::new(1u32);
+   |
 
 error[E0308]: mismatched types
-  --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:22:9
+  --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:20:9
    |
 LL | fn baz() -> impl std::fmt::Display {
    |             ---------------------- expected because this return type...
@@ -48,12 +66,21 @@ LL |         1u32
    |
    = note: to return `impl Trait`, all returned values must be of the same type
    = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
-   = help: you can instead return a boxed trait object using `Box<dyn std::fmt::Display>`
    = note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
-   = help: alternatively, create a new `enum` with a variant for each returned type
+   = help: you could instead create a new `enum` with a variant for each returned type
+help: you could change the return type to be a boxed trait object
+   |
+LL | fn baz() -> Box<dyn std::fmt::Display> {
+   |             ^^^^^^^                  ^
+help: if you change the return type to expect trait objects, box the returned expressions
+   |
+LL |         return Box::new(0i32);
+LL |     } else {
+LL |         Box::new(1u32)
+   |
 
 error[E0308]: `if` and `else` have incompatible types
-  --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:31:9
+  --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:28:9
    |
 LL | /     if false {
 LL | |         0i32
@@ -61,12 +88,22 @@ LL | |         0i32
 LL | |     } else {
 LL | |         1u32
    | |         ^^^^ expected `i32`, found `u32`
-LL | |
 LL | |     }
    | |_____- `if` and `else` have incompatible types
+   |
+help: you could change the return type to be a boxed trait object
+   |
+LL | fn qux() -> Box<dyn std::fmt::Display> {
+   |             ^^^^^^^                  ^
+help: if you change the return type to expect trait objects, box the returned expressions
+   |
+LL |         Box::new(0i32)
+LL |     } else {
+LL |         Box::new(1u32)
+   |
 
 error[E0308]: mismatched types
-  --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:39:14
+  --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:35:14
    |
 LL | fn bat() -> impl std::fmt::Display {
    |             ---------------------- expected because this return type...
@@ -78,17 +115,24 @@ LL |         _ => 1u32,
    |
    = note: to return `impl Trait`, all returned values must be of the same type
    = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
-   = help: you can instead return a boxed trait object using `Box<dyn std::fmt::Display>`
    = note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
-   = help: alternatively, create a new `enum` with a variant for each returned type
+   = help: you could instead create a new `enum` with a variant for each returned type
+help: you could change the return type to be a boxed trait object
+   |
+LL | fn bat() -> Box<dyn std::fmt::Display> {
+   |             ^^^^^^^                  ^
+help: if you change the return type to expect trait objects, box the returned expressions
+   |
+LL |         0 => return Box::new(0i32),
+LL |         _ => Box::new(1u32),
+   |
 
 error[E0308]: mismatched types
-  --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:45:5
+  --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:40:5
    |
 LL |   fn can() -> impl std::fmt::Display {
    |               ---------------------- expected because this return type...
 LL | /     match 13 {
-LL | |
 LL | |         0 => return 0i32,
    | |                     ---- ...is found to be `i32` here
 LL | |         1 => 1u32,
@@ -98,12 +142,23 @@ LL | |     }
    |
    = note: to return `impl Trait`, all returned values must be of the same type
    = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
-   = help: you can instead return a boxed trait object using `Box<dyn std::fmt::Display>`
    = note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
-   = help: alternatively, create a new `enum` with a variant for each returned type
+   = help: you could instead create a new `enum` with a variant for each returned type
+help: you could change the return type to be a boxed trait object
+   |
+LL | fn can() -> Box<dyn std::fmt::Display> {
+   |             ^^^^^^^                  ^
+help: if you change the return type to expect trait objects, box the returned expressions
+   |
+LL |     Box::new(match 13 {
+LL |         0 => return Box::new(0i32),
+LL |         1 => 1u32,
+LL |         _ => 2u32,
+LL |     })
+   |
 
 error[E0308]: mismatched types
-  --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:59:13
+  --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:53:13
    |
 LL | fn cat() -> impl std::fmt::Display {
    |             ---------------------- expected because this return type...
@@ -116,10 +171,148 @@ LL |             1u32
    |
    = note: to return `impl Trait`, all returned values must be of the same type
    = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
-   = help: you can instead return a boxed trait object using `Box<dyn std::fmt::Display>`
    = note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
-   = help: alternatively, create a new `enum` with a variant for each returned type
+   = help: you could instead create a new `enum` with a variant for each returned type
+help: you could change the return type to be a boxed trait object
+   |
+LL | fn cat() -> Box<dyn std::fmt::Display> {
+   |             ^^^^^^^                  ^
+help: if you change the return type to expect trait objects, box the returned expressions
+   |
+LL |             return Box::new(0i32);
+LL |         }
+LL |         _ => {
+LL |             Box::new(1u32)
+   |
+
+error[E0308]: `match` arms have incompatible types
+  --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:61:14
+   |
+LL | /     match 13 {
+LL | |         0 => 0i32,
+   | |              ---- this is found to be of type `i32`
+LL | |         1 => 1u32,
+   | |              ^^^^ expected `i32`, found `u32`
+LL | |         _ => 2u32,
+LL | |     }
+   | |_____- `match` arms have incompatible types
+   |
+help: you could change the return type to be a boxed trait object
+   |
+LL | fn dog() -> Box<dyn std::fmt::Display> {
+   |             ^^^^^^^                  ^
+help: if you change the return type to expect trait objects, box the returned expressions
+   |
+LL |         0 => Box::new(0i32),
+LL |         1 => Box::new(1u32),
+   |
+
+error[E0308]: `if` and `else` have incompatible types
+  --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:97:9
+   |
+LL | /     if let Some(42) = Some(42) {
+LL | |         0i32
+   | |         ---- expected because of this
+LL | |     } else {
+LL | |         1u32
+   | |         ^^^^ expected `i32`, found `u32`
+LL | |     }
+   | |_____- `if` and `else` have incompatible types
+   |
+help: you could change the return type to be a boxed trait object
+   |
+LL | fn apt() -> Box<dyn std::fmt::Display> {
+   |             ^^^^^^^                  ^
+help: if you change the return type to expect trait objects, box the returned expressions
+   |
+LL |         Box::new(0i32)
+LL |     } else {
+LL |         Box::new(1u32)
+   |
+
+error[E0746]: return type cannot have an unboxed trait object
+  --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:66:13
+   |
+LL | fn hat() -> dyn std::fmt::Display {
+   |             ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
+   = note: if all the returned values were of the same type you could use `impl std::fmt::Display` as the return type
+   = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
+   = note: you can create a new `enum` with a variant for each returned type
+help: return a boxed trait object instead
+   |
+LL | fn hat() -> Box<dyn std::fmt::Display> {
+LL |     match 13 {
+LL |         0 => {
+LL |             return Box::new(0i32);
+LL |         }
+LL |         _ => {
+ ...
+
+error[E0308]: `match` arms have incompatible types
+  --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:80:14
+   |
+LL | /     match 13 {
+LL | |         0 => 0i32,
+   | |              ---- this is found to be of type `i32`
+LL | |         1 => 1u32,
+   | |              ^^^^ expected `i32`, found `u32`
+LL | |         _ => 2u32,
+LL | |     }
+   | |_____- `match` arms have incompatible types
+
+error[E0746]: return type cannot have an unboxed trait object
+  --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:77:13
+   |
+LL | fn pug() -> dyn std::fmt::Display {
+   |             ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
+   = note: if all the returned values were of the same type you could use `impl std::fmt::Display` as the return type
+   = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
+   = note: you can create a new `enum` with a variant for each returned type
+help: return a boxed trait object instead
+   |
+LL | fn pug() -> Box<dyn std::fmt::Display> {
+LL |     match 13 {
+LL |         0 => Box::new(0i32),
+LL |         1 => Box::new(1u32),
+LL |         _ => Box::new(2u32),
+   |
+
+error[E0308]: `if` and `else` have incompatible types
+  --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:89:9
+   |
+LL | /     if false {
+LL | |         0i32
+   | |         ---- expected because of this
+LL | |     } else {
+LL | |         1u32
+   | |         ^^^^ expected `i32`, found `u32`
+LL | |     }
+   | |_____- `if` and `else` have incompatible types
+
+error[E0746]: return type cannot have an unboxed trait object
+  --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:85:13
+   |
+LL | fn man() -> dyn std::fmt::Display {
+   |             ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
+   = note: if all the returned values were of the same type you could use `impl std::fmt::Display` as the return type
+   = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
+   = note: you can create a new `enum` with a variant for each returned type
+help: return a boxed trait object instead
+   |
+LL | fn man() -> Box<dyn std::fmt::Display> {
+LL |     if false {
+LL |         Box::new(0i32)
+LL |     } else {
+LL |         Box::new(1u32)
+   |
 
-error: aborting due to 7 previous errors
+error: aborting due to 14 previous errors
 
-For more information about this error, try `rustc --explain E0308`.
+Some errors have detailed explanations: E0308, E0746.
+For more information about an error, try `rustc --explain E0308`.
diff --git a/src/test/ui/str-multiline.rs b/src/test/ui/str-multiline.rs
deleted file mode 100644 (file)
index 2b2e001..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-// run-pass
-
-pub fn main() {
-    let a: String = "this \
-is a test".to_string();
-    let b: String =
-        "this \
-              is \
-              another \
-              test".to_string();
-    assert_eq!(a, "this is a test".to_string());
-    assert_eq!(b, "this is another test".to_string());
-}
diff --git a/src/test/ui/string-escapes.rs b/src/test/ui/string-escapes.rs
deleted file mode 100644 (file)
index cee5e27..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-// run-pass
-
-fn main() {
-    let x = "\\\\\
-    ";
-    assert_eq!(x, r"\\"); // extraneous whitespace stripped
-}
index 29bad31ef969f361373f52e90b95cc3c101f83ee..b913b929079c6ad119192b292c4cc9101a982d08 100644 (file)
@@ -17,6 +17,15 @@ error[E0027]: pattern does not mention field `present`
    |
 LL |     let Foo { #[cfg(any())] present: () } = foo;
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing field `present`
+   |
+help: include the missing field in the pattern
+   |
+LL |     let Foo { present } = foo;
+   |             ^^^^^^^^^^^
+help: if you don't care about this missing field, you can explicitely ignore it
+   |
+LL |     let Foo { .. } = foo;
+   |             ^^^^^^
 
 error[E0026]: struct `Foo` does not have a field named `absent`
   --> $DIR/struct-field-cfg.rs:16:42
index 6526ef58a447978e0e096812f2dafc4464f55b2d..f3e9ce76f1e2abf55d9b24e67ebe0e7e1edb593f 100644 (file)
@@ -15,6 +15,15 @@ error[E0027]: pattern does not mention fields `b`, `c`
    |
 LL |         let A { x, y } = self.d;
    |             ^^^^^^^^^^ missing fields `b`, `c`
+   |
+help: include the missing fields in the pattern
+   |
+LL |         let A { x, y, b, c } = self.d;
+   |                     ^^^^^^
+help: if you don't care about these missing fields, you can explicitely ignore them
+   |
+LL |         let A { x, y, .. } = self.d;
+   |                     ^^^^
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/trait-impl-bound-suggestions.fixed b/src/test/ui/trait-impl-bound-suggestions.fixed
new file mode 100644 (file)
index 0000000..db3a95f
--- /dev/null
@@ -0,0 +1,20 @@
+// run-rustfix
+
+#[allow(unused)]
+use std::fmt::Debug;
+// Rustfix should add this, or use `std::fmt::Debug` instead.
+
+#[allow(dead_code)]
+struct ConstrainedStruct<X: Copy> {
+    x: X
+}
+
+#[allow(dead_code)]
+trait InsufficientlyConstrainedGeneric<X=()> where X: Copy {
+    fn return_the_constrained_type(&self, x: X) -> ConstrainedStruct<X> {
+        //~^ ERROR the trait bound `X: Copy` is not satisfied
+        ConstrainedStruct { x }
+    }
+}
+
+pub fn main() { }
diff --git a/src/test/ui/trait-impl-bound-suggestions.rs b/src/test/ui/trait-impl-bound-suggestions.rs
new file mode 100644 (file)
index 0000000..bf75175
--- /dev/null
@@ -0,0 +1,20 @@
+// run-rustfix
+
+#[allow(unused)]
+use std::fmt::Debug;
+// Rustfix should add this, or use `std::fmt::Debug` instead.
+
+#[allow(dead_code)]
+struct ConstrainedStruct<X: Copy> {
+    x: X
+}
+
+#[allow(dead_code)]
+trait InsufficientlyConstrainedGeneric<X=()> {
+    fn return_the_constrained_type(&self, x: X) -> ConstrainedStruct<X> {
+        //~^ ERROR the trait bound `X: Copy` is not satisfied
+        ConstrainedStruct { x }
+    }
+}
+
+pub fn main() { }
diff --git a/src/test/ui/trait-impl-bound-suggestions.stderr b/src/test/ui/trait-impl-bound-suggestions.stderr
new file mode 100644 (file)
index 0000000..3a21e9c
--- /dev/null
@@ -0,0 +1,17 @@
+error[E0277]: the trait bound `X: Copy` is not satisfied
+  --> $DIR/trait-impl-bound-suggestions.rs:14:52
+   |
+LL | struct ConstrainedStruct<X: Copy> {
+   |                             ---- required by this bound in `ConstrainedStruct`
+...
+LL |     fn return_the_constrained_type(&self, x: X) -> ConstrainedStruct<X> {
+   |                                                    ^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `X`
+   |
+help: consider further restricting type parameter `X`
+   |
+LL | trait InsufficientlyConstrainedGeneric<X=()> where X: Copy {
+   |                                              ^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
index fa6f342241025b9e2a7cab7108a9039652a54972..d8c7f595e62efcdf03555cd975d71761e7a7e586 100644 (file)
@@ -56,8 +56,8 @@ LL | trait Base<T = String>: Super<T> { }
    |
 help: consider further restricting type parameter `T`
    |
-LL | trait Base<T = String>: Super<T>, T: Copy { }
-   |                                 ^^^^^^^^^
+LL | trait Base<T = String>: Super<T> where T: Copy { }
+   |                                  ^^^^^^^^^^^^^
 
 error[E0277]: cannot add `u8` to `i32`
   --> $DIR/type-check-defaults.rs:24:66
index daa03ce6b6fd85d47473ca9942124e28cd949cbe..4df3ed502827ea80695b4d89fe4784abd8a5ca45 100644 (file)
@@ -48,6 +48,11 @@ fn main() {
         {
             let y = Y { a: S };
         }
-        assert_eq!(CHECK, 2); // 2, dtor of Y is called
+        assert_eq!(CHECK, 2); // 2, Y has no dtor
+        {
+            let u2 = U { a: 1 };
+            std::mem::forget(u2);
+        }
+        assert_eq!(CHECK, 2); // 2, dtor of U *not* called for u2
     }
 }
diff --git a/src/test/ui/union/union-move.rs b/src/test/ui/union/union-move.rs
new file mode 100644 (file)
index 0000000..a0a2d0d
--- /dev/null
@@ -0,0 +1,53 @@
+//! Test the behavior of moving out of non-`Copy` union fields.
+//! Avoid types that `Drop`, we want to focus on moving.
+#![feature(untagged_unions)]
+
+use std::cell::RefCell;
+
+fn move_out<T>(x: T) {}
+
+union U1 {
+    f1_nocopy: RefCell<i32>,
+    f2_nocopy: RefCell<i32>,
+    f3_copy: i32,
+}
+
+union U2 {
+    f1_nocopy: RefCell<i32>,
+}
+impl Drop for U2 {
+    fn drop(&mut self) {}
+}
+
+fn test1(x: U1) {
+    // Moving out of a nocopy field prevents accessing other nocopy field.
+    unsafe {
+        move_out(x.f1_nocopy);
+        move_out(x.f2_nocopy); //~ ERROR use of moved value: `x`
+    }
+}
+
+fn test2(x: U1) {
+    // "Moving" out of copy field doesn't prevent later field accesses.
+    unsafe {
+        move_out(x.f3_copy);
+        move_out(x.f2_nocopy); // no error
+    }
+}
+
+fn test3(x: U1) {
+    // Moving out of a nocopy field prevents accessing other copy field.
+    unsafe {
+        move_out(x.f2_nocopy);
+        move_out(x.f3_copy); //~ ERROR use of moved value: `x`
+    }
+}
+
+fn test4(x: U2) {
+    // Cannot move out of union that implements `Drop`.
+    unsafe {
+        move_out(x.f1_nocopy); //~ ERROR cannot move out of type `U2`, which implements the `Drop`
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/union/union-move.stderr b/src/test/ui/union/union-move.stderr
new file mode 100644 (file)
index 0000000..5679192
--- /dev/null
@@ -0,0 +1,35 @@
+error[E0382]: use of moved value: `x`
+  --> $DIR/union-move.rs:26:18
+   |
+LL | fn test1(x: U1) {
+   |          - move occurs because `x` has type `U1`, which does not implement the `Copy` trait
+...
+LL |         move_out(x.f1_nocopy);
+   |                  ----------- value moved here
+LL |         move_out(x.f2_nocopy);
+   |                  ^^^^^^^^^^^ value used here after move
+
+error[E0382]: use of moved value: `x`
+  --> $DIR/union-move.rs:42:18
+   |
+LL | fn test3(x: U1) {
+   |          - move occurs because `x` has type `U1`, which does not implement the `Copy` trait
+...
+LL |         move_out(x.f2_nocopy);
+   |                  ----------- value moved here
+LL |         move_out(x.f3_copy);
+   |                  ^^^^^^^^^ value used here after move
+
+error[E0509]: cannot move out of type `U2`, which implements the `Drop` trait
+  --> $DIR/union-move.rs:49:18
+   |
+LL |         move_out(x.f1_nocopy);
+   |                  ^^^^^^^^^^^
+   |                  |
+   |                  cannot move out of here
+   |                  move occurs because `x.f1_nocopy` has type `RefCell<i32>`, which does not implement the `Copy` trait
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0382, E0509.
+For more information about an error, try `rustc --explain E0382`.
index 875e0123259b0b6299903fe4aea0a12ecde9324f..8777a6b1e8834899f51b7e09cc9b8d85b2417110 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 875e0123259b0b6299903fe4aea0a12ecde9324f
+Subproject commit 8777a6b1e8834899f51b7e09cc9b8d85b2417110
index 65320d6a0e0bd98e9230b0e1143c0bab5a519562..3b031a552e5cec205dfa97c18662d3bd0202a074 100644 (file)
 pub const SERDE_DESERIALIZE: [&str; 2] = ["_serde", "Deserialize"];
 pub const SERDE_DE_VISITOR: [&str; 3] = ["serde", "de", "Visitor"];
 pub const SLICE_INTO_VEC: [&str; 4] = ["alloc", "slice", "<impl [T]>", "into_vec"];
-pub const SLICE_ITER: [&str; 3] = ["core", "slice", "Iter"];
+pub const SLICE_ITER: [&str; 4] = ["core", "slice", "iter", "Iter"];
 pub const STDERR: [&str; 4] = ["std", "io", "stdio", "stderr"];
 pub const STDOUT: [&str; 4] = ["std", "io", "stdio", "stdout"];
 pub const STD_CONVERT_IDENTITY: [&str; 3] = ["std", "convert", "identity"];
index 7ec12116c2ca1f8c0358f04dd0ed6b19566e6278..4fe493a850d48f81e26d2cfa811728647e06fd26 100644 (file)
@@ -142,6 +142,16 @@ fn is_exception(file: &Path, link: &str) -> bool {
     if let Some(entry) = LINKCHECK_EXCEPTIONS.iter().find(|&(f, _)| file.ends_with(f)) {
         entry.1.contains(&link)
     } else {
+        // FIXME(#63351): Concat trait in alloc/slice reexported in primitive page
+        //
+        // NOTE: This cannot be added to `LINKCHECK_EXCEPTIONS` because the resolved path
+        // calculated in `check` function is outside `build/<triple>/doc` dir.
+        // So the `strip_prefix` method just returns the old absolute broken path.
+        if file.ends_with("std/primitive.slice.html") {
+            if link.ends_with("primitive.slice.html") {
+                return true;
+            }
+        }
         false
     }
 }
diff --git a/src/tools/lint-docs/Cargo.toml b/src/tools/lint-docs/Cargo.toml
new file mode 100644 (file)
index 0000000..657b115
--- /dev/null
@@ -0,0 +1,13 @@
+[package]
+name = "lint-docs"
+version = "0.1.0"
+authors = ["The Rust Project Developers"]
+edition = "2018"
+description = "A script to extract the lint documentation for the rustc book."
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+serde_json = "1.0.57"
+tempfile = "3.1.0"
+walkdir = "2.3.1"
diff --git a/src/tools/lint-docs/src/groups.rs b/src/tools/lint-docs/src/groups.rs
new file mode 100644 (file)
index 0000000..a212459
--- /dev/null
@@ -0,0 +1,114 @@
+use crate::Lint;
+use std::collections::{BTreeMap, BTreeSet};
+use std::error::Error;
+use std::fmt::Write;
+use std::fs;
+use std::path::Path;
+use std::process::Command;
+
+static GROUP_DESCRIPTIONS: &[(&str, &str)] = &[
+    ("unused", "Lints that detect things being declared but not used, or excess syntax"),
+    ("rustdoc", "Rustdoc-specific lints"),
+    ("rust-2018-idioms", "Lints to nudge you toward idiomatic features of Rust 2018"),
+    ("nonstandard-style", "Violation of standard naming conventions"),
+    ("future-incompatible", "Lints that detect code that has future-compatibility problems"),
+    ("rust-2018-compatibility", "Lints used to transition code from the 2015 edition to 2018"),
+];
+
+/// Updates the documentation of lint groups.
+pub(crate) fn generate_group_docs(
+    lints: &[Lint],
+    rustc_path: &Path,
+    out_path: &Path,
+) -> Result<(), Box<dyn Error>> {
+    let groups = collect_groups(rustc_path)?;
+    let groups_path = out_path.join("groups.md");
+    let contents = fs::read_to_string(&groups_path)
+        .map_err(|e| format!("could not read {}: {}", groups_path.display(), e))?;
+    let new_contents = contents.replace("{{groups-table}}", &make_groups_table(lints, &groups)?);
+    // Delete the output because rustbuild uses hard links in its copies.
+    let _ = fs::remove_file(&groups_path);
+    fs::write(&groups_path, new_contents)
+        .map_err(|e| format!("could not write to {}: {}", groups_path.display(), e))?;
+    Ok(())
+}
+
+type LintGroups = BTreeMap<String, BTreeSet<String>>;
+
+/// Collects the group names from rustc.
+fn collect_groups(rustc: &Path) -> Result<LintGroups, Box<dyn Error>> {
+    let mut result = BTreeMap::new();
+    let mut cmd = Command::new(rustc);
+    cmd.arg("-Whelp");
+    let output = cmd.output().map_err(|e| format!("failed to run command {:?}\n{}", cmd, e))?;
+    if !output.status.success() {
+        return Err(format!(
+            "failed to collect lint info: {:?}\n--- stderr\n{}--- stdout\n{}\n",
+            output.status,
+            std::str::from_utf8(&output.stderr).unwrap(),
+            std::str::from_utf8(&output.stdout).unwrap(),
+        )
+        .into());
+    }
+    let stdout = std::str::from_utf8(&output.stdout).unwrap();
+    let lines = stdout.lines();
+    let group_start = lines.skip_while(|line| !line.contains("groups provided")).skip(1);
+    let table_start = group_start.skip_while(|line| !line.contains("----")).skip(1);
+    for line in table_start {
+        if line.is_empty() {
+            break;
+        }
+        let mut parts = line.trim().splitn(2, ' ');
+        let name = parts.next().expect("name in group");
+        if name == "warnings" {
+            // This is special.
+            continue;
+        }
+        let lints =
+            parts.next().ok_or_else(|| format!("expected lints following name, got `{}`", line))?;
+        let lints = lints.split(',').map(|l| l.trim().to_string()).collect();
+        assert!(result.insert(name.to_string(), lints).is_none());
+    }
+    if result.is_empty() {
+        return Err(
+            format!("expected at least one group in -Whelp output, got:\n{}", stdout).into()
+        );
+    }
+    Ok(result)
+}
+
+fn make_groups_table(lints: &[Lint], groups: &LintGroups) -> Result<String, Box<dyn Error>> {
+    let mut result = String::new();
+    let mut to_link = Vec::new();
+    result.push_str("| Group | Description | Lints |\n");
+    result.push_str("|-------|-------------|-------|\n");
+    result.push_str("| warnings | All lints that are set to issue warnings | See [warn-by-default] for the default set of warnings |\n");
+    for (group_name, group_lints) in groups {
+        let description = GROUP_DESCRIPTIONS.iter().find(|(n, _)| n == group_name)
+            .ok_or_else(|| format!("lint group `{}` does not have a description, please update the GROUP_DESCRIPTIONS list", group_name))?
+            .1;
+        to_link.extend(group_lints);
+        let brackets: Vec<_> = group_lints.iter().map(|l| format!("[{}]", l)).collect();
+        write!(result, "| {} | {} | {} |\n", group_name, description, brackets.join(", ")).unwrap();
+    }
+    result.push('\n');
+    result.push_str("[warn-by-default]: listing/warn-by-default.md\n");
+    for lint_name in to_link {
+        let lint_def =
+            lints.iter().find(|l| l.name == lint_name.replace("-", "_")).ok_or_else(|| {
+                format!(
+                    "`rustc -W help` defined lint `{}` but that lint does not appear to exist",
+                    lint_name
+                )
+            })?;
+        write!(
+            result,
+            "[{}]: listing/{}#{}\n",
+            lint_name,
+            lint_def.level.doc_filename(),
+            lint_name
+        )
+        .unwrap();
+    }
+    Ok(result)
+}
diff --git a/src/tools/lint-docs/src/lib.rs b/src/tools/lint-docs/src/lib.rs
new file mode 100644 (file)
index 0000000..92b3d18
--- /dev/null
@@ -0,0 +1,475 @@
+use std::error::Error;
+use std::fmt::Write;
+use std::fs;
+use std::path::{Path, PathBuf};
+use std::process::Command;
+use walkdir::WalkDir;
+
+mod groups;
+
+struct Lint {
+    name: String,
+    doc: Vec<String>,
+    level: Level,
+    path: PathBuf,
+    lineno: usize,
+}
+
+impl Lint {
+    fn doc_contains(&self, text: &str) -> bool {
+        self.doc.iter().any(|line| line.contains(text))
+    }
+
+    fn is_ignored(&self) -> bool {
+        self.doc
+            .iter()
+            .filter(|line| line.starts_with("```rust"))
+            .all(|line| line.contains(",ignore"))
+    }
+}
+
+#[derive(Clone, Copy, PartialEq)]
+enum Level {
+    Allow,
+    Warn,
+    Deny,
+}
+
+impl Level {
+    fn doc_filename(&self) -> &str {
+        match self {
+            Level::Allow => "allowed-by-default.md",
+            Level::Warn => "warn-by-default.md",
+            Level::Deny => "deny-by-default.md",
+        }
+    }
+}
+
+/// Collects all lints, and writes the markdown documentation at the given directory.
+pub fn extract_lint_docs(
+    src_path: &Path,
+    out_path: &Path,
+    rustc_path: &Path,
+    verbose: bool,
+) -> Result<(), Box<dyn Error>> {
+    let mut lints = gather_lints(src_path)?;
+    for lint in &mut lints {
+        generate_output_example(lint, rustc_path, verbose).map_err(|e| {
+            format!(
+                "failed to test example in lint docs for `{}` in {}:{}: {}",
+                lint.name,
+                lint.path.display(),
+                lint.lineno,
+                e
+            )
+        })?;
+    }
+    save_lints_markdown(&lints, &out_path.join("listing"))?;
+    groups::generate_group_docs(&lints, rustc_path, out_path)?;
+    Ok(())
+}
+
+/// Collects all lints from all files in the given directory.
+fn gather_lints(src_path: &Path) -> Result<Vec<Lint>, Box<dyn Error>> {
+    let mut lints = Vec::new();
+    for entry in WalkDir::new(src_path).into_iter().filter_map(|e| e.ok()) {
+        if !entry.path().extension().map_or(false, |ext| ext == "rs") {
+            continue;
+        }
+        lints.extend(lints_from_file(entry.path())?);
+    }
+    if lints.is_empty() {
+        return Err("no lints were found!".into());
+    }
+    Ok(lints)
+}
+
+/// Collects all lints from the given file.
+fn lints_from_file(path: &Path) -> Result<Vec<Lint>, Box<dyn Error>> {
+    let mut lints = Vec::new();
+    let contents = fs::read_to_string(path)
+        .map_err(|e| format!("could not read {}: {}", path.display(), e))?;
+    let mut lines = contents.lines().enumerate();
+    loop {
+        // Find a lint declaration.
+        let lint_start = loop {
+            match lines.next() {
+                Some((lineno, line)) => {
+                    if line.trim().starts_with("declare_lint!") {
+                        break lineno + 1;
+                    }
+                }
+                None => return Ok(lints),
+            }
+        };
+        // Read the lint.
+        let mut doc_lines = Vec::new();
+        let (doc, name) = loop {
+            match lines.next() {
+                Some((lineno, line)) => {
+                    let line = line.trim();
+                    if line.starts_with("/// ") {
+                        doc_lines.push(line.trim()[4..].to_string());
+                    } else if line.starts_with("///") {
+                        doc_lines.push("".to_string());
+                    } else if line.starts_with("// ") {
+                        // Ignore comments.
+                        continue;
+                    } else {
+                        let name = lint_name(line).map_err(|e| {
+                            format!(
+                                "could not determine lint name in {}:{}: {}, line was `{}`",
+                                path.display(),
+                                lineno,
+                                e,
+                                line
+                            )
+                        })?;
+                        if doc_lines.is_empty() {
+                            return Err(format!(
+                                "did not find doc lines for lint `{}` in {}",
+                                name,
+                                path.display()
+                            )
+                            .into());
+                        }
+                        break (doc_lines, name);
+                    }
+                }
+                None => {
+                    return Err(format!(
+                        "unexpected EOF for lint definition at {}:{}",
+                        path.display(),
+                        lint_start
+                    )
+                    .into());
+                }
+            }
+        };
+        // These lints are specifically undocumented. This should be reserved
+        // for internal rustc-lints only.
+        if name == "deprecated_in_future" {
+            continue;
+        }
+        // Read the level.
+        let level = loop {
+            match lines.next() {
+                // Ignore comments.
+                Some((_, line)) if line.trim().starts_with("// ") => {}
+                Some((lineno, line)) => match line.trim() {
+                    "Allow," => break Level::Allow,
+                    "Warn," => break Level::Warn,
+                    "Deny," => break Level::Deny,
+                    _ => {
+                        return Err(format!(
+                            "unexpected lint level `{}` in {}:{}",
+                            line,
+                            path.display(),
+                            lineno
+                        )
+                        .into());
+                    }
+                },
+                None => {
+                    return Err(format!(
+                        "expected lint level in {}:{}, got EOF",
+                        path.display(),
+                        lint_start
+                    )
+                    .into());
+                }
+            }
+        };
+        // The rest of the lint definition is ignored.
+        assert!(!doc.is_empty());
+        lints.push(Lint { name, doc, level, path: PathBuf::from(path), lineno: lint_start });
+    }
+}
+
+/// Extracts the lint name (removing the visibility modifier, and checking validity).
+fn lint_name(line: &str) -> Result<String, &'static str> {
+    // Skip over any potential `pub` visibility.
+    match line.trim().split(' ').next_back() {
+        Some(name) => {
+            if !name.ends_with(',') {
+                return Err("lint name should end with comma");
+            }
+            let name = &name[..name.len() - 1];
+            if !name.chars().all(|ch| ch.is_uppercase() || ch == '_') || name.is_empty() {
+                return Err("lint name did not have expected format");
+            }
+            Ok(name.to_lowercase().to_string())
+        }
+        None => Err("could not find lint name"),
+    }
+}
+
+/// Mutates the lint definition to replace the `{{produces}}` marker with the
+/// actual output from the compiler.
+fn generate_output_example(
+    lint: &mut Lint,
+    rustc_path: &Path,
+    verbose: bool,
+) -> Result<(), Box<dyn Error>> {
+    // Explicit list of lints that are allowed to not have an example. Please
+    // try to avoid adding to this list.
+    if matches!(
+        lint.name.as_str(),
+        "unused_features" // broken lint
+        | "unstable_features" // deprecated
+    ) {
+        return Ok(());
+    }
+    if lint.doc_contains("[rustdoc book]") && !lint.doc_contains("{{produces}}") {
+        // Rustdoc lints are documented in the rustdoc book, don't check these.
+        return Ok(());
+    }
+    check_style(lint)?;
+    // Unfortunately some lints have extra requirements that this simple test
+    // setup can't handle (like extern crates). An alternative is to use a
+    // separate test suite, and use an include mechanism such as mdbook's
+    // `{{#rustdoc_include}}`.
+    if !lint.is_ignored() {
+        replace_produces(lint, rustc_path, verbose)?;
+    }
+    Ok(())
+}
+
+/// Checks the doc style of the lint.
+fn check_style(lint: &Lint) -> Result<(), Box<dyn Error>> {
+    for &expected in &["### Example", "### Explanation", "{{produces}}"] {
+        if expected == "{{produces}}" && lint.is_ignored() {
+            continue;
+        }
+        if !lint.doc_contains(expected) {
+            return Err(format!("lint docs should contain the line `{}`", expected).into());
+        }
+    }
+    if let Some(first) = lint.doc.first() {
+        if !first.starts_with(&format!("The `{}` lint", lint.name)) {
+            return Err(format!(
+                "lint docs should start with the text \"The `{}` lint\" to introduce the lint",
+                lint.name
+            )
+            .into());
+        }
+    }
+    Ok(())
+}
+
+/// Mutates the lint docs to replace the `{{produces}}` marker with the actual
+/// output from the compiler.
+fn replace_produces(
+    lint: &mut Lint,
+    rustc_path: &Path,
+    verbose: bool,
+) -> Result<(), Box<dyn Error>> {
+    let mut lines = lint.doc.iter_mut();
+    loop {
+        // Find start of example.
+        let options = loop {
+            match lines.next() {
+                Some(line) if line.starts_with("```rust") => {
+                    break line[7..].split(',').collect::<Vec<_>>();
+                }
+                Some(line) if line.contains("{{produces}}") => {
+                    return Err("lint marker {{{{produces}}}} found, \
+                        but expected to immediately follow a rust code block"
+                        .into());
+                }
+                Some(_) => {}
+                None => return Ok(()),
+            }
+        };
+        // Find the end of example.
+        let mut example = Vec::new();
+        loop {
+            match lines.next() {
+                Some(line) if line == "```" => break,
+                Some(line) => example.push(line),
+                None => {
+                    return Err(format!(
+                        "did not find end of example triple ticks ```, docs were:\n{:?}",
+                        lint.doc
+                    )
+                    .into());
+                }
+            }
+        }
+        // Find the {{produces}} line.
+        loop {
+            match lines.next() {
+                Some(line) if line.is_empty() => {}
+                Some(line) if line == "{{produces}}" => {
+                    let output =
+                        generate_lint_output(&lint.name, &example, &options, rustc_path, verbose)?;
+                    line.replace_range(
+                        ..,
+                        &format!(
+                            "This will produce:\n\
+                        \n\
+                        ```text\n\
+                        {}\
+                        ```",
+                            output
+                        ),
+                    );
+                    break;
+                }
+                // No {{produces}} after example, find next example.
+                Some(_line) => break,
+                None => return Ok(()),
+            }
+        }
+    }
+}
+
+/// Runs the compiler against the example, and extracts the output.
+fn generate_lint_output(
+    name: &str,
+    example: &[&mut String],
+    options: &[&str],
+    rustc_path: &Path,
+    verbose: bool,
+) -> Result<String, Box<dyn Error>> {
+    if verbose {
+        eprintln!("compiling lint {}", name);
+    }
+    let tempdir = tempfile::TempDir::new()?;
+    let tempfile = tempdir.path().join("lint_example.rs");
+    let mut source = String::new();
+    let needs_main = !example.iter().any(|line| line.contains("fn main"));
+    // Remove `# ` prefix for hidden lines.
+    let unhidden =
+        example.iter().map(|line| if line.starts_with("# ") { &line[2..] } else { line });
+    let mut lines = unhidden.peekable();
+    while let Some(line) = lines.peek() {
+        if line.starts_with("#!") {
+            source.push_str(line);
+            source.push('\n');
+            lines.next();
+        } else {
+            break;
+        }
+    }
+    if needs_main {
+        source.push_str("fn main() {\n");
+    }
+    for line in lines {
+        source.push_str(line);
+        source.push('\n')
+    }
+    if needs_main {
+        source.push_str("}\n");
+    }
+    fs::write(&tempfile, source)
+        .map_err(|e| format!("failed to write {}: {}", tempfile.display(), e))?;
+    let mut cmd = Command::new(rustc_path);
+    if options.contains(&"edition2015") {
+        cmd.arg("--edition=2015");
+    } else {
+        cmd.arg("--edition=2018");
+    }
+    cmd.arg("--error-format=json");
+    if options.contains(&"test") {
+        cmd.arg("--test");
+    }
+    cmd.arg("lint_example.rs");
+    cmd.current_dir(tempdir.path());
+    let output = cmd.output().map_err(|e| format!("failed to run command {:?}\n{}", cmd, e))?;
+    let stderr = std::str::from_utf8(&output.stderr).unwrap();
+    let msgs = stderr
+        .lines()
+        .filter(|line| line.starts_with('{'))
+        .map(serde_json::from_str)
+        .collect::<Result<Vec<serde_json::Value>, _>>()?;
+    match msgs
+        .iter()
+        .find(|msg| matches!(&msg["code"]["code"], serde_json::Value::String(s) if s==name))
+    {
+        Some(msg) => {
+            let rendered = msg["rendered"].as_str().expect("rendered field should exist");
+            Ok(rendered.to_string())
+        }
+        None => {
+            match msgs.iter().find(
+                |msg| matches!(&msg["rendered"], serde_json::Value::String(s) if s.contains(name)),
+            ) {
+                Some(msg) => {
+                    let rendered = msg["rendered"].as_str().expect("rendered field should exist");
+                    Ok(rendered.to_string())
+                }
+                None => {
+                    let rendered: Vec<&str> =
+                        msgs.iter().filter_map(|msg| msg["rendered"].as_str()).collect();
+                    let non_json: Vec<&str> =
+                        stderr.lines().filter(|line| !line.starts_with('{')).collect();
+                    Err(format!(
+                        "did not find lint `{}` in output of example, got:\n{}\n{}",
+                        name,
+                        non_json.join("\n"),
+                        rendered.join("\n")
+                    )
+                    .into())
+                }
+            }
+        }
+    }
+}
+
+static ALLOWED_MD: &str = r#"# Allowed-by-default lints
+
+These lints are all set to the 'allow' level by default. As such, they won't show up
+unless you set them to a higher lint level with a flag or attribute.
+
+"#;
+
+static WARN_MD: &str = r#"# Warn-by-default lints
+
+These lints are all set to the 'warn' level by default.
+
+"#;
+
+static DENY_MD: &str = r#"# Deny-by-default lints
+
+These lints are all set to the 'deny' level by default.
+
+"#;
+
+/// Saves the mdbook lint chapters at the given path.
+fn save_lints_markdown(lints: &[Lint], out_dir: &Path) -> Result<(), Box<dyn Error>> {
+    save_level(lints, Level::Allow, out_dir, ALLOWED_MD)?;
+    save_level(lints, Level::Warn, out_dir, WARN_MD)?;
+    save_level(lints, Level::Deny, out_dir, DENY_MD)?;
+    Ok(())
+}
+
+fn save_level(
+    lints: &[Lint],
+    level: Level,
+    out_dir: &Path,
+    header: &str,
+) -> Result<(), Box<dyn Error>> {
+    let mut result = String::new();
+    result.push_str(header);
+    let mut these_lints: Vec<_> = lints.iter().filter(|lint| lint.level == level).collect();
+    these_lints.sort_unstable_by_key(|lint| &lint.name);
+    for lint in &these_lints {
+        write!(result, "* [`{}`](#{})\n", lint.name, lint.name.replace("_", "-")).unwrap();
+    }
+    result.push('\n');
+    for lint in &these_lints {
+        write!(result, "## {}\n\n", lint.name.replace("_", "-")).unwrap();
+        for line in &lint.doc {
+            result.push_str(line);
+            result.push('\n');
+        }
+        result.push('\n');
+    }
+    let out_path = out_dir.join(level.doc_filename());
+    // Delete the output because rustbuild uses hard links in its copies.
+    let _ = fs::remove_file(&out_path);
+    fs::write(&out_path, result)
+        .map_err(|e| format!("could not write to {}: {}", out_path.display(), e))?;
+    Ok(())
+}
diff --git a/src/tools/lint-docs/src/main.rs b/src/tools/lint-docs/src/main.rs
new file mode 100644 (file)
index 0000000..45d97bd
--- /dev/null
@@ -0,0 +1,56 @@
+use std::error::Error;
+use std::path::PathBuf;
+
+fn main() {
+    if let Err(e) = doit() {
+        println!("error: {}", e);
+        std::process::exit(1);
+    }
+}
+
+fn doit() -> Result<(), Box<dyn Error>> {
+    let mut args = std::env::args().skip(1);
+    let mut src_path = None;
+    let mut out_path = None;
+    let mut rustc_path = None;
+    let mut verbose = false;
+    while let Some(arg) = args.next() {
+        match arg.as_str() {
+            "--src" => {
+                src_path = match args.next() {
+                    Some(s) => Some(PathBuf::from(s)),
+                    None => return Err("--src requires a value".into()),
+                };
+            }
+            "--out" => {
+                out_path = match args.next() {
+                    Some(s) => Some(PathBuf::from(s)),
+                    None => return Err("--out requires a value".into()),
+                };
+            }
+            "--rustc" => {
+                rustc_path = match args.next() {
+                    Some(s) => Some(PathBuf::from(s)),
+                    None => return Err("--rustc requires a value".into()),
+                };
+            }
+            "-v" | "--verbose" => verbose = true,
+            s => return Err(format!("unexpected argument `{}`", s).into()),
+        }
+    }
+    if src_path.is_none() {
+        return Err("--src must be specified to the directory with the compiler source".into());
+    }
+    if out_path.is_none() {
+        return Err("--out must be specified to the directory with the lint listing docs".into());
+    }
+    if rustc_path.is_none() {
+        return Err("--rustc must be specified to the path of rustc".into());
+    }
+    lint_docs::extract_lint_docs(
+        &src_path.unwrap(),
+        &out_path.unwrap(),
+        &rustc_path.unwrap(),
+        verbose,
+    )
+}
index 0275b08d1521606fa733f76fe5d5707717456fb4..0d03fe6ef57d3956e92382e0e1f1a916015191cb 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 0275b08d1521606fa733f76fe5d5707717456fb4
+Subproject commit 0d03fe6ef57d3956e92382e0e1f1a916015191cb