]> git.lizzy.rs Git - rust.git/commitdiff
Auto merge of #80267 - 0urobor0s:ouro/61592, r=jyn514
authorbors <bors@rust-lang.org>
Thu, 31 Dec 2020 09:07:52 +0000 (09:07 +0000)
committerbors <bors@rust-lang.org>
Thu, 31 Dec 2020 09:07:52 +0000 (09:07 +0000)
Rustdoc render public underscore_imports as Re-exports

Fixes #61592

1067 files changed:
.github/ISSUE_TEMPLATE/library_tracking_issue.md
Cargo.lock
RELEASES.md
compiler/rustc_arena/src/lib.rs
compiler/rustc_ast/src/ast.rs
compiler/rustc_ast/src/attr/mod.rs
compiler/rustc_ast/src/token.rs
compiler/rustc_ast/src/tokenstream.rs
compiler/rustc_ast/src/util/classify.rs
compiler/rustc_ast/src/util/comments.rs
compiler/rustc_ast/src/util/comments/tests.rs
compiler/rustc_ast_lowering/src/lib.rs
compiler/rustc_ast_passes/src/ast_validation.rs
compiler/rustc_ast_passes/src/feature_gate.rs
compiler/rustc_ast_pretty/src/pp.rs
compiler/rustc_ast_pretty/src/pprust/state.rs
compiler/rustc_builtin_macros/src/deriving/clone.rs
compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
compiler/rustc_builtin_macros/src/format.rs
compiler/rustc_builtin_macros/src/format_foreign.rs
compiler/rustc_builtin_macros/src/llvm_asm.rs
compiler/rustc_builtin_macros/src/proc_macro_harness.rs
compiler/rustc_codegen_cranelift/.vscode/settings.json
compiler/rustc_codegen_cranelift/Cargo.lock
compiler/rustc_codegen_cranelift/Cargo.toml
compiler/rustc_codegen_cranelift/Readme.md
compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock
compiler/rustc_codegen_cranelift/build_sysroot/Cargo.toml
compiler/rustc_codegen_cranelift/example/std_example.rs
compiler/rustc_codegen_cranelift/rust-toolchain
compiler/rustc_codegen_cranelift/scripts/cargo.sh
compiler/rustc_codegen_cranelift/scripts/filter_profile.rs
compiler/rustc_codegen_cranelift/scripts/tests.sh
compiler/rustc_codegen_cranelift/src/backend.rs
compiler/rustc_codegen_cranelift/src/base.rs
compiler/rustc_codegen_cranelift/src/bin/cg_clif.rs
compiler/rustc_codegen_cranelift/src/bin/cg_clif_build_sysroot.rs
compiler/rustc_codegen_cranelift/src/constant.rs
compiler/rustc_codegen_cranelift/src/debuginfo/emit.rs
compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs
compiler/rustc_codegen_cranelift/src/driver/aot.rs
compiler/rustc_codegen_cranelift/src/driver/jit.rs
compiler/rustc_codegen_cranelift/src/driver/mod.rs
compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs
compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs
compiler/rustc_codegen_cranelift/src/lib.rs
compiler/rustc_codegen_cranelift/src/optimize/peephole.rs
compiler/rustc_codegen_cranelift/src/pretty_clif.rs
compiler/rustc_codegen_cranelift/src/vtable.rs
compiler/rustc_codegen_llvm/src/back/write.rs
compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
compiler/rustc_codegen_llvm/src/lib.rs
compiler/rustc_codegen_ssa/src/back/link.rs
compiler/rustc_codegen_ssa/src/base.rs
compiler/rustc_codegen_ssa/src/lib.rs
compiler/rustc_codegen_ssa/src/mir/analyze.rs
compiler/rustc_codegen_ssa/src/mir/block.rs
compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
compiler/rustc_data_structures/src/graph/scc/mod.rs
compiler/rustc_data_structures/src/lib.rs
compiler/rustc_driver/src/lib.rs
compiler/rustc_error_codes/src/error_codes/E0730.md
compiler/rustc_error_codes/src/error_codes/E0770.md
compiler/rustc_expand/src/base.rs
compiler/rustc_expand/src/config.rs
compiler/rustc_expand/src/expand.rs
compiler/rustc_expand/src/mbe.rs
compiler/rustc_expand/src/mbe/macro_parser.rs
compiler/rustc_expand/src/mbe/macro_rules.rs
compiler/rustc_expand/src/mbe/quoted.rs
compiler/rustc_expand/src/proc_macro.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/hir.rs
compiler/rustc_incremental/src/assert_dep_graph.rs
compiler/rustc_infer/src/infer/error_reporting/mod.rs
compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs
compiler/rustc_infer/src/infer/free_regions.rs
compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
compiler/rustc_infer/src/infer/mod.rs
compiler/rustc_infer/src/traits/project.rs
compiler/rustc_interface/src/interface.rs
compiler/rustc_interface/src/passes.rs
compiler/rustc_interface/src/queries.rs
compiler/rustc_lint/src/builtin.rs
compiler/rustc_lint/src/context.rs
compiler/rustc_lint/src/levels.rs
compiler/rustc_lint/src/lib.rs
compiler/rustc_lint/src/redundant_semicolon.rs
compiler/rustc_lint_defs/src/builtin.rs
compiler/rustc_macros/src/query.rs
compiler/rustc_macros/src/session_diagnostic.rs
compiler/rustc_metadata/src/native_libs.rs
compiler/rustc_middle/src/dep_graph/mod.rs
compiler/rustc_middle/src/hir/map/blocks.rs
compiler/rustc_middle/src/hir/map/mod.rs
compiler/rustc_middle/src/hir/place.rs
compiler/rustc_middle/src/lib.rs
compiler/rustc_middle/src/lint.rs
compiler/rustc_middle/src/middle/privacy.rs
compiler/rustc_middle/src/middle/region.rs
compiler/rustc_middle/src/mir/coverage.rs
compiler/rustc_middle/src/mir/graph_cyclic_cache.rs [new file with mode: 0644]
compiler/rustc_middle/src/mir/mod.rs
compiler/rustc_middle/src/mir/visit.rs
compiler/rustc_middle/src/query/mod.rs
compiler/rustc_middle/src/ty/context.rs
compiler/rustc_middle/src/ty/error.rs
compiler/rustc_middle/src/ty/inhabitedness/def_id_forest.rs
compiler/rustc_middle/src/ty/layout.rs
compiler/rustc_middle/src/ty/list.rs
compiler/rustc_middle/src/ty/mod.rs
compiler/rustc_middle/src/ty/print/pretty.rs
compiler/rustc_middle/src/ty/query/on_disk_cache.rs
compiler/rustc_middle/src/ty/sty.rs
compiler/rustc_middle/src/util/bug.rs
compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs
compiler/rustc_mir/src/borrow_check/type_check/liveness/local_use_map.rs
compiler/rustc_mir/src/const_eval/eval_queries.rs
compiler/rustc_mir/src/interpret/intrinsics.rs
compiler/rustc_mir/src/interpret/validity.rs
compiler/rustc_mir/src/transform/coverage/counters.rs
compiler/rustc_mir/src/transform/coverage/mod.rs
compiler/rustc_mir/src/transform/function_item_references.rs
compiler/rustc_mir/src/transform/instcombine.rs
compiler/rustc_mir/src/transform/promote_consts.rs
compiler/rustc_mir/src/transform/rustc_peek.rs
compiler/rustc_mir/src/transform/simplify_try.rs
compiler/rustc_mir/src/util/borrowck_errors.rs
compiler/rustc_mir/src/util/pretty.rs
compiler/rustc_mir_build/src/build/expr/as_place.rs
compiler/rustc_mir_build/src/build/expr/into.rs
compiler/rustc_mir_build/src/build/mod.rs
compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
compiler/rustc_parse/src/lib.rs
compiler/rustc_parse/src/parser/diagnostics.rs
compiler/rustc_parse/src/parser/expr.rs
compiler/rustc_parse/src/parser/generics.rs
compiler/rustc_parse/src/parser/item.rs
compiler/rustc_parse/src/parser/mod.rs
compiler/rustc_parse/src/parser/path.rs
compiler/rustc_passes/src/dead.rs
compiler/rustc_passes/src/liveness.rs
compiler/rustc_privacy/src/lib.rs
compiler/rustc_query_system/src/dep_graph/dep_node.rs
compiler/rustc_query_system/src/dep_graph/graph.rs
compiler/rustc_query_system/src/dep_graph/mod.rs
compiler/rustc_query_system/src/dep_graph/prev.rs
compiler/rustc_query_system/src/dep_graph/query.rs
compiler/rustc_query_system/src/dep_graph/serialized.rs
compiler/rustc_resolve/src/build_reduced_graph.rs
compiler/rustc_resolve/src/def_collector.rs
compiler/rustc_resolve/src/late.rs
compiler/rustc_resolve/src/late/diagnostics.rs
compiler/rustc_resolve/src/late/lifetimes.rs
compiler/rustc_resolve/src/lib.rs
compiler/rustc_resolve/src/macros.rs
compiler/rustc_save_analysis/src/lib.rs
compiler/rustc_serialize/src/lib.rs
compiler/rustc_session/src/filesearch.rs
compiler/rustc_session/src/parse.rs
compiler/rustc_span/src/edition.rs
compiler/rustc_span/src/hygiene.rs
compiler/rustc_span/src/lev_distance.rs
compiler/rustc_span/src/lib.rs
compiler/rustc_span/src/source_map.rs
compiler/rustc_span/src/span_encoding.rs
compiler/rustc_span/src/symbol.rs
compiler/rustc_trait_selection/src/infer.rs
compiler/rustc_trait_selection/src/traits/auto_trait.rs
compiler/rustc_trait_selection/src/traits/coherence.rs
compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
compiler/rustc_trait_selection/src/traits/mod.rs
compiler/rustc_trait_selection/src/traits/project.rs
compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
compiler/rustc_trait_selection/src/traits/select/mod.rs
compiler/rustc_traits/src/chalk/mod.rs
compiler/rustc_typeck/src/astconv/generics.rs
compiler/rustc_typeck/src/check/check.rs
compiler/rustc_typeck/src/check/demand.rs
compiler/rustc_typeck/src/check/dropck.rs
compiler/rustc_typeck/src/check/expr.rs
compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
compiler/rustc_typeck/src/check/intrinsic.rs
compiler/rustc_typeck/src/check/method/probe.rs
compiler/rustc_typeck/src/check/regionck.rs
compiler/rustc_typeck/src/check/upvar.rs
compiler/rustc_typeck/src/check/wfcheck.rs
compiler/rustc_typeck/src/collect.rs
compiler/rustc_typeck/src/expr_use_visitor.rs
compiler/rustc_typeck/src/mem_categorization.rs
config.toml.example
library/alloc/src/collections/binary_heap.rs
library/alloc/src/collections/btree/append.rs
library/alloc/src/collections/btree/map.rs
library/alloc/src/collections/btree/map/tests.rs
library/alloc/src/collections/btree/mod.rs
library/alloc/src/collections/btree/node.rs
library/alloc/src/collections/btree/node/tests.rs
library/alloc/src/collections/btree/set.rs
library/alloc/src/collections/btree/set/tests.rs
library/alloc/src/collections/btree/split.rs
library/alloc/src/collections/linked_list.rs
library/alloc/src/collections/vec_deque/mod.rs
library/alloc/src/lib.rs
library/alloc/src/rc.rs
library/alloc/src/rc/tests.rs
library/alloc/src/string.rs
library/alloc/src/sync.rs
library/alloc/src/sync/tests.rs
library/alloc/src/vec.rs [deleted file]
library/alloc/src/vec/cow.rs [new file with mode: 0644]
library/alloc/src/vec/drain.rs [new file with mode: 0644]
library/alloc/src/vec/drain_filter.rs [new file with mode: 0644]
library/alloc/src/vec/in_place_drop.rs [new file with mode: 0644]
library/alloc/src/vec/into_iter.rs [new file with mode: 0644]
library/alloc/src/vec/is_zero.rs [new file with mode: 0644]
library/alloc/src/vec/mod.rs [new file with mode: 0644]
library/alloc/src/vec/partial_eq.rs [new file with mode: 0644]
library/alloc/src/vec/set_len_on_drop.rs [new file with mode: 0644]
library/alloc/src/vec/source_iter_marker.rs [new file with mode: 0644]
library/alloc/src/vec/spec_extend.rs [new file with mode: 0644]
library/alloc/src/vec/spec_from_elem.rs [new file with mode: 0644]
library/alloc/src/vec/spec_from_iter.rs [new file with mode: 0644]
library/alloc/src/vec/spec_from_iter_nested.rs [new file with mode: 0644]
library/alloc/src/vec/splice.rs [new file with mode: 0644]
library/alloc/tests/lib.rs
library/core/src/alloc/global.rs
library/core/src/array/mod.rs
library/core/src/char/convert.rs
library/core/src/intrinsics.rs
library/core/src/iter/adapters/intersperse.rs [new file with mode: 0644]
library/core/src/iter/adapters/mod.rs
library/core/src/iter/mod.rs
library/core/src/iter/traits/exact_size.rs
library/core/src/iter/traits/iterator.rs
library/core/src/lib.rs
library/core/src/macros/mod.rs
library/core/src/mem/maybe_uninit.rs
library/core/src/mem/mod.rs
library/core/src/num/int_macros.rs
library/core/src/num/mod.rs
library/core/src/num/nonzero.rs
library/core/src/num/shells/int_macros.rs
library/core/src/num/uint_macros.rs
library/core/src/num/wrapping.rs
library/core/src/ptr/const_ptr.rs
library/core/src/ptr/mod.rs
library/core/src/ptr/mut_ptr.rs
library/core/src/slice/cmp.rs
library/core/src/slice/mod.rs
library/core/src/str/mod.rs
library/core/src/sync/atomic.rs
library/core/tests/atomic.rs
library/core/tests/const_ptr.rs [new file with mode: 0644]
library/core/tests/iter.rs
library/core/tests/lib.rs
library/core/tests/mem.rs
library/core/tests/nonzero.rs
library/panic_abort/src/lib.rs
library/panic_unwind/src/lib.rs
library/proc_macro/src/lib.rs
library/rtstartup/rsbegin.rs
library/rtstartup/rsend.rs
library/rustc-std-workspace-core/README.md
library/std/src/collections/hash/map.rs
library/std/src/collections/hash/set.rs
library/std/src/ffi/os_str.rs
library/std/src/lib.rs
library/std/src/macros.rs
library/std/src/panicking.rs
library/std/src/sync/mpsc/blocking.rs
library/std/src/sync/mpsc/oneshot.rs
library/std/src/sync/mpsc/shared.rs
library/std/src/sync/mpsc/stream.rs
library/std/src/sync/once.rs
library/std/src/sys/sgx/abi/mod.rs
library/std/src/sys/sgx/waitqueue/spin_mutex.rs
library/std/src/sys/unix/time.rs
library/std/src/sys/windows/mutex.rs
library/std/src/sys/windows/thread_parker.rs
library/std/src/sys_common/condvar/check.rs
library/std/src/sys_common/thread_local_key.rs
library/std/src/sys_common/thread_parker/futex.rs
library/stdarch
src/bootstrap/CHANGELOG.md
src/bootstrap/README.md
src/bootstrap/bootstrap.py
src/bootstrap/builder.rs
src/bootstrap/compile.rs
src/bootstrap/config.rs
src/bootstrap/configure.py
src/bootstrap/dist.rs
src/bootstrap/doc.rs
src/bootstrap/flags.rs
src/bootstrap/lib.rs
src/bootstrap/mk/Makefile.in
src/bootstrap/tarball.rs [new file with mode: 0644]
src/bootstrap/test.rs
src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile
src/ci/docker/host-x86_64/test-various/Dockerfile
src/ci/pgo.sh [new file with mode: 0755]
src/ci/run.sh
src/doc/book
src/doc/nomicon
src/doc/reference
src/doc/rust-by-example
src/doc/rustc/book.toml
src/doc/rustdoc/book.toml
src/doc/rustdoc/src/command-line-arguments.md
src/doc/rustdoc/src/what-is-rustdoc.md
src/doc/unstable-book/src/language-features/ffi-pure.md
src/etc/generate-deriving-span-tests.py
src/etc/natvis/intrinsic.natvis
src/etc/natvis/liballoc.natvis
src/etc/natvis/libcore.natvis
src/etc/natvis/libstd.natvis
src/librustdoc/clean/auto_trait.rs
src/librustdoc/clean/blanket_impl.rs
src/librustdoc/clean/inline.rs
src/librustdoc/clean/mod.rs
src/librustdoc/clean/types.rs
src/librustdoc/clean/utils.rs
src/librustdoc/doctest.rs
src/librustdoc/doctest/tests.rs
src/librustdoc/doctree.rs
src/librustdoc/fold.rs
src/librustdoc/formats/cache.rs
src/librustdoc/formats/item_type.rs
src/librustdoc/formats/mod.rs
src/librustdoc/formats/renderer.rs
src/librustdoc/html/format.rs
src/librustdoc/html/highlight.rs
src/librustdoc/html/highlight/tests.rs
src/librustdoc/html/markdown.rs
src/librustdoc/html/render/cache.rs
src/librustdoc/html/render/mod.rs
src/librustdoc/html/sources.rs
src/librustdoc/html/static/rustdoc.css
src/librustdoc/html/static/themes/ayu.css
src/librustdoc/html/static/themes/dark.css
src/librustdoc/html/static/themes/light.css
src/librustdoc/json/conversions.rs
src/librustdoc/json/mod.rs
src/librustdoc/lib.rs
src/librustdoc/passes/calculate_doc_coverage.rs
src/librustdoc/passes/collect_intra_doc_links.rs
src/librustdoc/passes/collect_trait_impls.rs
src/librustdoc/passes/doc_test_lints.rs
src/librustdoc/passes/strip_hidden.rs
src/librustdoc/passes/stripper.rs
src/librustdoc/visit_ast.rs
src/stage0.txt
src/test/codegen/slice-ref-equality.rs [new file with mode: 0644]
src/test/compile-fail/asm-src-loc-codegen-units.rs [deleted file]
src/test/compile-fail/asm-src-loc.rs [deleted file]
src/test/compile-fail/auxiliary/crateresolve1-1.rs [deleted file]
src/test/compile-fail/auxiliary/crateresolve1-2.rs [deleted file]
src/test/compile-fail/auxiliary/crateresolve1-3.rs [deleted file]
src/test/compile-fail/auxiliary/depends.rs [deleted file]
src/test/compile-fail/auxiliary/needs-panic-runtime.rs [deleted file]
src/test/compile-fail/auxiliary/panic-runtime-lang-items.rs [deleted file]
src/test/compile-fail/auxiliary/panic-runtime-unwind.rs [deleted file]
src/test/compile-fail/auxiliary/panic-runtime-unwind2.rs [deleted file]
src/test/compile-fail/auxiliary/some-panic-impl.rs [deleted file]
src/test/compile-fail/auxiliary/wants-panic-runtime-unwind.rs [deleted file]
src/test/compile-fail/auxiliary/weak-lang-items.rs [deleted file]
src/test/compile-fail/coerce-unsafe-closure-to-unsafe-fn-ptr.rs [deleted file]
src/test/compile-fail/coerce-unsafe-to-closure.rs [deleted file]
src/test/compile-fail/consts/const-fn-error.rs [deleted file]
src/test/compile-fail/consts/issue-55878.rs [deleted file]
src/test/compile-fail/crateresolve1.rs [deleted file]
src/test/compile-fail/empty-extern-arg.rs [deleted file]
src/test/compile-fail/invalid-link-args.rs [deleted file]
src/test/compile-fail/issue-10755.rs [deleted file]
src/test/compile-fail/issue-23595-1.rs [deleted file]
src/test/compile-fail/issue-27675-unchecked-bounds.rs [deleted file]
src/test/compile-fail/issue-43733-2.rs [deleted file]
src/test/compile-fail/issue-44415.rs [deleted file]
src/test/compile-fail/issue-46209-private-enum-variant-reexport.rs [deleted file]
src/test/compile-fail/issue-52443.rs [deleted file]
src/test/compile-fail/meta-expected-error-wrong-rev.rs [deleted file]
src/test/compile-fail/must_use-in-stdlib-traits.rs [deleted file]
src/test/compile-fail/not-utf8.bin [deleted file]
src/test/compile-fail/not-utf8.rs [deleted file]
src/test/compile-fail/panic-handler-missing.rs [deleted file]
src/test/compile-fail/panic-handler-twice.rs [deleted file]
src/test/compile-fail/runtime-depend-on-needs-runtime.rs [deleted file]
src/test/compile-fail/runtime-depend-on-needs-runtime.stderr [deleted file]
src/test/compile-fail/specialization/issue-50452.rs [deleted file]
src/test/compile-fail/two-panic-runtimes.rs [deleted file]
src/test/compile-fail/unwind-tables-panic-required.rs [deleted file]
src/test/compile-fail/unwind-tables-target-required.rs [deleted file]
src/test/compile-fail/want-abort-got-unwind.rs [deleted file]
src/test/compile-fail/want-abort-got-unwind2.rs [deleted file]
src/test/compile-fail/weak-lang-item.rs [deleted file]
src/test/debuginfo/pretty-std-collections-hash.rs
src/test/debuginfo/pretty-std.rs
src/test/mir-opt/const_prop/checked_add.main.ConstProp.diff
src/test/mir-opt/const_prop/indirect.main.ConstProp.diff
src/test/mir-opt/const_prop/issue_67019.main.ConstProp.diff
src/test/mir-opt/const_prop/mutable_variable_aggregate.main.ConstProp.diff
src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.32bit.diff
src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.64bit.diff
src/test/mir-opt/const_prop/return_place.add.ConstProp.diff
src/test/mir-opt/const_prop/tuple_literal_propagation.main.ConstProp.diff
src/test/mir-opt/lower_intrinsics.forget.LowerIntrinsics.diff
src/test/mir-opt/lower_intrinsics.rs
src/test/mir-opt/simplify_locals_removes_unused_consts.main.SimplifyLocals.diff
src/test/run-make-fulldeps/coverage-reports/Makefile
src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.doctest.txt [new file with mode: 0644]
src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt
src/test/run-make-fulldeps/coverage-reports/normalize_paths.py [new file with mode: 0755]
src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.doctest/doctest.main.-------.InstrumentCoverage.0.html [new file with mode: 0644]
src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.doctest_crate/doctest_crate.fn_run_in_doctests.-------.InstrumentCoverage.0.html [new file with mode: 0644]
src/test/run-make-fulldeps/coverage/compiletest-ignore-dir
src/test/run-make-fulldeps/coverage/coverage_tools.mk
src/test/run-make-fulldeps/coverage/doctest.rs [new file with mode: 0644]
src/test/run-make-fulldeps/coverage/lib/doctest_crate.rs [new file with mode: 0644]
src/test/run-make-fulldeps/many-crates-but-no-match/Makefile
src/test/run-make-fulldeps/separate-link/Makefile [new file with mode: 0644]
src/test/run-make-fulldeps/type-mismatch-same-crate-name/crateC.rs
src/test/rustdoc-ui/error-in-impl-trait/const-generics.rs
src/test/rustdoc-ui/intra-doc/non-path-primitives.rs [new file with mode: 0644]
src/test/rustdoc-ui/intra-doc/non-path-primitives.stderr [new file with mode: 0644]
src/test/rustdoc-ui/reference-link-has-one-warning.rs [deleted file]
src/test/rustdoc-ui/reference-link-has-one-warning.stderr [deleted file]
src/test/rustdoc-ui/reference-links.rs [new file with mode: 0644]
src/test/rustdoc-ui/reference-links.stderr [new file with mode: 0644]
src/test/rustdoc/async-fn.rs
src/test/rustdoc/codeblock-title.rs
src/test/rustdoc/const-generics/auxiliary/extern_crate.rs
src/test/rustdoc/const-generics/const-generics-docs.rs
src/test/rustdoc/const-generics/type-alias.rs
src/test/rustdoc/intra-doc/non-path-primitives.rs [new file with mode: 0644]
src/test/ui-fulldeps/dropck-tarena-cycle-checked.rs
src/test/ui-fulldeps/dropck_tarena_sound_drop.rs
src/test/ui/array-slice-vec/box-of-array-of-drop-1.rs
src/test/ui/array-slice-vec/box-of-array-of-drop-2.rs
src/test/ui/array-slice-vec/copy-out-of-array-1.rs
src/test/ui/array-slice-vec/match_arr_unknown_len.stderr
src/test/ui/array-slice-vec/nested-vec-3.rs
src/test/ui/associated-consts/associated-const-type-parameter-arrays.rs
src/test/ui/associated-consts/associated-const-type-parameter-arrays.stderr
src/test/ui/associated-item/associated-item-duplicate-bounds.rs
src/test/ui/associated-item/associated-item-duplicate-bounds.stderr
src/test/ui/associated-types/associated-types-projection-to-unrelated-trait.rs
src/test/ui/associated-types/defaults-cyclic-fail-1.rs
src/test/ui/associated-types/defaults-cyclic-fail-1.stderr
src/test/ui/associated-types/defaults-cyclic-fail-2.rs
src/test/ui/associated-types/defaults-cyclic-fail-2.stderr
src/test/ui/associated-types/defaults-wf.stderr
src/test/ui/associated-types/impl-wf-cycle-1.rs [new file with mode: 0644]
src/test/ui/associated-types/impl-wf-cycle-1.stderr [new file with mode: 0644]
src/test/ui/associated-types/impl-wf-cycle-2.rs [new file with mode: 0644]
src/test/ui/associated-types/impl-wf-cycle-2.stderr [new file with mode: 0644]
src/test/ui/associated-types/issue-23595-1.rs [new file with mode: 0644]
src/test/ui/associated-types/issue-23595-1.stderr [new file with mode: 0644]
src/test/ui/associated-types/issue-27675-unchecked-bounds.rs [new file with mode: 0644]
src/test/ui/associated-types/issue-27675-unchecked-bounds.stderr [new file with mode: 0644]
src/test/ui/async-await/issues/issue-78654.full.stderr
src/test/ui/async-await/issues/issue-78654.min.stderr
src/test/ui/async-await/issues/issue-78654.rs
src/test/ui/bad/bad-sized.stderr
src/test/ui/binding/const-param.full.stderr [new file with mode: 0644]
src/test/ui/binding/const-param.min.stderr [new file with mode: 0644]
src/test/ui/binding/const-param.rs
src/test/ui/binding/const-param.stderr [deleted file]
src/test/ui/borrowck/borrowck-mut-borrow-linear-errors.stderr
src/test/ui/borrowck/mut-borrow-in-loop.stderr
src/test/ui/borrowck/two-phase-across-loop.stderr
src/test/ui/closures/coerce-unsafe-closure-to-unsafe-fn-ptr.rs [new file with mode: 0644]
src/test/ui/closures/coerce-unsafe-closure-to-unsafe-fn-ptr.stderr [new file with mode: 0644]
src/test/ui/closures/coerce-unsafe-to-closure.rs [new file with mode: 0644]
src/test/ui/closures/coerce-unsafe-to-closure.stderr [new file with mode: 0644]
src/test/ui/const-generics/apit-with-const-param.rs
src/test/ui/const-generics/argument_order.full.stderr
src/test/ui/const-generics/argument_order.min.stderr
src/test/ui/const-generics/argument_order.rs
src/test/ui/const-generics/array-size-in-generic-struct-param.full.stderr
src/test/ui/const-generics/array-size-in-generic-struct-param.min.stderr
src/test/ui/const-generics/array-size-in-generic-struct-param.rs
src/test/ui/const-generics/array-wrapper-struct-ctor.rs
src/test/ui/const-generics/associated-type-bound-fail.full.stderr
src/test/ui/const-generics/associated-type-bound-fail.min.stderr
src/test/ui/const-generics/associated-type-bound-fail.rs
src/test/ui/const-generics/associated-type-bound.rs
src/test/ui/const-generics/auxiliary/const_generic_lib.rs
src/test/ui/const-generics/auxiliary/crayte.rs
src/test/ui/const-generics/auxiliary/impl-const.rs
src/test/ui/const-generics/broken-mir-1.rs
src/test/ui/const-generics/broken-mir-2.rs
src/test/ui/const-generics/cannot-infer-type-for-const-param.rs
src/test/ui/const-generics/closing-args-token.full.stderr
src/test/ui/const-generics/closing-args-token.min.stderr
src/test/ui/const-generics/closing-args-token.rs
src/test/ui/const-generics/coerce_unsized_array.rs
src/test/ui/const-generics/concrete-const-as-fn-arg.rs
src/test/ui/const-generics/concrete-const-impl-method.rs
src/test/ui/const-generics/condition-in-trait-const-arg.rs
src/test/ui/const-generics/const-arg-in-const-arg.min.stderr
src/test/ui/const-generics/const-arg-in-const-arg.rs
src/test/ui/const-generics/const-arg-in-fn.rs
src/test/ui/const-generics/const-arg-type-arg-misordered.full.stderr
src/test/ui/const-generics/const-arg-type-arg-misordered.min.stderr
src/test/ui/const-generics/const-arg-type-arg-misordered.rs
src/test/ui/const-generics/const-argument-if-length.full.stderr
src/test/ui/const-generics/const-argument-if-length.min.stderr
src/test/ui/const-generics/const-argument-if-length.rs
src/test/ui/const-generics/const-expression-parameter.full.stderr
src/test/ui/const-generics/const-expression-parameter.min.stderr
src/test/ui/const-generics/const-expression-parameter.rs
src/test/ui/const-generics/const-fn-with-const-param.rs
src/test/ui/const-generics/const-generic-array-wrapper.rs
src/test/ui/const-generics/const-generic-type_name.rs
src/test/ui/const-generics/const-param-after-const-literal-arg.rs
src/test/ui/const-generics/const-param-before-other-params.full.stderr
src/test/ui/const-generics/const-param-before-other-params.min.stderr
src/test/ui/const-generics/const-param-before-other-params.rs
src/test/ui/const-generics/const-param-elided-lifetime.full.stderr
src/test/ui/const-generics/const-param-elided-lifetime.min.stderr
src/test/ui/const-generics/const-param-elided-lifetime.rs
src/test/ui/const-generics/const-param-from-outer-fn.full.stderr
src/test/ui/const-generics/const-param-from-outer-fn.min.stderr
src/test/ui/const-generics/const-param-from-outer-fn.rs
src/test/ui/const-generics/const-param-hygiene.rs
src/test/ui/const-generics/const-param-in-async.rs
src/test/ui/const-generics/const-param-in-trait-ungated.rs [deleted file]
src/test/ui/const-generics/const-param-in-trait-ungated.stderr [deleted file]
src/test/ui/const-generics/const-param-in-trait.rs
src/test/ui/const-generics/const-param-shadowing.rs
src/test/ui/const-generics/const-param-shadowing.stderr
src/test/ui/const-generics/const-param-type-depends-on-const-param.full.stderr
src/test/ui/const-generics/const-param-type-depends-on-const-param.min.stderr
src/test/ui/const-generics/const-param-type-depends-on-const-param.rs
src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.rs
src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.stderr
src/test/ui/const-generics/const-param-type-depends-on-type-param.full.stderr
src/test/ui/const-generics/const-param-type-depends-on-type-param.min.stderr
src/test/ui/const-generics/const-param-type-depends-on-type-param.rs
src/test/ui/const-generics/const-parameter-uppercase-lint.full.stderr
src/test/ui/const-generics/const-parameter-uppercase-lint.min.stderr
src/test/ui/const-generics/const-parameter-uppercase-lint.rs
src/test/ui/const-generics/const-types.rs
src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.full.stderr
src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.min.stderr
src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.rs
src/test/ui/const-generics/const_evaluatable_checked/simple.min.stderr
src/test/ui/const-generics/const_evaluatable_checked/simple.rs
src/test/ui/const-generics/const_evaluatable_checked/simple_fail.full.stderr
src/test/ui/const-generics/const_evaluatable_checked/simple_fail.min.stderr
src/test/ui/const-generics/const_evaluatable_checked/simple_fail.rs
src/test/ui/const-generics/core-types.rs
src/test/ui/const-generics/cross_crate_complex.rs
src/test/ui/const-generics/defaults/complex-unord-param.min.stderr
src/test/ui/const-generics/defaults/complex-unord-param.rs
src/test/ui/const-generics/defaults/intermixed-lifetime.full.stderr
src/test/ui/const-generics/defaults/intermixed-lifetime.min.stderr
src/test/ui/const-generics/defaults/intermixed-lifetime.rs
src/test/ui/const-generics/defaults/needs-feature.min.stderr
src/test/ui/const-generics/defaults/needs-feature.none.stderr
src/test/ui/const-generics/defaults/needs-feature.rs
src/test/ui/const-generics/defaults/simple-defaults.min.stderr
src/test/ui/const-generics/defaults/simple-defaults.rs
src/test/ui/const-generics/defaults/wrong-order.full.stderr
src/test/ui/const-generics/defaults/wrong-order.min.stderr
src/test/ui/const-generics/defaults/wrong-order.rs
src/test/ui/const-generics/derive-debug-array-wrapper.rs
src/test/ui/const-generics/different_byref.full.stderr
src/test/ui/const-generics/different_byref.min.stderr
src/test/ui/const-generics/different_byref.rs
src/test/ui/const-generics/different_byref_simple.full.stderr
src/test/ui/const-generics/different_byref_simple.min.stderr
src/test/ui/const-generics/different_byref_simple.rs
src/test/ui/const-generics/dyn-supertraits.rs
src/test/ui/const-generics/exhaustive-value.full.stderr
src/test/ui/const-generics/exhaustive-value.min.stderr
src/test/ui/const-generics/exhaustive-value.rs
src/test/ui/const-generics/fn-const-param-call.full.stderr
src/test/ui/const-generics/fn-const-param-call.min.stderr
src/test/ui/const-generics/fn-const-param-call.rs
src/test/ui/const-generics/fn-const-param-infer.full.stderr
src/test/ui/const-generics/fn-const-param-infer.min.stderr
src/test/ui/const-generics/fn-const-param-infer.rs
src/test/ui/const-generics/fn-taking-const-generic-array.rs
src/test/ui/const-generics/forbid-non-structural_match-types.full.stderr
src/test/ui/const-generics/forbid-non-structural_match-types.min.stderr
src/test/ui/const-generics/forbid-non-structural_match-types.rs
src/test/ui/const-generics/foreign-item-const-parameter.full.stderr
src/test/ui/const-generics/foreign-item-const-parameter.min.stderr
src/test/ui/const-generics/foreign-item-const-parameter.rs
src/test/ui/const-generics/generic-function-call-in-array-length.full.stderr
src/test/ui/const-generics/generic-function-call-in-array-length.min.stderr
src/test/ui/const-generics/generic-function-call-in-array-length.rs
src/test/ui/const-generics/generic-param-mismatch.full.stderr
src/test/ui/const-generics/generic-param-mismatch.min.stderr
src/test/ui/const-generics/generic-param-mismatch.rs
src/test/ui/const-generics/generic-sum-in-array-length.full.stderr
src/test/ui/const-generics/generic-sum-in-array-length.min.stderr
src/test/ui/const-generics/generic-sum-in-array-length.rs
src/test/ui/const-generics/impl-const-generic-struct.rs
src/test/ui/const-generics/impl-trait-with-const-arguments.full.stderr
src/test/ui/const-generics/impl-trait-with-const-arguments.min.stderr
src/test/ui/const-generics/impl-trait-with-const-arguments.rs
src/test/ui/const-generics/incorrect-number-of-const-args.full.stderr
src/test/ui/const-generics/incorrect-number-of-const-args.min.stderr
src/test/ui/const-generics/incorrect-number-of-const-args.rs
src/test/ui/const-generics/infer/cannot-infer-const-args.full.stderr
src/test/ui/const-generics/infer/cannot-infer-const-args.min.stderr
src/test/ui/const-generics/infer/cannot-infer-const-args.rs
src/test/ui/const-generics/infer/issue-77092.rs
src/test/ui/const-generics/infer/issue-77092.stderr
src/test/ui/const-generics/infer/method-chain.full.stderr
src/test/ui/const-generics/infer/method-chain.min.stderr
src/test/ui/const-generics/infer/method-chain.rs
src/test/ui/const-generics/infer/uninferred-consts.full.stderr
src/test/ui/const-generics/infer/uninferred-consts.min.stderr
src/test/ui/const-generics/infer/uninferred-consts.rs
src/test/ui/const-generics/infer_arg_from_pat.rs
src/test/ui/const-generics/infer_arr_len_from_pat.rs
src/test/ui/const-generics/integer-literal-generic-arg-in-where-clause.rs
src/test/ui/const-generics/intrinsics-type_name-as-const-argument.full.stderr
src/test/ui/const-generics/intrinsics-type_name-as-const-argument.min.stderr
src/test/ui/const-generics/intrinsics-type_name-as-const-argument.rs
src/test/ui/const-generics/issue-61522-array-len-succ.full.stderr
src/test/ui/const-generics/issue-61522-array-len-succ.min.stderr
src/test/ui/const-generics/issue-61522-array-len-succ.rs
src/test/ui/const-generics/issue-66596-impl-trait-for-str-const-arg.min.stderr
src/test/ui/const-generics/issue-66596-impl-trait-for-str-const-arg.rs
src/test/ui/const-generics/issue-67375.full.stderr
src/test/ui/const-generics/issue-67375.min.stderr
src/test/ui/const-generics/issue-67375.rs
src/test/ui/const-generics/issue-67945-1.full.stderr
src/test/ui/const-generics/issue-67945-1.min.stderr
src/test/ui/const-generics/issue-67945-1.rs
src/test/ui/const-generics/issue-67945-2.full.stderr
src/test/ui/const-generics/issue-67945-2.min.stderr
src/test/ui/const-generics/issue-67945-2.rs
src/test/ui/const-generics/issue-67945-3.full.stderr
src/test/ui/const-generics/issue-67945-3.min.stderr
src/test/ui/const-generics/issue-67945-3.rs
src/test/ui/const-generics/issue-68104-print-stack-overflow.rs
src/test/ui/const-generics/issue-70180-1-stalled_on.rs
src/test/ui/const-generics/issue-70180-2-stalled_on.rs
src/test/ui/const-generics/issue-71986.rs
src/test/ui/const-generics/issue-74906.rs
src/test/ui/const-generics/issues/auxiliary/const_generic_issues_lib.rs
src/test/ui/const-generics/issues/issue-56445.full.stderr
src/test/ui/const-generics/issues/issue-56445.min.stderr
src/test/ui/const-generics/issues/issue-56445.rs
src/test/ui/const-generics/issues/issue-60263.rs [deleted file]
src/test/ui/const-generics/issues/issue-60263.stderr [deleted file]
src/test/ui/const-generics/issues/issue-60818-struct-constructors.full.stderr
src/test/ui/const-generics/issues/issue-60818-struct-constructors.rs
src/test/ui/const-generics/issues/issue-61336-1.full.stderr
src/test/ui/const-generics/issues/issue-61336-1.rs
src/test/ui/const-generics/issues/issue-61336-2.full.stderr
src/test/ui/const-generics/issues/issue-61336-2.min.stderr
src/test/ui/const-generics/issues/issue-61336-2.rs
src/test/ui/const-generics/issues/issue-61336.full.stderr
src/test/ui/const-generics/issues/issue-61336.min.stderr
src/test/ui/const-generics/issues/issue-61336.rs
src/test/ui/const-generics/issues/issue-61422.full.stderr
src/test/ui/const-generics/issues/issue-61422.rs
src/test/ui/const-generics/issues/issue-61432.full.stderr
src/test/ui/const-generics/issues/issue-61432.rs
src/test/ui/const-generics/issues/issue-61747.full.stderr
src/test/ui/const-generics/issues/issue-61747.min.stderr
src/test/ui/const-generics/issues/issue-61747.rs
src/test/ui/const-generics/issues/issue-61935.full.stderr
src/test/ui/const-generics/issues/issue-61935.min.stderr
src/test/ui/const-generics/issues/issue-61935.rs
src/test/ui/const-generics/issues/issue-62187-encountered-polymorphic-const.rs
src/test/ui/const-generics/issues/issue-62220.full.stderr
src/test/ui/const-generics/issues/issue-62220.min.stderr
src/test/ui/const-generics/issues/issue-62220.rs
src/test/ui/const-generics/issues/issue-62456.full.stderr
src/test/ui/const-generics/issues/issue-62456.min.stderr
src/test/ui/const-generics/issues/issue-62456.rs
src/test/ui/const-generics/issues/issue-62504.full.stderr
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-62579-no-match.min.stderr
src/test/ui/const-generics/issues/issue-62579-no-match.rs
src/test/ui/const-generics/issues/issue-62878.full.stderr
src/test/ui/const-generics/issues/issue-62878.min.stderr
src/test/ui/const-generics/issues/issue-62878.rs
src/test/ui/const-generics/issues/issue-63322-forbid-dyn.full.stderr
src/test/ui/const-generics/issues/issue-63322-forbid-dyn.min.stderr
src/test/ui/const-generics/issues/issue-63322-forbid-dyn.rs
src/test/ui/const-generics/issues/issue-64494.full.stderr
src/test/ui/const-generics/issues/issue-64494.min.stderr
src/test/ui/const-generics/issues/issue-64494.rs
src/test/ui/const-generics/issues/issue-64519.rs
src/test/ui/const-generics/issues/issue-66205.full.stderr
src/test/ui/const-generics/issues/issue-66205.min.stderr
src/test/ui/const-generics/issues/issue-66205.rs
src/test/ui/const-generics/issues/issue-66906.rs
src/test/ui/const-generics/issues/issue-67185-1.rs
src/test/ui/const-generics/issues/issue-67185-2.full.stderr
src/test/ui/const-generics/issues/issue-67185-2.min.stderr
src/test/ui/const-generics/issues/issue-67185-2.rs
src/test/ui/const-generics/issues/issue-67739.full.stderr
src/test/ui/const-generics/issues/issue-67739.min.stderr
src/test/ui/const-generics/issues/issue-67739.rs
src/test/ui/const-generics/issues/issue-68366.full.stderr
src/test/ui/const-generics/issues/issue-68366.min.stderr
src/test/ui/const-generics/issues/issue-68366.rs
src/test/ui/const-generics/issues/issue-68596.rs
src/test/ui/const-generics/issues/issue-68615-adt.min.stderr
src/test/ui/const-generics/issues/issue-68615-adt.rs
src/test/ui/const-generics/issues/issue-68615-array.min.stderr
src/test/ui/const-generics/issues/issue-68615-array.rs
src/test/ui/const-generics/issues/issue-68977.full.stderr
src/test/ui/const-generics/issues/issue-68977.min.stderr
src/test/ui/const-generics/issues/issue-68977.rs
src/test/ui/const-generics/issues/issue-70125-1.rs
src/test/ui/const-generics/issues/issue-70125-2.rs
src/test/ui/const-generics/issues/issue-70167.rs
src/test/ui/const-generics/issues/issue-71169.full.stderr
src/test/ui/const-generics/issues/issue-71169.min.stderr
src/test/ui/const-generics/issues/issue-71169.rs
src/test/ui/const-generics/issues/issue-71381.full.stderr
src/test/ui/const-generics/issues/issue-71381.min.stderr
src/test/ui/const-generics/issues/issue-71381.rs
src/test/ui/const-generics/issues/issue-71382.full.stderr
src/test/ui/const-generics/issues/issue-71382.min.stderr
src/test/ui/const-generics/issues/issue-71382.rs
src/test/ui/const-generics/issues/issue-71611.full.stderr
src/test/ui/const-generics/issues/issue-71611.min.stderr
src/test/ui/const-generics/issues/issue-71611.rs
src/test/ui/const-generics/issues/issue-72352.full.stderr
src/test/ui/const-generics/issues/issue-72352.min.stderr
src/test/ui/const-generics/issues/issue-72352.rs
src/test/ui/const-generics/issues/issue-72787.full.stderr
src/test/ui/const-generics/issues/issue-72787.min.stderr
src/test/ui/const-generics/issues/issue-72787.rs
src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.full.stderr
src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.min.stderr
src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.rs
src/test/ui/const-generics/issues/issue-73491.min.stderr
src/test/ui/const-generics/issues/issue-73491.rs
src/test/ui/const-generics/issues/issue-73508.full.stderr
src/test/ui/const-generics/issues/issue-73508.min.stderr
src/test/ui/const-generics/issues/issue-73508.rs
src/test/ui/const-generics/issues/issue-74101.min.stderr
src/test/ui/const-generics/issues/issue-74101.rs
src/test/ui/const-generics/issues/issue-74255.min.stderr
src/test/ui/const-generics/issues/issue-74255.rs
src/test/ui/const-generics/issues/issue-74950.min.stderr
src/test/ui/const-generics/issues/issue-74950.rs
src/test/ui/const-generics/issues/issue-75047.min.stderr
src/test/ui/const-generics/issues/issue-75047.rs
src/test/ui/const-generics/issues/issue-76701-ty-param-in-const.full.stderr
src/test/ui/const-generics/issues/issue-76701-ty-param-in-const.min.stderr
src/test/ui/const-generics/issues/issue-76701-ty-param-in-const.rs
src/test/ui/const-generics/issues/issue-80062.rs [new file with mode: 0644]
src/test/ui/const-generics/issues/issue-80062.stderr [new file with mode: 0644]
src/test/ui/const-generics/issues/issue-80375.rs [new file with mode: 0644]
src/test/ui/const-generics/issues/issue-80375.stderr [new file with mode: 0644]
src/test/ui/const-generics/issues/issue70273-assoc-fn.rs
src/test/ui/const-generics/macro_rules-braces.full.stderr
src/test/ui/const-generics/macro_rules-braces.min.stderr
src/test/ui/const-generics/macro_rules-braces.rs
src/test/ui/const-generics/min-and-full-same-time.rs [deleted file]
src/test/ui/const-generics/min-and-full-same-time.stderr [deleted file]
src/test/ui/const-generics/min_const_generics/assoc_const.rs
src/test/ui/const-generics/min_const_generics/complex-expression.rs
src/test/ui/const-generics/min_const_generics/complex-expression.stderr
src/test/ui/const-generics/min_const_generics/complex-types.rs
src/test/ui/const-generics/min_const_generics/complex-types.stderr
src/test/ui/const-generics/min_const_generics/const-evaluatable-unchecked.rs
src/test/ui/const-generics/min_const_generics/const-evaluatable-unchecked.stderr
src/test/ui/const-generics/min_const_generics/const-expression-suggest-missing-braces-without-turbofish.rs
src/test/ui/const-generics/min_const_generics/const-expression-suggest-missing-braces-without-turbofish.stderr
src/test/ui/const-generics/min_const_generics/const-expression-suggest-missing-braces.rs
src/test/ui/const-generics/min_const_generics/const-expression-suggest-missing-braces.stderr
src/test/ui/const-generics/min_const_generics/const_fn_in_generics.rs
src/test/ui/const-generics/min_const_generics/default_function_param.rs
src/test/ui/const-generics/min_const_generics/default_function_param.stderr
src/test/ui/const-generics/min_const_generics/default_trait_param.rs
src/test/ui/const-generics/min_const_generics/default_trait_param.stderr
src/test/ui/const-generics/min_const_generics/feature-gate-min_const_generics.rs [deleted file]
src/test/ui/const-generics/min_const_generics/feature-gate-min_const_generics.stderr [deleted file]
src/test/ui/const-generics/min_const_generics/forbid-non-static-lifetimes.rs
src/test/ui/const-generics/min_const_generics/forbid-non-static-lifetimes.stderr
src/test/ui/const-generics/min_const_generics/invalid-patterns.rs
src/test/ui/const-generics/min_const_generics/invalid-patterns.stderr
src/test/ui/const-generics/min_const_generics/macro-fail.rs
src/test/ui/const-generics/min_const_generics/macro-fail.stderr
src/test/ui/const-generics/min_const_generics/macro.rs
src/test/ui/const-generics/min_const_generics/self-ty-in-const-1.rs
src/test/ui/const-generics/min_const_generics/self-ty-in-const-1.stderr
src/test/ui/const-generics/min_const_generics/self-ty-in-const-2.rs
src/test/ui/const-generics/min_const_generics/self-ty-in-const-2.stderr
src/test/ui/const-generics/min_const_generics/static-reference-array-const-param.rs
src/test/ui/const-generics/min_const_generics/static-reference-array-const-param.stderr
src/test/ui/const-generics/min_const_generics/transmute-const-param-static-reference.rs
src/test/ui/const-generics/min_const_generics/transmute-const-param-static-reference.stderr
src/test/ui/const-generics/mut-ref-const-param-array.rs
src/test/ui/const-generics/nested-type.full.stderr
src/test/ui/const-generics/nested-type.min.stderr
src/test/ui/const-generics/nested-type.rs
src/test/ui/const-generics/occurs-check/unify-fixpoint.stderr
src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.full.stderr
src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.min.stderr
src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.rs
src/test/ui/const-generics/promotion.rs
src/test/ui/const-generics/raw-ptr-const-param-deref.full.stderr
src/test/ui/const-generics/raw-ptr-const-param-deref.min.stderr
src/test/ui/const-generics/raw-ptr-const-param-deref.rs
src/test/ui/const-generics/raw-ptr-const-param.full.stderr
src/test/ui/const-generics/raw-ptr-const-param.min.stderr
src/test/ui/const-generics/raw-ptr-const-param.rs
src/test/ui/const-generics/slice-const-param-mismatch.full.stderr
src/test/ui/const-generics/slice-const-param-mismatch.min.stderr
src/test/ui/const-generics/slice-const-param-mismatch.rs
src/test/ui/const-generics/slice-const-param.min.stderr
src/test/ui/const-generics/slice-const-param.rs
src/test/ui/const-generics/std/const-generics-range.min.stderr
src/test/ui/const-generics/std/const-generics-range.rs
src/test/ui/const-generics/struct-with-invalid-const-param.full.stderr
src/test/ui/const-generics/struct-with-invalid-const-param.min.stderr
src/test/ui/const-generics/struct-with-invalid-const-param.rs
src/test/ui/const-generics/trait-const-args.rs
src/test/ui/const-generics/transparent-maybeunit-array-wrapper.rs
src/test/ui/const-generics/type-after-const-ok.min.stderr
src/test/ui/const-generics/type-after-const-ok.rs
src/test/ui/const-generics/type-dependent/auxiliary/type_dependent_lib.rs
src/test/ui/const-generics/type-dependent/const-arg-in-const-arg.rs
src/test/ui/const-generics/type-dependent/issue-61936.rs
src/test/ui/const-generics/type-dependent/issue-63695.rs
src/test/ui/const-generics/type-dependent/issue-67144-1.rs
src/test/ui/const-generics/type-dependent/issue-67144-2.rs
src/test/ui/const-generics/type-dependent/issue-69816.rs
src/test/ui/const-generics/type-dependent/issue-70217.rs
src/test/ui/const-generics/type-dependent/issue-70507.rs
src/test/ui/const-generics/type-dependent/issue-70586.rs
src/test/ui/const-generics/type-dependent/issue-71348.min.stderr
src/test/ui/const-generics/type-dependent/issue-71348.rs
src/test/ui/const-generics/type-dependent/issue-71382.full.stderr
src/test/ui/const-generics/type-dependent/issue-71382.min.stderr
src/test/ui/const-generics/type-dependent/issue-71382.rs
src/test/ui/const-generics/type-dependent/issue-71805.rs
src/test/ui/const-generics/type-dependent/issue-73730.rs
src/test/ui/const-generics/type-dependent/non-local.rs
src/test/ui/const-generics/type-dependent/qpath.rs
src/test/ui/const-generics/type-dependent/simple.rs
src/test/ui/const-generics/type-dependent/type-mismatch.full.stderr
src/test/ui/const-generics/type-dependent/type-mismatch.min.stderr
src/test/ui/const-generics/type-dependent/type-mismatch.rs
src/test/ui/const-generics/type_of_anon_const.rs
src/test/ui/const-generics/types-mismatch-const-args.full.stderr
src/test/ui/const-generics/types-mismatch-const-args.min.stderr
src/test/ui/const-generics/types-mismatch-const-args.rs
src/test/ui/const-generics/uninferred-consts-during-codegen-1.rs
src/test/ui/const-generics/uninferred-consts-during-codegen-2.rs
src/test/ui/const-generics/unknown_adt.full.stderr
src/test/ui/const-generics/unknown_adt.min.stderr
src/test/ui/const-generics/unknown_adt.rs
src/test/ui/const-generics/unused-const-param.rs
src/test/ui/const-generics/unused_braces.full.fixed
src/test/ui/const-generics/unused_braces.full.stderr
src/test/ui/const-generics/unused_braces.min.fixed
src/test/ui/const-generics/unused_braces.min.stderr
src/test/ui/const-generics/unused_braces.rs
src/test/ui/const-generics/wf-misc.full.stderr
src/test/ui/const-generics/wf-misc.min.stderr
src/test/ui/const-generics/wf-misc.rs
src/test/ui/const-generics/where-clauses.rs
src/test/ui/const-ptr/out_of_bounds_read.rs [new file with mode: 0644]
src/test/ui/const-ptr/out_of_bounds_read.stderr [new file with mode: 0644]
src/test/ui/consts/const-fn-error.rs [new file with mode: 0644]
src/test/ui/consts/const-fn-error.stderr [new file with mode: 0644]
src/test/ui/consts/const-size_of_val-align_of_val.rs
src/test/ui/consts/issue-44415.rs [new file with mode: 0644]
src/test/ui/consts/issue-44415.stderr [new file with mode: 0644]
src/test/ui/consts/issue-55878.rs [new file with mode: 0644]
src/test/ui/consts/issue-55878.stderr [new file with mode: 0644]
src/test/ui/crate-loading/auxiliary/crateresolve1-1.rs [new file with mode: 0644]
src/test/ui/crate-loading/auxiliary/crateresolve1-2.rs [new file with mode: 0644]
src/test/ui/crate-loading/auxiliary/crateresolve1-3.rs [new file with mode: 0644]
src/test/ui/crate-loading/crateresolve1.rs [new file with mode: 0644]
src/test/ui/dropck/dropck_trait_cycle_checked.rs
src/test/ui/dropck/reject-specialized-drops-8142.rs
src/test/ui/dropck/reject-specialized-drops-8142.stderr
src/test/ui/enum-discriminant/issue-70453-generics-in-discr-ice-2.rs
src/test/ui/enum-discriminant/issue-70453-generics-in-discr-ice-2.stderr
src/test/ui/enum-discriminant/issue-70453-generics-in-discr-ice.rs
src/test/ui/enum-discriminant/issue-70453-generics-in-discr-ice.stderr
src/test/ui/enum-discriminant/issue-70453-polymorphic-ctfe.rs
src/test/ui/enum-discriminant/issue-70453-polymorphic-ctfe.stderr
src/test/ui/enum/issue-67945-1.rs
src/test/ui/enum/issue-67945-1.stderr
src/test/ui/enum/issue-67945-2.rs
src/test/ui/enum/issue-67945-2.stderr
src/test/ui/error-codes/E0730.stderr
src/test/ui/error-codes/E0771.stderr
src/test/ui/extern-flag/empty-extern-arg.rs [new file with mode: 0644]
src/test/ui/extern-flag/empty-extern-arg.stderr [new file with mode: 0644]
src/test/ui/feature-gates/feature-gate-const_generics-ptr.rs [deleted file]
src/test/ui/feature-gates/feature-gate-const_generics-ptr.stderr [deleted file]
src/test/ui/feature-gates/feature-gate-const_generics.rs
src/test/ui/feature-gates/feature-gate-const_generics.stderr
src/test/ui/fn/issue-80179.rs [new file with mode: 0644]
src/test/ui/fn/issue-80179.stderr [new file with mode: 0644]
src/test/ui/fsu-moves-and-copies.rs
src/test/ui/functions-closures/closure-expected-type/README.md
src/test/ui/generic-associated-types/issue-74824.rs [new file with mode: 0644]
src/test/ui/generic-associated-types/issue-74824.stderr [new file with mode: 0644]
src/test/ui/generics/param-in-ct-in-ty-param-default.rs
src/test/ui/generics/param-in-ct-in-ty-param-default.stderr
src/test/ui/hygiene/generic_params.stderr
src/test/ui/hygiene/issue-61574-const-parameters.stderr
src/test/ui/issues/issue-20433.stderr
src/test/ui/issues/issue-21475.rs
src/test/ui/issues/issue-23122-2.stderr
src/test/ui/issues/issue-26251.rs
src/test/ui/issues/issue-26996.rs
src/test/ui/issues/issue-27021.rs
src/test/ui/issues/issue-28498-ugeh-with-lifetime-param.rs
src/test/ui/issues/issue-28498-ugeh-with-passed-to-fn.rs
src/test/ui/issues/issue-28498-ugeh-with-trait-bound.rs
src/test/ui/issues/issue-39559.rs
src/test/ui/issues/issue-39559.stderr
src/test/ui/issues/issue-43733.rs [deleted file]
src/test/ui/issues/issue-43733.stderr [deleted file]
src/test/ui/issues/issue-49298.rs
src/test/ui/issues/issue-59508-1.stderr
src/test/ui/issues/issue-59508.stderr
src/test/ui/lazy_normalization_consts/feature-gate-lazy_normalization_consts.rs
src/test/ui/lazy_normalization_consts/feature-gate-lazy_normalization_consts.stderr
src/test/ui/lifetime-before-type-params.stderr
src/test/ui/linkage-attr/invalid-link-args.rs [new file with mode: 0644]
src/test/ui/linkage-attr/issue-10755.rs [new file with mode: 0644]
src/test/ui/lint/expansion-time.rs
src/test/ui/lint/expansion-time.stderr
src/test/ui/lint/function-item-references.rs
src/test/ui/lint/lint-const-item-mutation.stderr
src/test/ui/lint/must_use-in-stdlib-traits.rs [new file with mode: 0644]
src/test/ui/lint/must_use-in-stdlib-traits.stderr [new file with mode: 0644]
src/test/ui/lint/redundant-semicolon/item-stmt-semi.rs
src/test/ui/lint/redundant-semicolon/item-stmt-semi.stderr [new file with mode: 0644]
src/test/ui/llvm-asm/asm-src-loc-codegen-units.rs [new file with mode: 0644]
src/test/ui/llvm-asm/asm-src-loc.rs [new file with mode: 0644]
src/test/ui/macros/issue-39404.rs
src/test/ui/macros/issue-39404.stderr
src/test/ui/macros/macro-comma-behavior-rpass.rs
src/test/ui/macros/macro-comma-behavior.core.stderr
src/test/ui/macros/macro-comma-behavior.rs
src/test/ui/macros/macro-comma-behavior.std.stderr
src/test/ui/macros/macro-comma-support-rpass.rs
src/test/ui/macros/macro-match-nonterminal.rs
src/test/ui/macros/macro-match-nonterminal.stderr
src/test/ui/macros/not-utf8.bin [new file with mode: 0644]
src/test/ui/macros/not-utf8.rs [new file with mode: 0644]
src/test/ui/macros/not-utf8.stderr [new file with mode: 0644]
src/test/ui/meta/meta-expected-error-wrong-rev.a.stderr [new file with mode: 0644]
src/test/ui/meta/meta-expected-error-wrong-rev.rs [new file with mode: 0644]
src/test/ui/mir/mir-inlining/array-clone-with-generic-size.rs
src/test/ui/never_type/issue-52443.rs [new file with mode: 0644]
src/test/ui/never_type/issue-52443.stderr [new file with mode: 0644]
src/test/ui/nll/closures-in-loops.stderr
src/test/ui/nll/issue-62007-assign-const-index.stderr
src/test/ui/nll/issue-62007-assign-differing-fields.stderr
src/test/ui/nll/polonius/assignment-to-differing-field.stderr
src/test/ui/object-lifetime-default-from-rptr-box.rs
src/test/ui/panic-handler/auxiliary/weak-lang-items.rs [new file with mode: 0644]
src/test/ui/panic-handler/panic-handler-missing.rs [new file with mode: 0644]
src/test/ui/panic-handler/panic-handler-twice.rs [new file with mode: 0644]
src/test/ui/panic-handler/weak-lang-item.rs [new file with mode: 0644]
src/test/ui/panic-handler/weak-lang-item.stderr [new file with mode: 0644]
src/test/ui/panic-runtime/auxiliary/depends.rs [new file with mode: 0644]
src/test/ui/panic-runtime/auxiliary/needs-panic-runtime.rs [new file with mode: 0644]
src/test/ui/panic-runtime/runtime-depend-on-needs-runtime.rs [new file with mode: 0644]
src/test/ui/panic-runtime/two-panic-runtimes.rs [new file with mode: 0644]
src/test/ui/panic-runtime/unwind-tables-panic-required.rs [new file with mode: 0644]
src/test/ui/panic-runtime/unwind-tables-target-required.rs [new file with mode: 0644]
src/test/ui/panic-runtime/want-abort-got-unwind.rs [new file with mode: 0644]
src/test/ui/panic-runtime/want-abort-got-unwind2.rs [new file with mode: 0644]
src/test/ui/parser/incorrect-move-async-order-issue-79694.fixed [new file with mode: 0644]
src/test/ui/parser/incorrect-move-async-order-issue-79694.rs [new file with mode: 0644]
src/test/ui/parser/incorrect-move-async-order-issue-79694.stderr [new file with mode: 0644]
src/test/ui/parser/issue-14303-enum.stderr
src/test/ui/parser/issue-14303-fn-def.stderr
src/test/ui/parser/issue-14303-impl.stderr
src/test/ui/parser/issue-14303-struct.stderr
src/test/ui/parser/issue-14303-trait.stderr
src/test/ui/parser/macro/issue-33569.rs
src/test/ui/parser/macro/issue-33569.stderr
src/test/ui/parser/multibyte-char-use-seperator-issue-80134.rs [new file with mode: 0644]
src/test/ui/parser/multibyte-char-use-seperator-issue-80134.stderr [new file with mode: 0644]
src/test/ui/pattern/usefulness/consts-opaque.rs
src/test/ui/pattern/usefulness/consts-opaque.stderr
src/test/ui/pattern/usefulness/integer-ranges/exhaustiveness.rs
src/test/ui/pattern/usefulness/integer-ranges/exhaustiveness.stderr
src/test/ui/pattern/usefulness/integer-ranges/overlapping_range_endpoints.rs
src/test/ui/pattern/usefulness/integer-ranges/overlapping_range_endpoints.stderr
src/test/ui/pattern/usefulness/integer-ranges/reachability.rs
src/test/ui/pattern/usefulness/integer-ranges/reachability.stderr
src/test/ui/polymorphization/const_parameters/closures.stderr
src/test/ui/polymorphization/const_parameters/functions.stderr
src/test/ui/polymorphization/generators.stderr
src/test/ui/privacy/issue-46209-private-enum-variant-reexport.rs [new file with mode: 0644]
src/test/ui/privacy/issue-46209-private-enum-variant-reexport.stderr [new file with mode: 0644]
src/test/ui/regions/regions-early-bound-trait-param.rs
src/test/ui/regions/regions-variance-contravariant-use-contravariant.rs
src/test/ui/regions/regions-variance-covariant-use-covariant.rs
src/test/ui/resolve/issue-65035-static-with-parent-generics.stderr
src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr
src/test/ui/simd/simd-array-type.rs
src/test/ui/simd/simd-generics.rs
src/test/ui/simd/simd-intrinsic-generic-arithmetic-saturating.rs
src/test/ui/simd/simd-intrinsic-generic-arithmetic.rs
src/test/ui/similar-tokens.fixed [deleted file]
src/test/ui/similar-tokens.rs
src/test/ui/similar-tokens.stderr
src/test/ui/span/dropck_arr_cycle_checked.rs
src/test/ui/span/dropck_vec_cycle_checked.rs
src/test/ui/specialization/defaultimpl/projection.rs
src/test/ui/specialization/issue-50452-fail.rs [new file with mode: 0644]
src/test/ui/specialization/issue-50452-fail.stderr [new file with mode: 0644]
src/test/ui/specialization/specialization-projection.rs
src/test/ui/structs-enums/discrim-explicit-23030.rs
src/test/ui/structs-enums/object-lifetime-default-from-rptr-struct.rs
src/test/ui/suggestions/suggest-move-lifetimes.stderr
src/test/ui/svh/auxiliary/svh-uta-base.rs
src/test/ui/svh/auxiliary/svh-uta-change-use-trait.rs
src/test/ui/svh/auxiliary/svh-utb.rs
src/test/ui/svh/svh-use-trait.rs
src/test/ui/symbol-names/const-generics-demangling.rs
src/test/ui/symbol-names/const-generics-demangling.stderr
src/test/ui/symbol-names/const-generics.rs
src/test/ui/symbol-names/issue-76365.rs
src/test/ui/threads-sendsync/issue-43733-2.rs [new file with mode: 0644]
src/test/ui/threads-sendsync/issue-43733.rs [new file with mode: 0644]
src/test/ui/threads-sendsync/issue-43733.stderr [new file with mode: 0644]
src/test/ui/traits/traits-repeated-supertrait.rs
src/test/ui/type-alias-impl-trait/assoc-type-const.stderr
src/test/ui/unsafe-fn-called-from-unsafe-blk.rs
src/test/ui/unsafe-fn-called-from-unsafe-fn.rs
src/tools/build-manifest/src/main.rs
src/tools/cargo
src/tools/clippy/Cargo.toml
src/tools/clippy/README.md
src/tools/clippy/clippy_lints/src/lifetimes.rs
src/tools/clippy/src/driver.rs
src/tools/clippy/src/main.rs
src/tools/clippy/tests/dogfood.rs
src/tools/clippy/tests/ui/match_expr_like_matches_macro.fixed
src/tools/clippy/tests/ui/match_expr_like_matches_macro.rs
src/tools/compiletest/src/common.rs
src/tools/compiletest/src/header.rs
src/tools/compiletest/src/main.rs
src/tools/compiletest/src/runtest.rs
src/tools/lint-docs/src/groups.rs
src/tools/rust-installer
src/tools/rustc-workspace-hack/Cargo.toml
src/tools/rustfmt
src/tools/tidy/src/features.rs
src/tools/x/README.md
src/version
triagebot.toml

index b8544e6a4e0fd57376e05f6a983dd68ec756f71a..3e42594c8280dc50b93fe31713b85194e4d71f1e 100644 (file)
@@ -2,7 +2,7 @@
 name: Library Tracking Issue
 about: A tracking issue for an unstable library feature.
 title: Tracking Issue for XXX
-labels: C-tracking-issue T-libs
+labels: C-tracking-issue, T-libs
 ---
 <!--
 Thank you for creating a tracking issue!
index fcfd23f2dae5f4c3739d6878b64a9c7c092614aa..4676e4127e83c62bdafc6f3696d8bd2fdacaa1fd 100644 (file)
@@ -895,9 +895,9 @@ dependencies = [
 
 [[package]]
 name = "curl"
-version = "0.4.31"
+version = "0.4.34"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9447ad28eee2a5cfb031c329d46bef77487244fff6a724b378885b8691a35f78"
+checksum = "e268162af1a5fe89917ae25ba3b0a77c8da752bdc58e7dbb4f15b91fbd33756e"
 dependencies = [
  "curl-sys",
  "libc",
@@ -910,9 +910,9 @@ dependencies = [
 
 [[package]]
 name = "curl-sys"
-version = "0.4.34+curl-7.71.1"
+version = "0.4.39+curl-7.74.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ad4eff0be6985b7e709f64b5a541f700e9ad1407190a29f4884319eb663ed1d6"
+checksum = "07a8ce861e7b68a0b394e814d7ee9f1b2750ff8bd10372c6ad3bacc10e86f874"
 dependencies = [
  "cc",
  "libc",
@@ -1330,9 +1330,9 @@ dependencies = [
 
 [[package]]
 name = "git2"
-version = "0.13.12"
+version = "0.13.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ca6f1a0238d7f8f8fd5ee642f4ebac4dbc03e03d1f78fbe7a3ede35dcf7e2224"
+checksum = "186dd99cc77576e58344ad614fa9bb27bad9d048f85de3ca850c1f4e8b048260"
 dependencies = [
  "bitflags",
  "libc",
@@ -1345,9 +1345,9 @@ dependencies = [
 
 [[package]]
 name = "git2-curl"
-version = "0.14.0"
+version = "0.14.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "502d532a2d06184beb3bc869d4d90236e60934e3382c921b203fa3c33e212bd7"
+checksum = "883539cb0ea94bab3f8371a98cd8e937bbe9ee7c044499184aa4c17deb643a50"
 dependencies = [
  "curl",
  "git2",
@@ -1759,9 +1759,9 @@ dependencies = [
 
 [[package]]
 name = "libgit2-sys"
-version = "0.12.14+1.1.0"
+version = "0.12.16+1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8f25af58e6495f7caf2919d08f212de550cfa3ed2f5e744988938ea292b9f549"
+checksum = "9f91b2f931ee975a98155195be8cd82d02e8e029d7d793d2bac1b8181ac97020"
 dependencies = [
  "cc",
  "libc",
@@ -3435,6 +3435,7 @@ dependencies = [
  "byteorder",
  "crossbeam-utils 0.7.2",
  "libc",
+ "libz-sys",
  "proc-macro2",
  "quote",
  "serde",
@@ -4396,7 +4397,7 @@ dependencies = [
 
 [[package]]
 name = "rustfmt-nightly"
-version = "1.4.29"
+version = "1.4.30"
 dependencies = [
  "annotate-snippets 0.6.1",
  "anyhow",
@@ -5342,7 +5343,7 @@ dependencies = [
  "chrono",
  "lazy_static",
  "matchers",
- "parking_lot 0.11.0",
+ "parking_lot 0.9.0",
  "regex",
  "serde",
  "serde_json",
index 9fd796fd775bf995f9d8a624704a36f1bbbabe7d..8f04980e390367dcf5bb9c187f710a00ead0d819 100644 (file)
@@ -1,3 +1,131 @@
+Version 1.49.0 (2020-12-31)
+============================
+
+Language
+-----------------------
+
+- [Unions can now implement `Drop`, and you can now have a field in a union
+  with `ManuallyDrop<T>`.][77547]
+- [You can now cast uninhabited enums to integers.][76199]
+- [You can now bind by reference and by move in patterns.][76119] This
+  allows you to selectively borrow individual components of a type. E.g.
+  ```rust
+  #[derive(Debug)]
+  struct Person {
+      name: String,
+      age: u8,
+  }
+
+  let person = Person {
+      name: String::from("Alice"),
+      age: 20,
+  };
+
+  // `name` is moved out of person, but `age` is referenced.
+  let Person { name, ref age } = person;
+  println!("{} {}", name, age);
+  ```
+
+Compiler
+-----------------------
+
+- [Added tier 1\* support for `aarch64-unknown-linux-gnu`.][78228]
+- [Added tier 2 support for `aarch64-apple-darwin`.][75991]
+- [Added tier 2 support for `aarch64-pc-windows-msvc`.][75914]
+- [Added tier 3 support for `mipsel-unknown-none`.][78676]
+- [Raised the minimum supported LLVM version to LLVM 9.][78848]
+- [Output from threads spawned in tests is now captured.][78227]
+- [Change os and vendor values to "none" and "unknown" for some targets][78951]
+
+\* Refer to Rust's [platform support page][forge-platform-support] for more
+information on Rust's tiered platform support.
+
+Libraries
+-----------------------
+
+- [`RangeInclusive` now checks for exhaustion when calling `contains` and indexing.][78109]
+- [`ToString::to_string` now no longer shrinks the internal buffer in the default implementation.][77997]
+- [`ops::{Index, IndexMut}` are now implemented for fixed sized arrays of any length.][74989]
+
+Stabilized APIs
+---------------
+
+- [`slice::select_nth_unstable`]
+- [`slice::select_nth_unstable_by`]
+- [`slice::select_nth_unstable_by_key`]
+
+The following previously stable methods are now `const`.
+
+- [`Poll::is_ready`]
+- [`Poll::is_pending`]
+
+Cargo
+-----------------------
+- [Building a crate with `cargo-package` should now be independently reproducible.][cargo/8864]
+- [`cargo-tree` now marks proc-macro crates.][cargo/8765]
+- [Added `CARGO_PRIMARY_PACKAGE` build-time environment variable.][cargo/8758] This
+  variable will be set if the crate being built is one the user selected to build, either
+  with `-p` or through defaults.
+- [You can now use glob patterns when specifying packages & targets.][cargo/8752]
+
+
+Compatibility Notes
+-------------------
+
+- [Demoted `i686-unknown-freebsd` from host tier 2 to target tier 2 support.][78746]
+- [Macros that end with a semi-colon are now treated as statements even if they expand to nothing.][78376]
+- [Rustc will now check for the validity of some built-in attributes on enum variants.][77015]
+  Previously such invalid or unused attributes could be ignored.
+- Leading whitespace is stripped more uniformly in documentation comments, which may change behavior. You
+  read [this post about the changes][rustdoc-ws-post] for more details.
+- [Trait bounds are no longer inferred for associated types.][79904]
+
+Internal Only
+-------------
+These changes provide no direct user facing benefits, but represent significant
+improvements to the internals and overall performance of rustc and
+related tools.
+
+- [rustc's internal crates are now compiled using the `initial-exec` Thread
+  Local Storage model.][78201]
+- [Calculate visibilities once in resolve.][78077]
+- [Added `system` to the `llvm-libunwind` bootstrap config option.][77703]
+- [Added `--color` for configuring terminal color support to bootstrap.][79004]
+
+
+[75991]: https://github.com/rust-lang/rust/pull/75991
+[78951]: https://github.com/rust-lang/rust/pull/78951
+[78848]: https://github.com/rust-lang/rust/pull/78848
+[78746]: https://github.com/rust-lang/rust/pull/78746
+[78376]: https://github.com/rust-lang/rust/pull/78376
+[78228]: https://github.com/rust-lang/rust/pull/78228
+[78227]: https://github.com/rust-lang/rust/pull/78227
+[78201]: https://github.com/rust-lang/rust/pull/78201
+[78109]: https://github.com/rust-lang/rust/pull/78109
+[78077]: https://github.com/rust-lang/rust/pull/78077
+[77997]: https://github.com/rust-lang/rust/pull/77997
+[77703]: https://github.com/rust-lang/rust/pull/77703
+[77547]: https://github.com/rust-lang/rust/pull/77547
+[77015]: https://github.com/rust-lang/rust/pull/77015
+[76199]: https://github.com/rust-lang/rust/pull/76199
+[76119]: https://github.com/rust-lang/rust/pull/76119
+[75914]: https://github.com/rust-lang/rust/pull/75914
+[74989]: https://github.com/rust-lang/rust/pull/74989
+[79004]: https://github.com/rust-lang/rust/pull/79004
+[78676]: https://github.com/rust-lang/rust/pull/78676
+[79904]: https://github.com/rust-lang/rust/issues/79904
+[cargo/8864]: https://github.com/rust-lang/cargo/pull/8864
+[cargo/8765]: https://github.com/rust-lang/cargo/pull/8765
+[cargo/8758]: https://github.com/rust-lang/cargo/pull/8758
+[cargo/8752]: https://github.com/rust-lang/cargo/pull/8752
+[`slice::select_nth_unstable`]: https://doc.rust-lang.org/nightly/std/primitive.slice.html#method.select_nth_unstable
+[`slice::select_nth_unstable_by`]: https://doc.rust-lang.org/nightly/std/primitive.slice.html#method.select_nth_unstable_by
+[`slice::select_nth_unstable_by_key`]: https://doc.rust-lang.org/nightly/std/primitive.slice.html#method.select_nth_unstable_by_key
+[`hint::spin_loop`]: https://doc.rust-lang.org/stable/std/hint/fn.spin_loop.html
+[`Poll::is_ready`]: https://doc.rust-lang.org/stable/std/task/enum.Poll.html#method.is_ready
+[`Poll::is_pending`]: https://doc.rust-lang.org/stable/std/task/enum.Poll.html#method.is_pending
+[rustdoc-ws-post]: https://blog.guillaume-gomez.fr/articles/2020-11-11+New+doc+comment+handling+in+rustdoc
+
 Version 1.48.0 (2020-11-19)
 ==========================
 
@@ -10,7 +138,7 @@ Language
 Compiler
 --------
 - [Stabilised the `-C link-self-contained=<yes|no>` compiler flag.][76158] This tells
-  `rustc` whether to link its own C runtime and libraries or to rely on a external 
+  `rustc` whether to link its own C runtime and libraries or to rely on a external
   linker to find them. (Supported only on `windows-gnu`, `linux-musl`, and `wasi` platforms.)
 - [You can now use `-C target-feature=+crt-static` on `linux-gnu` targets.][77386]
   Note: If you're using cargo you must explicitly pass the `--target` flag.
@@ -82,7 +210,7 @@ Compatibility Notes
 - [Foreign exceptions are now caught by `catch_unwind` and will cause an abort.][70212]
   Note: This behaviour is not guaranteed and is still considered undefined behaviour,
   see the [`catch_unwind`] documentation for further information.
-  
+
 
 
 Internal Only
@@ -102,7 +230,7 @@ related tools.
 [76030]: https://github.com/rust-lang/rust/pull/76030/
 [70212]: https://github.com/rust-lang/rust/pull/70212/
 [27675]: https://github.com/rust-lang/rust/issues/27675/
-[54121]: https://github.com/rust-lang/rust/issues/54121/  
+[54121]: https://github.com/rust-lang/rust/issues/54121/
 [71274]: https://github.com/rust-lang/rust/pull/71274/
 [77386]: https://github.com/rust-lang/rust/pull/77386/
 [77153]: https://github.com/rust-lang/rust/pull/77153/
index f468bad635a9baca66df23ecf507e3a409d783da..a0493056b816b8c8df0e6db135a0e6e2a3d45483 100644 (file)
@@ -16,7 +16,7 @@
 #![feature(new_uninit)]
 #![feature(maybe_uninit_slice)]
 #![feature(array_value_iter)]
-#![feature(min_const_generics)]
+#![cfg_attr(bootstrap, feature(min_const_generics))]
 #![feature(min_specialization)]
 #![cfg_attr(test, feature(test))]
 
index 220bbed7e78b639eaf75fd6d8e4451603bd6b522..cf31e566c384e1c5d52c68c909d7c52b311b5fe4 100644 (file)
@@ -167,10 +167,7 @@ pub enum GenericArgs {
 
 impl GenericArgs {
     pub fn is_angle_bracketed(&self) -> bool {
-        match *self {
-            AngleBracketed(..) => true,
-            _ => false,
-        }
+        matches!(self, AngleBracketed(..))
     }
 
     pub fn span(&self) -> Span {
@@ -629,23 +626,20 @@ pub fn walk(&self, it: &mut impl FnMut(&Pat) -> bool) {
 
     /// Is this a `..` pattern?
     pub fn is_rest(&self) -> bool {
-        match self.kind {
-            PatKind::Rest => true,
-            _ => false,
-        }
+        matches!(self.kind, PatKind::Rest)
     }
 }
 
-/// A single field in a struct pattern
+/// A single field in a struct pattern.
 ///
-/// Patterns like the fields of Foo `{ x, ref y, ref mut z }`
-/// are treated the same asx: x, y: ref y, z: ref mut z`,
-/// except is_shorthand is true
+/// Patterns like the fields of `Foo { x, ref y, ref mut z }`
+/// are treated the same as `x: x, y: ref y, z: ref mut z`,
+/// except when `is_shorthand` is true.
 #[derive(Clone, Encodable, Decodable, Debug)]
 pub struct FieldPat {
-    /// The identifier for the field
+    /// The identifier for the field.
     pub ident: Ident,
-    /// The pattern the field is destructured to
+    /// The pattern the field is destructured to.
     pub pat: P<Pat>,
     pub is_shorthand: bool,
     pub attrs: AttrVec,
@@ -852,10 +846,7 @@ pub fn to_string(&self) -> &'static str {
         }
     }
     pub fn lazy(&self) -> bool {
-        match *self {
-            BinOpKind::And | BinOpKind::Or => true,
-            _ => false,
-        }
+        matches!(self, BinOpKind::And | BinOpKind::Or)
     }
 
     pub fn is_comparison(&self) -> bool {
@@ -963,17 +954,11 @@ pub fn add_trailing_semicolon(mut self) -> Self {
     }
 
     pub fn is_item(&self) -> bool {
-        match self.kind {
-            StmtKind::Item(_) => true,
-            _ => false,
-        }
+        matches!(self.kind, StmtKind::Item(_))
     }
 
     pub fn is_expr(&self) -> bool {
-        match self.kind {
-            StmtKind::Expr(_) => true,
-            _ => false,
-        }
+        matches!(self.kind, StmtKind::Expr(_))
     }
 }
 
@@ -1107,15 +1092,9 @@ pub fn returns(&self) -> bool {
         if let ExprKind::Block(ref block, _) = self.kind {
             match block.stmts.last().map(|last_stmt| &last_stmt.kind) {
                 // Implicit return
-                Some(&StmtKind::Expr(_)) => true,
-                Some(&StmtKind::Semi(ref expr)) => {
-                    if let ExprKind::Ret(_) = expr.kind {
-                        // Last statement is explicit return.
-                        true
-                    } else {
-                        false
-                    }
-                }
+                Some(StmtKind::Expr(_)) => true,
+                // Last statement is an explicit return?
+                Some(StmtKind::Semi(expr)) => matches!(expr.kind, ExprKind::Ret(_)),
                 // This is a block that doesn't end in either an implicit or explicit return.
                 _ => false,
             }
@@ -1128,7 +1107,7 @@ pub fn returns(&self) -> bool {
     /// Is this expr either `N`, or `{ N }`.
     ///
     /// If this is not the case, name resolution does not resolve `N` when using
-    /// `feature(min_const_generics)` as more complex expressions are not supported.
+    /// `min_const_generics` as more complex expressions are not supported.
     pub fn is_potential_trivial_const_param(&self) -> bool {
         let this = if let ExprKind::Block(ref block, None) = self.kind {
             if block.stmts.len() == 1 {
@@ -1652,26 +1631,17 @@ pub enum LitKind {
 impl LitKind {
     /// Returns `true` if this literal is a string.
     pub fn is_str(&self) -> bool {
-        match *self {
-            LitKind::Str(..) => true,
-            _ => false,
-        }
+        matches!(self, LitKind::Str(..))
     }
 
     /// Returns `true` if this literal is byte literal string.
     pub fn is_bytestr(&self) -> bool {
-        match self {
-            LitKind::ByteStr(_) => true,
-            _ => false,
-        }
+        matches!(self, LitKind::ByteStr(_))
     }
 
     /// Returns `true` if this is a numeric literal.
     pub fn is_numeric(&self) -> bool {
-        match *self {
-            LitKind::Int(..) | LitKind::Float(..) => true,
-            _ => false,
-        }
+        matches!(self, LitKind::Int(..) | LitKind::Float(..))
     }
 
     /// Returns `true` if this literal has no suffix.
@@ -1974,7 +1944,7 @@ pub fn is_implicit_self(&self) -> bool {
     }
 
     pub fn is_unit(&self) -> bool {
-        if let TyKind::Tup(ref tys) = *self { tys.is_empty() } else { false }
+        matches!(self, TyKind::Tup(tys) if tys.is_empty())
     }
 }
 
@@ -2237,10 +2207,7 @@ pub fn has_self(&self) -> bool {
         self.inputs.get(0).map_or(false, Param::is_self)
     }
     pub fn c_variadic(&self) -> bool {
-        self.inputs.last().map_or(false, |arg| match arg.ty.kind {
-            TyKind::CVarArgs => true,
-            _ => false,
-        })
+        self.inputs.last().map_or(false, |arg| matches!(arg.ty.kind, TyKind::CVarArgs))
     }
 }
 
index 19c7c479f0429b16c02d3a6390b640a46986e7ca..726ae5e51f7a668c3ccb5b45d2312ba9179295b2 100644 (file)
@@ -234,10 +234,7 @@ pub fn meta_item_list(&self) -> Option<&[NestedMetaItem]> {
     }
 
     pub fn is_word(&self) -> bool {
-        match self.kind {
-            MetaItemKind::Word => true,
-            _ => false,
-        }
+        matches!(self.kind, MetaItemKind::Word)
     }
 
     pub fn has_name(&self, name: Symbol) -> bool {
index a74464937c8b4cb503cbf4e1ede8ef316f8ef4f2..cd1e444bcf72a37f8888535a415c4f589935d922 100644 (file)
@@ -130,10 +130,7 @@ pub fn descr(self) -> &'static str {
     }
 
     crate fn may_have_suffix(self) -> bool {
-        match self {
-            Integer | Float | Err => true,
-            _ => false,
-        }
+        matches!(self, Integer | Float | Err)
     }
 }
 
@@ -305,10 +302,7 @@ pub fn similar_tokens(&self) -> Option<Vec<TokenKind>> {
     }
 
     pub fn should_end_const_arg(&self) -> bool {
-        match self {
-            Gt | Ge | BinOp(Shr) | BinOpEq(Shr) => true,
-            _ => false,
-        }
+        matches!(self, Gt | Ge | BinOp(Shr) | BinOpEq(Shr))
     }
 }
 
@@ -346,18 +340,21 @@ pub fn uninterpolated_span(&self) -> Span {
     }
 
     pub fn is_op(&self) -> bool {
-        match self.kind {
-            OpenDelim(..) | CloseDelim(..) | Literal(..) | DocComment(..) | Ident(..)
-            | Lifetime(..) | Interpolated(..) | Eof => false,
-            _ => true,
-        }
+        !matches!(
+            self.kind,
+            OpenDelim(..)
+                | CloseDelim(..)
+                | Literal(..)
+                | DocComment(..)
+                | Ident(..)
+                | Lifetime(..)
+                | Interpolated(..)
+                | Eof
+        )
     }
 
     pub fn is_like_plus(&self) -> bool {
-        match self.kind {
-            BinOp(Plus) | BinOpEq(Plus) => true,
-            _ => false,
-        }
+        matches!(self.kind, BinOp(Plus) | BinOpEq(Plus))
     }
 
     /// Returns `true` if the token can appear at the start of an expression.
@@ -379,13 +376,10 @@ pub fn can_begin_expr(&self) -> bool {
             ModSep                            | // global path
             Lifetime(..)                      | // labeled loop
             Pound                             => true, // expression attributes
-            Interpolated(ref nt) => match **nt {
-                NtLiteral(..) |
+            Interpolated(ref nt) => matches!(**nt, NtLiteral(..) |
                 NtExpr(..)    |
                 NtBlock(..)   |
-                NtPath(..) => true,
-                _ => false,
-            },
+                NtPath(..)),
             _ => false,
         }
     }
@@ -405,10 +399,7 @@ pub fn can_begin_type(&self) -> bool {
             Lifetime(..)                | // lifetime bound in trait object
             Lt | BinOp(Shl)             | // associated path
             ModSep                      => true, // global path
-            Interpolated(ref nt) => match **nt {
-                NtTy(..) | NtPath(..) => true,
-                _ => false,
-            },
+            Interpolated(ref nt) => matches!(**nt, NtTy(..) | NtPath(..)),
             _ => false,
         }
     }
@@ -417,10 +408,7 @@ pub fn can_begin_type(&self) -> bool {
     pub fn can_begin_const_arg(&self) -> bool {
         match self.kind {
             OpenDelim(Brace) => true,
-            Interpolated(ref nt) => match **nt {
-                NtExpr(..) | NtBlock(..) | NtLiteral(..) => true,
-                _ => false,
-            },
+            Interpolated(ref nt) => matches!(**nt, NtExpr(..) | NtBlock(..) | NtLiteral(..)),
             _ => self.can_begin_literal_maybe_minus(),
         }
     }
@@ -436,10 +424,7 @@ pub fn can_begin_bound(&self) -> bool {
 
     /// Returns `true` if the token is any literal.
     pub fn is_lit(&self) -> bool {
-        match self.kind {
-            Literal(..) => true,
-            _ => false,
-        }
+        matches!(self.kind, Literal(..))
     }
 
     /// Returns `true` if the token is any literal, a minus (which can prefix a literal,
index b2207f22816205f0c11dc16fa5ae7c21da3a65aa..0550f53a96fb3838918925dbce66390109035a69 100644 (file)
@@ -44,6 +44,12 @@ pub enum TokenTree {
     Delimited(DelimSpan, DelimToken, TokenStream),
 }
 
+#[derive(Copy, Clone)]
+pub enum CanSynthesizeMissingTokens {
+    Yes,
+    No,
+}
+
 // Ensure all fields of `TokenTree` is `Send` and `Sync`.
 #[cfg(parallel_compiler)]
 fn _dummy()
index 60422a2e573925033b2418f6b3b6cb8d7e59981f..90786520fe8025d5db38773f921d704e7fa80221 100644 (file)
 ///      |x| 5
 /// isn't parsed as (if true {...} else {...} | x) | 5
 pub fn expr_requires_semi_to_be_stmt(e: &ast::Expr) -> bool {
-    match e.kind {
+    !matches!(
+        e.kind,
         ast::ExprKind::If(..)
-        | ast::ExprKind::Match(..)
-        | ast::ExprKind::Block(..)
-        | ast::ExprKind::While(..)
-        | ast::ExprKind::Loop(..)
-        | ast::ExprKind::ForLoop(..)
-        | ast::ExprKind::TryBlock(..) => false,
-        _ => true,
-    }
+            | ast::ExprKind::Match(..)
+            | ast::ExprKind::Block(..)
+            | ast::ExprKind::While(..)
+            | ast::ExprKind::Loop(..)
+            | ast::ExprKind::ForLoop(..)
+            | ast::ExprKind::TryBlock(..)
+    )
 }
index e97c8cc4562f63d17182c28c56dc1375c577d912..542a330a031414f469f52a256793b93c311f1fc7 100644 (file)
@@ -25,9 +25,8 @@ pub struct Comment {
 
 /// Makes a doc string more presentable to users.
 /// Used by rustdoc and perhaps other tools, but not by rustc.
-pub fn beautify_doc_string(data: Symbol) -> String {
-    /// remove whitespace-only lines from the start/end of lines
-    fn vertical_trim(lines: Vec<String>) -> Vec<String> {
+pub fn beautify_doc_string(data: Symbol) -> Symbol {
+    fn get_vertical_trim(lines: &[&str]) -> Option<(usize, usize)> {
         let mut i = 0;
         let mut j = lines.len();
         // first line of all-stars should be omitted
@@ -47,55 +46,58 @@ fn vertical_trim(lines: Vec<String>) -> Vec<String> {
             j -= 1;
         }
 
-        lines[i..j].to_vec()
+        if i != 0 || j != lines.len() { Some((i, j)) } else { None }
     }
 
-    /// remove a "[ \t]*\*" block from each line, if possible
-    fn horizontal_trim(lines: Vec<String>) -> Vec<String> {
+    fn get_horizontal_trim(lines: &[&str]) -> Option<usize> {
         let mut i = usize::MAX;
-        let mut can_trim = true;
         let mut first = true;
 
-        for line in &lines {
+        for line in lines {
             for (j, c) in line.chars().enumerate() {
                 if j > i || !"* \t".contains(c) {
-                    can_trim = false;
-                    break;
+                    return None;
                 }
                 if c == '*' {
                     if first {
                         i = j;
                         first = false;
                     } else if i != j {
-                        can_trim = false;
+                        return None;
                     }
                     break;
                 }
             }
             if i >= line.len() {
-                can_trim = false;
-            }
-            if !can_trim {
-                break;
+                return None;
             }
         }
+        Some(i)
+    }
 
-        if can_trim {
-            lines.iter().map(|line| (&line[i + 1..line.len()]).to_string()).collect()
+    let data_s = data.as_str();
+    if data_s.contains('\n') {
+        let mut lines = data_s.lines().collect::<Vec<&str>>();
+        let mut changes = false;
+        let lines = if let Some((i, j)) = get_vertical_trim(&lines) {
+            changes = true;
+            // remove whitespace-only lines from the start/end of lines
+            &mut lines[i..j]
         } else {
-            lines
+            &mut lines
+        };
+        if let Some(horizontal) = get_horizontal_trim(&lines) {
+            changes = true;
+            // remove a "[ \t]*\*" block from each line, if possible
+            for line in lines.iter_mut() {
+                *line = &line[horizontal + 1..];
+            }
+        }
+        if changes {
+            return Symbol::intern(&lines.join("\n"));
         }
     }
-
-    let data = data.as_str();
-    if data.contains('\n') {
-        let lines = data.lines().map(|s| s.to_string()).collect::<Vec<String>>();
-        let lines = vertical_trim(lines);
-        let lines = horizontal_trim(lines);
-        lines.join("\n")
-    } else {
-        data.to_string()
-    }
+    data
 }
 
 /// Returns `None` if the first `col` chars of `s` contain a non-whitespace char.
@@ -178,10 +180,8 @@ pub fn gather_comments(sm: &SourceMap, path: FileName, src: String) -> Vec<Comme
             }
             rustc_lexer::TokenKind::BlockComment { doc_style, .. } => {
                 if doc_style.is_none() {
-                    let code_to_the_right = match text[pos + token.len..].chars().next() {
-                        Some('\r' | '\n') => false,
-                        _ => true,
-                    };
+                    let code_to_the_right =
+                        !matches!(text[pos + token.len..].chars().next(), Some('\r' | '\n'));
                     let style = match (code_to_the_left, code_to_the_right) {
                         (_, true) => CommentStyle::Mixed,
                         (false, false) => CommentStyle::Isolated,
index e19198f863ba830cc5ab9b1a9f83c7dd1feb2be4..98ab653e45f70e740da4226366cd194676986d14 100644 (file)
@@ -6,7 +6,7 @@ fn test_block_doc_comment_1() {
     with_default_session_globals(|| {
         let comment = "\n * Test \n **  Test\n *   Test\n";
         let stripped = beautify_doc_string(Symbol::intern(comment));
-        assert_eq!(stripped, " Test \n*  Test\n   Test");
+        assert_eq!(stripped.as_str(), " Test \n*  Test\n   Test");
     })
 }
 
@@ -15,7 +15,7 @@ fn test_block_doc_comment_2() {
     with_default_session_globals(|| {
         let comment = "\n * Test\n *  Test\n";
         let stripped = beautify_doc_string(Symbol::intern(comment));
-        assert_eq!(stripped, " Test\n  Test");
+        assert_eq!(stripped.as_str(), " Test\n  Test");
     })
 }
 
@@ -24,7 +24,7 @@ fn test_block_doc_comment_3() {
     with_default_session_globals(|| {
         let comment = "\n let a: *i32;\n *a = 5;\n";
         let stripped = beautify_doc_string(Symbol::intern(comment));
-        assert_eq!(stripped, " let a: *i32;\n *a = 5;");
+        assert_eq!(stripped.as_str(), " let a: *i32;\n *a = 5;");
     })
 }
 
@@ -32,12 +32,12 @@ fn test_block_doc_comment_3() {
 fn test_line_doc_comment() {
     with_default_session_globals(|| {
         let stripped = beautify_doc_string(Symbol::intern(" test"));
-        assert_eq!(stripped, " test");
+        assert_eq!(stripped.as_str(), " test");
         let stripped = beautify_doc_string(Symbol::intern("! test"));
-        assert_eq!(stripped, "! test");
+        assert_eq!(stripped.as_str(), "! test");
         let stripped = beautify_doc_string(Symbol::intern("test"));
-        assert_eq!(stripped, "test");
+        assert_eq!(stripped.as_str(), "test");
         let stripped = beautify_doc_string(Symbol::intern("!test"));
-        assert_eq!(stripped, "!test");
+        assert_eq!(stripped.as_str(), "!test");
     })
 }
index 2e1b5a74a7b7e03f4fd280a321d5afed3844437f..d17b29089d6949832278459f0979c76a8ba0ac64 100644 (file)
@@ -37,7 +37,7 @@
 
 use rustc_ast::node_id::NodeMap;
 use rustc_ast::token::{self, DelimToken, Nonterminal, Token};
-use rustc_ast::tokenstream::{DelimSpan, TokenStream, TokenTree};
+use rustc_ast::tokenstream::{CanSynthesizeMissingTokens, DelimSpan, TokenStream, TokenTree};
 use rustc_ast::visit::{self, AssocCtxt, Visitor};
 use rustc_ast::walk_list;
 use rustc_ast::{self as ast, *};
@@ -206,7 +206,8 @@ fn create_def(
     ) -> LocalDefId;
 }
 
-type NtToTokenstream = fn(&Nonterminal, &ParseSess, Span) -> TokenStream;
+type NtToTokenstream =
+    fn(&Nonterminal, &ParseSess, Span, CanSynthesizeMissingTokens) -> TokenStream;
 
 /// Context of `impl Trait` in code, which determines whether it is allowed in an HIR subtree,
 /// and if so, what meaning it has.
@@ -393,6 +394,47 @@ enum AnonymousLifetimeMode {
     PassThrough,
 }
 
+struct TokenStreamLowering<'a> {
+    parse_sess: &'a ParseSess,
+    synthesize_tokens: CanSynthesizeMissingTokens,
+    nt_to_tokenstream: NtToTokenstream,
+}
+
+impl<'a> TokenStreamLowering<'a> {
+    fn lower_token_stream(&mut self, tokens: TokenStream) -> TokenStream {
+        tokens.into_trees().flat_map(|tree| self.lower_token_tree(tree).into_trees()).collect()
+    }
+
+    fn lower_token_tree(&mut self, tree: TokenTree) -> TokenStream {
+        match tree {
+            TokenTree::Token(token) => self.lower_token(token),
+            TokenTree::Delimited(span, delim, tts) => {
+                TokenTree::Delimited(span, delim, self.lower_token_stream(tts)).into()
+            }
+        }
+    }
+
+    fn lower_token(&mut self, token: Token) -> TokenStream {
+        match token.kind {
+            token::Interpolated(nt) => {
+                let tts = (self.nt_to_tokenstream)(
+                    &nt,
+                    self.parse_sess,
+                    token.span,
+                    self.synthesize_tokens,
+                );
+                TokenTree::Delimited(
+                    DelimSpan::from_single(token.span),
+                    DelimToken::NoDelim,
+                    self.lower_token_stream(tts),
+                )
+                .into()
+            }
+            _ => TokenTree::Token(token).into(),
+        }
+    }
+}
+
 struct ImplTraitTypeIdVisitor<'a> {
     ids: &'a mut SmallVec<[NodeId; 1]>,
 }
@@ -955,40 +997,49 @@ fn lower_mac_args(&mut self, args: &MacArgs) -> MacArgs {
         match *args {
             MacArgs::Empty => MacArgs::Empty,
             MacArgs::Delimited(dspan, delim, ref tokens) => {
-                MacArgs::Delimited(dspan, delim, self.lower_token_stream(tokens.clone()))
-            }
-            MacArgs::Eq(eq_span, ref tokens) => {
-                MacArgs::Eq(eq_span, self.lower_token_stream(tokens.clone()))
-            }
-        }
-    }
-
-    fn lower_token_stream(&mut self, tokens: TokenStream) -> TokenStream {
-        tokens.into_trees().flat_map(|tree| self.lower_token_tree(tree).into_trees()).collect()
-    }
-
-    fn lower_token_tree(&mut self, tree: TokenTree) -> TokenStream {
-        match tree {
-            TokenTree::Token(token) => self.lower_token(token),
-            TokenTree::Delimited(span, delim, tts) => {
-                TokenTree::Delimited(span, delim, self.lower_token_stream(tts)).into()
+                // This is either a non-key-value attribute, or a `macro_rules!` body.
+                // We either not have any nonterminals present (in the case of an attribute),
+                // or have tokens available for all nonterminals in the case of a nested
+                // `macro_rules`: e.g:
+                //
+                // ```rust
+                // macro_rules! outer {
+                //     ($e:expr) => {
+                //         macro_rules! inner {
+                //             () => { $e }
+                //         }
+                //     }
+                // }
+                // ```
+                //
+                // In both cases, we don't want to synthesize any tokens
+                MacArgs::Delimited(
+                    dspan,
+                    delim,
+                    self.lower_token_stream(tokens.clone(), CanSynthesizeMissingTokens::No),
+                )
             }
+            // This is an inert key-value attribute - it will never be visible to macros
+            // after it gets lowered to HIR. Therefore, we can synthesize tokens with fake
+            // spans to handle nonterminals in `#[doc]` (e.g. `#[doc = $e]`).
+            MacArgs::Eq(eq_span, ref tokens) => MacArgs::Eq(
+                eq_span,
+                self.lower_token_stream(tokens.clone(), CanSynthesizeMissingTokens::Yes),
+            ),
         }
     }
 
-    fn lower_token(&mut self, token: Token) -> TokenStream {
-        match token.kind {
-            token::Interpolated(nt) => {
-                let tts = (self.nt_to_tokenstream)(&nt, &self.sess.parse_sess, token.span);
-                TokenTree::Delimited(
-                    DelimSpan::from_single(token.span),
-                    DelimToken::NoDelim,
-                    self.lower_token_stream(tts),
-                )
-                .into()
-            }
-            _ => TokenTree::Token(token).into(),
+    fn lower_token_stream(
+        &self,
+        tokens: TokenStream,
+        synthesize_tokens: CanSynthesizeMissingTokens,
+    ) -> TokenStream {
+        TokenStreamLowering {
+            parse_sess: &self.sess.parse_sess,
+            synthesize_tokens,
+            nt_to_tokenstream: self.nt_to_tokenstream,
         }
+        .lower_token_stream(tokens)
     }
 
     /// Given an associated type constraint like one of these:
@@ -1716,7 +1767,7 @@ fn lower_fn_params_to_names(&mut self, decl: &FnDecl) -> &'hir [Ident] {
         }
         self.arena.alloc_from_iter(inputs.iter().map(|param| match param.pat.kind {
             PatKind::Ident(_, ident, _) => ident,
-            _ => Ident::new(kw::Invalid, param.pat.span),
+            _ => Ident::new(kw::Empty, param.pat.span),
         }))
     }
 
@@ -1806,12 +1857,11 @@ fn lower_fn_decl(
             output,
             c_variadic,
             implicit_self: decl.inputs.get(0).map_or(hir::ImplicitSelfKind::None, |arg| {
-                let is_mutable_pat = match arg.pat.kind {
-                    PatKind::Ident(BindingMode::ByValue(mt) | BindingMode::ByRef(mt), _, _) => {
-                        mt == Mutability::Mut
-                    }
-                    _ => false,
-                };
+                use BindingMode::{ByRef, ByValue};
+                let is_mutable_pat = matches!(
+                    arg.pat.kind,
+                    PatKind::Ident(ByValue(Mutability::Mut) | ByRef(Mutability::Mut), ..)
+                );
 
                 match arg.ty.kind {
                     TyKind::ImplicitSelf if is_mutable_pat => hir::ImplicitSelfKind::Mut,
index bf6d332217613e36e799a0ec54febb072785ea43..f9eb69bb438156d63b47f3282336562ae46d6ee3 100644 (file)
@@ -184,7 +184,7 @@ fn err_handler(&self) -> &rustc_errors::Handler {
     }
 
     fn check_lifetime(&self, ident: Ident) {
-        let valid_names = [kw::UnderscoreLifetime, kw::StaticLifetime, kw::Invalid];
+        let valid_names = [kw::UnderscoreLifetime, kw::StaticLifetime, kw::Empty];
         if !valid_names.contains(&ident.name) && ident.without_first_quote().is_reserved() {
             self.err_handler().span_err(ident.span, "lifetimes cannot use keyword names");
         }
@@ -773,14 +773,12 @@ fn validate_generic_param_order<'a>(
         err.span_suggestion(
             span,
             &format!(
-                "reorder the parameters: lifetimes{}",
+                "reorder the parameters: lifetimes{}",
                 if sess.features_untracked().const_generics {
-                    ", then consts and types"
-                } else if sess.features_untracked().min_const_generics {
-                    ", then types, then consts"
+                    "then consts and types"
                 } else {
-                    ", then types"
-                },
+                    "then types, then consts"
+                }
             ),
             ordered_params.clone(),
             Applicability::MachineApplicable,
index bb222675239aa82c524bdcc8a3410f5287846645..6a9d6d2ed121eabad7d4405414c866b44a65e449 100644 (file)
@@ -1,7 +1,7 @@
 use rustc_ast as ast;
 use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
 use rustc_ast::{AssocTyConstraint, AssocTyConstraintKind, NodeId};
-use rustc_ast::{GenericParam, GenericParamKind, PatKind, RangeEnd, VariantData};
+use rustc_ast::{PatKind, RangeEnd, VariantData};
 use rustc_errors::struct_span_err;
 use rustc_feature::{AttributeGate, BUILTIN_ATTRIBUTE_MAP};
 use rustc_feature::{Features, GateIssue};
@@ -397,10 +397,8 @@ fn visit_foreign_item(&mut self, i: &'a ast::ForeignItem) {
         match i.kind {
             ast::ForeignItemKind::Fn(..) | ast::ForeignItemKind::Static(..) => {
                 let link_name = self.sess.first_attr_value_str_by_name(&i.attrs, sym::link_name);
-                let links_to_llvm = match link_name {
-                    Some(val) => val.as_str().starts_with("llvm."),
-                    _ => false,
-                };
+                let links_to_llvm =
+                    link_name.map_or(false, |val| val.as_str().starts_with("llvm."));
                 if links_to_llvm {
                     gate_feature_post!(
                         &self,
@@ -529,19 +527,6 @@ fn visit_fn(&mut self, fn_kind: FnKind<'a>, span: Span, _: NodeId) {
         visit::walk_fn(self, fn_kind, span)
     }
 
-    fn visit_generic_param(&mut self, param: &'a GenericParam) {
-        if let GenericParamKind::Const { .. } = param.kind {
-            gate_feature_fn!(
-                &self,
-                |x: &Features| x.const_generics || x.min_const_generics,
-                param.ident.span,
-                sym::min_const_generics,
-                "const generics are unstable"
-            );
-        }
-        visit::walk_generic_param(self, param)
-    }
-
     fn visit_assoc_ty_constraint(&mut self, constraint: &'a AssocTyConstraint) {
         if let AssocTyConstraintKind::Bound { .. } = constraint.kind {
             gate_feature_post!(
index 56e769ba6b71014c5c8f21241ba8dc35d860e074..ea298d28e72c6a983bc7409067d6273c635fbfca 100644 (file)
@@ -75,7 +75,7 @@
 //! breaking inconsistently to become
 //!
 //! ```
-//! foo(hello, there
+//! foo(hello, there,
 //!     good, friends);
 //! ```
 //!
@@ -83,7 +83,7 @@
 //!
 //! ```
 //! foo(hello,
-//!     there
+//!     there,
 //!     good,
 //!     friends);
 //! ```
index dcb6e115eda052873aca3fed5bec9b218d3787b0..333a396a0b4fc694e9dfd07482e8807fe7eb09f0 100644 (file)
@@ -2787,7 +2787,7 @@ pub fn print_mutability(&mut self, mutbl: ast::Mutability, print_const: bool) {
                     self.print_explicit_self(&eself);
                 } else {
                     let invalid = if let PatKind::Ident(_, ident, _) = input.pat.kind {
-                        ident.name == kw::Invalid
+                        ident.name == kw::Empty
                     } else {
                         false
                     };
index 957c8035399a2da862309d05c41ed00ae89a9730..ca1226b445d97beb94301349c1544660ea72cc1e 100644 (file)
@@ -38,10 +38,9 @@ pub fn expand_deriving_clone(
             | ItemKind::Enum(_, Generics { ref params, .. }) => {
                 let container_id = cx.current_expansion.id.expn_data().parent;
                 if cx.resolver.has_derive_copy(container_id)
-                    && !params.iter().any(|param| match param.kind {
-                        ast::GenericParamKind::Type { .. } => true,
-                        _ => false,
-                    })
+                    && !params
+                        .iter()
+                        .any(|param| matches!(param.kind, ast::GenericParamKind::Type { .. }))
                 {
                     bounds = vec![];
                     is_shallow = true;
index 68c11868af8885e65c8dc16af5fd04f7d07b113d..e78d1368b357e5f0b1ff89fc34d9b71fc92bbea0 100644 (file)
@@ -257,7 +257,10 @@ pub struct Substructure<'a> {
     pub type_ident: Ident,
     /// ident of the method
     pub method_ident: Ident,
-    /// dereferenced access to any `Self_` or `Ptr(Self_, _)` arguments
+    /// dereferenced access to any [`Self_`] or [`Ptr(Self_, _)][ptr]` arguments
+    ///
+    /// [`Self_`]: ty::Ty::Self_
+    /// [ptr]: ty::Ty::Ptr
     pub self_args: &'a [P<Expr>],
     /// verbatim access to any other arguments
     pub nonself_args: &'a [P<Expr>],
@@ -401,12 +404,10 @@ pub fn expand_ext(
                 let has_no_type_params = match item.kind {
                     ast::ItemKind::Struct(_, ref generics)
                     | ast::ItemKind::Enum(_, ref generics)
-                    | ast::ItemKind::Union(_, ref generics) => {
-                        !generics.params.iter().any(|param| match param.kind {
-                            ast::GenericParamKind::Type { .. } => true,
-                            _ => false,
-                        })
-                    }
+                    | ast::ItemKind::Union(_, ref generics) => !generics
+                        .params
+                        .iter()
+                        .any(|param| matches!(param.kind, ast::GenericParamKind::Type { .. })),
                     _ => unreachable!(),
                 };
                 let container_id = cx.current_expansion.id.expn_data().parent;
@@ -865,7 +866,7 @@ fn split_self_nonself_args(
                 Self_ if nonstatic => {
                     self_args.push(arg_expr);
                 }
-                Ptr(ref ty, _) if (if let Self_ = **ty { true } else { false }) && nonstatic => {
+                Ptr(ref ty, _) if matches!(**ty, Self_) && nonstatic => {
                     self_args.push(cx.expr_deref(trait_.span, arg_expr))
                 }
                 _ => {
index 550524e652af7eb20327b5ac4b17503cea1552d4..85ca1da6f1daa1a9eba11b5895de321657135a27 100644 (file)
@@ -1044,10 +1044,7 @@ pub fn expand_preparsed_format_args(
 
     let numbered_position_args = pieces.iter().any(|arg: &parse::Piece<'_>| match *arg {
         parse::String(_) => false,
-        parse::NextArgument(arg) => match arg.position {
-            parse::Position::ArgumentIs(_) => true,
-            _ => false,
-        },
+        parse::NextArgument(arg) => matches!(arg.position, parse::Position::ArgumentIs(_)),
     });
 
     cx.build_index_map();
index f00dfd1241fbbb6287ac8b91121874128deecc32..0496c72cb0050dfd6816e34928b256a89155612d 100644 (file)
@@ -580,10 +580,7 @@ fn at_next_cp_while<F>(mut cur: Cur<'_>, mut pred: F) -> Cur<'_>
     }
 
     fn is_flag(c: &char) -> bool {
-        match c {
-            '0' | '-' | '+' | ' ' | '#' | '\'' => true,
-            _ => false,
-        }
+        matches!(c, '0' | '-' | '+' | ' ' | '#' | '\'')
     }
 
     #[cfg(test)]
index db73fdbe24ff580b5b199711fc11c3663e56f9dc..d72bfa660e58f855725ff145087abd63b2181af3 100644 (file)
@@ -87,13 +87,15 @@ fn parse_inline_asm<'a>(
     // parsed as `llvm_asm!(z)` with `z = "x": y` which is type ascription.
     let first_colon = tts
         .trees()
-        .position(|tt| match tt {
-            tokenstream::TokenTree::Token(Token { kind: token::Colon | token::ModSep, .. }) => true,
-            _ => false,
+        .position(|tt| {
+            matches!(
+                tt,
+                tokenstream::TokenTree::Token(Token { kind: token::Colon | token::ModSep, .. })
+            )
         })
         .unwrap_or(tts.len());
     let mut p = cx.new_parser_from_tts(tts.trees().skip(first_colon).collect());
-    let mut asm = kw::Invalid;
+    let mut asm = kw::Empty;
     let mut asm_str_style = None;
     let mut outputs = Vec::new();
     let mut inputs = Vec::new();
index 4e91436199a53f6faad6413ab6392c545961d7b6..7582d9805390ec24295c9792a35c76bb3c0f4797 100644 (file)
@@ -256,10 +256,7 @@ fn visit_item(&mut self, item: &'a ast::Item) {
         // we're just not interested in this item.
         //
         // If we find one, try to locate a `#[proc_macro_derive]` attribute on it.
-        let is_fn = match item.kind {
-            ast::ItemKind::Fn(..) => true,
-            _ => false,
-        };
+        let is_fn = matches!(item.kind, ast::ItemKind::Fn(..));
 
         let mut found_attr: Option<&'a ast::Attribute> = None;
 
index 04ab5085c196c3f924e295cf4cf46be6386cc223..7618251acd5c26ae8972288cd292ed4afbe3cf89 100644 (file)
@@ -1,6 +1,7 @@
 {
     // source for rustc_* is not included in the rust-src component; disable the errors about this
     "rust-analyzer.diagnostics.disabled": ["unresolved-extern-crate"],
+    "rust-analyzer.assist.importMergeBehaviour": "last",
     "rust-analyzer.cargo.loadOutDirsFromCheck": true,
     "rust-analyzer.linkedProjects": [
         "./Cargo.toml",
index 67ed41e7652319f1b84975a1544ddf5f8d002bc2..0382835269d1fdef8cb38b6aeadd28282b885374 100644 (file)
@@ -50,7 +50,7 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 [[package]]
 name = "cranelift-bforest"
 version = "0.68.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#19640367dbf0da7093e61add3306c8d092644fb3"
+source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8f7f8ee0b4c5007ace6de29b45505c360450b1bb"
 dependencies = [
  "cranelift-entity",
 ]
@@ -58,7 +58,7 @@ dependencies = [
 [[package]]
 name = "cranelift-codegen"
 version = "0.68.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#19640367dbf0da7093e61add3306c8d092644fb3"
+source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8f7f8ee0b4c5007ace6de29b45505c360450b1bb"
 dependencies = [
  "byteorder",
  "cranelift-bforest",
@@ -76,7 +76,7 @@ dependencies = [
 [[package]]
 name = "cranelift-codegen-meta"
 version = "0.68.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#19640367dbf0da7093e61add3306c8d092644fb3"
+source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8f7f8ee0b4c5007ace6de29b45505c360450b1bb"
 dependencies = [
  "cranelift-codegen-shared",
  "cranelift-entity",
@@ -85,17 +85,17 @@ dependencies = [
 [[package]]
 name = "cranelift-codegen-shared"
 version = "0.68.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#19640367dbf0da7093e61add3306c8d092644fb3"
+source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8f7f8ee0b4c5007ace6de29b45505c360450b1bb"
 
 [[package]]
 name = "cranelift-entity"
 version = "0.68.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#19640367dbf0da7093e61add3306c8d092644fb3"
+source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8f7f8ee0b4c5007ace6de29b45505c360450b1bb"
 
 [[package]]
 name = "cranelift-frontend"
 version = "0.68.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#19640367dbf0da7093e61add3306c8d092644fb3"
+source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8f7f8ee0b4c5007ace6de29b45505c360450b1bb"
 dependencies = [
  "cranelift-codegen",
  "log",
@@ -103,10 +103,28 @@ dependencies = [
  "target-lexicon",
 ]
 
+[[package]]
+name = "cranelift-jit"
+version = "0.68.0"
+source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8f7f8ee0b4c5007ace6de29b45505c360450b1bb"
+dependencies = [
+ "anyhow",
+ "cranelift-codegen",
+ "cranelift-entity",
+ "cranelift-module",
+ "cranelift-native",
+ "errno",
+ "libc",
+ "log",
+ "region",
+ "target-lexicon",
+ "winapi",
+]
+
 [[package]]
 name = "cranelift-module"
 version = "0.68.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#19640367dbf0da7093e61add3306c8d092644fb3"
+source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8f7f8ee0b4c5007ace6de29b45505c360450b1bb"
 dependencies = [
  "anyhow",
  "cranelift-codegen",
@@ -118,7 +136,7 @@ dependencies = [
 [[package]]
 name = "cranelift-native"
 version = "0.68.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#19640367dbf0da7093e61add3306c8d092644fb3"
+source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8f7f8ee0b4c5007ace6de29b45505c360450b1bb"
 dependencies = [
  "cranelift-codegen",
  "raw-cpuid",
@@ -128,7 +146,7 @@ dependencies = [
 [[package]]
 name = "cranelift-object"
 version = "0.68.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#19640367dbf0da7093e61add3306c8d092644fb3"
+source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8f7f8ee0b4c5007ace6de29b45505c360450b1bb"
 dependencies = [
  "anyhow",
  "cranelift-codegen",
@@ -138,23 +156,6 @@ dependencies = [
  "target-lexicon",
 ]
 
-[[package]]
-name = "cranelift-simplejit"
-version = "0.68.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#19640367dbf0da7093e61add3306c8d092644fb3"
-dependencies = [
- "cranelift-codegen",
- "cranelift-entity",
- "cranelift-module",
- "cranelift-native",
- "errno",
- "libc",
- "log",
- "region",
- "target-lexicon",
- "winapi",
-]
-
 [[package]]
 name = "crc32fast"
 version = "1.2.1"
@@ -325,9 +326,9 @@ dependencies = [
  "ar",
  "cranelift-codegen",
  "cranelift-frontend",
+ "cranelift-jit",
  "cranelift-module",
  "cranelift-object",
- "cranelift-simplejit",
  "gimli",
  "indexmap",
  "libloading",
index cbff06749d3e93d51c1c1d8201be2a705b06cb8e..8e1933bb14e7c197fa8bb83050368c0187395c95 100644 (file)
@@ -12,7 +12,7 @@ crate-type = ["dylib"]
 cranelift-codegen = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main", features = ["unwind"] }
 cranelift-frontend = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main" }
 cranelift-module = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main" }
-cranelift-simplejit = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main", optional = true }
+cranelift-jit = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main", optional = true }
 cranelift-object = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main" }
 target-lexicon = "0.11.0"
 gimli = { version = "0.23.0", default-features = false, features = ["write"]}
@@ -27,7 +27,7 @@ libloading = { version = "0.6.0", optional = true }
 #cranelift-codegen = { path = "../wasmtime/cranelift/codegen" }
 #cranelift-frontend = { path = "../wasmtime/cranelift/frontend" }
 #cranelift-module = { path = "../wasmtime/cranelift/module" }
-#cranelift-simplejit = { path = "../wasmtime/cranelift/simplejit" }
+#cranelift-jit = { path = "../wasmtime/cranelift/jit" }
 #cranelift-object = { path = "../wasmtime/cranelift/object" }
 
 #[patch.crates-io]
@@ -35,7 +35,7 @@ libloading = { version = "0.6.0", optional = true }
 
 [features]
 default = ["jit", "inline_asm"]
-jit = ["cranelift-simplejit", "libloading"]
+jit = ["cranelift-jit", "libloading"]
 inline_asm = []
 
 [profile.dev]
index de54bf67f4a19b7208613335ef998e05c42cb361..22d9e00923f006f1711a5d6791fd8ac78ad9d827 100644 (file)
@@ -2,7 +2,7 @@
 
 > âš âš âš  Certain kinds of FFI don't work yet. âš âš âš 
 
-The goal of this project is to create an alternative codegen backend for the rust compiler based on [Cranelift](https://github.com/bytecodealliance/wasmtime/blob/master/cranelift).
+The goal of this project is to create an alternative codegen backend for the rust compiler based on [Cranelift](https://github.com/bytecodealliance/wasmtime/blob/main/cranelift).
 This has the potential to improve compilation times in debug mode.
 If your project doesn't use any of the things listed under "Not yet supported", it should work fine.
 If not please open an issue.
@@ -68,7 +68,15 @@ $ $cg_clif_dir/build/cargo.sh jit
 or
 
 ```bash
-$ $cg_clif_dir/build/bin/cg_clif --jit my_crate.rs
+$ $cg_clif_dir/build/bin/cg_clif -Cllvm-args=mode=jit -Cprefer-dynamic my_crate.rs
+```
+
+There is also an experimental lazy jit mode. In this mode functions are only compiled once they are
+first called. It currently does not work with multi-threaded programs. When a not yet compiled
+function is called from another thread than the main thread, you will get an ICE.
+
+```bash
+$ $cg_clif_dir/build/cargo.sh lazy-jit
 ```
 
 ### Shell
@@ -77,7 +85,7 @@ These are a few functions that allow you to easily run rust code from the shell
 
 ```bash
 function jit_naked() {
-    echo "$@" | $cg_clif_dir/build/bin/cg_clif - --jit
+    echo "$@" | $cg_clif_dir/build/bin/cg_clif - -Cllvm-args=mode=jit -Cprefer-dynamic
 }
 
 function jit() {
index a2b8f449f00ff06617abfcaef59d6a570a3e0ae4..990557694ead4a4282f943a825c31d23baff9e83 100644 (file)
@@ -47,9 +47,9 @@ checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
 
 [[package]]
 name = "cc"
-version = "1.0.65"
+version = "1.0.66"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "95752358c8f7552394baf48cd82695b345628ad3f170d607de3ca03b8dacca15"
+checksum = "4c0496836a84f8d0495758516b8621a622beb77c0fed418570e50764093ced48"
 
 [[package]]
 name = "cfg-if"
@@ -141,9 +141,9 @@ dependencies = [
 
 [[package]]
 name = "libc"
-version = "0.2.80"
+version = "0.2.81"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4d58d1b70b004888f764dfbf6a26a3b0342a1632d33968e4a179d8011c760614"
+checksum = "1482821306169ec4d07f6aca392a4681f66c75c9918aa49641a2595db64053cb"
 dependencies = [
  "rustc-std-workspace-core",
 ]
index e562dedb5324b1d8807668f435858f8a8646c712..3dbd28c286a246f25677b2420cc6fb07410961c8 100644 (file)
@@ -5,13 +5,14 @@ version = "0.0.0"
 
 [dependencies]
 core = { path = "./sysroot_src/library/core" }
-compiler_builtins = "0.1"
 alloc = { path = "./sysroot_src/library/alloc" }
 std = { path = "./sysroot_src/library/std", features = ["panic_unwind", "backtrace"] }
 test = { path = "./sysroot_src/library/test" }
 
 alloc_system = { path = "./alloc_system" }
 
+compiler_builtins = { version = "=0.1.36", default-features = false }
+
 [patch.crates-io]
 rustc-std-workspace-core = { path = "./sysroot_src/library/rustc-std-workspace-core" }
 rustc-std-workspace-alloc = { path = "./sysroot_src/library/rustc-std-workspace-alloc" }
index b38e25328a4eece82b29334128f293e498a4b188..015bbdfed4648ee106cb18d47f2e7217d7f30cd9 100644 (file)
@@ -15,6 +15,8 @@ fn main() {
     let stderr = ::std::io::stderr();
     let mut stderr = stderr.lock();
 
+    // FIXME support lazy jit when multi threading
+    #[cfg(not(lazy_jit))]
     std::thread::spawn(move || {
         println!("Hello from another thread!");
     });
index ed1e64f45db08a8fbd66430a89a151541949bca7..d6ad24bcf26ddf48007753c231b74bb11ac38281 100644 (file)
@@ -1 +1 @@
-nightly-2020-11-27
+nightly-2020-12-23
index dcd40acc02a53369b4332c3920dafa5d61908083..a3d6d303057b8050ed0d51c30c00ab0cbcf9d31c 100755 (executable)
@@ -10,7 +10,9 @@ cmd=$1
 shift || true
 
 if [[ "$cmd" = "jit" ]]; then
-cargo "+${TOOLCHAIN}" rustc "$@" -- --jit
+cargo "+${TOOLCHAIN}" rustc "$@" -- -Cllvm-args=mode=jit -Cprefer-dynamic
+elif [[ "$cmd" = "lazy-jit" ]]; then
+cargo "+${TOOLCHAIN}" rustc "$@" -- -Cllvm-args=mode=jit-lazy -Cprefer-dynamic
 else
 cargo "+${TOOLCHAIN}" "$cmd" "$@"
 fi
index 3327c10089d9b0847fe9fbdccf12c03f91aab412..15388926ec9ec62ddb5c707cc64c926317f75f09 100755 (executable)
@@ -4,7 +4,7 @@
 pushd $(dirname "$0")/../
 source build/config.sh
 popd
-PROFILE=$1 OUTPUT=$2 exec $RUSTC $RUSTFLAGS --jit $0
+PROFILE=$1 OUTPUT=$2 exec $RUSTC $RUSTFLAGS -Cllvm-args=mode=jit -Cprefer-dynamic $0
 #*/
 
 //! This program filters away uninteresting samples and trims uninteresting frames for stackcollapse
index 114b6f30a4a9119941af907bab0173333aaf8388..a61774f479ec7f9cb7ee3533042806ff61b21c05 100755 (executable)
@@ -15,7 +15,10 @@ function no_sysroot_tests() {
 
     if [[ "$JIT_SUPPORTED" = "1" ]]; then
         echo "[JIT] mini_core_hello_world"
-        CG_CLIF_JIT_ARGS="abc bcd" $MY_RUSTC --jit example/mini_core_hello_world.rs --cfg jit --target "$HOST_TRIPLE"
+        CG_CLIF_JIT_ARGS="abc bcd" $MY_RUSTC -Cllvm-args=mode=jit -Cprefer-dynamic example/mini_core_hello_world.rs --cfg jit --target "$HOST_TRIPLE"
+
+        echo "[JIT-lazy] mini_core_hello_world"
+        CG_CLIF_JIT_ARGS="abc bcd" $MY_RUSTC -Cllvm-args=mode=jit-lazy -Cprefer-dynamic example/mini_core_hello_world.rs --cfg jit --target "$HOST_TRIPLE"
     else
         echo "[JIT] mini_core_hello_world (skipped)"
     fi
@@ -37,7 +40,10 @@ function base_sysroot_tests() {
 
     if [[ "$JIT_SUPPORTED" = "1" ]]; then
         echo "[JIT] std_example"
-        $MY_RUSTC --jit example/std_example.rs --target "$HOST_TRIPLE"
+        $MY_RUSTC -Cllvm-args=mode=jit -Cprefer-dynamic example/std_example.rs --target "$HOST_TRIPLE"
+
+        echo "[JIT-lazy] std_example"
+        $MY_RUSTC -Cllvm-args=mode=jit-lazy -Cprefer-dynamic example/std_example.rs --cfg lazy_jit --target "$HOST_TRIPLE"
     else
         echo "[JIT] std_example (skipped)"
     fi
index 9e32259716f5105508d59d8bc0edbc01a5b30f7c..0ce34c904bdcc43d274263f46035c5302d5b5a78 100644 (file)
@@ -162,7 +162,7 @@ fn add_constructor(&mut self, func_id: FuncId) {
 }
 
 pub(crate) fn with_object(sess: &Session, name: &str, f: impl FnOnce(&mut Object)) -> Vec<u8> {
-    let triple = crate::build_isa(sess, true).triple().clone();
+    let triple = crate::build_isa(sess).triple().clone();
 
     let binary_format = match triple.binary_format {
         target_lexicon::BinaryFormat::Elf => object::BinaryFormat::Elf,
@@ -193,7 +193,7 @@ pub(crate) fn with_object(sess: &Session, name: &str, f: impl FnOnce(&mut Object
 
 pub(crate) fn make_module(sess: &Session, name: String) -> ObjectModule {
     let mut builder = ObjectBuilder::new(
-        crate::build_isa(sess, true),
+        crate::build_isa(sess),
         name + ".o",
         cranelift_module::default_libcall_names(),
     )
index 72073896a723b89f908879e70e15be35c68f17b5..34c9561d6762287a6113ee700e4042e6041b4352 100644 (file)
@@ -118,6 +118,8 @@ pub(crate) fn codegen_fn<'tcx>(
     context.eliminate_unreachable_code(cx.module.isa()).unwrap();
     context.dce(cx.module.isa()).unwrap();
 
+    context.want_disasm = crate::pretty_clif::should_write_ir(tcx);
+
     // Define function
     let module = &mut cx.module;
     tcx.sess.time("define function", || {
@@ -140,6 +142,16 @@ pub(crate) fn codegen_fn<'tcx>(
         &clif_comments,
     );
 
+    if let Some(mach_compile_result) = &context.mach_compile_result {
+        if let Some(disasm) = &mach_compile_result.disasm {
+            crate::pretty_clif::write_ir_file(
+                tcx,
+                &format!("{}.vcode", tcx.symbol_name(instance).name),
+                |file| file.write_all(disasm.as_bytes()),
+            )
+        }
+    }
+
     // Define debuginfo for function
     let isa = cx.module.isa();
     let debug_context = &mut cx.debug_context;
@@ -307,7 +319,9 @@ fn codegen_fn_content(fx: &mut FunctionCx<'_, '_, impl Module>) {
             } => {
                 let discr = codegen_operand(fx, discr).load_scalar(fx);
 
-                if switch_ty.kind() == fx.tcx.types.bool.kind() {
+                let use_bool_opt = switch_ty.kind() == fx.tcx.types.bool.kind()
+                    || (targets.iter().count() == 1 && targets.iter().next().unwrap().0 == 0);
+                if use_bool_opt {
                     assert_eq!(targets.iter().count(), 1);
                     let (then_value, then_block) = targets.iter().next().unwrap();
                     let then_block = fx.get_block(then_block);
@@ -325,12 +339,22 @@ fn codegen_fn_content(fx: &mut FunctionCx<'_, '_, impl Module>) {
                     let discr = crate::optimize::peephole::maybe_unwrap_bint(&mut fx.bcx, discr);
                     let discr =
                         crate::optimize::peephole::make_branchable_value(&mut fx.bcx, discr);
-                    if test_zero {
-                        fx.bcx.ins().brz(discr, then_block, &[]);
-                        fx.bcx.ins().jump(else_block, &[]);
+                    if let Some(taken) = crate::optimize::peephole::maybe_known_branch_taken(
+                        &fx.bcx, discr, test_zero,
+                    ) {
+                        if taken {
+                            fx.bcx.ins().jump(then_block, &[]);
+                        } else {
+                            fx.bcx.ins().jump(else_block, &[]);
+                        }
                     } else {
-                        fx.bcx.ins().brnz(discr, then_block, &[]);
-                        fx.bcx.ins().jump(else_block, &[]);
+                        if test_zero {
+                            fx.bcx.ins().brz(discr, then_block, &[]);
+                            fx.bcx.ins().jump(else_block, &[]);
+                        } else {
+                            fx.bcx.ins().brnz(discr, then_block, &[]);
+                            fx.bcx.ins().jump(else_block, &[]);
+                        }
                     }
                 } else {
                     let mut switch = ::cranelift_frontend::Switch::new();
index f4d23ebcf4e4dd445452399b549d7de8c6d633cf..58e45b4e9b972fbb1adbc6bbe112015654cc4f4c 100644 (file)
@@ -44,9 +44,7 @@ fn main() {
     let mut callbacks = CraneliftPassesCallbacks::default();
     rustc_driver::install_ice_hook();
     let exit_code = rustc_driver::catch_with_exit_code(|| {
-        let mut use_jit = false;
-
-        let mut args = std::env::args_os()
+        let args = std::env::args_os()
             .enumerate()
             .map(|(i, arg)| {
                 arg.into_string().unwrap_or_else(|arg| {
@@ -56,23 +54,10 @@ fn main() {
                     )
                 })
             })
-            .filter(|arg| {
-                if arg == "--jit" {
-                    use_jit = true;
-                    false
-                } else {
-                    true
-                }
-            })
             .collect::<Vec<_>>();
-        if use_jit {
-            args.push("-Cprefer-dynamic".to_string());
-        }
         let mut run_compiler = rustc_driver::RunCompiler::new(&args, &mut callbacks);
         run_compiler.set_make_codegen_backend(Some(Box::new(move |_| {
-            Box::new(rustc_codegen_cranelift::CraneliftCodegenBackend {
-                config: rustc_codegen_cranelift::BackendConfig { use_jit },
-            })
+            Box::new(rustc_codegen_cranelift::CraneliftCodegenBackend { config: None })
         })));
         run_compiler.run()
     });
index 165d33dcfb50919a625fd0d60cdf51052a82ca1f..8ee4cd46c94e0d2f36591b39622912437b95c225 100644 (file)
@@ -92,9 +92,7 @@ fn main() {
         let mut run_compiler = rustc_driver::RunCompiler::new(&args, &mut callbacks);
         if use_clif {
             run_compiler.set_make_codegen_backend(Some(Box::new(move |_| {
-                Box::new(rustc_codegen_cranelift::CraneliftCodegenBackend {
-                    config: rustc_codegen_cranelift::BackendConfig { use_jit: false },
-                })
+                Box::new(rustc_codegen_cranelift::CraneliftCodegenBackend { config: None })
             })));
         }
         run_compiler.run()
index 544b020b711900de19f66498d63f456c41cb22b8..beff84fb2e217ae04445e7979f807ddebf7b65ab 100644 (file)
@@ -100,7 +100,10 @@ fn codegen_static_ref<'tcx>(
     let global_ptr = fx.bcx.ins().global_value(fx.pointer_type, local_data_id);
     assert!(!layout.is_unsized(), "unsized statics aren't supported");
     assert!(
-        matches!(fx.bcx.func.global_values[local_data_id], GlobalValueData::Symbol { tls: false, ..}),
+        matches!(
+            fx.bcx.func.global_values[local_data_id],
+            GlobalValueData::Symbol { tls: false, .. }
+        ),
         "tls static referenced without Rvalue::ThreadLocalRef"
     );
     CPlace::for_ptr(crate::pointer::Pointer::new(global_ptr), layout)
@@ -447,7 +450,8 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut impl Module, cx: &mut Constan
             data_ctx.write_data_addr(offset.bytes() as u32, global_value, addend as i64);
         }
 
-        module.define_data(data_id, &data_ctx).unwrap();
+        // FIXME don't duplicate definitions in lazy jit mode
+        let _ = module.define_data(data_id, &data_ctx);
         cx.done.insert(data_id);
     }
 
index c21835b1fc3aaf8155a45c86c34365929352337d..6160f9b78d8b3a6d9cd3cefde854f4ca60813f67 100644 (file)
@@ -74,10 +74,7 @@ pub(super) fn new(endian: RunTimeEndian) -> Self {
 
     /// Perform the collected relocations to be usable for JIT usage.
     #[cfg(feature = "jit")]
-    pub(super) fn relocate_for_jit(
-        mut self,
-        jit_module: &cranelift_simplejit::SimpleJITModule,
-    ) -> Vec<u8> {
+    pub(super) fn relocate_for_jit(mut self, jit_module: &cranelift_jit::JITModule) -> Vec<u8> {
         use std::convert::TryInto;
 
         for reloc in self.relocs.drain(..) {
index e0f62b64e6bbb5350edbd091879908ec2c44a6f3..49de927cdba059d0fd4c154bccae6737d46c916e 100644 (file)
@@ -15,11 +15,11 @@ pub(crate) struct UnwindContext<'tcx> {
 }
 
 impl<'tcx> UnwindContext<'tcx> {
-    pub(crate) fn new(tcx: TyCtxt<'tcx>, isa: &dyn TargetIsa) -> Self {
+    pub(crate) fn new(tcx: TyCtxt<'tcx>, isa: &dyn TargetIsa, pic_eh_frame: bool) -> Self {
         let mut frame_table = FrameTable::default();
 
         let cie_id = if let Some(mut cie) = isa.create_systemv_cie() {
-            if isa.flags().is_pic() {
+            if pic_eh_frame {
                 cie.fde_address_encoding =
                     gimli::DwEhPe(gimli::DW_EH_PE_pcrel.0 | gimli::DW_EH_PE_sdata4.0);
             }
@@ -80,7 +80,7 @@ pub(crate) fn emit<P: WriteDebugInfo>(self, product: &mut P) {
     #[cfg(feature = "jit")]
     pub(crate) unsafe fn register_jit(
         self,
-        jit_module: &cranelift_simplejit::SimpleJITModule,
+        jit_module: &cranelift_jit::JITModule,
     ) -> Option<UnwindRegistry> {
         let mut eh_frame = EhFrame::from(super::emit::WriterRelocate::new(super::target_endian(
             self.tcx,
index 78d6ff0cb001c404f085d12c018f04cf5fcd3775..16f9bfc99189f5cbe1e7f3d59b24f7cca8364b8c 100644 (file)
@@ -8,7 +8,7 @@
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
 use rustc_middle::middle::cstore::EncodedMetadata;
-use rustc_middle::mir::mono::CodegenUnit;
+use rustc_middle::mir::mono::{CodegenUnit, MonoItem};
 use rustc_session::cgu_reuse_tracker::CguReuse;
 use rustc_session::config::{DebugInfo, OutputType};
 
@@ -146,11 +146,34 @@ fn module_codegen(tcx: TyCtxt<'_>, cgu_name: rustc_span::Symbol) -> ModuleCodege
         }
     }
 
-    let mut cx = crate::CodegenCx::new(tcx, module, tcx.sess.opts.debuginfo != DebugInfo::None);
+    let mut cx = crate::CodegenCx::new(
+        tcx,
+        module,
+        tcx.sess.opts.debuginfo != DebugInfo::None,
+        true,
+    );
     super::predefine_mono_items(&mut cx, &mono_items);
     for (mono_item, (linkage, visibility)) in mono_items {
         let linkage = crate::linkage::get_clif_linkage(mono_item, linkage, visibility);
-        super::codegen_mono_item(&mut cx, mono_item, linkage);
+        match mono_item {
+            MonoItem::Fn(inst) => {
+                cx.tcx.sess.time("codegen fn", || {
+                    crate::base::codegen_fn(&mut cx, inst, linkage)
+                });
+            }
+            MonoItem::Static(def_id) => {
+                crate::constant::codegen_static(&mut cx.constants_cx, def_id)
+            }
+            MonoItem::GlobalAsm(hir_id) => {
+                let item = cx.tcx.hir().expect_item(hir_id);
+                if let rustc_hir::ItemKind::GlobalAsm(rustc_hir::GlobalAsm { asm }) = item.kind {
+                    cx.global_asm.push_str(&*asm.as_str());
+                    cx.global_asm.push_str("\n\n");
+                } else {
+                    bug!("Expected GlobalAsm found {:?}", item);
+                }
+            }
+        }
     }
     let (mut module, global_asm, debug, mut unwind_context) =
         tcx.sess.time("finalize CodegenCx", || cx.finalize());
@@ -236,7 +259,7 @@ pub(super) fn run_aot(
     tcx.sess.abort_if_errors();
 
     let mut allocator_module = new_module(tcx, "allocator_shim".to_string());
-    let mut allocator_unwind_context = UnwindContext::new(tcx, allocator_module.isa());
+    let mut allocator_unwind_context = UnwindContext::new(tcx, allocator_module.isa(), true);
     let created_alloc_shim =
         crate::allocator::codegen(tcx, &mut allocator_module, &mut allocator_unwind_context);
 
index 5a844841c2ce5b0649723fccc8e1c06e3f8a3b09..9a42c675cc14498a1955983ce99e799a382ea63d 100644 (file)
@@ -1,16 +1,23 @@
 //! The JIT driver uses [`cranelift_simplejit`] to JIT execute programs without writing any object
 //! files.
 
+use std::cell::RefCell;
 use std::ffi::CString;
 use std::os::raw::{c_char, c_int};
 
 use rustc_codegen_ssa::CrateInfo;
+use rustc_middle::mir::mono::MonoItem;
 
-use cranelift_simplejit::{SimpleJITBuilder, SimpleJITModule};
+use cranelift_jit::{JITBuilder, JITModule};
 
 use crate::prelude::*;
+use crate::{CodegenCx, CodegenMode};
 
-pub(super) fn run_jit(tcx: TyCtxt<'_>) -> ! {
+thread_local! {
+    pub static CURRENT_MODULE: RefCell<Option<JITModule>> = RefCell::new(None);
+}
+
+pub(super) fn run_jit(tcx: TyCtxt<'_>, codegen_mode: CodegenMode) -> ! {
     if !tcx.sess.opts.output_types.should_codegen() {
         tcx.sess.fatal("JIT mode doesn't work with `cargo check`.");
     }
@@ -35,12 +42,13 @@ pub(super) fn run_jit(tcx: TyCtxt<'_>) -> ! {
 
     let imported_symbols = load_imported_symbols_for_jit(tcx);
 
-    let mut jit_builder = SimpleJITBuilder::with_isa(
-        crate::build_isa(tcx.sess, false),
+    let mut jit_builder = JITBuilder::with_isa(
+        crate::build_isa(tcx.sess),
         cranelift_module::default_libcall_names(),
     );
+    jit_builder.hotswap(matches!(codegen_mode, CodegenMode::JitLazy));
     jit_builder.symbols(imported_symbols);
-    let mut jit_module = SimpleJITModule::new(jit_builder);
+    let mut jit_module = JITModule::new(jit_builder);
     assert_eq!(pointer_ty(tcx), jit_module.target_config().pointer_type());
 
     let sig = Signature {
@@ -66,20 +74,42 @@ pub(super) fn run_jit(tcx: TyCtxt<'_>) -> ! {
         .into_iter()
         .collect::<Vec<(_, (_, _))>>();
 
-    let mut cx = crate::CodegenCx::new(tcx, jit_module, false);
+    let mut cx = crate::CodegenCx::new(tcx, jit_module, false, false);
 
-    let (mut jit_module, global_asm, _debug, mut unwind_context) =
-        super::time(tcx, "codegen mono items", || {
-            super::predefine_mono_items(&mut cx, &mono_items);
-            for (mono_item, (linkage, visibility)) in mono_items {
-                let linkage = crate::linkage::get_clif_linkage(mono_item, linkage, visibility);
-                super::codegen_mono_item(&mut cx, mono_item, linkage);
+    super::time(tcx, "codegen mono items", || {
+        super::predefine_mono_items(&mut cx, &mono_items);
+        for (mono_item, (linkage, visibility)) in mono_items {
+            let linkage = crate::linkage::get_clif_linkage(mono_item, linkage, visibility);
+            match mono_item {
+                MonoItem::Fn(inst) => match codegen_mode {
+                    CodegenMode::Aot => unreachable!(),
+                    CodegenMode::Jit => {
+                        cx.tcx.sess.time("codegen fn", || {
+                            crate::base::codegen_fn(&mut cx, inst, linkage)
+                        });
+                    }
+                    CodegenMode::JitLazy => codegen_shim(&mut cx, inst),
+                },
+                MonoItem::Static(def_id) => {
+                    crate::constant::codegen_static(&mut cx.constants_cx, def_id);
+                }
+                MonoItem::GlobalAsm(hir_id) => {
+                    let item = cx.tcx.hir().expect_item(hir_id);
+                    tcx.sess
+                        .span_fatal(item.span, "Global asm is not supported in JIT mode");
+                }
             }
-            tcx.sess.time("finalize CodegenCx", || cx.finalize())
-        });
+        }
+    });
+
+    let (mut jit_module, global_asm, _debug, mut unwind_context) =
+        tcx.sess.time("finalize CodegenCx", || cx.finalize());
+    jit_module.finalize_definitions();
+
     if !global_asm.is_empty() {
-        tcx.sess.fatal("Global asm is not supported in JIT mode");
+        tcx.sess.fatal("Inline asm is not supported in JIT mode");
     }
+
     crate::main_shim::maybe_create_entry_wrapper(tcx, &mut jit_module, &mut unwind_context, true);
     crate::allocator::codegen(tcx, &mut jit_module, &mut unwind_context);
 
@@ -91,7 +121,7 @@ pub(super) fn run_jit(tcx: TyCtxt<'_>) -> ! {
 
     let finalized_main: *const u8 = jit_module.get_finalized_function(main_func_id);
 
-    println!("Rustc codegen cranelift will JIT run the executable, because --jit was passed");
+    println!("Rustc codegen cranelift will JIT run the executable, because -Cllvm-args=mode=jit was passed");
 
     let f: extern "C" fn(c_int, *const *const c_char) -> c_int =
         unsafe { ::std::mem::transmute(finalized_main) };
@@ -107,11 +137,50 @@ pub(super) fn run_jit(tcx: TyCtxt<'_>) -> ! {
     // useful as some dynamic linkers use it as a marker to jump over.
     argv.push(std::ptr::null());
 
+    CURRENT_MODULE
+        .with(|current_module| assert!(current_module.borrow_mut().replace(jit_module).is_none()));
+
     let ret = f(args.len() as c_int, argv.as_ptr());
 
     std::process::exit(ret);
 }
 
+#[no_mangle]
+extern "C" fn __clif_jit_fn(instance_ptr: *const Instance<'static>) -> *const u8 {
+    rustc_middle::ty::tls::with(|tcx| {
+        // lift is used to ensure the correct lifetime for instance.
+        let instance = tcx.lift(unsafe { *instance_ptr }).unwrap();
+
+        CURRENT_MODULE.with(|jit_module| {
+            let mut jit_module = jit_module.borrow_mut();
+            let jit_module = jit_module.as_mut().unwrap();
+            let mut cx = crate::CodegenCx::new(tcx, jit_module, false, false);
+
+            let (name, sig) = crate::abi::get_function_name_and_sig(
+                tcx,
+                cx.module.isa().triple(),
+                instance,
+                true,
+            );
+            let func_id = cx
+                .module
+                .declare_function(&name, Linkage::Export, &sig)
+                .unwrap();
+            cx.module.prepare_for_function_redefine(func_id).unwrap();
+
+            tcx.sess.time("codegen fn", || {
+                crate::base::codegen_fn(&mut cx, instance, Linkage::Export)
+            });
+
+            let (jit_module, global_asm, _debug_context, unwind_context) = cx.finalize();
+            assert!(global_asm.is_empty());
+            jit_module.finalize_definitions();
+            std::mem::forget(unsafe { unwind_context.register_jit(&jit_module) });
+            jit_module.get_finalized_function(func_id)
+        })
+    })
+}
+
 fn load_imported_symbols_for_jit(tcx: TyCtxt<'_>) -> Vec<(String, *const u8)> {
     use rustc_middle::middle::dependency_format::Linkage;
 
@@ -171,3 +240,68 @@ fn load_imported_symbols_for_jit(tcx: TyCtxt<'_>) -> Vec<(String, *const u8)> {
 
     imported_symbols
 }
+
+pub(super) fn codegen_shim<'tcx>(cx: &mut CodegenCx<'tcx, impl Module>, inst: Instance<'tcx>) {
+    let tcx = cx.tcx;
+
+    let pointer_type = cx.module.target_config().pointer_type();
+
+    let (name, sig) =
+        crate::abi::get_function_name_and_sig(tcx, cx.module.isa().triple(), inst, true);
+    let func_id = cx
+        .module
+        .declare_function(&name, Linkage::Export, &sig)
+        .unwrap();
+
+    let instance_ptr = Box::into_raw(Box::new(inst));
+
+    let jit_fn = cx
+        .module
+        .declare_function(
+            "__clif_jit_fn",
+            Linkage::Import,
+            &Signature {
+                call_conv: cx.module.target_config().default_call_conv,
+                params: vec![AbiParam::new(pointer_type)],
+                returns: vec![AbiParam::new(pointer_type)],
+            },
+        )
+        .unwrap();
+
+    let mut trampoline = Function::with_name_signature(ExternalName::default(), sig.clone());
+    let mut builder_ctx = FunctionBuilderContext::new();
+    let mut trampoline_builder = FunctionBuilder::new(&mut trampoline, &mut builder_ctx);
+
+    let jit_fn = cx
+        .module
+        .declare_func_in_func(jit_fn, trampoline_builder.func);
+    let sig_ref = trampoline_builder.func.import_signature(sig);
+
+    let entry_block = trampoline_builder.create_block();
+    trampoline_builder.append_block_params_for_function_params(entry_block);
+    let fn_args = trampoline_builder
+        .func
+        .dfg
+        .block_params(entry_block)
+        .to_vec();
+
+    trampoline_builder.switch_to_block(entry_block);
+    let instance_ptr = trampoline_builder
+        .ins()
+        .iconst(pointer_type, instance_ptr as u64 as i64);
+    let jitted_fn = trampoline_builder.ins().call(jit_fn, &[instance_ptr]);
+    let jitted_fn = trampoline_builder.func.dfg.inst_results(jitted_fn)[0];
+    let call_inst = trampoline_builder
+        .ins()
+        .call_indirect(sig_ref, jitted_fn, &fn_args);
+    let ret_vals = trampoline_builder.func.dfg.inst_results(call_inst).to_vec();
+    trampoline_builder.ins().return_(&ret_vals);
+
+    cx.module
+        .define_function(
+            func_id,
+            &mut Context::for_function(trampoline),
+            &mut cranelift_codegen::binemit::NullTrapSink {},
+        )
+        .unwrap();
+}
index 7b8cc2ddd48d6da49f1ffbab26a2c6083a892d55..9f4ea9a386551f88436198bf27214f7f6902f39a 100644 (file)
@@ -7,6 +7,7 @@
 use rustc_middle::mir::mono::{Linkage as RLinkage, MonoItem, Visibility};
 
 use crate::prelude::*;
+use crate::CodegenMode;
 
 mod aot;
 #[cfg(feature = "jit")]
@@ -20,24 +21,25 @@ pub(crate) fn codegen_crate(
 ) -> Box<dyn Any> {
     tcx.sess.abort_if_errors();
 
-    if config.use_jit {
-        let is_executable = tcx
-            .sess
-            .crate_types()
-            .contains(&rustc_session::config::CrateType::Executable);
-        if !is_executable {
-            tcx.sess.fatal("can't jit non-executable crate");
-        }
+    match config.codegen_mode {
+        CodegenMode::Aot => aot::run_aot(tcx, metadata, need_metadata_module),
+        CodegenMode::Jit | CodegenMode::JitLazy => {
+            let is_executable = tcx
+                .sess
+                .crate_types()
+                .contains(&rustc_session::config::CrateType::Executable);
+            if !is_executable {
+                tcx.sess.fatal("can't jit non-executable crate");
+            }
 
-        #[cfg(feature = "jit")]
-        let _: ! = jit::run_jit(tcx);
+            #[cfg(feature = "jit")]
+            let _: ! = jit::run_jit(tcx, config.codegen_mode);
 
-        #[cfg(not(feature = "jit"))]
-        tcx.sess
-            .fatal("jit support was disabled when compiling rustc_codegen_cranelift");
+            #[cfg(not(feature = "jit"))]
+            tcx.sess
+                .fatal("jit support was disabled when compiling rustc_codegen_cranelift");
+        }
     }
-
-    aot::run_aot(tcx, metadata, need_metadata_module)
 }
 
 fn predefine_mono_items<'tcx>(
@@ -63,30 +65,6 @@ fn predefine_mono_items<'tcx>(
     });
 }
 
-fn codegen_mono_item<'tcx, M: Module>(
-    cx: &mut crate::CodegenCx<'tcx, M>,
-    mono_item: MonoItem<'tcx>,
-    linkage: Linkage,
-) {
-    match mono_item {
-        MonoItem::Fn(inst) => {
-            cx.tcx
-                .sess
-                .time("codegen fn", || crate::base::codegen_fn(cx, inst, linkage));
-        }
-        MonoItem::Static(def_id) => crate::constant::codegen_static(&mut cx.constants_cx, def_id),
-        MonoItem::GlobalAsm(hir_id) => {
-            let item = cx.tcx.hir().expect_item(hir_id);
-            if let rustc_hir::ItemKind::GlobalAsm(rustc_hir::GlobalAsm { asm }) = item.kind {
-                cx.global_asm.push_str(&*asm.as_str());
-                cx.global_asm.push_str("\n\n");
-            } else {
-                bug!("Expected GlobalAsm found {:?}", item);
-            }
-        }
-    }
-}
-
 fn time<R>(tcx: TyCtxt<'_>, name: &'static str, f: impl FnOnce() -> R) -> R {
     if std::env::var("CG_CLIF_DISPLAY_CG_TIME")
         .as_ref()
index 171445f2d71b62840204f24837e835ea7c3712ee..d58e4d499584210e78fda8527de716e4ccba5034 100644 (file)
@@ -23,8 +23,8 @@ pub(crate) fn codegen_llvm_intrinsic_call<'tcx>(
 
         // Used by `_mm_movemask_epi8` and `_mm256_movemask_epi8`
         llvm.x86.sse2.pmovmskb.128 | llvm.x86.avx2.pmovmskb | llvm.x86.sse2.movmsk.pd, (c a) {
-            let (lane_layout, lane_count) = lane_type_and_count(fx.tcx, a.layout());
-            let lane_ty = fx.clif_type(lane_layout.ty).unwrap();
+            let (lane_count, lane_ty) = a.layout().ty.simd_size_and_type(fx.tcx);
+            let lane_ty = fx.clif_type(lane_ty).unwrap();
             assert!(lane_count <= 32);
 
             let mut res = fx.bcx.ins().iconst(types::I32, 0);
index df8aa1b3e6983b7eb517774081b0bd0bacc08ffe..be5b247bb9f0bf7e1a4db31c2ed9c3593a78b92e 100644 (file)
     }
 }
 
-fn lane_type_and_count<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    layout: TyAndLayout<'tcx>,
-) -> (TyAndLayout<'tcx>, u16) {
-    assert!(layout.ty.is_simd());
-    let lane_count = match layout.fields {
-        rustc_target::abi::FieldsShape::Array { stride: _, count } => u16::try_from(count).unwrap(),
-        _ => unreachable!("lane_type_and_count({:?})", layout),
-    };
-    let lane_layout = layout
-        .field(
-            &ty::layout::LayoutCx {
-                tcx,
-                param_env: ParamEnv::reveal_all(),
-            },
-            0,
-        )
-        .unwrap();
-    (lane_layout, lane_count)
-}
-
 pub(crate) fn clif_vector_type<'tcx>(tcx: TyCtxt<'tcx>, layout: TyAndLayout<'tcx>) -> Option<Type> {
     let (element, count) = match &layout.abi {
         Abi::Vector { element, count } => (element.clone(), *count),
@@ -218,8 +197,10 @@ fn simd_for_each_lane<'tcx, M: Module>(
 ) {
     let layout = val.layout();
 
-    let (lane_layout, lane_count) = lane_type_and_count(fx.tcx, layout);
-    let (ret_lane_layout, ret_lane_count) = lane_type_and_count(fx.tcx, ret.layout());
+    let (lane_count, lane_ty) = layout.ty.simd_size_and_type(fx.tcx);
+    let lane_layout = fx.layout_of(lane_ty);
+    let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx);
+    let ret_lane_layout = fx.layout_of(ret_lane_ty);
     assert_eq!(lane_count, ret_lane_count);
 
     for lane_idx in 0..lane_count {
@@ -248,8 +229,10 @@ fn simd_pair_for_each_lane<'tcx, M: Module>(
     assert_eq!(x.layout(), y.layout());
     let layout = x.layout();
 
-    let (lane_layout, lane_count) = lane_type_and_count(fx.tcx, layout);
-    let (ret_lane_layout, ret_lane_count) = lane_type_and_count(fx.tcx, ret.layout());
+    let (lane_count, lane_ty) = layout.ty.simd_size_and_type(fx.tcx);
+    let lane_layout = fx.layout_of(lane_ty);
+    let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx);
+    let ret_lane_layout = fx.layout_of(ret_lane_ty);
     assert_eq!(lane_count, ret_lane_count);
 
     for lane in 0..lane_count {
@@ -269,13 +252,14 @@ fn simd_reduce<'tcx, M: Module>(
     ret: CPlace<'tcx>,
     f: impl Fn(&mut FunctionCx<'_, 'tcx, M>, TyAndLayout<'tcx>, Value, Value) -> Value,
 ) {
-    let (lane_layout, lane_count) = lane_type_and_count(fx.tcx, val.layout());
+    let (lane_count, lane_ty) = val.layout().ty.simd_size_and_type(fx.tcx);
+    let lane_layout = fx.layout_of(lane_ty);
     assert_eq!(lane_layout, ret.layout());
 
     let mut res_val = val.value_field(fx, mir::Field::new(0)).load_scalar(fx);
     for lane_idx in 1..lane_count {
         let lane = val
-            .value_field(fx, mir::Field::new(lane_idx.into()))
+            .value_field(fx, mir::Field::new(lane_idx.try_into().unwrap()))
             .load_scalar(fx);
         res_val = f(fx, lane_layout, res_val, lane);
     }
@@ -289,14 +273,14 @@ fn simd_reduce_bool<'tcx, M: Module>(
     ret: CPlace<'tcx>,
     f: impl Fn(&mut FunctionCx<'_, 'tcx, M>, Value, Value) -> Value,
 ) {
-    let (_lane_layout, lane_count) = lane_type_and_count(fx.tcx, val.layout());
+    let (lane_count, _lane_ty) = val.layout().ty.simd_size_and_type(fx.tcx);
     assert!(ret.layout().ty.is_bool());
 
     let res_val = val.value_field(fx, mir::Field::new(0)).load_scalar(fx);
     let mut res_val = fx.bcx.ins().band_imm(res_val, 1); // mask to boolean
     for lane_idx in 1..lane_count {
         let lane = val
-            .value_field(fx, mir::Field::new(lane_idx.into()))
+            .value_field(fx, mir::Field::new(lane_idx.try_into().unwrap()))
             .load_scalar(fx);
         let lane = fx.bcx.ins().band_imm(lane, 1); // mask to boolean
         res_val = f(fx, res_val, lane);
@@ -460,9 +444,6 @@ pub(crate) fn codegen_intrinsic_call<'tcx>(
                 "abort" => {
                     trap_abort(fx, "Called intrinsic::abort.");
                 }
-                "unreachable" => {
-                    trap_unreachable(fx, "[corruption] Called intrinsic::unreachable.");
-                }
                 "transmute" => {
                     crate::base::codegen_panic(fx, "Transmuting to uninhabited type.", span);
                 }
@@ -575,12 +556,6 @@ pub(crate) fn codegen_intrinsic_call<'tcx>(
                 fx.bcx.call_memmove(fx.cx.module.target_config(), dst, src, byte_amount);
             }
         };
-        discriminant_value, (c ptr) {
-            let pointee_layout = fx.layout_of(ptr.layout().ty.builtin_deref(true).unwrap().ty);
-            let val = CValue::by_ref(Pointer::new(ptr.load_scalar(fx)), pointee_layout);
-            let discr = crate::discriminant::codegen_get_discriminant(fx, val, ret.layout());
-            ret.write_cvalue(fx, discr);
-        };
         size_of_val, <T> (c ptr) {
             let layout = fx.layout_of(T);
             let size = if layout.is_unsized() {
@@ -641,22 +616,6 @@ pub(crate) fn codegen_intrinsic_call<'tcx>(
             );
             ret.write_cvalue(fx, res);
         };
-        _ if intrinsic.starts_with("wrapping_"), (c x, c y) {
-            assert_eq!(x.layout().ty, y.layout().ty);
-            let bin_op = match intrinsic {
-                "wrapping_add" => BinOp::Add,
-                "wrapping_sub" => BinOp::Sub,
-                "wrapping_mul" => BinOp::Mul,
-                _ => unreachable!("intrinsic {}", intrinsic),
-            };
-            let res = crate::num::codegen_int_binop(
-                fx,
-                bin_op,
-                x,
-                y,
-            );
-            ret.write_cvalue(fx, res);
-        };
         _ if intrinsic.starts_with("saturating_"), <T> (c lhs, c rhs) {
             assert_eq!(lhs.layout().ty, rhs.layout().ty);
             let bin_op = match intrinsic {
@@ -916,7 +875,7 @@ fn swap(bcx: &mut FunctionBuilder<'_>, v: Value) -> Value {
             dest.write_cvalue(fx, val);
         };
 
-        size_of | pref_align_of | min_align_of | needs_drop | type_id | type_name | variant_count, () {
+        pref_align_of | min_align_of | needs_drop | type_id | type_name | variant_count, () {
             let const_val =
                 fx.tcx.const_eval_instance(ParamEnv::reveal_all(), instance, None).unwrap();
             let val = crate::constant::codegen_const_value(
index 2b32e866e5ef6f088f89d3f3c563f8c3c239c27b..e0eb5c59590ffba54aeffe2931d933875cf9f093 100644 (file)
@@ -73,11 +73,11 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
             assert_eq!(x.layout(), y.layout());
             let layout = x.layout();
 
-            let (lane_type, lane_count) = lane_type_and_count(fx.tcx, layout);
-            let (ret_lane_type, ret_lane_count) = lane_type_and_count(fx.tcx, ret.layout());
+            let (lane_count, lane_ty) = layout.ty.simd_size_and_type(fx.tcx);
+            let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx);
 
-            assert_eq!(lane_type, ret_lane_type);
-            assert_eq!(n, ret_lane_count);
+            assert_eq!(lane_ty, ret_lane_ty);
+            assert_eq!(u64::from(n), ret_lane_count);
 
             let total_len = lane_count * 2;
 
@@ -105,14 +105,14 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
             };
 
             for &idx in &indexes {
-                assert!(idx < total_len, "idx {} out of range 0..{}", idx, total_len);
+                assert!(u64::from(idx) < total_len, "idx {} out of range 0..{}", idx, total_len);
             }
 
             for (out_idx, in_idx) in indexes.into_iter().enumerate() {
-                let in_lane = if in_idx < lane_count {
+                let in_lane = if u64::from(in_idx) < lane_count {
                     x.value_field(fx, mir::Field::new(in_idx.into()))
                 } else {
-                    y.value_field(fx, mir::Field::new((in_idx - lane_count).into()))
+                    y.value_field(fx, mir::Field::new(usize::from(in_idx) - usize::try_from(lane_count).unwrap()))
                 };
                 let out_lane = ret.place_field(fx, mir::Field::new(out_idx));
                 out_lane.write_cvalue(fx, in_lane);
@@ -131,7 +131,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
             };
 
             let idx = idx_const.val.try_to_bits(Size::from_bytes(4 /* u32*/)).unwrap_or_else(|| panic!("kind not scalar: {:?}", idx_const));
-            let (_lane_type, lane_count) = lane_type_and_count(fx.tcx, base.layout());
+            let (lane_count, _lane_ty) = base.layout().ty.simd_size_and_type(fx.tcx);
             if idx >= lane_count.into() {
                 fx.tcx.sess.span_fatal(fx.mir.span, &format!("[simd_insert] idx {} >= lane_count {}", idx, lane_count));
             }
@@ -160,7 +160,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
             };
 
             let idx = idx_const.val.try_to_bits(Size::from_bytes(4 /* u32*/)).unwrap_or_else(|| panic!("kind not scalar: {:?}", idx_const));
-            let (_lane_type, lane_count) = lane_type_and_count(fx.tcx, v.layout());
+            let (lane_count, _lane_ty) = v.layout().ty.simd_size_and_type(fx.tcx);
             if idx >= lane_count.into() {
                 fx.tcx.sess.span_fatal(fx.mir.span, &format!("[simd_extract] idx {} >= lane_count {}", idx, lane_count));
             }
@@ -212,12 +212,13 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
             assert_eq!(a.layout(), c.layout());
             let layout = a.layout();
 
-            let (_lane_layout, lane_count) = lane_type_and_count(fx.tcx, layout);
-            let (ret_lane_layout, ret_lane_count) = lane_type_and_count(fx.tcx, ret.layout());
+            let (lane_count, _lane_ty) = layout.ty.simd_size_and_type(fx.tcx);
+            let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx);
             assert_eq!(lane_count, ret_lane_count);
+            let ret_lane_layout = fx.layout_of(ret_lane_ty);
 
             for lane in 0..lane_count {
-                let lane = mir::Field::new(lane.into());
+                let lane = mir::Field::new(lane.try_into().unwrap());
                 let a_lane = a.value_field(fx, lane).load_scalar(fx);
                 let b_lane = b.value_field(fx, lane).load_scalar(fx);
                 let c_lane = c.value_field(fx, lane).load_scalar(fx);
index ba9ee0d450ee66c68821acab3f094304f92c0ba3..6e4f3bf2898d827900ec449dafd08325ea77b886 100644 (file)
@@ -5,7 +5,8 @@
     associated_type_bounds,
     never_type,
     try_blocks,
-    hash_drain_filter
+    hash_drain_filter,
+    str_split_once
 )]
 #![warn(rust_2018_idioms)]
 #![warn(unused_lifetimes)]
@@ -34,6 +35,7 @@
 extern crate rustc_driver;
 
 use std::any::Any;
+use std::str::FromStr;
 
 use rustc_codegen_ssa::traits::CodegenBackend;
 use rustc_codegen_ssa::CodegenResults;
@@ -141,8 +143,8 @@ struct CodegenCx<'tcx, M: Module> {
 }
 
 impl<'tcx, M: Module> CodegenCx<'tcx, M> {
-    fn new(tcx: TyCtxt<'tcx>, module: M, debug_info: bool) -> Self {
-        let unwind_context = UnwindContext::new(tcx, module.isa());
+    fn new(tcx: TyCtxt<'tcx>, module: M, debug_info: bool, pic_eh_frame: bool) -> Self {
+        let unwind_context = UnwindContext::new(tcx, module.isa(), pic_eh_frame);
         let debug_context = if debug_info {
             Some(DebugContext::new(tcx, module.isa()))
         } else {
@@ -172,12 +174,55 @@ fn finalize(mut self) -> (M, String, Option<DebugContext<'tcx>>, UnwindContext<'
 }
 
 #[derive(Copy, Clone, Debug)]
+pub enum CodegenMode {
+    Aot,
+    Jit,
+    JitLazy,
+}
+
+impl Default for CodegenMode {
+    fn default() -> Self {
+        CodegenMode::Aot
+    }
+}
+
+impl FromStr for CodegenMode {
+    type Err = String;
+
+    fn from_str(s: &str) -> Result<Self, Self::Err> {
+        match s {
+            "aot" => Ok(CodegenMode::Aot),
+            "jit" => Ok(CodegenMode::Jit),
+            "jit-lazy" => Ok(CodegenMode::JitLazy),
+            _ => Err(format!("Unknown codegen mode `{}`", s)),
+        }
+    }
+}
+
+#[derive(Copy, Clone, Debug, Default)]
 pub struct BackendConfig {
-    pub use_jit: bool,
+    pub codegen_mode: CodegenMode,
+}
+
+impl BackendConfig {
+    fn from_opts(opts: &[String]) -> Result<Self, String> {
+        let mut config = BackendConfig::default();
+        for opt in opts {
+            if let Some((name, value)) = opt.split_once('=') {
+                match name {
+                    "mode" => config.codegen_mode = value.parse()?,
+                    _ => return Err(format!("Unknown option `{}`", name)),
+                }
+            } else {
+                return Err(format!("Invalid option `{}`", opt));
+            }
+        }
+        Ok(config)
+    }
 }
 
 pub struct CraneliftCodegenBackend {
-    pub config: BackendConfig,
+    pub config: Option<BackendConfig>,
 }
 
 impl CodegenBackend for CraneliftCodegenBackend {
@@ -204,7 +249,13 @@ fn codegen_crate<'tcx>(
         metadata: EncodedMetadata,
         need_metadata_module: bool,
     ) -> Box<dyn Any> {
-        let res = driver::codegen_crate(tcx, metadata, need_metadata_module, self.config);
+        let config = if let Some(config) = self.config {
+            config
+        } else {
+            BackendConfig::from_opts(&tcx.sess.opts.cg.llvm_args)
+                .unwrap_or_else(|err| tcx.sess.fatal(&err))
+        };
+        let res = driver::codegen_crate(tcx, metadata, need_metadata_module, config);
 
         rustc_symbol_mangling::test::report_symbol_names(tcx);
 
@@ -250,17 +301,13 @@ fn target_triple(sess: &Session) -> target_lexicon::Triple {
     sess.target.llvm_target.parse().unwrap()
 }
 
-fn build_isa(sess: &Session, enable_pic: bool) -> Box<dyn isa::TargetIsa + 'static> {
+fn build_isa(sess: &Session) -> Box<dyn isa::TargetIsa + 'static> {
     use target_lexicon::BinaryFormat;
 
     let target_triple = crate::target_triple(sess);
 
     let mut flags_builder = settings::builder();
-    if enable_pic {
-        flags_builder.enable("is_pic").unwrap();
-    } else {
-        flags_builder.set("is_pic", "false").unwrap();
-    }
+    flags_builder.enable("is_pic").unwrap();
     flags_builder.set("enable_probestack", "false").unwrap(); // __cranelift_probestack is not provided
     flags_builder
         .set(
@@ -283,8 +330,6 @@ fn build_isa(sess: &Session, enable_pic: bool) -> Box<dyn isa::TargetIsa + 'stat
 
     flags_builder.set("enable_simd", "true").unwrap();
 
-    // FIXME(CraneStation/cranelift#732) fix LICM in presence of jump tables
-    /*
     use rustc_session::config::OptLevel;
     match sess.opts.optimize {
         OptLevel::No => {
@@ -297,7 +342,7 @@ fn build_isa(sess: &Session, enable_pic: bool) -> Box<dyn isa::TargetIsa + 'stat
         OptLevel::Size | OptLevel::SizeMin => {
             sess.warn("Optimizing for size is not supported. Just ignoring the request");
         }
-    }*/
+    }
 
     let flags = settings::Flags::new(flags_builder);
 
@@ -311,7 +356,5 @@ fn build_isa(sess: &Session, enable_pic: bool) -> Box<dyn isa::TargetIsa + 'stat
 /// This is the entrypoint for a hot plugged rustc_codegen_cranelift
 #[no_mangle]
 pub fn __rustc_codegen_backend() -> Box<dyn CodegenBackend> {
-    Box::new(CraneliftCodegenBackend {
-        config: BackendConfig { use_jit: false },
-    })
+    Box::new(CraneliftCodegenBackend { config: None })
 }
index f8e0f3af3d0ad08587559bebef6972e540ea684f..a575ed8dc35f80b0a3662df42cade581ab5cf672 100644 (file)
@@ -73,7 +73,7 @@ pub(crate) fn make_branchable_value(bcx: &mut FunctionBuilder<'_>, arg: Value) -
     })()
     .unwrap_or_else(|| {
         match bcx.func.dfg.value_type(arg) {
-            types::I8 | types::I32 => {
+            types::I8 | types::I16 => {
                 // WORKAROUND for brz.i8 and brnz.i8 not yet being implemented
                 bcx.ins().uextend(types::I32, arg)
             }
@@ -81,3 +81,40 @@ pub(crate) fn make_branchable_value(bcx: &mut FunctionBuilder<'_>, arg: Value) -
         }
     })
 }
+
+/// Returns whether the branch is statically known to be taken or `None` if it isn't statically known.
+pub(crate) fn maybe_known_branch_taken(
+    bcx: &FunctionBuilder<'_>,
+    arg: Value,
+    test_zero: bool,
+) -> Option<bool> {
+    let arg_inst = if let ValueDef::Result(arg_inst, 0) = bcx.func.dfg.value_def(arg) {
+        arg_inst
+    } else {
+        return None;
+    };
+
+    match bcx.func.dfg[arg_inst] {
+        InstructionData::UnaryBool {
+            opcode: Opcode::Bconst,
+            imm,
+        } => {
+            if test_zero {
+                Some(!imm)
+            } else {
+                Some(imm)
+            }
+        }
+        InstructionData::UnaryImm {
+            opcode: Opcode::Iconst,
+            imm,
+        } => {
+            if test_zero {
+                Some(imm.bits() == 0)
+            } else {
+                Some(imm.bits() != 0)
+            }
+        }
+        _ => None,
+    }
+}
index a9f060e51d8f88fa680393f912beb298f062fdba..22c94fec82fc13a61b03ff1063376ecef26f652d 100644 (file)
@@ -53,6 +53,7 @@
 //! ```
 
 use std::fmt;
+use std::io::Write;
 
 use cranelift_codegen::{
     entity::SecondaryMap,
@@ -200,32 +201,24 @@ pub(crate) fn add_comment<S: Into<String> + AsRef<str>, E: Into<AnyEntity>>(
     }
 }
 
-pub(crate) fn write_clif_file<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    postfix: &str,
-    isa: Option<&dyn cranelift_codegen::isa::TargetIsa>,
-    instance: Instance<'tcx>,
-    context: &cranelift_codegen::Context,
-    mut clif_comments: &CommentWriter,
-) {
-    use std::io::Write;
-
-    if !cfg!(debug_assertions)
-        && !tcx
+pub(crate) fn should_write_ir(tcx: TyCtxt<'_>) -> bool {
+    cfg!(debug_assertions)
+        || tcx
             .sess
             .opts
             .output_types
             .contains_key(&OutputType::LlvmAssembly)
-    {
+}
+
+pub(crate) fn write_ir_file<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    name: &str,
+    write: impl FnOnce(&mut dyn Write) -> std::io::Result<()>,
+) {
+    if !should_write_ir(tcx) {
         return;
     }
 
-    let value_ranges = isa.map(|isa| {
-        context
-            .build_value_labels_ranges(isa)
-            .expect("value location ranges")
-    });
-
     let clif_output_dir = tcx.output_filenames(LOCAL_CRATE).with_extension("clif");
 
     match std::fs::create_dir(&clif_output_dir) {
@@ -234,41 +227,58 @@ pub(crate) fn write_clif_file<'tcx>(
         res @ Err(_) => res.unwrap(),
     }
 
-    let clif_file_name = clif_output_dir.join(format!(
-        "{}.{}.clif",
-        tcx.symbol_name(instance).name,
-        postfix
-    ));
-
-    let mut clif = String::new();
-    cranelift_codegen::write::decorate_function(
-        &mut clif_comments,
-        &mut clif,
-        &context.func,
-        &DisplayFunctionAnnotations {
-            isa: Some(&*crate::build_isa(
-                tcx.sess, true, /* PIC doesn't matter here */
-            )),
-            value_ranges: value_ranges.as_ref(),
-        },
-    )
-    .unwrap();
+    let clif_file_name = clif_output_dir.join(name);
 
     let res: std::io::Result<()> = try {
         let mut file = std::fs::File::create(clif_file_name)?;
-        let target_triple = crate::target_triple(tcx.sess);
-        writeln!(file, "test compile")?;
-        writeln!(file, "set is_pic")?;
-        writeln!(file, "set enable_simd")?;
-        writeln!(file, "target {} haswell", target_triple)?;
-        writeln!(file)?;
-        file.write_all(clif.as_bytes())?;
+        write(&mut file)?;
     };
     if let Err(err) = res {
-        tcx.sess.warn(&format!("err writing clif file: {}", err));
+        tcx.sess.warn(&format!("error writing ir file: {}", err));
     }
 }
 
+pub(crate) fn write_clif_file<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    postfix: &str,
+    isa: Option<&dyn cranelift_codegen::isa::TargetIsa>,
+    instance: Instance<'tcx>,
+    context: &cranelift_codegen::Context,
+    mut clif_comments: &CommentWriter,
+) {
+    write_ir_file(
+        tcx,
+        &format!("{}.{}.clif", tcx.symbol_name(instance).name, postfix),
+        |file| {
+            let value_ranges = isa.map(|isa| {
+                context
+                    .build_value_labels_ranges(isa)
+                    .expect("value location ranges")
+            });
+
+            let mut clif = String::new();
+            cranelift_codegen::write::decorate_function(
+                &mut clif_comments,
+                &mut clif,
+                &context.func,
+                &DisplayFunctionAnnotations {
+                    isa: Some(&*crate::build_isa(tcx.sess)),
+                    value_ranges: value_ranges.as_ref(),
+                },
+            )
+            .unwrap();
+
+            writeln!(file, "test compile")?;
+            writeln!(file, "set is_pic")?;
+            writeln!(file, "set enable_simd")?;
+            writeln!(file, "target {} haswell", crate::target_triple(tcx.sess))?;
+            writeln!(file)?;
+            file.write_all(clif.as_bytes())?;
+            Ok(())
+        },
+    );
+}
+
 impl<M: Module> fmt::Debug for FunctionCx<'_, '_, M> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         writeln!(f, "{:?}", self.instance.substs)?;
index 238abc0d8bdfa557ecd65611a91af4063383d8c8..8f15586a9dc06b8c2444280a3d80509cefb36552 100644 (file)
@@ -158,7 +158,8 @@ fn build_vtable<'tcx>(
         )
         .unwrap();
 
-    fx.cx.module.define_data(data_id, &data_ctx).unwrap();
+    // FIXME don't duplicate definitions in lazy jit mode
+    let _ = fx.cx.module.define_data(data_id, &data_ctx);
 
     data_id
 }
index 3fda1e26dae9e0d04ca7eab93ad2b8b77c1db82b..230e11f274eaebecd52c30dc8ce93231a6a1f1ef 100644 (file)
@@ -485,7 +485,7 @@ pub(crate) unsafe fn optimize(
     diag_handler: &Handler,
     module: &ModuleCodegen<ModuleLlvm>,
     config: &ModuleConfig,
-) -> Result<(), FatalError> {
+) {
     let _timer = cgcx.prof.generic_activity_with_arg("LLVM_module_optimize", &module.name[..]);
 
     let llmod = module.module_llvm.llmod();
@@ -511,7 +511,7 @@ pub(crate) unsafe fn optimize(
                 _ => llvm::OptStage::PreLinkNoLTO,
             };
             optimize_with_new_llvm_pass_manager(cgcx, module, config, opt_level, opt_stage);
-            return Ok(());
+            return;
         }
 
         if cgcx.prof.llvm_recording_enabled() {
@@ -634,7 +634,6 @@ pub(crate) unsafe fn optimize(
         llvm::LLVMDisposePassManager(fpm);
         llvm::LLVMDisposePassManager(mpm);
     }
-    Ok(())
 }
 
 unsafe fn add_sanitizer_passes(config: &ModuleConfig, passes: &mut Vec<&'static mut llvm::Pass>) {
index fa285f3488f8415f28e28be1bbc0b81f44c71720..36a21b38c035d27876ebedd8b398d91844c1ea1d 100644 (file)
@@ -2322,13 +2322,13 @@ fn set_members_of_composite_type(
             DIB(cx),
             composite_type_metadata,
             Some(type_array),
-            type_params,
+            Some(type_params),
         );
     }
 }
 
 /// Computes the type parameters for a type, if any, for the given metadata.
-fn compute_type_parameters(cx: &CodegenCx<'ll, 'tcx>, ty: Ty<'tcx>) -> Option<&'ll DIArray> {
+fn compute_type_parameters(cx: &CodegenCx<'ll, 'tcx>, ty: Ty<'tcx>) -> &'ll DIArray {
     if let ty::Adt(def, substs) = *ty.kind() {
         if substs.types().next().is_some() {
             let generics = cx.tcx.generics_of(def.did);
@@ -2358,10 +2358,10 @@ fn compute_type_parameters(cx: &CodegenCx<'ll, 'tcx>, ty: Ty<'tcx>) -> Option<&'
                 })
                 .collect();
 
-            return Some(create_DIArray(DIB(cx), &template_params[..]));
+            return create_DIArray(DIB(cx), &template_params[..]);
         }
     }
-    return Some(create_DIArray(DIB(cx), &[]));
+    return create_DIArray(DIB(cx), &[]);
 
     fn get_parameter_names(cx: &CodegenCx<'_, '_>, generics: &ty::Generics) -> Vec<Symbol> {
         let mut names = generics
index a58c2fbd8ab2c2219af509bac12afcd9268a357a..92ac770aca554ed338b9c4b5056933884da0e8b1 100644 (file)
@@ -160,7 +160,7 @@ unsafe fn optimize(
         module: &ModuleCodegen<Self::Module>,
         config: &ModuleConfig,
     ) -> Result<(), FatalError> {
-        back::write::optimize(cgcx, diag_handler, module, config)
+        Ok(back::write::optimize(cgcx, diag_handler, module, config))
     }
     unsafe fn optimize_thin(
         cgcx: &CodegenContext<Self>,
@@ -298,21 +298,19 @@ fn link(
         codegen_results: CodegenResults,
         outputs: &OutputFilenames,
     ) -> Result<(), ErrorReported> {
+        use crate::back::archive::LlvmArchiveBuilder;
+        use rustc_codegen_ssa::back::link::link_binary;
+
         // Run the linker on any artifacts that resulted from the LLVM run.
         // This should produce either a finished executable or library.
-        sess.time("link_crate", || {
-            use crate::back::archive::LlvmArchiveBuilder;
-            use rustc_codegen_ssa::back::link::link_binary;
-
-            let target_cpu = crate::llvm_util::target_cpu(sess);
-            link_binary::<LlvmArchiveBuilder<'_>>(
-                sess,
-                &codegen_results,
-                outputs,
-                &codegen_results.crate_name.as_str(),
-                target_cpu,
-            );
-        });
+        let target_cpu = crate::llvm_util::target_cpu(sess);
+        link_binary::<LlvmArchiveBuilder<'_>>(
+            sess,
+            &codegen_results,
+            outputs,
+            &codegen_results.crate_name.as_str(),
+            target_cpu,
+        );
 
         Ok(())
     }
index ccd4d103ddb7f3fc3d26a4969065edbc6e0302b2..a3a2ef0417568dffcd0a39ef8125d5706ee4f9b8 100644 (file)
@@ -2,7 +2,7 @@
 use rustc_data_structures::temp_dir::MaybeTempDir;
 use rustc_fs_util::fix_windows_verbatim_for_gcc;
 use rustc_hir::def_id::CrateNum;
-use rustc_middle::middle::cstore::{EncodedMetadata, LibSource, NativeLib};
+use rustc_middle::middle::cstore::{EncodedMetadata, LibSource};
 use rustc_middle::middle::dependency_format::Linkage;
 use rustc_session::config::{self, CFGuard, CrateType, DebugInfo};
 use rustc_session::config::{OutputFilenames, OutputType, PrintRequest, SanitizerSet};
@@ -22,7 +22,8 @@
 use super::linker::{self, Linker};
 use super::rpath::{self, RPathConfig};
 use crate::{
-    looks_like_rust_object_file, CodegenResults, CompiledModule, CrateInfo, METADATA_FILENAME,
+    looks_like_rust_object_file, CodegenResults, CompiledModule, CrateInfo, NativeLib,
+    METADATA_FILENAME,
 };
 
 use cc::windows_registry;
index 21138f967a2737c3c891b56898fac07a950c64ff..14ace02844e4304eae213f398a46e26dcdf65926 100644 (file)
@@ -46,7 +46,6 @@
 use rustc_session::config::{self, EntryFnType};
 use rustc_session::utils::NativeLibKind;
 use rustc_session::Session;
-use rustc_symbol_mangling::test as symbol_names_test;
 use rustc_target::abi::{Align, LayoutOf, VariantIdx};
 
 use std::cmp;
@@ -486,8 +485,6 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
 
         ongoing_codegen.codegen_finished(tcx);
 
-        finalize_tcx(tcx);
-
         ongoing_codegen.check_for_errors(tcx.sess);
 
         return ongoing_codegen;
@@ -688,14 +685,8 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
         total_codegen_time.into_inner(),
     );
 
-    rustc_incremental::assert_module_sources::assert_module_sources(tcx);
-
-    symbol_names_test::report_symbol_names(tcx);
-
     ongoing_codegen.check_for_errors(tcx.sess);
 
-    finalize_tcx(tcx);
-
     ongoing_codegen.into_inner()
 }
 
@@ -746,18 +737,6 @@ fn drop(&mut self) {
     }
 }
 
-fn finalize_tcx(tcx: TyCtxt<'_>) {
-    tcx.sess.time("assert_dep_graph", || rustc_incremental::assert_dep_graph(tcx));
-    tcx.sess.time("serialize_dep_graph", || rustc_incremental::save_dep_graph(tcx));
-
-    // We assume that no queries are run past here. If there are new queries
-    // after this point, they'll show up as "<unknown>" in self-profiling data.
-    {
-        let _prof_timer = tcx.prof.generic_activity("self_profile_alloc_query_strings");
-        tcx.alloc_self_profile_query_strings();
-    }
-}
-
 impl CrateInfo {
     pub fn new(tcx: TyCtxt<'_>) -> CrateInfo {
         let mut info = CrateInfo {
@@ -766,7 +745,7 @@ pub fn new(tcx: TyCtxt<'_>) -> CrateInfo {
             profiler_runtime: None,
             is_no_builtins: Default::default(),
             native_libraries: Default::default(),
-            used_libraries: tcx.native_libraries(LOCAL_CRATE),
+            used_libraries: tcx.native_libraries(LOCAL_CRATE).iter().map(Into::into).collect(),
             link_args: tcx.link_args(LOCAL_CRATE),
             crate_name: Default::default(),
             used_crates_dynamic: cstore::used_crates(tcx, LinkagePreference::RequireDynamic),
@@ -787,7 +766,8 @@ pub fn new(tcx: TyCtxt<'_>) -> CrateInfo {
         info.missing_lang_items.reserve(n_crates);
 
         for &cnum in crates.iter() {
-            info.native_libraries.insert(cnum, tcx.native_libraries(cnum));
+            info.native_libraries
+                .insert(cnum, tcx.native_libraries(cnum).iter().map(Into::into).collect());
             info.crate_name.insert(cnum, tcx.crate_name(cnum).to_string());
             info.used_crate_source.insert(cnum, tcx.used_crate_source(cnum));
             if tcx.is_panic_runtime(cnum) {
index ee889d552412e295d8df11790f1afb5ecac25b9e..e27eac3f69b00e5fe25620529303c436cf53012c 100644 (file)
 #[macro_use]
 extern crate rustc_middle;
 
+use rustc_ast as ast;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::sync::Lrc;
 use rustc_hir::def_id::CrateNum;
 use rustc_hir::LangItem;
 use rustc_middle::dep_graph::WorkProduct;
-use rustc_middle::middle::cstore::{CrateSource, LibSource, NativeLib};
+use rustc_middle::middle::cstore::{self, CrateSource, LibSource};
 use rustc_middle::middle::dependency_format::Dependencies;
 use rustc_middle::ty::query::Providers;
 use rustc_session::config::{OutputFilenames, OutputType, RUST_CGU_EXT};
+use rustc_session::utils::NativeLibKind;
 use rustc_span::symbol::Symbol;
 use std::path::{Path, PathBuf};
 
@@ -105,6 +107,19 @@ pub struct MemFlags: u8 {
     }
 }
 
+#[derive(Clone, Debug, Encodable, Decodable, HashStable)]
+pub struct NativeLib {
+    pub kind: NativeLibKind,
+    pub name: Option<Symbol>,
+    pub cfg: Option<ast::MetaItem>,
+}
+
+impl From<&cstore::NativeLib> for NativeLib {
+    fn from(lib: &cstore::NativeLib) -> Self {
+        NativeLib { kind: lib.kind, name: lib.name, cfg: lib.cfg.clone() }
+    }
+}
+
 /// Misc info we load from metadata to persist beyond the tcx.
 ///
 /// Note: though `CrateNum` is only meaningful within the same tcx, information within `CrateInfo`
@@ -119,9 +134,9 @@ pub struct CrateInfo {
     pub compiler_builtins: Option<CrateNum>,
     pub profiler_runtime: Option<CrateNum>,
     pub is_no_builtins: FxHashSet<CrateNum>,
-    pub native_libraries: FxHashMap<CrateNum, Lrc<Vec<NativeLib>>>,
+    pub native_libraries: FxHashMap<CrateNum, Vec<NativeLib>>,
     pub crate_name: FxHashMap<CrateNum, String>,
-    pub used_libraries: Lrc<Vec<NativeLib>>,
+    pub used_libraries: Vec<NativeLib>,
     pub link_args: Lrc<Vec<String>>,
     pub used_crate_source: FxHashMap<CrateNum, Lrc<CrateSource>>,
     pub used_crates_static: Vec<(CrateNum, LibSource)>,
index 44bb0deeae97f771f074d72ca6cb4df8d8619edf..57e49ba8d1a56031411972aeff8e772d2c659732 100644 (file)
@@ -112,12 +112,12 @@ fn process_place(
             };
 
             // Allow uses of projections that are ZSTs or from scalar fields.
-            let is_consume = match context {
+            let is_consume = matches!(
+                context,
                 PlaceContext::NonMutatingUse(
                     NonMutatingUseContext::Copy | NonMutatingUseContext::Move,
-                ) => true,
-                _ => false,
-            };
+                )
+            );
             if is_consume {
                 let base_ty =
                     mir::Place::ty_from(place_ref.local, proj_base, self.fx.mir, cx.tcx());
index ce56f1635495e8082cdcab3be0e68e515d2217e9..ecac05fd955720b35a1b291f46e5fbf963466d4a 100644 (file)
@@ -522,7 +522,7 @@ fn codegen_call_terminator(
         mut bx: Bx,
         terminator: &mir::Terminator<'tcx>,
         func: &mir::Operand<'tcx>,
-        args: &Vec<mir::Operand<'tcx>>,
+        args: &[mir::Operand<'tcx>],
         destination: &Option<(mir::Place<'tcx>, mir::BasicBlock)>,
         cleanup: Option<mir::BasicBlock>,
         fn_span: Span,
index d5b2cbaa558430107530c319d202dd399cc5ffb2..f1eae605da0181b12967dea276510702b23f894c 100644 (file)
@@ -170,7 +170,7 @@ pub fn debug_introduce_local(&self, bx: &mut Bx, local: mir::Local) {
                 // (after #67586 gets fixed).
                 None
             } else {
-                let name = kw::Invalid;
+                let name = kw::Empty;
                 let decl = &self.mir.local_decls[local];
                 let dbg_var = if full_debug_info {
                     self.adjusted_span_and_dbg_scope(decl.source_info).map(
@@ -204,7 +204,7 @@ pub fn debug_introduce_local(&self, bx: &mut Bx, local: mir::Local) {
             None
         } else {
             Some(match whole_local_var.or(fallback_var) {
-                Some(var) if var.name != kw::Invalid => var.name.to_string(),
+                Some(var) if var.name != kw::Empty => var.name.to_string(),
                 _ => format!("{:?}", local),
             })
         };
index 5b3d8233f3da3b960c1c2cef55edacfd49b52128..e2cbb09ce5e6d29e54c70975f4ff5c49f5903298 100644 (file)
@@ -523,7 +523,7 @@ struct VisitingNodeFrame<G: DirectedGraph, Successors> {
                             successors_len: 0,
                             min_depth: depth,
                             min_cycle_root: successor_node,
-                            successor_node: successor_node,
+                            successor_node,
                         });
                         continue 'recurse;
                     }
index d903a557c7fdf692b16702002b3727ceefd138a4..5880bbd3de44e83018d2d69b3476fd47aef11df0 100644 (file)
@@ -15,8 +15,7 @@
 #![feature(fn_traits)]
 #![feature(int_bits_const)]
 #![feature(min_specialization)]
-#![cfg_attr(bootstrap, feature(optin_builtin_traits))]
-#![cfg_attr(not(bootstrap), feature(auto_traits))]
+#![feature(auto_traits)]
 #![feature(nll)]
 #![feature(allow_internal_unstable)]
 #![feature(hash_raw_entry)]
@@ -27,7 +26,7 @@
 #![feature(thread_id_value)]
 #![feature(extend_one)]
 #![feature(const_panic)]
-#![feature(min_const_generics)]
+#![cfg_attr(bootstrap, feature(min_const_generics))]
 #![feature(new_uninit)]
 #![feature(once_cell)]
 #![feature(maybe_uninit_uninit_array)]
index b3466f49b9f2582678d60c1044cfeac543dac745..d57ab2433ad1b291c0306046e3de028d9b253e72 100644 (file)
@@ -603,7 +603,7 @@ fn handle_explain(registry: Registry, code: &str, output: ErrorOutputType) {
     }
 }
 
-fn show_content_with_pager(content: &String) {
+fn show_content_with_pager(content: &str) {
     let pager_name = env::var_os("PAGER").unwrap_or_else(|| {
         if cfg!(windows) { OsString::from("more.com") } else { OsString::from("less") }
     });
index 016b3f38aa310598bba2365a47289709238af03a..56d0e6afa183dcc4eeb85fc9b0bcc4da8dd00cd7 100644 (file)
@@ -3,8 +3,6 @@ An array without a fixed length was pattern-matched.
 Erroneous code example:
 
 ```compile_fail,E0730
-#![feature(const_generics)]
-
 fn is_123<const N: usize>(x: [u32; N]) -> bool {
     match x {
         [1, 2, ..] => true, // error: cannot pattern-match on an
index 278bf9b907b240358802d40bf5c53a59f6238035..b39163a9de3fd7b63bc2fdc85cac7d72f0f93114 100644 (file)
@@ -10,6 +10,5 @@ fn foo<T, const N: T>() {} // error!
 To fix this error, use a concrete type for the const parameter:
 
 ```
-#![feature(const_generics)]
 fn foo<T, const N: usize>() {}
 ```
index 335f3b7a9a011b703480b1d1e19a31193f0830da..774a0764d114f952f251549f74c1afff1d441c1a 100644 (file)
@@ -2,8 +2,8 @@
 use crate::module::DirectoryOwnership;
 
 use rustc_ast::ptr::P;
-use rustc_ast::token;
-use rustc_ast::tokenstream::TokenStream;
+use rustc_ast::token::{self, Nonterminal};
+use rustc_ast::tokenstream::{CanSynthesizeMissingTokens, TokenStream};
 use rustc_ast::visit::{AssocCtxt, Visitor};
 use rustc_ast::{self as ast, Attribute, NodeId, PatKind};
 use rustc_attr::{self as attr, Deprecation, HasAttrs, Stability};
@@ -119,8 +119,8 @@ pub fn visit_with<'a, V: Visitor<'a>>(&'a self, visitor: &mut V) {
         }
     }
 
-    crate fn into_tokens(self, sess: &ParseSess) -> TokenStream {
-        let nt = match self {
+    crate fn into_nonterminal(self) -> Nonterminal {
+        match self {
             Annotatable::Item(item) => token::NtItem(item),
             Annotatable::TraitItem(item) | Annotatable::ImplItem(item) => {
                 token::NtItem(P(item.and_then(ast::AssocItem::into_item)))
@@ -137,8 +137,11 @@ pub fn visit_with<'a, V: Visitor<'a>>(&'a self, visitor: &mut V) {
             | Annotatable::Param(..)
             | Annotatable::StructField(..)
             | Annotatable::Variant(..) => panic!("unexpected annotatable"),
-        };
-        nt_to_tokenstream(&nt, sess, DUMMY_SP)
+        }
+    }
+
+    crate fn into_tokens(self, sess: &ParseSess) -> TokenStream {
+        nt_to_tokenstream(&self.into_nonterminal(), sess, DUMMY_SP, CanSynthesizeMissingTokens::No)
     }
 
     pub fn expect_item(self) -> P<ast::Item> {
index 563783c5b795db575cf37bf1061798d1dfbd15a9..1193f66651ce9dda9c34d8c53ed34a80bae5f1db 100644 (file)
@@ -29,6 +29,7 @@
 pub struct StripUnconfigured<'a> {
     pub sess: &'a Session,
     pub features: Option<&'a Features>,
+    pub modified: bool,
 }
 
 fn get_features(
@@ -199,7 +200,7 @@ fn active_features_up_to(edition: Edition) -> impl Iterator<Item = &'static Feat
 
 // `cfg_attr`-process the crate's attributes and compute the crate's features.
 pub fn features(sess: &Session, mut krate: ast::Crate) -> (ast::Crate, Features) {
-    let mut strip_unconfigured = StripUnconfigured { sess, features: None };
+    let mut strip_unconfigured = StripUnconfigured { sess, features: None, modified: false };
 
     let unconfigured_attrs = krate.attrs.clone();
     let diag = &sess.parse_sess.span_diagnostic;
@@ -243,7 +244,12 @@ macro_rules! configure {
 impl<'a> StripUnconfigured<'a> {
     pub fn configure<T: HasAttrs>(&mut self, mut node: T) -> Option<T> {
         self.process_cfg_attrs(&mut node);
-        self.in_cfg(node.attrs()).then_some(node)
+        if self.in_cfg(node.attrs()) {
+            Some(node)
+        } else {
+            self.modified = true;
+            None
+        }
     }
 
     /// Parse and expand all `cfg_attr` attributes into a list of attributes
@@ -270,6 +276,9 @@ fn process_cfg_attr(&mut self, attr: Attribute) -> Vec<Attribute> {
             return vec![attr];
         }
 
+        // A `#[cfg_attr]` either gets removed, or replaced with a new attribute
+        self.modified = true;
+
         let (cfg_predicate, expanded_attrs) = match self.parse_cfg_attr(&attr) {
             None => return vec![],
             Some(r) => r,
index 2da5bde028fc12925b98a88700ed5068bc2481a5..5d40d478b963d7bce9adef36551494e5010e5650 100644 (file)
@@ -12,7 +12,7 @@
 use rustc_ast::token;
 use rustc_ast::tokenstream::TokenStream;
 use rustc_ast::visit::{self, AssocCtxt, Visitor};
-use rustc_ast::{self as ast, AttrItem, Block, LitKind, NodeId, PatKind, Path};
+use rustc_ast::{self as ast, AttrItem, AttrStyle, Block, LitKind, NodeId, PatKind, Path};
 use rustc_ast::{ItemKind, MacArgs, MacCallStmt, MacStmtStyle, StmtKind, Unsafe};
 use rustc_ast_pretty::pprust;
 use rustc_attr::{self as attr, is_builtin_attr, HasAttrs};
@@ -522,12 +522,29 @@ pub fn fully_expand_fragment(&mut self, input_fragment: AstFragment) -> AstFragm
                         item.visit_attrs(|attrs| attrs.retain(|a| !a.has_name(sym::derive)));
                         (item, Vec::new())
                     } else {
-                        let mut item = StripUnconfigured {
+                        let mut visitor = StripUnconfigured {
                             sess: self.cx.sess,
                             features: self.cx.ecfg.features,
-                        }
-                        .fully_configure(item);
+                            modified: false,
+                        };
+                        let mut item = visitor.fully_configure(item);
                         item.visit_attrs(|attrs| attrs.retain(|a| !a.has_name(sym::derive)));
+                        if visitor.modified && !derives.is_empty() {
+                            // Erase the tokens if cfg-stripping modified the item
+                            // This will cause us to synthesize fake tokens
+                            // when `nt_to_tokenstream` is called on this item.
+                            match &mut item {
+                                Annotatable::Item(item) => item.tokens = None,
+                                Annotatable::Stmt(stmt) => {
+                                    if let StmtKind::Item(item) = &mut stmt.kind {
+                                        item.tokens = None
+                                    } else {
+                                        panic!("Unexpected stmt {:?}", stmt);
+                                    }
+                                }
+                                _ => panic!("Unexpected annotatable {:?}", item),
+                            }
+                        }
 
                         invocations.reserve(derives.len());
                         let derive_placeholders = derives
@@ -622,7 +639,11 @@ fn collect_invocations(
 
         let invocations = {
             let mut collector = InvocationCollector {
-                cfg: StripUnconfigured { sess: &self.cx.sess, features: self.cx.ecfg.features },
+                cfg: StripUnconfigured {
+                    sess: &self.cx.sess,
+                    features: self.cx.ecfg.features,
+                    modified: false,
+                },
                 cx: self.cx,
                 invocations: Vec::new(),
                 monotonic: self.monotonic,
@@ -716,7 +737,15 @@ fn expand_invoc(
                 SyntaxExtensionKind::Attr(expander) => {
                     self.gate_proc_macro_input(&item);
                     self.gate_proc_macro_attr_item(span, &item);
-                    let tokens = item.into_tokens(&self.cx.sess.parse_sess);
+                    let tokens = match attr.style {
+                        AttrStyle::Outer => item.into_tokens(&self.cx.sess.parse_sess),
+                        // FIXME: Properly collect tokens for inner attributes
+                        AttrStyle::Inner => rustc_parse::fake_token_stream(
+                            &self.cx.sess.parse_sess,
+                            &item.into_nonterminal(),
+                            span,
+                        ),
+                    };
                     let attr_item = attr.unwrap_normal_item();
                     if let MacArgs::Eq(..) = attr_item.args {
                         self.cx.span_err(span, "key-value macro attributes are not supported");
index eb4aab116f00f7218d031466934bdbe058914e2a..cbc4d14a65a1bf605a8515e80e4633493f6fd4c6 100644 (file)
@@ -84,7 +84,7 @@ enum TokenTree {
     /// e.g., `$var`
     MetaVar(Span, Ident),
     /// e.g., `$var:expr`. This is only used in the left hand side of MBE macros.
-    MetaVarDecl(Span, Ident /* name to bind */, NonterminalKind),
+    MetaVarDecl(Span, Ident /* name to bind */, Option<NonterminalKind>),
 }
 
 impl TokenTree {
index 3cf2d8f8ac1ef9b39bc62acee45bf98f55cf3d32..0c44f5fe9e10a89f7b24faf507ca7962965739fb 100644 (file)
@@ -378,6 +378,11 @@ fn n_rec<I: Iterator<Item = NamedMatch>>(
                     n_rec(sess, next_m, res.by_ref(), ret_val)?;
                 }
             }
+            TokenTree::MetaVarDecl(span, _, None) => {
+                if sess.missing_fragment_specifiers.borrow_mut().remove(&span).is_some() {
+                    return Err((span, "missing fragment specifier".to_string()));
+                }
+            }
             TokenTree::MetaVarDecl(sp, bind_name, _) => match ret_val
                 .entry(MacroRulesNormalizedIdent::new(bind_name))
             {
@@ -446,6 +451,7 @@ fn or_pat_mode(edition: Edition) -> OrPatNonterminalMode {
 ///
 /// A `ParseResult`. Note that matches are kept track of through the items generated.
 fn inner_parse_loop<'root, 'tt>(
+    sess: &ParseSess,
     cur_items: &mut SmallVec<[MatcherPosHandle<'root, 'tt>; 1]>,
     next_items: &mut Vec<MatcherPosHandle<'root, 'tt>>,
     eof_items: &mut SmallVec<[MatcherPosHandle<'root, 'tt>; 1]>,
@@ -563,9 +569,16 @@ fn inner_parse_loop<'root, 'tt>(
                     })));
                 }
 
+                // We need to match a metavar (but the identifier is invalid)... this is an error
+                TokenTree::MetaVarDecl(span, _, None) => {
+                    if sess.missing_fragment_specifiers.borrow_mut().remove(&span).is_some() {
+                        return Error(span, "missing fragment specifier".to_string());
+                    }
+                }
+
                 // We need to match a metavar with a valid ident... call out to the black-box
                 // parser by adding an item to `bb_items`.
-                TokenTree::MetaVarDecl(span, _, kind) => {
+                TokenTree::MetaVarDecl(span, _, Some(kind)) => {
                     // Built-in nonterminals never start with these tokens, so we can eliminate
                     // them from consideration.
                     //
@@ -640,6 +653,7 @@ pub(super) fn parse_tt(parser: &mut Cow<'_, Parser<'_>>, ms: &[TokenTree]) -> Na
         // parsing from the black-box parser done. The result is that `next_items` will contain a
         // bunch of possible next matcher positions in `next_items`.
         match inner_parse_loop(
+            parser.sess,
             &mut cur_items,
             &mut next_items,
             &mut eof_items,
@@ -701,7 +715,7 @@ pub(super) fn parse_tt(parser: &mut Cow<'_, Parser<'_>>, ms: &[TokenTree]) -> Na
             let nts = bb_items
                 .iter()
                 .map(|item| match item.top_elts.get_tt(item.idx) {
-                    TokenTree::MetaVarDecl(_, bind, kind) => format!("{} ('{}')", kind, bind),
+                    TokenTree::MetaVarDecl(_, bind, Some(kind)) => format!("{} ('{}')", kind, bind),
                     _ => panic!(),
                 })
                 .collect::<Vec<String>>()
@@ -731,7 +745,7 @@ pub(super) fn parse_tt(parser: &mut Cow<'_, Parser<'_>>, ms: &[TokenTree]) -> Na
             assert_eq!(bb_items.len(), 1);
 
             let mut item = bb_items.pop().unwrap();
-            if let TokenTree::MetaVarDecl(span, _, kind) = item.top_elts.get_tt(item.idx) {
+            if let TokenTree::MetaVarDecl(span, _, Some(kind)) = item.top_elts.get_tt(item.idx) {
                 let match_cur = item.match_cur;
                 // We use the span of the metavariable declaration to determine any
                 // edition-specific matching behavior for non-terminals.
index 66463eeb907135963b1e1453be108deb2e6349c1..89d375b257da570b9ee8a5d65ca054a8dc5d8356 100644 (file)
@@ -401,7 +401,7 @@ pub fn compile_declarative_macro(
     let diag = &sess.parse_sess.span_diagnostic;
     let lhs_nm = Ident::new(sym::lhs, def.span);
     let rhs_nm = Ident::new(sym::rhs, def.span);
-    let tt_spec = NonterminalKind::TT;
+    let tt_spec = Some(NonterminalKind::TT);
 
     // Parse the macro_rules! invocation
     let (macro_rules, body) = match &def.kind {
@@ -578,7 +578,7 @@ fn check_lhs_no_empty_seq(sess: &ParseSess, tts: &[mbe::TokenTree]) -> bool {
             TokenTree::Sequence(span, ref seq) => {
                 if seq.separator.is_none()
                     && seq.tts.iter().all(|seq_tt| match *seq_tt {
-                        TokenTree::MetaVarDecl(_, _, NonterminalKind::Vis) => true,
+                        TokenTree::MetaVarDecl(_, _, Some(NonterminalKind::Vis)) => true,
                         TokenTree::Sequence(_, ref sub_seq) => {
                             sub_seq.kleene.op == mbe::KleeneOp::ZeroOrMore
                                 || sub_seq.kleene.op == mbe::KleeneOp::ZeroOrOne
@@ -961,7 +961,7 @@ fn check_matcher_core(
         // Now `last` holds the complete set of NT tokens that could
         // end the sequence before SUFFIX. Check that every one works with `suffix`.
         for token in &last.tokens {
-            if let TokenTree::MetaVarDecl(_, name, kind) = *token {
+            if let TokenTree::MetaVarDecl(_, name, Some(kind)) = *token {
                 for next_token in &suffix_first.tokens {
                     match is_in_follow(next_token, kind) {
                         IsInFollow::Yes => {}
@@ -1019,7 +1019,7 @@ fn check_matcher_core(
 }
 
 fn token_can_be_followed_by_any(tok: &mbe::TokenTree) -> bool {
-    if let mbe::TokenTree::MetaVarDecl(_, _, kind) = *tok {
+    if let mbe::TokenTree::MetaVarDecl(_, _, Some(kind)) = *tok {
         frag_can_be_followed_by_any(kind)
     } else {
         // (Non NT's can always be followed by anything in matchers.)
@@ -1123,7 +1123,7 @@ fn is_in_follow(tok: &mbe::TokenTree, kind: NonterminalKind) -> IsInFollow {
                         }
                         _ => IsInFollow::No(TOKENS),
                     },
-                    TokenTree::MetaVarDecl(_, _, NonterminalKind::Block) => IsInFollow::Yes,
+                    TokenTree::MetaVarDecl(_, _, Some(NonterminalKind::Block)) => IsInFollow::Yes,
                     _ => IsInFollow::No(TOKENS),
                 }
             }
@@ -1158,7 +1158,7 @@ fn is_in_follow(tok: &mbe::TokenTree, kind: NonterminalKind) -> IsInFollow {
                     TokenTree::MetaVarDecl(
                         _,
                         _,
-                        NonterminalKind::Ident | NonterminalKind::Ty | NonterminalKind::Path,
+                        Some(NonterminalKind::Ident | NonterminalKind::Ty | NonterminalKind::Path),
                     ) => IsInFollow::Yes,
                     _ => IsInFollow::No(TOKENS),
                 }
@@ -1171,7 +1171,8 @@ fn quoted_tt_to_string(tt: &mbe::TokenTree) -> String {
     match *tt {
         mbe::TokenTree::Token(ref token) => pprust::token_to_string(&token),
         mbe::TokenTree::MetaVar(_, name) => format!("${}", name),
-        mbe::TokenTree::MetaVarDecl(_, name, kind) => format!("${}:{}", name, kind),
+        mbe::TokenTree::MetaVarDecl(_, name, Some(kind)) => format!("${}:{}", name, kind),
+        mbe::TokenTree::MetaVarDecl(_, name, None) => format!("${}:", name),
         _ => panic!(
             "{}",
             "unexpected mbe::TokenTree::{Sequence or Delimited} \
index 48db532c78f3061fd52bb4a36be01df7d42164e0..01b11bb979d68749ea9e558bd2a101c0a9df9691 100644 (file)
@@ -3,7 +3,7 @@
 
 use rustc_ast::token::{self, Token};
 use rustc_ast::tokenstream;
-use rustc_ast::NodeId;
+use rustc_ast::{NodeId, DUMMY_NODE_ID};
 use rustc_ast_pretty::pprust;
 use rustc_session::parse::ParseSess;
 use rustc_span::symbol::{kw, Ident};
@@ -73,7 +73,7 @@ pub(super) fn parse(
                                                 .emit();
                                             token::NonterminalKind::Ident
                                         });
-                                    result.push(TokenTree::MetaVarDecl(span, ident, kind));
+                                    result.push(TokenTree::MetaVarDecl(span, ident, Some(kind)));
                                     continue;
                                 }
                                 _ => token.span,
@@ -83,8 +83,11 @@ pub(super) fn parse(
                     }
                     tree => tree.as_ref().map(tokenstream::TokenTree::span).unwrap_or(start_sp),
                 };
-                sess.span_diagnostic.struct_span_err(span, "missing fragment specifier").emit();
-                continue;
+                if node_id != DUMMY_NODE_ID {
+                    // Macros loaded from other crates have dummy node ids.
+                    sess.missing_fragment_specifiers.borrow_mut().insert(span, node_id);
+                }
+                result.push(TokenTree::MetaVarDecl(span, ident, None));
             }
 
             // Not a metavar or no matchers allowed, so just return the tree
index 36707a1ae272da6b61bdbb3389dba5cd7302c105..e8e098b621295b898750510464a46c1bb856d894 100644 (file)
@@ -3,7 +3,7 @@
 
 use rustc_ast::ptr::P;
 use rustc_ast::token;
-use rustc_ast::tokenstream::{TokenStream, TokenTree};
+use rustc_ast::tokenstream::{CanSynthesizeMissingTokens, TokenStream, TokenTree};
 use rustc_ast::{self as ast, *};
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::{struct_span_err, Applicability, ErrorReported};
@@ -94,7 +94,12 @@ fn expand(
         let input = if item.pretty_printing_compatibility_hack() {
             TokenTree::token(token::Interpolated(Lrc::new(item)), DUMMY_SP).into()
         } else {
-            nt_to_tokenstream(&item, &ecx.sess.parse_sess, DUMMY_SP)
+            nt_to_tokenstream(
+                &item,
+                &ecx.sess.parse_sess,
+                DUMMY_SP,
+                CanSynthesizeMissingTokens::Yes,
+            )
         };
 
         let server = proc_macro_server::Rustc::new(ecx);
index 4cfb188783ba110c42165132188d698c3a535152..02ae842675f37029e50827f3a7733618c8dcc5ae 100644 (file)
@@ -2,7 +2,8 @@
 
 use rustc_ast as ast;
 use rustc_ast::token;
-use rustc_ast::tokenstream::{self, DelimSpan, Spacing::*, TokenStream, TreeAndSpacing};
+use rustc_ast::tokenstream::{self, CanSynthesizeMissingTokens};
+use rustc_ast::tokenstream::{DelimSpan, Spacing::*, TokenStream, TreeAndSpacing};
 use rustc_ast_pretty::pprust;
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::Diagnostic;
@@ -178,7 +179,7 @@ macro_rules! op {
                 {
                     TokenTree::Ident(Ident::new(sess, name.name, is_raw, name.span))
                 } else {
-                    let stream = nt_to_tokenstream(&nt, sess, span);
+                    let stream = nt_to_tokenstream(&nt, sess, span, CanSynthesizeMissingTokens::No);
                     TokenTree::Group(Group {
                         delimiter: Delimiter::None,
                         stream,
index 4401ec0a04ea57028ca516088f7d457dae8d88aa..aa54ffb132dc9686b73f00aeb3e90a695c380ce5 100644 (file)
@@ -273,6 +273,8 @@ macro_rules! declare_features {
     /// Allows patterns with concurrent by-move and by-ref bindings.
     /// For example, you can write `Foo(a, ref b)` where `a` is by-move and `b` is by-ref.
     (accepted, move_ref_pattern, "1.48.0", Some(68354), None),
+    /// The smallest useful subset of `const_generics`.
+    (accepted, min_const_generics, "1.51.0", Some(74878), None),
 
     // -------------------------------------------------------------------------
     // feature-group-end: accepted features
index 845e03150d71a85fda573010f84ca6f50e09a971..d60ae8ef75b81ac69592e88baf3633d4af5a62d2 100644 (file)
@@ -578,9 +578,6 @@ pub fn set(&self, features: &mut Features, span: Span) {
     /// Allows calling `transmute` in const fn
     (active, const_fn_transmute, "1.46.0", Some(53605), None),
 
-    /// The smallest useful subset of `const_generics`.
-    (active, min_const_generics, "1.47.0", Some(74878), None),
-
     /// Allows `if let` guard in match arms.
     (active, if_let_guard, "1.47.0", Some(51114), None),
 
@@ -651,5 +648,7 @@ pub fn set(&self, features: &mut Features, span: Span) {
 
 /// Some features are not allowed to be used together at the same time, if
 /// the two are present, produce an error.
-pub const INCOMPATIBLE_FEATURES: &[(Symbol, Symbol)] =
-    &[(sym::const_generics, sym::min_const_generics)];
+///
+/// Currently empty, but we will probably need this again in the future,
+/// so let's keep it in for now.
+pub const INCOMPATIBLE_FEATURES: &[(Symbol, Symbol)] = &[];
index 2abebbd030387d477d55b460c9d0e2fb7d7eed6d..4ba1416be540e8088c48f46fca6e706d2029ce8a 100644 (file)
@@ -28,7 +28,7 @@ pub struct Lifetime {
     pub span: Span,
 
     /// Either "`'a`", referring to a named lifetime definition,
-    /// or "``" (i.e., `kw::Invalid`), for elision placeholders.
+    /// or "``" (i.e., `kw::Empty`), for elision placeholders.
     ///
     /// HIR lowering inserts these placeholders in type paths that
     /// refer to type definitions needing lifetime parameters,
@@ -607,7 +607,7 @@ pub struct Crate<'hir> {
     // over the ids in increasing order. In principle it should not
     // matter what order we visit things in, but in *practice* it
     // does, because it can affect the order in which errors are
-    // detected, which in turn can make compile-fail tests yield
+    // detected, which in turn can make UI tests yield
     // slightly different results.
     pub items: BTreeMap<HirId, Item<'hir>>,
 
index e17396422f13fa33ab15833cd2b8d0e19e7086d7..9b4388c911f1bb036b813e21d084b6ee749594bb 100644 (file)
@@ -12,7 +12,7 @@
 //! In this code, we report errors on each `rustc_if_this_changed`
 //! annotation. If a path exists in all cases, then we would report
 //! "all path(s) exist". Otherwise, we report: "no path to `foo`" for
-//! each case where no path exists. `compile-fail` tests can then be
+//! each case where no path exists. `ui` tests can then be
 //! used to check when paths exist or do not.
 //!
 //! The full form of the `rustc_if_this_changed` annotation is
index 6b7edde9a67aff756474a48c4ee55ae7bbd303c5..6d6bf4bf5f7058d750a1cd8fd852e0e93a3a9d03 100644 (file)
@@ -417,7 +417,7 @@ pub fn report_region_errors(&self, errors: &Vec<RegionResolutionError<'tcx>>) {
     // obviously it never weeds out ALL errors.
     fn process_errors(
         &self,
-        errors: &Vec<RegionResolutionError<'tcx>>,
+        errors: &[RegionResolutionError<'tcx>],
     ) -> Vec<RegionResolutionError<'tcx>> {
         debug!("process_errors()");
 
@@ -442,7 +442,7 @@ fn process_errors(
         };
 
         let mut errors = if errors.iter().all(|e| is_bound_failure(e)) {
-            errors.clone()
+            errors.to_owned()
         } else {
             errors.iter().filter(|&e| !is_bound_failure(e)).cloned().collect()
         };
index 4d3217a9c0bd977afada57fb34527163c2642667..0958afa03082a22e1da445c7c44baa6e3eccbe3a 100644 (file)
@@ -132,10 +132,7 @@ fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>) {
                 [segment]
                     if segment
                         .res
-                        .map(|res| match res {
-                            Res::SelfTy(_, _) | Res::Def(hir::def::DefKind::TyParam, _) => true,
-                            _ => false,
-                        })
+                        .map(|res| matches!(res, Res::SelfTy(_, _) | Res::Def(hir::def::DefKind::TyParam, _)))
                         .unwrap_or(false) =>
                 {
                     self.types.push(path.span);
index 32f73237dd410411d3b51dd8c437928af1cfdfe2..728dc2de370319897fee6eb3dff68a2e66940bd1 100644 (file)
@@ -93,10 +93,7 @@ fn check_relation(&self, r_a: Region<'tcx>, r_b: Region<'tcx>) -> bool {
 
     /// True for free regions other than `'static`.
     pub fn is_free(&self, r: Region<'_>) -> bool {
-        match *r {
-            ty::ReEarlyBound(_) | ty::ReFree(_) => true,
-            _ => false,
-        }
+        matches!(r, ty::ReEarlyBound(_) | ty::ReFree(_))
     }
 
     /// True if `r` is a free region or static of the sort that this
index d7b2ce7ee208383194e2841adfe84678a7ce98ba..ab34cda8cc18f514edec1adcd522ea453b05d3cd 100644 (file)
@@ -393,10 +393,7 @@ fn expansion(&self, var_values: &mut LexicalRegionResolutions<'tcx>) {
                 if self.expand_node(a_region, b_vid, b_data) {
                     changes.push(b_vid);
                 }
-                match *b_data {
-                    VarValue::Value(ReStatic) | VarValue::ErrorValue => false,
-                    _ => true,
-                }
+                !matches!(b_data, VarValue::Value(ReStatic) | VarValue::ErrorValue)
             });
         }
     }
@@ -972,11 +969,7 @@ fn bound_is_met(
             }
 
             VerifyBound::IsEmpty => {
-                if let ty::ReEmpty(_) = min {
-                    true
-                } else {
-                    false
-                }
+                matches!(min, ty::ReEmpty(_))
             }
 
             VerifyBound::AnyBound(bs) => {
index 069f708856ea46a1bd46f7cdfb5c7da80077ca60..56d9634213ae515b4c39c85d86a55b36b1bb249a 100644 (file)
@@ -1317,7 +1317,7 @@ pub fn resolve_vars_if_possible<T>(&self, value: T) -> T
         T: TypeFoldable<'tcx>,
     {
         if !value.needs_infer() {
-            return value.clone(); // Avoid duplicated subst-folding.
+            return value; // Avoid duplicated subst-folding.
         }
         let mut r = resolve::OpportunisticVarResolver::new(self);
         value.fold_with(&mut r)
index 65284bcee912c446d44df88659d67548098f4286..33bddf1dedc1b2a6fa055207cbc5892b66e1357e 100644 (file)
@@ -90,6 +90,7 @@ pub fn new(ty: ty::ProjectionTy<'tcx>) -> Self {
 pub enum ProjectionCacheEntry<'tcx> {
     InProgress,
     Ambiguous,
+    Recur,
     Error,
     NormalizedTy(NormalizedTy<'tcx>),
 }
@@ -143,7 +144,12 @@ pub fn insert_ty(&mut self, key: ProjectionCacheKey<'tcx>, value: NormalizedTy<'
             "ProjectionCacheEntry::insert_ty: adding cache entry: key={:?}, value={:?}",
             key, value
         );
-        let fresh_key = self.map().insert(key, ProjectionCacheEntry::NormalizedTy(value));
+        let mut map = self.map();
+        if let Some(ProjectionCacheEntry::Recur) = map.get(&key) {
+            debug!("Not overwriting Recur");
+            return;
+        }
+        let fresh_key = map.insert(key, ProjectionCacheEntry::NormalizedTy(value));
         assert!(!fresh_key, "never started projecting `{:?}`", key);
     }
 
@@ -197,6 +203,14 @@ pub fn ambiguous(&mut self, key: ProjectionCacheKey<'tcx>) {
         assert!(!fresh, "never started projecting `{:?}`", key);
     }
 
+    /// Indicates that while trying to normalize `key`, `key` was required to
+    /// be normalized again. Selection or evaluation should eventually report
+    /// an error here.
+    pub fn recur(&mut self, key: ProjectionCacheKey<'tcx>) {
+        let fresh = self.map().insert(key, ProjectionCacheEntry::Recur);
+        assert!(!fresh, "never started projecting `{:?}`", key);
+    }
+
     /// Indicates that trying to normalize `key` resulted in
     /// error.
     pub fn error(&mut self, key: ProjectionCacheKey<'tcx>) {
index acd49d86c2c84e951c60d52b437085d653da8c25..28eb1fed6a0ab6ae415bbab188878a0bb7fe8803 100644 (file)
@@ -25,8 +25,9 @@
 pub type Result<T> = result::Result<T, ErrorReported>;
 
 /// Represents a compiler session.
+///
 /// Can be used to run `rustc_interface` queries.
-/// Created by passing `Config` to `run_compiler`.
+/// Created by passing [`Config`] to [`run_compiler`].
 pub struct Compiler {
     pub(crate) sess: Lrc<Session>,
     codegen_backend: Lrc<Box<dyn CodegenBackend>>,
index c13d26c79d738c89c8edc0a102b2c10e81f7cc41..461ee08592275c9eab7dda327d11446640991383 100644 (file)
@@ -29,6 +29,7 @@
 use rustc_plugin_impl as plugin;
 use rustc_resolve::{Resolver, ResolverArenas};
 use rustc_session::config::{CrateType, Input, OutputFilenames, OutputType, PpMode, PpSourceMode};
+use rustc_session::lint;
 use rustc_session::output::{filename_for_input, filename_for_metadata};
 use rustc_session::search_paths::PathKind;
 use rustc_session::Session;
@@ -95,7 +96,7 @@ fn count_nodes(krate: &ast::Crate) -> usize {
 /// harness if one is to be provided, injection of a dependency on the
 /// standard library and prelude, and name resolution.
 ///
-/// Returns `None` if we're aborting after handling -W help.
+/// Returns [`None`] if we're aborting after handling -W help.
 pub fn configure_and_expand(
     sess: Lrc<Session>,
     lint_store: Lrc<LintStore>,
@@ -306,11 +307,27 @@ fn configure_and_expand_inner<'a>(
             ecx.check_unused_macros();
         });
 
+        let mut missing_fragment_specifiers: Vec<_> = ecx
+            .sess
+            .parse_sess
+            .missing_fragment_specifiers
+            .borrow()
+            .iter()
+            .map(|(span, node_id)| (*span, *node_id))
+            .collect();
+        missing_fragment_specifiers.sort_unstable_by_key(|(span, _)| *span);
+
+        let recursion_limit_hit = ecx.reduced_recursion_limit.is_some();
+
+        for (span, node_id) in missing_fragment_specifiers {
+            let lint = lint::builtin::MISSING_FRAGMENT_SPECIFIER;
+            let msg = "missing fragment specifier";
+            resolver.lint_buffer().buffer_lint(lint, node_id, span, msg);
+        }
         if cfg!(windows) {
             env::set_var("PATH", &old_path);
         }
 
-        let recursion_limit_hit = ecx.reduced_recursion_limit.is_some();
         if recursion_limit_hit {
             // If we hit a recursion limit, exit early to avoid later passes getting overwhelmed
             // with a large AST
@@ -872,7 +889,7 @@ fn analysis(tcx: TyCtxt<'_>, cnum: CrateNum) -> Result<()> {
 
     // Avoid overwhelming user with errors if borrow checking failed.
     // I'm not sure how helpful this is, to be honest, but it avoids a
-    // lot of annoying errors in the compile-fail tests (basically,
+    // lot of annoying errors in the ui tests (basically,
     // lint warnings and so on -- kindck used to do this abort, but
     // kindck is gone now). -nmatsakis
     if sess.has_errors() {
@@ -996,6 +1013,23 @@ pub fn start_codegen<'tcx>(
         codegen_backend.codegen_crate(tcx, metadata, need_metadata_module)
     });
 
+    // Don't run these test assertions when not doing codegen. Compiletest tries to build
+    // build-fail tests in check mode first and expects it to not give an error in that case.
+    if tcx.sess.opts.output_types.should_codegen() {
+        rustc_incremental::assert_module_sources::assert_module_sources(tcx);
+        rustc_symbol_mangling::test::report_symbol_names(tcx);
+    }
+
+    tcx.sess.time("assert_dep_graph", || rustc_incremental::assert_dep_graph(tcx));
+    tcx.sess.time("serialize_dep_graph", || rustc_incremental::save_dep_graph(tcx));
+
+    // We assume that no queries are run past here. If there are new queries
+    // after this point, they'll show up as "<unknown>" in self-profiling data.
+    {
+        let _prof_timer = tcx.prof.generic_activity("self_profile_alloc_query_strings");
+        tcx.alloc_self_profile_query_strings();
+    }
+
     info!("Post-codegen\n{:?}", tcx.debug_stats());
 
     if tcx.sess.opts.output_types.contains_key(&OutputType::Mir) {
index 4c340b3fc1f58052918c870880a0e0ef55896c4f..9c49f926d417bb9e5b31656343435db0ba716b30 100644 (file)
 use std::rc::Rc;
 
 /// Represent the result of a query.
-/// This result can be stolen with the `take` method and generated with the `compute` method.
+///
+/// This result can be stolen with the [`take`] method and generated with the [`compute`] method.
+///
+/// [`take`]: Self::take
+/// [`compute`]: Self::compute
 pub struct Query<T> {
     result: RefCell<Option<Result<T>>>,
 }
@@ -276,7 +280,7 @@ pub fn ongoing_codegen(&'tcx self) -> Result<&Query<Box<dyn Any>>> {
                 // Don't do code generation if there were any errors
                 self.session().compile_status()?;
 
-                // Hook for compile-fail tests.
+                // Hook for UI tests.
                 Self::check_for_rustc_errors_attr(tcx);
 
                 Ok(passes::start_codegen(&***self.codegen_backend(), tcx, &*outputs.peek()))
@@ -285,7 +289,7 @@ pub fn ongoing_codegen(&'tcx self) -> Result<&Query<Box<dyn Any>>> {
     }
 
     /// Check for the `#[rustc_error]` annotation, which forces an error in codegen. This is used
-    /// to write compile-fail tests that actually test that compilation succeeds without reporting
+    /// to write UI tests that actually test that compilation succeeds without reporting
     /// an error.
     fn check_for_rustc_errors_attr(tcx: TyCtxt<'_>) {
         let def_id = match tcx.entry_fn(LOCAL_CRATE) {
@@ -399,6 +403,7 @@ pub fn link(self) -> Result<()> {
             return Ok(());
         }
 
+        let _timer = sess.prof.verbose_generic_activity("link_crate");
         self.codegen_backend.link(&self.sess, codegen_results, &self.prepare_outputs)
     }
 }
index 676c85e4afdceda21bd13b190a4895f9b472e545..a8371274f61f8cabf9cc5ca1f655a51db67c4a80 100644 (file)
@@ -868,7 +868,7 @@ fn check_trait_item(&mut self, cx: &EarlyContext<'_>, it: &ast::AssocItem) {
         if let ast::AssocItemKind::Fn(_, ref sig, _, _) = it.kind {
             for arg in sig.decl.inputs.iter() {
                 if let ast::PatKind::Ident(_, ident, None) = arg.pat.kind {
-                    if ident.name == kw::Invalid {
+                    if ident.name == kw::Empty {
                         cx.struct_span_lint(ANONYMOUS_PARAMETERS, arg.pat.span, |lint| {
                             let ty_snip = cx.sess.source_map().span_to_snippet(arg.ty.span);
 
@@ -2299,7 +2299,7 @@ fn check_crate(&mut self, cx: &EarlyContext<'_>, _: &ast::Crate) {
     }
 }
 
-const HAS_MIN_FEATURES: &[Symbol] = &[sym::const_generics, sym::specialization];
+const HAS_MIN_FEATURES: &[Symbol] = &[sym::specialization];
 
 declare_lint! {
     /// The `invalid_value` lint detects creating a value that is not valid,
index bfeef4904893adb6cd165fdc6e7e69bc00a63986..c82fe50af870621c4f4400400f278104f58a5032 100644 (file)
@@ -261,6 +261,7 @@ pub fn register_group(
         }
     }
 
+    #[track_caller]
     pub fn register_renamed(&mut self, old_name: &str, new_name: &str) {
         let target = match self.by_name.get(new_name) {
             Some(&Id(lint_id)) => lint_id,
@@ -728,7 +729,7 @@ pub fn qpath_res(&self, qpath: &hir::QPath<'_>, id: hir::HirId) -> Res {
 
     /// Check if a `DefId`'s path matches the given absolute type path usage.
     ///
-    /// Anonymous scopes such as `extern` imports are matched with `kw::Invalid`;
+    /// Anonymous scopes such as `extern` imports are matched with `kw::Empty`;
     /// inherent `impl` blocks are matched with the name of the type.
     ///
     /// Instead of using this method, it is often preferable to instead use
index 3e22eba15aaef69a764541f466ac4ee1cb77e274..5cece569903c77aa8d02e88b6c286ede650321e1 100644 (file)
@@ -12,7 +12,9 @@
 use rustc_middle::hir::map::Map;
 use rustc_middle::lint::LevelSource;
 use rustc_middle::lint::LintDiagnosticBuilder;
-use rustc_middle::lint::{struct_lint_level, LintLevelMap, LintLevelSets, LintSet, LintSource};
+use rustc_middle::lint::{
+    struct_lint_level, LintLevelMap, LintLevelSets, LintLevelSource, LintSet,
+};
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::lint::{builtin, Level, Lint, LintId};
@@ -91,7 +93,7 @@ fn process_command_line(&mut self, sess: &Session, store: &LintStore) {
             };
             for id in ids {
                 self.check_gated_lint(id, DUMMY_SP);
-                let src = LintSource::CommandLine(lint_flag_val, orig_level);
+                let src = LintLevelSource::CommandLine(lint_flag_val, orig_level);
                 specs.insert(id, (level, src));
             }
         }
@@ -128,19 +130,19 @@ fn insert_spec(
                 );
                 diag_builder.span_label(src.span(), "overruled by previous forbid");
                 match old_src {
-                    LintSource::Default => {
+                    LintLevelSource::Default => {
                         diag_builder.note(&format!(
                             "`forbid` lint level is the default for {}",
                             id.to_string()
                         ));
                     }
-                    LintSource::Node(_, forbid_source_span, reason) => {
+                    LintLevelSource::Node(_, forbid_source_span, reason) => {
                         diag_builder.span_label(forbid_source_span, "`forbid` level set here");
                         if let Some(rationale) = reason {
                             diag_builder.note(&rationale.as_str());
                         }
                     }
-                    LintSource::CommandLine(_, _) => {
+                    LintLevelSource::CommandLine(_, _) => {
                         diag_builder.note("`forbid` lint level was set on command line");
                     }
                 }
@@ -276,7 +278,7 @@ pub(crate) fn push(
                 let name = meta_item.path.segments.last().expect("empty lint name").ident.name;
                 match store.check_lint_name(&name.as_str(), tool_name) {
                     CheckLintNameResult::Ok(ids) => {
-                        let src = LintSource::Node(name, li.span(), reason);
+                        let src = LintLevelSource::Node(name, li.span(), reason);
                         for &id in ids {
                             self.check_gated_lint(id, attr.span);
                             self.insert_spec(&mut specs, id, (level, src));
@@ -287,7 +289,7 @@ pub(crate) fn push(
                         match result {
                             Ok(ids) => {
                                 let complete_name = &format!("{}::{}", tool_name.unwrap(), name);
-                                let src = LintSource::Node(
+                                let src = LintLevelSource::Node(
                                     Symbol::intern(complete_name),
                                     li.span(),
                                     reason,
@@ -324,7 +326,7 @@ pub(crate) fn push(
                                     },
                                 );
 
-                                let src = LintSource::Node(
+                                let src = LintLevelSource::Node(
                                     Symbol::intern(&new_lint_name),
                                     li.span(),
                                     reason,
@@ -403,7 +405,7 @@ pub(crate) fn push(
                 }
 
                 let (lint_attr_name, lint_attr_span) = match *src {
-                    LintSource::Node(name, span, _) => (name, span),
+                    LintLevelSource::Node(name, span, _) => (name, span),
                     _ => continue,
                 };
 
@@ -460,7 +462,7 @@ pub fn pop(&mut self, push: BuilderPush) {
     }
 
     /// Find the lint level for a lint.
-    pub fn lint_level(&self, lint: &'static Lint) -> (Level, LintSource) {
+    pub fn lint_level(&self, lint: &'static Lint) -> (Level, LintLevelSource) {
         self.sets.get_lint_level(lint, self.cur, None, self.sess)
     }
 
index 80ef855c3859e14f650a46a7d061467719bb2675..2336b52619ab8a0e40230522d306b06ab17b1d17 100644 (file)
@@ -283,7 +283,6 @@ macro_rules! register_passes {
         UNUSED_MUT,
         UNREACHABLE_CODE,
         UNREACHABLE_PATTERNS,
-        OVERLAPPING_PATTERNS,
         UNUSED_MUST_USE,
         UNUSED_UNSAFE,
         PATH_STATEMENTS,
@@ -335,6 +334,7 @@ macro_rules! register_passes {
     store.register_renamed("exceeding_bitshifts", "arithmetic_overflow");
     store.register_renamed("redundant_semicolon", "redundant_semicolons");
     store.register_renamed("intra_doc_link_resolution_failure", "broken_intra_doc_links");
+    store.register_renamed("overlapping_patterns", "overlapping_range_endpoints");
     store.register_removed("unknown_features", "replaced by an error");
     store.register_removed("unsigned_negation", "replaced by negate_unsigned feature gate");
     store.register_removed("negate_unsigned", "cast a signed value instead");
index 428198cae8917377ee7ea648b37cae10b037b207..0fe6564880f010b8e46de5a64a3c589753a39f34 100644 (file)
 
 impl EarlyLintPass for RedundantSemicolons {
     fn check_block(&mut self, cx: &EarlyContext<'_>, block: &Block) {
-        let mut after_item_stmt = false;
         let mut seq = None;
         for stmt in block.stmts.iter() {
             match (&stmt.kind, &mut seq) {
                 (StmtKind::Empty, None) => seq = Some((stmt.span, false)),
                 (StmtKind::Empty, Some(seq)) => *seq = (seq.0.to(stmt.span), true),
-                (_, seq) => {
-                    maybe_lint_redundant_semis(cx, seq, after_item_stmt);
-                    after_item_stmt = matches!(stmt.kind, StmtKind::Item(_));
-                }
+                (_, seq) => maybe_lint_redundant_semis(cx, seq),
             }
         }
-        maybe_lint_redundant_semis(cx, &mut seq, after_item_stmt);
+        maybe_lint_redundant_semis(cx, &mut seq);
     }
 }
 
-fn maybe_lint_redundant_semis(
-    cx: &EarlyContext<'_>,
-    seq: &mut Option<(Span, bool)>,
-    after_item_stmt: bool,
-) {
+fn maybe_lint_redundant_semis(cx: &EarlyContext<'_>, seq: &mut Option<(Span, bool)>) {
     if let Some((span, multiple)) = seq.take() {
         // FIXME: Find a better way of ignoring the trailing
         // semicolon from macro expansion
@@ -56,12 +48,6 @@ fn maybe_lint_redundant_semis(
             return;
         }
 
-        // FIXME: Lint on semicolons after item statements
-        // once doing so doesn't break bootstrapping
-        if after_item_stmt {
-            return;
-        }
-
         cx.struct_span_lint(REDUNDANT_SEMICOLONS, span, |lint| {
             let (msg, rem) = if multiple {
                 ("unnecessary trailing semicolons", "remove these semicolons")
index a9358c9610a5e6029171fface5491af493370a37..1c692d4f207620197a4a3f3102cae67b8c7df5ad 100644 (file)
 }
 
 declare_lint! {
-    /// The `overlapping_patterns` lint detects `match` arms that have
-    /// [range patterns] that overlap.
+    /// The `overlapping_range_endpoints` lint detects `match` arms that have [range patterns] that
+    /// overlap on their endpoints.
     ///
     /// [range patterns]: https://doc.rust-lang.org/nightly/reference/patterns.html#range-patterns
     ///
     ///
     /// ### 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,
+    /// It is likely a mistake to have range patterns in a match expression that overlap in this
+    /// way. 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_RANGE_ENDPOINTS,
     Warn,
-    "detects overlapping patterns"
+    "detects range patterns with overlapping endpoints"
 }
 
 declare_lint! {
     };
 }
 
+declare_lint! {
+    /// The `missing_fragment_specifier` lint is issued when an unused pattern in a
+    /// `macro_rules!` macro definition has a meta-variable (e.g. `$e`) that is not
+    /// followed by a fragment specifier (e.g. `:expr`).
+    ///
+    /// This warning can always be fixed by removing the unused pattern in the
+    /// `macro_rules!` macro definition.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// macro_rules! foo {
+    ///    () => {};
+    ///    ($name) => { };
+    /// }
+    ///
+    /// fn main() {
+    ///    foo!();
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// To fix this, remove the unused pattern from the `macro_rules!` macro definition:
+    ///
+    /// ```rust
+    /// macro_rules! foo {
+    ///     () => {};
+    /// }
+    /// fn main() {
+    ///     foo!();
+    /// }
+    /// ```
+    pub MISSING_FRAGMENT_SPECIFIER,
+    Deny,
+    "detects missing fragment specifiers in unused `macro_rules!` patterns",
+    @future_incompatible = FutureIncompatibleInfo {
+        reference: "issue #40107 <https://github.com/rust-lang/rust/issues/40107>",
+        edition: None,
+    };
+}
+
 declare_lint! {
     /// The `late_bound_lifetime_arguments` lint detects generic lifetime
     /// arguments in path segments with late bound lifetime parameters.
         DEAD_CODE,
         UNREACHABLE_CODE,
         UNREACHABLE_PATTERNS,
-        OVERLAPPING_PATTERNS,
+        OVERLAPPING_RANGE_ENDPOINTS,
         BINDINGS_WITH_VARIANT_NAME,
         UNUSED_MACROS,
         WARNINGS,
         CONST_ITEM_MUTATION,
         SAFE_PACKED_BORROWS,
         PATTERNS_IN_FNS_WITHOUT_BODY,
+        MISSING_FRAGMENT_SPECIFIER,
         LATE_BOUND_LIFETIME_ARGUMENTS,
         ORDER_DEPENDENT_TRAIT_OBJECTS,
         COHERENCE_LEAK_CHECK,
index 12990ae2d94a5c18abe1adae784407df87d2698e..6d876784be65368fcff190fd872d8ff9fb673f53 100644 (file)
@@ -5,8 +5,8 @@
 use syn::punctuated::Punctuated;
 use syn::spanned::Spanned;
 use syn::{
-    braced, parenthesized, parse_macro_input, AttrStyle, Attribute, Block, Error, Expr, Ident,
-    ReturnType, Token, Type,
+    braced, parenthesized, parse_macro_input, parse_quote, AttrStyle, Attribute, Block, Error,
+    Expr, Ident, ReturnType, Token, Type,
 };
 
 mod kw {
@@ -272,6 +272,40 @@ fn process_modifiers(query: &mut Query) -> QueryModifiers {
                 if desc.is_some() {
                     panic!("duplicate modifier `desc` for query `{}`", query.name);
                 }
+                // If there are no doc-comments, give at least some idea of what
+                // it does by showing the query description.
+                if query.doc_comments.is_empty() {
+                    use ::syn::*;
+                    let mut list = list.iter();
+                    let format_str: String = match list.next() {
+                        Some(&Expr::Lit(ExprLit { lit: Lit::Str(ref lit_str), .. })) => {
+                            lit_str.value().replace("`{}`", "{}") // We add them later anyways for consistency
+                        }
+                        _ => panic!("Expected a string literal"),
+                    };
+                    let mut fmt_fragments = format_str.split("{}");
+                    let mut doc_string = fmt_fragments.next().unwrap().to_string();
+                    list.map(::quote::ToTokens::to_token_stream).zip(fmt_fragments).for_each(
+                        |(tts, next_fmt_fragment)| {
+                            use ::core::fmt::Write;
+                            write!(
+                                &mut doc_string,
+                                " `{}` {}",
+                                tts.to_string().replace(" . ", "."),
+                                next_fmt_fragment,
+                            )
+                            .unwrap();
+                        },
+                    );
+                    let doc_string = format!(
+                        "[query description - consider adding a doc-comment!] {}",
+                        doc_string
+                    );
+                    let comment = parse_quote! {
+                        #[doc = #doc_string]
+                    };
+                    query.doc_comments.push(comment);
+                }
                 desc = Some((tcx, list));
             }
             QueryModifier::FatalCycle => {
index 610b9155cfc182059d58a39901bd3be03dd46585..5c061a9d3c7949a529c077090889d80a51265a8b 100644 (file)
@@ -574,7 +574,7 @@ fn generate_non_option_field_code(
     /// format!("Expected a point greater than ({x}, {y})", x = self.x, y = self.y)
     /// ```
     /// This function builds the entire call to format!.
-    fn build_format(&self, input: &String, span: proc_macro2::Span) -> proc_macro2::TokenStream {
+    fn build_format(&self, input: &str, span: proc_macro2::Span) -> proc_macro2::TokenStream {
         // This set is used later to generate the final format string. To keep builds reproducible,
         // the iteration order needs to be deterministic, hence why we use a BTreeSet here instead
         // of a HashSet.
index fe29f9d177f92c1a4fb5d2b4c5b28086e86de8b4..744fdc83a91ec8d3089ce74ebf634062a7b2a62a 100644 (file)
@@ -132,7 +132,7 @@ fn visit_foreign_item(&mut self, _it: &'tcx hir::ForeignItem<'tcx>) {}
 
 impl Collector<'tcx> {
     fn register_native_lib(&mut self, span: Option<Span>, lib: NativeLib) {
-        if lib.name.as_ref().map(|&s| s == kw::Invalid).unwrap_or(false) {
+        if lib.name.as_ref().map(|&s| s == kw::Empty).unwrap_or(false) {
             match span {
                 Some(span) => {
                     struct_span_err!(
index e641c1cd77bdb608288499816938ef7c3b773342..728bfef9f467373bf7cf712f62547afb819c20ea 100644 (file)
@@ -5,7 +5,7 @@
 use rustc_data_structures::sync::Lock;
 use rustc_data_structures::thin_vec::ThinVec;
 use rustc_errors::Diagnostic;
-use rustc_hir::def_id::{DefPathHash, LocalDefId};
+use rustc_hir::def_id::LocalDefId;
 
 mod dep_node;
 
@@ -91,9 +91,9 @@ impl<'tcx> DepContext for TyCtxt<'tcx> {
     type DepKind = DepKind;
     type StableHashingContext = StableHashingContext<'tcx>;
 
-    fn register_reused_dep_path_hash(&self, hash: DefPathHash) {
+    fn register_reused_dep_node(&self, dep_node: &DepNode) {
         if let Some(cache) = self.queries.on_disk_cache.as_ref() {
-            cache.register_reused_dep_path_hash(*self, hash)
+            cache.register_reused_dep_node(*self, dep_node)
         }
     }
 
index 6f572a4875f865765d5aaae582b7fb298b17f2ec..9d392c7b26bf7f7606bc8bbe96a786799e3c4dba 100644 (file)
@@ -42,37 +42,25 @@ trait MaybeFnLike {
 
 impl MaybeFnLike for hir::Item<'_> {
     fn is_fn_like(&self) -> bool {
-        match self.kind {
-            hir::ItemKind::Fn(..) => true,
-            _ => false,
-        }
+        matches!(self.kind, hir::ItemKind::Fn(..))
     }
 }
 
 impl MaybeFnLike for hir::ImplItem<'_> {
     fn is_fn_like(&self) -> bool {
-        match self.kind {
-            hir::ImplItemKind::Fn(..) => true,
-            _ => false,
-        }
+        matches!(self.kind, hir::ImplItemKind::Fn(..))
     }
 }
 
 impl MaybeFnLike for hir::TraitItem<'_> {
     fn is_fn_like(&self) -> bool {
-        match self.kind {
-            hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(_)) => true,
-            _ => false,
-        }
+        matches!(self.kind, hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(_)))
     }
 }
 
 impl MaybeFnLike for hir::Expr<'_> {
     fn is_fn_like(&self) -> bool {
-        match self.kind {
-            hir::ExprKind::Closure(..) => true,
-            _ => false,
-        }
+        matches!(self.kind, hir::ExprKind::Closure(..))
     }
 }
 
index 598e28c1a3ab00ac9442f021aeb8aaadb07b512f..09d5b102103120aebae9b7084e1aaf7f5c055547 100644 (file)
@@ -379,7 +379,7 @@ pub fn body_owned_by(&self, id: HirId) -> BodyId {
     pub fn body_param_names(&self, id: BodyId) -> impl Iterator<Item = Ident> + 'hir {
         self.body(id).params.iter().map(|arg| match arg.pat.kind {
             PatKind::Binding(_, _, ident, _) => ident,
-            _ => Ident::new(kw::Invalid, rustc_span::DUMMY_SP),
+            _ => Ident::new(kw::Empty, rustc_span::DUMMY_SP),
         })
     }
 
index 1e2e9df88c584e40ceca08ee97db682d60d5d315..00db19019c480d690023a13d2ecd605f23762d51 100644 (file)
@@ -110,10 +110,7 @@ pub fn new(
         base: PlaceBase,
         projections: Vec<Projection<'tcx>>,
     ) -> PlaceWithHirId<'tcx> {
-        PlaceWithHirId {
-            hir_id: hir_id,
-            place: Place { base_ty: base_ty, base: base, projections: projections },
-        }
+        PlaceWithHirId { hir_id, place: Place { base_ty, base, projections } }
     }
 }
 
index cdc5940d9baedc878b8d576e5eded5134892706d..6ae83a7f667504a70c31e19fd84eb75f1ee87deb 100644 (file)
@@ -8,7 +8,7 @@
 //! - **MIR.** The "mid-level (M) intermediate representation (IR)" is
 //!   defined in the `mir` module. This module contains only the
 //!   *definition* of the MIR; the passes that transform and operate
-//!   on MIR are found in `librustc_mir` crate.
+//!   on MIR are found in `rustc_mir` crate.
 //! - **Types.** The internal representation of types used in rustc is
 //!   defined in the `ty` module. This includes the **type context**
 //!   (or `tcx`), which is the central context during most of
index a61d37cc90eba5d0a8345bf624eb29fcebb105a6..64d850192f4493b8e0d51fe609d5be3ec39ffce6 100644 (file)
@@ -13,7 +13,7 @@
 
 /// How a lint level was set.
 #[derive(Clone, Copy, PartialEq, Eq, HashStable)]
-pub enum LintSource {
+pub enum LintLevelSource {
     /// Lint is at the default level as declared
     /// in rustc or a plugin.
     Default,
@@ -22,30 +22,31 @@ pub enum LintSource {
     Node(Symbol, Span, Option<Symbol> /* RFC 2383 reason */),
 
     /// Lint level was set by a command-line flag.
-    /// The provided `Level` is the level specified on the command line -
-    /// the actual level may be lower due to `--cap-lints`
+    /// The provided `Level` is the level specified on the command line.
+    /// (The actual level may be lower due to `--cap-lints`.)
     CommandLine(Symbol, Level),
 }
 
-impl LintSource {
+impl LintLevelSource {
     pub fn name(&self) -> Symbol {
         match *self {
-            LintSource::Default => symbol::kw::Default,
-            LintSource::Node(name, _, _) => name,
-            LintSource::CommandLine(name, _) => name,
+            LintLevelSource::Default => symbol::kw::Default,
+            LintLevelSource::Node(name, _, _) => name,
+            LintLevelSource::CommandLine(name, _) => name,
         }
     }
 
     pub fn span(&self) -> Span {
         match *self {
-            LintSource::Default => DUMMY_SP,
-            LintSource::Node(_, span, _) => span,
-            LintSource::CommandLine(_, _) => DUMMY_SP,
+            LintLevelSource::Default => DUMMY_SP,
+            LintLevelSource::Node(_, span, _) => span,
+            LintLevelSource::CommandLine(_, _) => DUMMY_SP,
         }
     }
 }
 
-pub type LevelSource = (Level, LintSource);
+/// A tuple of a lint level and its source.
+pub type LevelSource = (Level, LintLevelSource);
 
 pub struct LintLevelSets {
     pub list: Vec<LintSet>,
@@ -113,7 +114,7 @@ pub fn get_lint_id_level(
         id: LintId,
         mut idx: u32,
         aux: Option<&FxHashMap<LintId, LevelSource>>,
-    ) -> (Option<Level>, LintSource) {
+    ) -> (Option<Level>, LintLevelSource) {
         if let Some(specs) = aux {
             if let Some(&(level, src)) = specs.get(&id) {
                 return (Some(level), src);
@@ -125,7 +126,7 @@ pub fn get_lint_id_level(
                     if let Some(&(level, src)) = specs.get(&id) {
                         return (Some(level), src);
                     }
-                    return (None, LintSource::Default);
+                    return (None, LintLevelSource::Default);
                 }
                 LintSet::Node { ref specs, parent } => {
                     if let Some(&(level, src)) = specs.get(&id) {
@@ -213,7 +214,7 @@ pub fn struct_lint_level<'s, 'd>(
     sess: &'s Session,
     lint: &'static Lint,
     level: Level,
-    src: LintSource,
+    src: LintLevelSource,
     span: Option<MultiSpan>,
     decorate: impl for<'a> FnOnce(LintDiagnosticBuilder<'a>) + 'd,
 ) {
@@ -223,7 +224,7 @@ fn struct_lint_level_impl(
         sess: &'s Session,
         lint: &'static Lint,
         level: Level,
-        src: LintSource,
+        src: LintLevelSource,
         span: Option<MultiSpan>,
         decorate: Box<dyn for<'b> FnOnce(LintDiagnosticBuilder<'b>) + 'd>,
     ) {
@@ -274,14 +275,14 @@ fn struct_lint_level_impl(
 
         let name = lint.name_lower();
         match src {
-            LintSource::Default => {
+            LintLevelSource::Default => {
                 sess.diag_note_once(
                     &mut err,
                     DiagnosticMessageId::from(lint),
                     &format!("`#[{}({})]` on by default", level.as_str(), name),
                 );
             }
-            LintSource::CommandLine(lint_flag_val, orig_level) => {
+            LintLevelSource::CommandLine(lint_flag_val, orig_level) => {
                 let flag = match orig_level {
                     Level::Warn => "-W",
                     Level::Deny => "-D",
@@ -310,7 +311,7 @@ fn struct_lint_level_impl(
                     );
                 }
             }
-            LintSource::Node(lint_attr_name, src, reason) => {
+            LintLevelSource::Node(lint_attr_name, src, reason) => {
                 if let Some(rationale) = reason {
                     err.note(&rationale.as_str());
                 }
index 254b57a005e8e7438148954c9e17fd05cc50321c..54188985d7c5f18f56c24980d5f7ed37140d9e7a 100644 (file)
@@ -8,7 +8,9 @@
 use std::fmt;
 use std::hash::Hash;
 
-// Accessibility levels, sorted in ascending order
+/// Represents the levels of accessibility an item can have.
+///
+/// The variants are sorted in ascending order of accessibility.
 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, HashStable)]
 pub enum AccessLevel {
     /// Superset of `AccessLevel::Reachable` used to mark impl Trait items.
@@ -18,13 +20,13 @@ pub enum AccessLevel {
     /// public, then type `T` is reachable. Its values can be obtained by other crates
     /// even if the type itself is not nameable.
     Reachable,
-    /// Public items + items accessible to other crates with help of `pub use` re-exports
+    /// Public items + items accessible to other crates with the help of `pub use` re-exports.
     Exported,
-    /// Items accessible to other crates directly, without help of re-exports
+    /// Items accessible to other crates directly, without the help of re-exports.
     Public,
 }
 
-// Accessibility levels for reachable HIR nodes
+/// Holds a map of accessibility levels for reachable HIR nodes.
 #[derive(Clone)]
 pub struct AccessLevels<Id = HirId> {
     pub map: FxHashMap<Id, AccessLevel>,
index d060549ca8137191c73eae593251900541d7ae23..eb48198991c294dd08cf0864999d31bad36adf80 100644 (file)
@@ -332,7 +332,7 @@ pub struct ScopeTree {
 pub struct YieldData {
     /// The `Span` of the yield.
     pub span: Span,
-    /// The number of expressions and patterns appearing before the `yield` in the body plus one.
+    /// The number of expressions and patterns appearing before the `yield` in the body, plus one.
     pub expr_and_pat_count: usize,
     pub source: hir::YieldSource,
 }
@@ -449,9 +449,7 @@ pub fn is_subscope_of(&self, subscope: Scope, superscope: Scope) -> bool {
     }
 
     /// Checks whether the given scope contains a `yield`. If so,
-    /// returns `Some((span, expr_count))` with the span of a yield we found and
-    /// the number of expressions and patterns appearing before the `yield` in the body + 1.
-    /// If there a are multiple yields in a scope, the one with the highest number is returned.
+    /// returns `Some(YieldData)`. If not, returns `None`.
     pub fn yield_in_scope(&self, scope: Scope) -> Option<YieldData> {
         self.yield_in_scope.get(&scope).cloned()
     }
index 8a6bf9dff7b6fb2ecb84464d239831b1a41aea34..95096d0fb719c314c6d8e9df8e81ce450df39a16 100644 (file)
@@ -118,17 +118,11 @@ pub fn as_operand_id(&self) -> ExpressionOperandId {
     }
 
     pub fn is_counter(&self) -> bool {
-        match self {
-            Self::Counter { .. } => true,
-            _ => false,
-        }
+        matches!(self, Self::Counter { .. })
     }
 
     pub fn is_expression(&self) -> bool {
-        match self {
-            Self::Expression { .. } => true,
-            _ => false,
-        }
+        matches!(self, Self::Expression { .. })
     }
 
     pub fn is_unreachable(&self) -> bool {
diff --git a/compiler/rustc_middle/src/mir/graph_cyclic_cache.rs b/compiler/rustc_middle/src/mir/graph_cyclic_cache.rs
new file mode 100644 (file)
index 0000000..5f02897
--- /dev/null
@@ -0,0 +1,62 @@
+use rustc_data_structures::graph::{
+    self, DirectedGraph, WithNumNodes, WithStartNode, WithSuccessors,
+};
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_data_structures::sync::OnceCell;
+use rustc_serialize as serialize;
+
+/// Helper type to cache the result of `graph::is_cyclic`.
+#[derive(Clone, Debug)]
+pub(super) struct GraphIsCyclicCache {
+    cache: OnceCell<bool>,
+}
+
+impl GraphIsCyclicCache {
+    #[inline]
+    pub(super) fn new() -> Self {
+        GraphIsCyclicCache { cache: OnceCell::new() }
+    }
+
+    pub(super) fn is_cyclic<G>(&self, graph: &G) -> bool
+    where
+        G: ?Sized + DirectedGraph + WithStartNode + WithSuccessors + WithNumNodes,
+    {
+        *self.cache.get_or_init(|| graph::is_cyclic(graph))
+    }
+
+    /// Invalidates the cache.
+    #[inline]
+    pub(super) fn invalidate(&mut self) {
+        // Invalidating the cache requires mutating the MIR, which in turn requires a unique
+        // reference (`&mut`) to the `mir::Body`. Because of this, we can assume that all
+        // callers of `invalidate` have a unique reference to the MIR and thus to the
+        // cache. This means we never need to do synchronization when `invalidate` is called,
+        // we can simply reinitialize the `OnceCell`.
+        self.cache = OnceCell::new();
+    }
+}
+
+impl<S: serialize::Encoder> serialize::Encodable<S> for GraphIsCyclicCache {
+    #[inline]
+    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
+        serialize::Encodable::encode(&(), s)
+    }
+}
+
+impl<D: serialize::Decoder> serialize::Decodable<D> for GraphIsCyclicCache {
+    #[inline]
+    fn decode(d: &mut D) -> Result<Self, D::Error> {
+        serialize::Decodable::decode(d).map(|_v: ()| Self::new())
+    }
+}
+
+impl<CTX> HashStable<CTX> for GraphIsCyclicCache {
+    #[inline]
+    fn hash_stable(&self, _: &mut CTX, _: &mut StableHasher) {
+        // do nothing
+    }
+}
+
+TrivialTypeFoldableAndLiftImpls! {
+    GraphIsCyclicCache,
+}
index ad48c3510484b03bb7a731443838809ec425fd57..a69555fd1a8cec34ceb0cfb2a534511aaa45bd9e 100644 (file)
 use std::slice;
 use std::{iter, mem, option};
 
+use self::graph_cyclic_cache::GraphIsCyclicCache;
 use self::predecessors::{PredecessorCache, Predecessors};
 pub use self::query::*;
 
 pub mod abstract_const;
 pub mod coverage;
+mod graph_cyclic_cache;
 pub mod interpret;
 pub mod mono;
 mod predecessors;
@@ -227,6 +229,7 @@ pub struct Body<'tcx> {
     pub is_polymorphic: bool,
 
     predecessor_cache: PredecessorCache,
+    is_cyclic: GraphIsCyclicCache,
 }
 
 impl<'tcx> Body<'tcx> {
@@ -267,6 +270,7 @@ pub fn new(
             required_consts: Vec::new(),
             is_polymorphic: false,
             predecessor_cache: PredecessorCache::new(),
+            is_cyclic: GraphIsCyclicCache::new(),
         };
         body.is_polymorphic = body.has_param_types_or_consts();
         body
@@ -296,6 +300,7 @@ pub fn new_cfg_only(basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>) ->
             var_debug_info: Vec::new(),
             is_polymorphic: false,
             predecessor_cache: PredecessorCache::new(),
+            is_cyclic: GraphIsCyclicCache::new(),
         };
         body.is_polymorphic = body.has_param_types_or_consts();
         body
@@ -309,11 +314,12 @@ pub fn basic_blocks(&self) -> &IndexVec<BasicBlock, BasicBlockData<'tcx>> {
     #[inline]
     pub fn basic_blocks_mut(&mut self) -> &mut IndexVec<BasicBlock, BasicBlockData<'tcx>> {
         // Because the user could mutate basic block terminators via this reference, we need to
-        // invalidate the predecessor cache.
+        // invalidate the caches.
         //
         // FIXME: Use a finer-grained API for this, so only transformations that alter terminators
-        // invalidate the predecessor cache.
+        // invalidate the caches.
         self.predecessor_cache.invalidate();
+        self.is_cyclic.invalidate();
         &mut self.basic_blocks
     }
 
@@ -322,6 +328,7 @@ pub fn basic_blocks_and_local_decls_mut(
         &mut self,
     ) -> (&mut IndexVec<BasicBlock, BasicBlockData<'tcx>>, &mut LocalDecls<'tcx>) {
         self.predecessor_cache.invalidate();
+        self.is_cyclic.invalidate();
         (&mut self.basic_blocks, &mut self.local_decls)
     }
 
@@ -334,13 +341,14 @@ pub fn basic_blocks_local_decls_mut_and_var_debug_info(
         &mut Vec<VarDebugInfo<'tcx>>,
     ) {
         self.predecessor_cache.invalidate();
+        self.is_cyclic.invalidate();
         (&mut self.basic_blocks, &mut self.local_decls, &mut self.var_debug_info)
     }
 
     /// Returns `true` if a cycle exists in the control-flow graph that is reachable from the
     /// `START_BLOCK`.
     pub fn is_cfg_cyclic(&self) -> bool {
-        graph::is_cyclic(self)
+        self.is_cyclic.is_cyclic(self)
     }
 
     #[inline]
index e281010eb06ec7bf16d28d8d14229326ff3e25a3..023555d91cc920d71d29e53fcf9c79738f5cc562 100644 (file)
@@ -306,13 +306,13 @@ fn super_basic_block_data(&mut self,
 
                 let mut index = 0;
                 for statement in statements {
-                    let location = Location { block: block, statement_index: index };
+                    let location = Location { block, statement_index: index };
                     self.visit_statement(statement, location);
                     index += 1;
                 }
 
                 if let Some(terminator) = terminator {
-                    let location = Location { block: block, statement_index: index };
+                    let location = Location { block, statement_index: index };
                     self.visit_terminator(terminator, location);
                 }
             }
index 1b5f7a2c12e72a8e355d6c67b9680a4879d74f1a..1e836d0a8425363e3b56ccb158fefa2a71f75920 100644 (file)
@@ -576,11 +576,13 @@ fn describe_as_module(def_id: LocalDefId, tcx: TyCtxt<'_>) -> String {
             desc { |tcx| "collecting associated items of {}", tcx.def_path_str(key) }
         }
 
-        query impl_trait_ref(key: DefId) -> Option<ty::TraitRef<'tcx>> {
-            desc { |tcx| "computing trait implemented by `{}`", tcx.def_path_str(key) }
+        /// Given an `impl_id`, return the trait it implements.
+        /// Return `None` if this is an inherent impl.
+        query impl_trait_ref(impl_id: DefId) -> Option<ty::TraitRef<'tcx>> {
+            desc { |tcx| "computing trait implemented by `{}`", tcx.def_path_str(impl_id) }
         }
-        query impl_polarity(key: DefId) -> ty::ImplPolarity {
-            desc { |tcx| "computing implementation polarity of `{}`", tcx.def_path_str(key) }
+        query impl_polarity(impl_id: DefId) -> ty::ImplPolarity {
+            desc { |tcx| "computing implementation polarity of `{}`", tcx.def_path_str(impl_id) }
         }
 
         query issue33140_self_ty(key: DefId) -> Option<ty::Ty<'tcx>> {
@@ -917,8 +919,10 @@ fn describe_as_module(def_id: LocalDefId, tcx: TyCtxt<'_>) -> String {
     }
 
     TypeChecking {
-        query trait_of_item(def_id: DefId) -> Option<DefId> {
-            desc { |tcx| "finding trait defining `{}`", tcx.def_path_str(def_id) }
+        /// Given an `associated_item`, find the trait it belongs to.
+        /// Return `None` if the `DefId` is not an associated item.
+        query trait_of_item(associated_item: DefId) -> Option<DefId> {
+            desc { |tcx| "finding trait defining `{}`", tcx.def_path_str(associated_item) }
         }
     }
 
@@ -948,20 +952,29 @@ fn describe_as_module(def_id: LocalDefId, tcx: TyCtxt<'_>) -> String {
     }
 
     TypeChecking {
-        query all_local_trait_impls(key: CrateNum) -> &'tcx BTreeMap<DefId, Vec<hir::HirId>> {
+        /// Return all `impl` blocks in the current crate.
+        ///
+        /// To allow caching this between crates, you must pass in [`LOCAL_CRATE`] as the crate number.
+        /// Passing in any other crate will cause an ICE.
+        ///
+        /// [`LOCAL_CRATE`]: rustc_hir::def_id::LOCAL_CRATE
+        query all_local_trait_impls(local_crate: CrateNum) -> &'tcx BTreeMap<DefId, Vec<hir::HirId>> {
             desc { "local trait impls" }
         }
-        query trait_impls_of(key: DefId) -> ty::trait_def::TraitImpls {
+
+        /// Given a trait `trait_id`, return all known `impl` blocks.
+        query trait_impls_of(trait_id: DefId) -> ty::trait_def::TraitImpls {
             storage(ArenaCacheSelector<'tcx>)
-            desc { |tcx| "trait impls of `{}`", tcx.def_path_str(key) }
+            desc { |tcx| "trait impls of `{}`", tcx.def_path_str(trait_id) }
         }
-        query specialization_graph_of(key: DefId) -> specialization_graph::Graph {
+
+        query specialization_graph_of(trait_id: DefId) -> specialization_graph::Graph {
             storage(ArenaCacheSelector<'tcx>)
-            desc { |tcx| "building specialization graph of trait `{}`", tcx.def_path_str(key) }
+            desc { |tcx| "building specialization graph of trait `{}`", tcx.def_path_str(trait_id) }
             cache_on_disk_if { true }
         }
-        query object_safety_violations(key: DefId) -> &'tcx [traits::ObjectSafetyViolation] {
-            desc { |tcx| "determine object safety of trait `{}`", tcx.def_path_str(key) }
+        query object_safety_violations(trait_id: DefId) -> &'tcx [traits::ObjectSafetyViolation] {
+            desc { |tcx| "determine object safety of trait `{}`", tcx.def_path_str(trait_id) }
         }
 
         /// Gets the ParameterEnvironment for a given item; this environment
@@ -969,6 +982,7 @@ fn describe_as_module(def_id: LocalDefId, tcx: TyCtxt<'_>) -> String {
         /// type-checking etc, and it does not normalize specializable
         /// associated types. This is almost always what you want,
         /// unless you are doing MIR optimizations, in which case you
+        /// might want to use `reveal_all()` method to change modes.
         query param_env(def_id: DefId) -> ty::ParamEnv<'tcx> {
             desc { |tcx| "computing normalized predicates of `{}`", tcx.def_path_str(def_id) }
         }
@@ -1229,10 +1243,15 @@ fn describe_as_module(def_id: LocalDefId, tcx: TyCtxt<'_>) -> String {
     }
 
     TypeChecking {
+        /// Given a crate and a trait, look up all impls of that trait in the crate.
+        /// Return `(impl_id, self_ty)`.
         query implementations_of_trait(_: (CrateNum, DefId))
             -> &'tcx [(DefId, Option<ty::fast_reject::SimplifiedType>)] {
             desc { "looking up implementations of a trait in a crate" }
         }
+
+        /// Given a crate, look up all trait impls in that crate.
+        /// Return `(impl_id, self_ty)`.
         query all_trait_implementations(_: CrateNum)
             -> &'tcx [(DefId, Option<ty::fast_reject::SimplifiedType>)] {
             desc { "looking up all (?) trait implementations" }
index 4205e2ca5aa61d526d8b992c911cc516b34a723a..b2db09cbc80652fdf1ba2f6d092461d8bd6e80b5 100644 (file)
@@ -5,7 +5,7 @@
 use crate::hir::exports::ExportMap;
 use crate::ich::{NodeIdHashingMode, StableHashingContext};
 use crate::infer::canonical::{Canonical, CanonicalVarInfo, CanonicalVarInfos};
-use crate::lint::{struct_lint_level, LintDiagnosticBuilder, LintSource};
+use crate::lint::{struct_lint_level, LintDiagnosticBuilder, LintLevelSource};
 use crate::middle;
 use crate::middle::cstore::{CrateStoreDyn, EncodedMetadata};
 use crate::middle::resolve_lifetime::{self, ObjectLifetimeDefault};
@@ -1386,7 +1386,7 @@ pub fn borrowck_mode(self) -> BorrowckMode {
     #[inline]
     pub fn lazy_normalization(self) -> bool {
         let features = self.features();
-        // Note: We do not enable lazy normalization for `features.min_const_generics`.
+        // Note: We do not enable lazy normalization for `min_const_generics`.
         features.const_generics || features.lazy_normalization_consts
     }
 
@@ -2559,7 +2559,7 @@ pub fn lint_level_at_node(
         self,
         lint: &'static Lint,
         mut id: hir::HirId,
-    ) -> (Level, LintSource) {
+    ) -> (Level, LintLevelSource) {
         let sets = self.lint_levels(LOCAL_CRATE);
         loop {
             if let Some(pair) = sets.level_and_source(lint, id, self.sess) {
index fc02e78b2fadf240a840894e59e4522f8e9133d1..fe20925b38798b246765626fed97bac695ed403a 100644 (file)
@@ -647,14 +647,11 @@ fn expected_projection(
         let current_method_ident = body_owner.and_then(|n| n.ident()).map(|i| i.name);
 
         // We don't want to suggest calling an assoc fn in a scope where that isn't feasible.
-        let callable_scope = match body_owner {
-            Some(
+        let callable_scope = matches!(body_owner, Some(
                 hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(..), .. })
                 | hir::Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Fn(..), .. })
                 | hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(..), .. }),
-            ) => true,
-            _ => false,
-        };
+            ));
         let impl_comparison = matches!(
             cause_code,
             ObligationCauseCode::CompareImplMethodObligation { .. }
index ee6b06a1cc803568944a15b7f6ba12c94a875de4..d9aebfc8293b6ef504f466fe0e038af7f13951b9 100644 (file)
@@ -17,7 +17,7 @@ pub struct DefIdForest {
     /// If A and B are DefIds in the `DefIdForest`, and A is a descendant
     /// of B, then only B will be in `root_ids`.
     /// We use a `SmallVec` here because (for its use for caching inhabitedness)
-    /// its rare that this will contain even two IDs.
+    /// it's rare that this will contain even two IDs.
     root_ids: SmallVec<[DefId; 1]>,
 }
 
index b545b92c9252a5efd36db54c96fe39d9253528f1..4475d4e9f2deac8421494998ecdbb44ab7975a0b 100644 (file)
@@ -1634,7 +1634,7 @@ fn generator_layout(
 
         let layout = tcx.intern_layout(Layout {
             variants: Variants::Multiple {
-                tag: tag,
+                tag,
                 tag_encoding: TagEncoding::Direct,
                 tag_field: tag_index,
                 variants,
index 83a2bdf90f9af0843baa178201445f830e012449..e657088a5e4655ac7a2b8e3a5e86d621e766f01d 100644 (file)
@@ -24,7 +24,7 @@
 /// This means we can use pointer for both
 /// equality comparisons and hashing.
 ///
-/// Unlike slices, The types contained in `List` are expected to be `Copy`
+/// Unlike slices, the types contained in `List` are expected to be `Copy`
 /// and iterating over a `List` returns `T` instead of a reference.
 ///
 /// Note: `Slice` was already taken by the `Ty`.
index c163a37c5a11e0529daf8c985e8e0565bbe18eb5..1fe1400fabecf820404535217cb8261d860ea234 100644 (file)
@@ -1,3 +1,14 @@
+//! Defines how the compiler represents types internally.
+//!
+//! Two important entities in this module are:
+//!
+//! - [`rustc_middle::ty::Ty`], used to represent the semantics of a type.
+//! - [`rustc_middle::ty::TyCtxt`], the central data structure in the compiler.
+//!
+//! For more information, see ["The `ty` module: representing types"] in the ructc-dev-guide.
+//!
+//! ["The `ty` module: representing types"]: https://rustc-dev-guide.rust-lang.org/ty.html
+
 // ignore-tidy-filelength
 pub use self::fold::{TypeFoldable, TypeFolder, TypeVisitor};
 pub use self::AssocItemContainer::*;
@@ -1627,8 +1638,6 @@ pub struct BoundConst<'tcx> {
 /// which cause cycle errors.
 ///
 /// ```rust
-/// #![feature(const_generics)]
-///
 /// struct A;
 /// impl A {
 ///     fn foo<const N: usize>(&self) -> [u8; N] { [0; N] }
index 9b178d9d2bd008cc93d9b9c42f9ecbf8b7216a51..893572785f76b0dde108da22218cc9de28b4dfb5 100644 (file)
@@ -1481,7 +1481,7 @@ fn path_append(
         // FIXME(eddyb) `name` should never be empty, but it
         // currently is for `extern { ... }` "foreign modules".
         let name = disambiguated_data.data.name();
-        if name != DefPathDataName::Named(kw::Invalid) {
+        if name != DefPathDataName::Named(kw::Empty) {
             if !self.empty_path {
                 write!(self, "::")?;
             }
@@ -1608,14 +1608,14 @@ fn region_should_not_be_omitted(&self, region: ty::Region<'_>) -> bool {
 
         match *region {
             ty::ReEarlyBound(ref data) => {
-                data.name != kw::Invalid && data.name != kw::UnderscoreLifetime
+                data.name != kw::Empty && data.name != kw::UnderscoreLifetime
             }
 
             ty::ReLateBound(_, ty::BoundRegion { kind: br })
             | ty::ReFree(ty::FreeRegion { bound_region: br, .. })
             | ty::RePlaceholder(ty::Placeholder { name: br, .. }) => {
                 if let ty::BrNamed(_, name) = br {
-                    if name != kw::Invalid && name != kw::UnderscoreLifetime {
+                    if name != kw::Empty && name != kw::UnderscoreLifetime {
                         return true;
                     }
                 }
@@ -1685,7 +1685,7 @@ pub fn pretty_print_region(mut self, region: ty::Region<'_>) -> Result<Self, fmt
         // `explain_region()` or `note_and_explain_region()`.
         match *region {
             ty::ReEarlyBound(ref data) => {
-                if data.name != kw::Invalid {
+                if data.name != kw::Empty {
                     p!(write("{}", data.name));
                     return Ok(self);
                 }
@@ -1694,7 +1694,7 @@ pub fn pretty_print_region(mut self, region: ty::Region<'_>) -> Result<Self, fmt
             | ty::ReFree(ty::FreeRegion { bound_region: br, .. })
             | ty::RePlaceholder(ty::Placeholder { name: br, .. }) => {
                 if let ty::BrNamed(_, name) = br {
-                    if name != kw::Invalid && name != kw::UnderscoreLifetime {
+                    if name != kw::Empty && name != kw::UnderscoreLifetime {
                         p!(write("{}", name));
                         return Ok(self);
                     }
index e006dfeb66336d21cfbbf3e7ae848d267428b6b6..8a1165bbd647a296bf8fc19ff2fdb387976e959c 100644 (file)
@@ -1,4 +1,4 @@
-use crate::dep_graph::{DepNodeIndex, SerializedDepNodeIndex};
+use crate::dep_graph::{DepNode, DepNodeIndex, SerializedDepNodeIndex};
 use crate::mir::interpret::{AllocDecodingSession, AllocDecodingState};
 use crate::mir::{self, interpret};
 use crate::ty::codec::{OpaqueEncoder, RefDecodable, TyDecoder, TyEncoder};
@@ -264,6 +264,13 @@ pub fn serialize<'tcx, E>(&self, tcx: TyCtxt<'tcx>, encoder: &mut E) -> Result<(
                 (file_to_file_index, file_index_to_stable_id)
             };
 
+            // Register any dep nodes that we reused from the previous session,
+            // but didn't `DepNode::construct` in this session. This ensures
+            // that their `DefPathHash` to `RawDefId` mappings are registered
+            // in 'latest_foreign_def_path_hashes' if necessary, since that
+            // normally happens in `DepNode::construct`.
+            tcx.dep_graph.register_reused_dep_nodes(tcx);
+
             // Load everything into memory so we can write it out to the on-disk
             // cache. The vast majority of cacheable query results should already
             // be in memory, so this should be a cheap operation.
@@ -467,8 +474,8 @@ pub(crate) fn store_foreign_def_id_hash(&self, def_id: DefId, hash: DefPathHash)
             .insert(hash, RawDefId { krate: def_id.krate.as_u32(), index: def_id.index.as_u32() });
     }
 
-    /// If the given `hash` still exists in the current compilation,
-    /// calls `store_foreign_def_id` with its current `DefId`.
+    /// If the given `dep_node`'s hash still exists in the current compilation,
+    /// and its current `DefId` is foreign, calls `store_foreign_def_id` with it.
     ///
     /// Normally, `store_foreign_def_id_hash` can be called directly by
     /// the dependency graph when we construct a `DepNode`. However,
@@ -476,13 +483,24 @@ pub(crate) fn store_foreign_def_id_hash(&self, def_id: DefId, hash: DefPathHash)
     /// session, we only have the `DefPathHash` available. This method is used
     /// to that any `DepNode` that we re-use has a `DefPathHash` -> `RawId` written
     /// out for usage in the next compilation session.
-    pub fn register_reused_dep_path_hash(&self, tcx: TyCtxt<'tcx>, hash: DefPathHash) {
-        // We can't simply copy the `RawDefId` from `foreign_def_path_hashes` to
-        // `latest_foreign_def_path_hashes`, since the `RawDefId` might have
-        // changed in the current compilation session (e.g. we've added/removed crates,
-        // or added/removed definitions before/after the target definition).
-        if let Some(def_id) = self.def_path_hash_to_def_id(tcx, hash) {
-            self.store_foreign_def_id_hash(def_id, hash);
+    pub fn register_reused_dep_node(&self, tcx: TyCtxt<'tcx>, dep_node: &DepNode) {
+        // For reused dep nodes, we only need to store the mapping if the node
+        // is one whose query key we can reconstruct from the hash. We use the
+        // mapping to aid that reconstruction in the next session. While we also
+        // use it to decode `DefId`s we encoded in the cache as `DefPathHashes`,
+        // they're already registered during `DefId` encoding.
+        if dep_node.kind.can_reconstruct_query_key() {
+            let hash = DefPathHash(dep_node.hash.into());
+
+            // We can't simply copy the `RawDefId` from `foreign_def_path_hashes` to
+            // `latest_foreign_def_path_hashes`, since the `RawDefId` might have
+            // changed in the current compilation session (e.g. we've added/removed crates,
+            // or added/removed definitions before/after the target definition).
+            if let Some(def_id) = self.def_path_hash_to_def_id(tcx, hash) {
+                if !def_id.is_local() {
+                    self.store_foreign_def_id_hash(def_id, hash);
+                }
+            }
         }
     }
 
@@ -648,7 +666,7 @@ pub(crate) fn def_path_hash_to_def_id(
 
 //- DECODING -------------------------------------------------------------------
 
-/// A decoder that can read from the incr. comp. cache. It is similar to the one
+/// A decoder that can read from the incremental compilation cache. It is similar to the one
 /// we use for crate metadata decoding in that it can rebase spans and eventually
 /// will also handle things that contain `Ty` instances.
 crate struct CacheDecoder<'a, 'tcx> {
@@ -936,7 +954,7 @@ fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> {
 
 //- ENCODING -------------------------------------------------------------------
 
-/// An encoder that can write the incr. comp. cache.
+/// An encoder that can write to the incremental compilation cache.
 struct CacheEncoder<'a, 'tcx, E: OpaqueEncoder> {
     tcx: TyCtxt<'tcx>,
     encoder: &'a mut E,
index dc72a713a7d865ec75de96e0b68d8cda9dc0bc9d..744c7a541a53c58e2abcb802be2bc1012aea351f 100644 (file)
@@ -215,10 +215,7 @@ pub enum TyKind<'tcx> {
 impl TyKind<'tcx> {
     #[inline]
     pub fn is_primitive(&self) -> bool {
-        match self {
-            Bool | Char | Int(_) | Uint(_) | Float(_) => true,
-            _ => false,
-        }
+        matches!(self, Bool | Char | Int(_) | Uint(_) | Float(_))
     }
 
     /// Get the article ("a" or "an") to use with this type.
@@ -1427,28 +1424,33 @@ pub struct EarlyBoundRegion {
     pub name: Symbol,
 }
 
+/// A **ty**pe **v**ariable **ID**.
 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)]
 pub struct TyVid {
     pub index: u32,
 }
 
+/// A **`const`** **v**ariable **ID**.
 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)]
 pub struct ConstVid<'tcx> {
     pub index: u32,
     pub phantom: PhantomData<&'tcx ()>,
 }
 
+/// An **int**egral (`u32`, `i32`, `usize`, etc.) type **v**ariable **ID**.
 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)]
 pub struct IntVid {
     pub index: u32,
 }
 
+/// An **float**ing-point (`f32` or `f64`) type **v**ariable **ID**.
 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)]
 pub struct FloatVid {
     pub index: u32,
 }
 
 rustc_index::newtype_index! {
+    /// A **region** (lifetime) **v**ariable **ID**.
     pub struct RegionVid {
         DEBUG_FORMAT = custom,
     }
@@ -1460,18 +1462,40 @@ fn index(self) -> usize {
     }
 }
 
+/// A placeholder for a type that hasn't been inferred yet.
+///
+/// E.g., if we have an empty array (`[]`), then we create a fresh
+/// type variable for the element type since we won't know until it's
+/// used what the element type is supposed to be.
 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)]
 #[derive(HashStable)]
 pub enum InferTy {
+    /// A type variable.
     TyVar(TyVid),
+    /// An integral type variable (`{integer}`).
+    ///
+    /// These are created when the compiler sees an integer literal like
+    /// `1` that could be several different types (`u8`, `i32`, `u32`, etc.).
+    /// We don't know until it's used what type it's supposed to be, so
+    /// we create a fresh type variable.
     IntVar(IntVid),
+    /// A floating-point type variable (`{float}`).
+    ///
+    /// These are created when the compiler sees an float literal like
+    /// `1.0` that could be either an `f32` or an `f64`.
+    /// We don't know until it's used what type it's supposed to be, so
+    /// we create a fresh type variable.
     FloatVar(FloatVid),
 
-    /// A `FreshTy` is one that is generated as a replacement for an
-    /// unbound type variable. This is convenient for caching etc. See
-    /// `infer::freshen` for more details.
+    /// A [`FreshTy`][Self::FreshTy] is one that is generated as a replacement
+    /// for an unbound type variable. This is convenient for caching etc. See
+    /// `rustc_infer::infer::freshen` for more details.
+    ///
+    /// Compare with [`TyVar`][Self::TyVar].
     FreshTy(u32),
+    /// Like [`FreshTy`][Self::FreshTy], but as a replacement for [`IntVar`][Self::IntVar].
     FreshIntTy(u32),
+    /// Like [`FreshTy`][Self::FreshTy], but as a replacement for [`FloatVar`][Self::FloatVar].
     FreshFloatTy(u32),
 }
 
@@ -1572,17 +1596,11 @@ pub fn has_name(&self) -> bool {
     }
 
     pub fn is_late_bound(&self) -> bool {
-        match *self {
-            ty::ReLateBound(..) => true,
-            _ => false,
-        }
+        matches!(*self, ty::ReLateBound(..))
     }
 
     pub fn is_placeholder(&self) -> bool {
-        match *self {
-            ty::RePlaceholder(..) => true,
-            _ => false,
-        }
+        matches!(*self, ty::RePlaceholder(..))
     }
 
     pub fn bound_at_or_above_binder(&self, index: ty::DebruijnIndex) -> bool {
index 0903ef5089861737c190dbb57773ca4178a65e0c..e79adcdb545988885030842b59ce92fef2b31fe2 100644 (file)
@@ -21,6 +21,7 @@ pub fn span_bug_fmt<S: Into<MultiSpan>>(span: S, args: fmt::Arguments<'_>) -> !
     opt_span_bug_fmt(Some(span), args, Location::caller());
 }
 
+#[track_caller]
 fn opt_span_bug_fmt<S: Into<MultiSpan>>(
     span: Option<S>,
     args: fmt::Arguments<'_>,
index 81571fd73003fb448587f786462b289c693b792b..4ebc1cdca60597ec83d4c2c54a3639fc5197c505 100644 (file)
@@ -954,7 +954,7 @@ fn closure_span(
         &self,
         def_id: DefId,
         target_place: PlaceRef<'tcx>,
-        places: &Vec<Operand<'tcx>>,
+        places: &[Operand<'tcx>],
     ) -> Option<(Span, Option<GeneratorKind>, Span)> {
         debug!(
             "closure_span: def_id={:?} target_place={:?} places={:?}",
index 995e3a60a0c76fa8c6e2083a10a93bfbc93577d6..7e8a33efe114ef6fb6a275c5a1b2a1fb70c170a2 100644 (file)
@@ -58,11 +58,7 @@ fn next(elem: &Self) -> Option<AppearanceIndex> {
 }
 
 impl LocalUseMap {
-    crate fn build(
-        live_locals: &Vec<Local>,
-        elements: &RegionValueElements,
-        body: &Body<'_>,
-    ) -> Self {
+    crate fn build(live_locals: &[Local], elements: &RegionValueElements, body: &Body<'_>) -> Self {
         let nones = IndexVec::from_elem_n(None, body.local_decls.len());
         let mut local_use_map = LocalUseMap {
             first_def_at: nones.clone(),
index f13b4b7b919247893983addd97075617152494e4..df163f6562842d1be5387996021df23c8c2fed46 100644 (file)
@@ -383,25 +383,19 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
         Ok(mplace) => {
             // Since evaluation had no errors, valiate the resulting constant:
             let validation = try {
-                // FIXME do not validate promoteds until a decision on
-                // https://github.com/rust-lang/rust/issues/67465 and
-                // https://github.com/rust-lang/rust/issues/67534 is made.
-                // Promoteds can contain unexpected `UnsafeCell` and reference `static`s, but their
-                // otherwise restricted form ensures that this is still sound. We just lose the
-                // extra safety net of some of the dynamic checks. They can also contain invalid
-                // values, but since we do not usually check intermediate results of a computation
-                // for validity, it might be surprising to do that here.
-                if cid.promoted.is_none() {
-                    let mut ref_tracking = RefTracking::new(mplace);
-                    let mut inner = false;
-                    while let Some((mplace, path)) = ref_tracking.todo.pop() {
-                        let mode = match tcx.static_mutability(cid.instance.def_id()) {
-                            Some(_) => CtfeValidationMode::Regular, // a `static`
-                            None => CtfeValidationMode::Const { inner },
-                        };
-                        ecx.const_validate_operand(mplace.into(), path, &mut ref_tracking, mode)?;
-                        inner = true;
-                    }
+                let mut ref_tracking = RefTracking::new(mplace);
+                let mut inner = false;
+                while let Some((mplace, path)) = ref_tracking.todo.pop() {
+                    let mode = match tcx.static_mutability(cid.instance.def_id()) {
+                        Some(_) if cid.promoted.is_some() => {
+                            // Promoteds in statics are allowed to point to statics.
+                            CtfeValidationMode::Const { inner, allow_static_ptrs: true }
+                        }
+                        Some(_) => CtfeValidationMode::Regular, // a `static`
+                        None => CtfeValidationMode::Const { inner, allow_static_ptrs: false },
+                    };
+                    ecx.const_validate_operand(mplace.into(), path, &mut ref_tracking, mode)?;
+                    inner = true;
                 }
             };
             if let Err(error) = validation {
index 474e1f8e577f8b647be644be217823779244fd31..58858c09f44ef0079afd6c30465995a7e1a07631 100644 (file)
@@ -141,9 +141,11 @@ pub fn emulate_intrinsic(
             }
 
             sym::min_align_of_val | sym::size_of_val => {
-                let place = self.deref_operand(args[0])?;
+                // Avoid `deref_operand` -- this is not a deref, the ptr does not have to be
+                // dereferencable!
+                let place = self.ref_to_mplace(self.read_immediate(args[0])?)?;
                 let (size, align) = self
-                    .size_and_align_of(place.meta, place.layout)?
+                    .size_and_align_of_mplace(place)?
                     .ok_or_else(|| err_unsup_format!("`extern type` does not have known layout"))?;
 
                 let result = match intrinsic_name {
@@ -322,6 +324,29 @@ pub fn emulate_intrinsic(
                 let result = Scalar::from_uint(truncated_bits, layout.size);
                 self.write_scalar(result, dest)?;
             }
+            sym::copy | sym::copy_nonoverlapping => {
+                let elem_ty = instance.substs.type_at(0);
+                let elem_layout = self.layout_of(elem_ty)?;
+                let count = self.read_scalar(args[2])?.to_machine_usize(self)?;
+                let elem_align = elem_layout.align.abi;
+
+                let size = elem_layout.size.checked_mul(count, self).ok_or_else(|| {
+                    err_ub_format!("overflow computing total size of `{}`", intrinsic_name)
+                })?;
+                let src = self.read_scalar(args[0])?.check_init()?;
+                let src = self.memory.check_ptr_access(src, size, elem_align)?;
+                let dest = self.read_scalar(args[1])?.check_init()?;
+                let dest = self.memory.check_ptr_access(dest, size, elem_align)?;
+
+                if let (Some(src), Some(dest)) = (src, dest) {
+                    self.memory.copy(
+                        src,
+                        dest,
+                        size,
+                        intrinsic_name == sym::copy_nonoverlapping,
+                    )?;
+                }
+            }
             sym::offset => {
                 let ptr = self.read_scalar(args[0])?.check_init()?;
                 let offset_count = self.read_scalar(args[1])?.to_machine_isize(self)?;
index 2d235d65c4d3812e04694ebded070094ce502dc4..423d1270ac8652709ecfe67f1474c65f7439a421 100644 (file)
@@ -117,11 +117,12 @@ pub enum PathElem {
 pub enum CtfeValidationMode {
     /// Regular validation, nothing special happening.
     Regular,
-    /// Validation of a `const`. `inner` says if this is an inner, indirect allocation (as opposed
-    /// to the top-level const allocation).
-    /// Being an inner allocation makes a difference because the top-level allocation of a `const`
-    /// is copied for each use, but the inner allocations are implicitly shared.
-    Const { inner: bool },
+    /// Validation of a `const`.
+    /// `inner` says if this is an inner, indirect allocation (as opposed to the top-level const
+    /// allocation). Being an inner allocation makes a difference because the top-level allocation
+    /// of a `const` is copied for each use, but the inner allocations are implicitly shared.
+    /// `allow_static_ptrs` says if pointers to statics are permitted (which is the case for promoteds in statics).
+    Const { inner: bool, allow_static_ptrs: bool },
 }
 
 /// State for tracking recursive validation of references
@@ -152,7 +153,7 @@ pub fn track(&mut self, op: T, path: impl FnOnce() -> PATH) {
 }
 
 /// Format a path
-fn write_path(out: &mut String, path: &Vec<PathElem>) {
+fn write_path(out: &mut String, path: &[PathElem]) {
     use self::PathElem::*;
 
     for elem in path.iter() {
@@ -390,7 +391,7 @@ fn check_safe_pointer(
         }
         // Make sure this is dereferenceable and all.
         let size_and_align = try_validation!(
-            self.ecx.size_and_align_of(place.meta, place.layout),
+            self.ecx.size_and_align_of_mplace(place),
             self.path,
             err_ub!(InvalidMeta(msg)) => { "invalid {} metadata: {}", kind, msg },
         );
@@ -437,7 +438,10 @@ fn check_safe_pointer(
                 if let Some(GlobalAlloc::Static(did)) = alloc_kind {
                     assert!(!self.ecx.tcx.is_thread_local_static(did));
                     assert!(self.ecx.tcx.is_static(did));
-                    if matches!(self.ctfe_mode, Some(CtfeValidationMode::Const { .. })) {
+                    if matches!(
+                        self.ctfe_mode,
+                        Some(CtfeValidationMode::Const { allow_static_ptrs: false, .. })
+                    ) {
                         // See const_eval::machine::MemoryExtra::can_access_statics for why
                         // this check is so important.
                         // This check is reachable when the const just referenced the static,
@@ -742,9 +746,9 @@ fn visit_value(&mut self, op: OpTy<'tcx, M::PointerTag>) -> InterpResult<'tcx> {
         // Sanity check: `builtin_deref` does not know any pointers that are not primitive.
         assert!(op.layout.ty.builtin_deref(true).is_none());
 
-        // Special check preventing `UnsafeCell` in constants
+        // Special check preventing `UnsafeCell` in the inner part of constants
         if let Some(def) = op.layout.ty.ty_adt_def() {
-            if matches!(self.ctfe_mode, Some(CtfeValidationMode::Const { inner: true }))
+            if matches!(self.ctfe_mode, Some(CtfeValidationMode::Const { inner: true, .. }))
                 && Some(def.did) == self.ecx.tcx.lang_items().unsafe_cell_type()
             {
                 throw_validation_failure!(self.path, { "`UnsafeCell` in a `const`" });
index 20f6a16e0f75712190548ed9aa573a4310f4f673..b5921aac561437326c851914cdb1baa68f0dd0a6 100644 (file)
@@ -140,7 +140,7 @@ fn new(
     /// message for subsequent debugging.
     fn make_bcb_counters(
         &mut self,
-        coverage_spans: &Vec<CoverageSpan>,
+        coverage_spans: &[CoverageSpan],
     ) -> Result<Vec<CoverageKind>, Error> {
         debug!("make_bcb_counters(): adding a counter or expression to each BasicCoverageBlock");
         let num_bcbs = self.basic_coverage_blocks.num_nodes();
@@ -465,7 +465,7 @@ fn recursive_get_or_make_edge_counter_operand(
     fn choose_preferred_expression_branch(
         &self,
         traversal: &TraverseCoverageGraphWithLoops,
-        branches: &Vec<BcbBranch>,
+        branches: &[BcbBranch],
     ) -> BcbBranch {
         let branch_needs_a_counter =
             |branch: &BcbBranch| branch.counter(&self.basic_coverage_blocks).is_none();
@@ -509,7 +509,7 @@ fn choose_preferred_expression_branch(
     fn find_some_reloop_branch(
         &self,
         traversal: &TraverseCoverageGraphWithLoops,
-        branches: &Vec<BcbBranch>,
+        branches: &[BcbBranch],
     ) -> Option<BcbBranch> {
         let branch_needs_a_counter =
             |branch: &BcbBranch| branch.counter(&self.basic_coverage_blocks).is_none();
index 4590d37c182e405d292f3d8fa545b827846b0322..93133e9b7f06364b52f3b549b7714fae78d858ea 100644 (file)
@@ -30,6 +30,7 @@
 };
 use rustc_middle::ty::TyCtxt;
 use rustc_span::def_id::DefId;
+use rustc_span::source_map::SourceMap;
 use rustc_span::{CharPos, Pos, SourceFile, Span, Symbol};
 
 /// A simple error message wrapper for `coverage::Error`s.
@@ -311,7 +312,7 @@ fn inject_coverage_span_counters(
                 self.mir_body,
                 counter_kind,
                 self.bcb_leader_bb(bcb),
-                Some(make_code_region(file_name, &self.source_file, span, body_span)),
+                Some(make_code_region(source_map, file_name, &self.source_file, span, body_span)),
             );
         }
     }
@@ -489,6 +490,7 @@ fn inject_intermediate_expression(mir_body: &mut mir::Body<'tcx>, expression: Co
 
 /// Convert the Span into its file name, start line and column, and end line and column
 fn make_code_region(
+    source_map: &SourceMap,
     file_name: Symbol,
     source_file: &Lrc<SourceFile>,
     span: Span,
@@ -508,6 +510,8 @@ fn make_code_region(
     } else {
         source_file.lookup_file_pos(span.hi())
     };
+    let start_line = source_map.doctest_offset_line(&source_file.name, start_line);
+    let end_line = source_map.doctest_offset_line(&source_file.name, end_line);
     CodeRegion {
         file_name,
         start_line: start_line as u32,
index d592580af9cecf8c59f1a553279af679c67d8b4d..7c8c349da1d6c55544d01e2b49d9e888394267cf 100644 (file)
@@ -99,7 +99,7 @@ fn check_bound_args(
         &self,
         def_id: DefId,
         substs_ref: SubstsRef<'tcx>,
-        args: &Vec<Operand<'tcx>>,
+        args: &[Operand<'tcx>],
         source_info: SourceInfo,
     ) {
         let param_env = self.tcx.param_env(def_id);
@@ -162,7 +162,7 @@ fn is_fn_ref(ty: Ty<'tcx>) -> Option<(DefId, SubstsRef<'tcx>)> {
             .unwrap_or(None)
     }
 
-    fn nth_arg_span(&self, args: &Vec<Operand<'tcx>>, n: usize) -> Span {
+    fn nth_arg_span(&self, args: &[Operand<'tcx>], n: usize) -> Span {
         match &args[n] {
             Operand::Copy(place) | Operand::Move(place) => {
                 self.body.local_decls[place.local].source_info.span
index 3eb2b500d6627324dd0950e91556b780511286d3..990ca313c5ddceaba6eb143d66cb27effee64e9d 100644 (file)
@@ -29,8 +29,10 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
             optimization_finder.optimizations
         };
 
-        // Then carry out those optimizations.
-        MutVisitor::visit_body(&mut InstCombineVisitor { optimizations, tcx }, body);
+        if !optimizations.is_empty() {
+            // Then carry out those optimizations.
+            MutVisitor::visit_body(&mut InstCombineVisitor { optimizations, tcx }, body);
+        }
     }
 }
 
@@ -95,7 +97,7 @@ fn visit_rvalue(&mut self, rvalue: &mut Rvalue<'tcx>, location: Location) {
             }
         }
 
-        self.super_rvalue(rvalue, location)
+        // We do not call super_rvalue as we are not interested in any other parts of the tree
     }
 }
 
@@ -299,7 +301,7 @@ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
 
         self.find_unneeded_equality_comparison(rvalue, location);
 
-        self.super_rvalue(rvalue, location)
+        // We do not call super_rvalue as we are not interested in any other parts of the tree
     }
 }
 
@@ -310,3 +312,21 @@ struct OptimizationList<'tcx> {
     unneeded_equality_comparison: FxHashMap<Location, Operand<'tcx>>,
     unneeded_deref: FxHashMap<Location, Place<'tcx>>,
 }
+
+impl<'tcx> OptimizationList<'tcx> {
+    fn is_empty(&self) -> bool {
+        match self {
+            OptimizationList {
+                and_stars,
+                arrays_lengths,
+                unneeded_equality_comparison,
+                unneeded_deref,
+            } => {
+                and_stars.is_empty()
+                    && arrays_lengths.is_empty()
+                    && unneeded_equality_comparison.is_empty()
+                    && unneeded_deref.is_empty()
+            }
+        }
+    }
+}
index 8d5ed747c3f8f25ed3f8611096ac72cbb43cdc7b..ea92e23e9bffb6e03fe4a59ec07964720c39a425 100644 (file)
@@ -90,7 +90,7 @@ pub enum TempState {
 impl TempState {
     pub fn is_promotable(&self) -> bool {
         debug!("is_promotable: self={:?}", self);
-        matches!(self, TempState::Defined { .. } )
+        matches!(self, TempState::Defined { .. })
     }
 }
 
@@ -309,50 +309,26 @@ fn validate_candidate(&self, candidate: Candidate) -> Result<(), Unpromotable> {
                 let statement = &self.body[loc.block].statements[loc.statement_index];
                 match &statement.kind {
                     StatementKind::Assign(box (_, Rvalue::Ref(_, kind, place))) => {
-                        match kind {
-                            BorrowKind::Shared | BorrowKind::Mut { .. } => {}
-
-                            // FIXME(eddyb) these aren't promoted here but *could*
-                            // be promoted as part of a larger value because
-                            // `validate_rvalue`  doesn't check them, need to
-                            // figure out what is the intended behavior.
-                            BorrowKind::Shallow | BorrowKind::Unique => return Err(Unpromotable),
-                        }
-
                         // We can only promote interior borrows of promotable temps (non-temps
                         // don't get promoted anyway).
                         self.validate_local(place.local)?;
 
+                        // The reference operation itself must be promotable.
+                        // (Needs to come after `validate_local` to avoid ICEs.)
+                        self.validate_ref(*kind, place)?;
+
+                        // We do not check all the projections (they do not get promoted anyway),
+                        // but we do stay away from promoting anything involving a dereference.
                         if place.projection.contains(&ProjectionElem::Deref) {
                             return Err(Unpromotable);
                         }
-                        if self.qualif_local::<qualifs::NeedsDrop>(place.local) {
-                            return Err(Unpromotable);
-                        }
 
-                        // FIXME(eddyb) this duplicates part of `validate_rvalue`.
-                        let has_mut_interior =
-                            self.qualif_local::<qualifs::HasMutInterior>(place.local);
-                        if has_mut_interior {
+                        // We cannot promote things that need dropping, since the promoted value
+                        // would not get dropped.
+                        if self.qualif_local::<qualifs::NeedsDrop>(place.local) {
                             return Err(Unpromotable);
                         }
 
-                        if let BorrowKind::Mut { .. } = kind {
-                            let ty = place.ty(self.body, self.tcx).ty;
-
-                            // In theory, any zero-sized value could be borrowed
-                            // mutably without consequences. However, only &mut []
-                            // is allowed right now.
-                            if let ty::Array(_, len) = ty.kind() {
-                                match len.try_eval_usize(self.tcx, self.param_env) {
-                                    Some(0) => {}
-                                    _ => return Err(Unpromotable),
-                                }
-                            } else {
-                                return Err(Unpromotable);
-                            }
-                        }
-
                         Ok(())
                     }
                     _ => bug!(),
@@ -572,58 +548,115 @@ fn validate_operand(&self, operand: &Operand<'tcx>) -> Result<(), Unpromotable>
         }
     }
 
-    fn validate_rvalue(&self, rvalue: &Rvalue<'tcx>) -> Result<(), Unpromotable> {
-        match *rvalue {
-            Rvalue::Cast(CastKind::Misc, ref operand, cast_ty) => {
-                let operand_ty = operand.ty(self.body, self.tcx);
-                let cast_in = CastTy::from_ty(operand_ty).expect("bad input type for cast");
-                let cast_out = CastTy::from_ty(cast_ty).expect("bad output type for cast");
-                if let (CastTy::Ptr(_) | CastTy::FnPtr, CastTy::Int(_)) = (cast_in, cast_out) {
-                    // ptr-to-int casts are not possible in consts and thus not promotable
+    fn validate_ref(&self, kind: BorrowKind, place: &Place<'tcx>) -> Result<(), Unpromotable> {
+        match kind {
+            // Reject these borrow types just to be safe.
+            // FIXME(RalfJung): could we allow them? Should we? No point in it until we have a usecase.
+            BorrowKind::Shallow | BorrowKind::Unique => return Err(Unpromotable),
+
+            BorrowKind::Shared => {
+                let has_mut_interior = self.qualif_local::<qualifs::HasMutInterior>(place.local);
+                if has_mut_interior {
                     return Err(Unpromotable);
                 }
             }
 
-            Rvalue::BinaryOp(op, ref lhs, _) => {
-                if let ty::RawPtr(_) | ty::FnPtr(..) = lhs.ty(self.body, self.tcx).kind() {
-                    assert!(
-                        op == BinOp::Eq
-                            || op == BinOp::Ne
-                            || op == BinOp::Le
-                            || op == BinOp::Lt
-                            || op == BinOp::Ge
-                            || op == BinOp::Gt
-                            || op == BinOp::Offset
-                    );
+            BorrowKind::Mut { .. } => {
+                let ty = place.ty(self.body, self.tcx).ty;
 
-                    // raw pointer operations are not allowed inside consts and thus not promotable
+                // In theory, any zero-sized value could be borrowed
+                // mutably without consequences. However, only &mut []
+                // is allowed right now.
+                if let ty::Array(_, len) = ty.kind() {
+                    match len.try_eval_usize(self.tcx, self.param_env) {
+                        Some(0) => {}
+                        _ => return Err(Unpromotable),
+                    }
+                } else {
                     return Err(Unpromotable);
                 }
             }
-
-            Rvalue::NullaryOp(NullOp::Box, _) => return Err(Unpromotable),
-
-            // FIXME(RalfJung): the rest is *implicitly considered promotable*... that seems dangerous.
-            _ => {}
         }
 
+        Ok(())
+    }
+
+    fn validate_rvalue(&self, rvalue: &Rvalue<'tcx>) -> Result<(), Unpromotable> {
         match rvalue {
-            Rvalue::ThreadLocalRef(_) => Err(Unpromotable),
+            Rvalue::Use(operand)
+            | Rvalue::Repeat(operand, _)
+            | Rvalue::UnaryOp(UnOp::Not | UnOp::Neg, operand) => {
+                self.validate_operand(operand)?;
+            }
 
-            Rvalue::NullaryOp(..) => Ok(()),
+            Rvalue::Discriminant(place) | Rvalue::Len(place) => {
+                self.validate_place(place.as_ref())?
+            }
 
-            Rvalue::Discriminant(place) | Rvalue::Len(place) => self.validate_place(place.as_ref()),
+            Rvalue::ThreadLocalRef(_) => return Err(Unpromotable),
 
-            Rvalue::Use(operand)
-            | Rvalue::Repeat(operand, _)
-            | Rvalue::UnaryOp(_, operand)
-            | Rvalue::Cast(_, operand, _) => self.validate_operand(operand),
+            Rvalue::Cast(kind, operand, cast_ty) => {
+                if matches!(kind, CastKind::Misc) {
+                    let operand_ty = operand.ty(self.body, self.tcx);
+                    let cast_in = CastTy::from_ty(operand_ty).expect("bad input type for cast");
+                    let cast_out = CastTy::from_ty(cast_ty).expect("bad output type for cast");
+                    if let (CastTy::Ptr(_) | CastTy::FnPtr, CastTy::Int(_)) = (cast_in, cast_out) {
+                        // ptr-to-int casts are not possible in consts and thus not promotable
+                        return Err(Unpromotable);
+                    }
+                    // int-to-ptr casts are fine, they just use the integer value at pointer type.
+                }
+
+                self.validate_operand(operand)?;
+            }
+
+            Rvalue::BinaryOp(op, lhs, rhs) | Rvalue::CheckedBinaryOp(op, lhs, rhs) => {
+                let op = *op;
+                if let ty::RawPtr(_) | ty::FnPtr(..) = lhs.ty(self.body, self.tcx).kind() {
+                    // raw pointer operations are not allowed inside consts and thus not promotable
+                    assert!(matches!(
+                        op,
+                        BinOp::Eq
+                            | BinOp::Ne
+                            | BinOp::Le
+                            | BinOp::Lt
+                            | BinOp::Ge
+                            | BinOp::Gt
+                            | BinOp::Offset
+                    ));
+                    return Err(Unpromotable);
+                }
+
+                match op {
+                    // FIXME: reject operations that can fail -- namely, division and modulo.
+                    BinOp::Eq
+                    | BinOp::Ne
+                    | BinOp::Le
+                    | BinOp::Lt
+                    | BinOp::Ge
+                    | BinOp::Gt
+                    | BinOp::Offset
+                    | BinOp::Add
+                    | BinOp::Sub
+                    | BinOp::Mul
+                    | BinOp::Div
+                    | BinOp::Rem
+                    | BinOp::BitXor
+                    | BinOp::BitAnd
+                    | BinOp::BitOr
+                    | BinOp::Shl
+                    | BinOp::Shr => {}
+                }
 
-            Rvalue::BinaryOp(_, lhs, rhs) | Rvalue::CheckedBinaryOp(_, lhs, rhs) => {
                 self.validate_operand(lhs)?;
-                self.validate_operand(rhs)
+                self.validate_operand(rhs)?;
             }
 
+            Rvalue::NullaryOp(op, _) => match op {
+                NullOp::Box => return Err(Unpromotable),
+                NullOp::SizeOf => {}
+            },
+
             Rvalue::AddressOf(_, place) => {
                 // We accept `&raw *`, i.e., raw reborrows -- creating a raw pointer is
                 // no problem, only using it is.
@@ -636,53 +669,36 @@ fn validate_rvalue(&self, rvalue: &Rvalue<'tcx>) -> Result<(), Unpromotable> {
                         });
                     }
                 }
-                Err(Unpromotable)
+                return Err(Unpromotable);
             }
 
             Rvalue::Ref(_, kind, place) => {
-                if let BorrowKind::Mut { .. } = kind {
-                    let ty = place.ty(self.body, self.tcx).ty;
-
-                    // In theory, any zero-sized value could be borrowed
-                    // mutably without consequences. However, only &mut []
-                    // is allowed right now.
-                    if let ty::Array(_, len) = ty.kind() {
-                        match len.try_eval_usize(self.tcx, self.param_env) {
-                            Some(0) => {}
-                            _ => return Err(Unpromotable),
-                        }
-                    } else {
-                        return Err(Unpromotable);
-                    }
-                }
-
                 // Special-case reborrows to be more like a copy of the reference.
-                let mut place = place.as_ref();
-                if let [proj_base @ .., ProjectionElem::Deref] = &place.projection {
-                    let base_ty = Place::ty_from(place.local, proj_base, self.body, self.tcx).ty;
+                let mut place_simplified = place.as_ref();
+                if let [proj_base @ .., ProjectionElem::Deref] = &place_simplified.projection {
+                    let base_ty =
+                        Place::ty_from(place_simplified.local, proj_base, self.body, self.tcx).ty;
                     if let ty::Ref(..) = base_ty.kind() {
-                        place = PlaceRef { local: place.local, projection: proj_base };
+                        place_simplified =
+                            PlaceRef { local: place_simplified.local, projection: proj_base };
                     }
                 }
 
-                self.validate_place(place)?;
-
-                let has_mut_interior = self.qualif_local::<qualifs::HasMutInterior>(place.local);
-                if has_mut_interior {
-                    return Err(Unpromotable);
-                }
+                self.validate_place(place_simplified)?;
 
-                Ok(())
+                // Check that the reference is fine (using the original place!).
+                // (Needs to come after `validate_place` to avoid ICEs.)
+                self.validate_ref(*kind, place)?;
             }
 
-            Rvalue::Aggregate(_, ref operands) => {
+            Rvalue::Aggregate(_, operands) => {
                 for o in operands {
                     self.validate_operand(o)?;
                 }
-
-                Ok(())
             }
         }
+
+        Ok(())
     }
 
     fn validate_call(
index 205f718d6e446a2ba007593ab7f1960093e0625d..7598be4e4a11d8e9c51c2085f479058efe8c0da8 100644 (file)
@@ -92,7 +92,7 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
 /// "rustc_peek: bit not set".
 ///
 /// The intention is that one can write unit tests for dataflow by
-/// putting code into a compile-fail test and using `rustc_peek` to
+/// putting code into an UI test and using `rustc_peek` to
 /// make observations about the results of dataflow static analyses.
 ///
 /// (If there are any calls to `rustc_peek` that do not match the
index bea95bf43d21eb3ac880fa31aed7d7fee1fa734b..a3459887a9a7596700bb6b92c44a869204ba7668 100644 (file)
@@ -306,7 +306,7 @@ fn optimization_applies<'tcx>(
         return false;
     }
 
-    // Verify the assigment chain consists of the form b = a; c = b; d = c; etc...
+    // Verify the assignment chain consists of the form b = a; c = b; d = c; etc...
     if opt_info.field_tmp_assignments.is_empty() {
         trace!("NO: no assignments found");
         return false;
index 83bf7584f2e2fc84f0e314e603155904bdb474f1..56d8045813c425c2d7cb67a8cbdf8eec88d6b549 100644 (file)
@@ -68,9 +68,10 @@ impl<'cx, 'tcx> crate::borrow_check::MirBorrowckCtxt<'cx, 'tcx> {
             err.span_label(
                 new_loan_span,
                 format!(
-                    "mutable borrow starts here in previous \
-                     iteration of loop{}",
-                    opt_via
+                    "{}{} was mutably borrowed here in the previous iteration of the loop{}",
+                    desc,
+                    via(opt_via),
+                    opt_via,
                 ),
             );
             if let Some(old_load_end_span) = old_load_end_span {
index b6a1b652cf6a34830a9578e09f02b623adae56f4..89ce29bd101297af402590bf072f26ea60ec78d7 100644 (file)
@@ -17,7 +17,7 @@
 };
 use rustc_middle::mir::visit::Visitor;
 use rustc_middle::mir::*;
-use rustc_middle::ty::{self, TyCtxt, TypeFoldable, TypeVisitor};
+use rustc_middle::ty::{self, TyCtxt, TyS, TypeFoldable, TypeVisitor};
 use rustc_target::abi::Size;
 use std::ops::ControlFlow;
 
@@ -408,6 +408,18 @@ fn push(&mut self, lines: &str) {
     }
 }
 
+fn use_verbose(ty: &&TyS<'tcx>) -> bool {
+    match ty.kind() {
+        ty::Int(_) | ty::Uint(_) | ty::Bool | ty::Char | ty::Float(_) => false,
+        // Unit type
+        ty::Tuple(g_args) if g_args.is_empty() => false,
+        ty::Tuple(g_args) => g_args.iter().any(|g_arg| use_verbose(&g_arg.expect_ty())),
+        ty::Array(ty, _) => use_verbose(ty),
+        ty::FnDef(..) => false,
+        _ => true,
+    }
+}
+
 impl Visitor<'tcx> for ExtraComments<'tcx> {
     fn visit_constant(&mut self, constant: &Constant<'tcx>, location: Location) {
         self.super_constant(constant, location);
@@ -430,16 +442,10 @@ fn visit_constant(&mut self, constant: &Constant<'tcx>, location: Location) {
     fn visit_const(&mut self, constant: &&'tcx ty::Const<'tcx>, _: Location) {
         self.super_const(constant);
         let ty::Const { ty, val, .. } = constant;
-        match ty.kind() {
-            ty::Int(_) | ty::Uint(_) | ty::Bool | ty::Char | ty::Float(_) => {}
-            // Unit type
-            ty::Tuple(tys) if tys.is_empty() => {}
-            ty::FnDef(..) => {}
-            _ => {
-                self.push("ty::Const");
-                self.push(&format!("+ ty: {:?}", ty));
-                self.push(&format!("+ val: {:?}", val));
-            }
+        if use_verbose(ty) {
+            self.push("ty::Const");
+            self.push(&format!("+ ty: {:?}", ty));
+            self.push(&format!("+ val: {:?}", val));
         }
     }
 
index e1a3dc87c8c8dc696a21971c946295fa7da0b631..cf2e4e8916d0a397c5f8b320f8acf39951417687 100644 (file)
@@ -79,7 +79,7 @@
 /// part of a path that is captued by a closure. We stop applying projections once we see the first
 /// projection that isn't captured by a closure.
 fn convert_to_hir_projections_and_truncate_for_capture<'tcx>(
-    mir_projections: &Vec<PlaceElem<'tcx>>,
+    mir_projections: &[PlaceElem<'tcx>],
 ) -> Vec<HirProjectionKind> {
 
     let mut hir_projections  = Vec::new();
@@ -128,7 +128,7 @@ fn convert_to_hir_projections_and_truncate_for_capture<'tcx>(
 ///        list are being applied to the same root variable.
 fn is_ancestor_or_same_capture(
     proj_possible_ancestor: &Vec<HirProjectionKind>,
-    proj_capture: &Vec<HirProjectionKind>,
+    proj_capture: &[HirProjectionKind],
 ) -> bool {
     // We want to make sure `is_ancestor_or_same_capture("x.0.0", "x.0")` to return false.
     // Therefore we can't just check if all projections are same in the zipped iterator below.
@@ -171,7 +171,7 @@ fn find_capture_matching_projections<'a, 'tcx>(
     typeck_results: &'a ty::TypeckResults<'tcx>,
     var_hir_id: HirId,
     closure_def_id: DefId,
-    projections: &Vec<PlaceElem<'tcx>>,
+    projections: &[PlaceElem<'tcx>],
 ) -> Option<(usize, &'a ty::CapturedPlace<'tcx>)> {
     let closure_min_captures = typeck_results.closure_min_captures.get(&closure_def_id)?;
     let root_variable_min_captures = closure_min_captures.get(&var_hir_id)?;
index 1f70fdb5ae30b4d2475376820a7c7353c516bbcf..09281799041eeb11ec761aede42467a7ebac201f 100644 (file)
@@ -40,11 +40,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         let expr_span = expr.span;
         let source_info = this.source_info(expr_span);
 
-        let expr_is_block_or_scope = match expr.kind {
-            ExprKind::Block { .. } => true,
-            ExprKind::Scope { .. } => true,
-            _ => false,
-        };
+        let expr_is_block_or_scope = matches!(expr.kind, ExprKind::Block { .. } | ExprKind::Scope { .. });
 
         let schedule_drop = move |this: &mut Self| {
             if let Some(drop_scope) = scope {
index e041464381220c04af1a7962e3a13e7caa4009c8..996615995259d58bf77b17dd8d987516585a5394 100644 (file)
@@ -854,7 +854,7 @@ fn args_and_body(
                     let mut mutability = Mutability::Not;
 
                     // FIXME(project-rfc-2229#8): Store more precise information
-                    let mut name = kw::Invalid;
+                    let mut name = kw::Empty;
                     if let Some(Node::Binding(pat)) = tcx_hir.find(var_id) {
                         if let hir::PatKind::Binding(_, _, ident, _) = pat.kind {
                             name = ident.name;
index 8b21a9b24e6e2df9285aac8f01181caefb7d44ab..db2fa5730a338b2e6129dbaf66d38273ae9fe34b 100644 (file)
@@ -1,6 +1,47 @@
-//! This module provides functions to deconstruct and reconstruct patterns into a constructor
-//! applied to some fields. This is used by the `_match` module to compute pattern
-//! usefulness/exhaustiveness.
+//! [`super::usefulness`] explains most of what is happening in this file. As explained there,
+//! values and patterns are made from constructors applied to fields. This file defines a
+//! `Constructor` enum, a `Fields` struct, and various operations to manipulate them and convert
+//! them from/to patterns.
+//!
+//! There's one idea that is not detailed in [`super::usefulness`] because the details are not
+//! needed there: _constructor splitting_.
+//!
+//! # Constructor splitting
+//!
+//! The idea is as follows: given a constructor `c` and a matrix, we want to specialize in turn
+//! with all the value constructors that are covered by `c`, and compute usefulness for each.
+//! Instead of listing all those constructors (which is intractable), we group those value
+//! constructors together as much as possible. Example:
+//!
+//! ```
+//! match (0, false) {
+//!     (0 ..=100, true) => {} // `p_1`
+//!     (50..=150, false) => {} // `p_2`
+//!     (0 ..=200, _) => {} // `q`
+//! }
+//! ```
+//!
+//! The naive approach would try all numbers in the range `0..=200`. But we can be a lot more
+//! clever: `0` and `1` for example will match the exact same rows, and return equivalent
+//! witnesses. In fact all of `0..50` would. We can thus restrict our exploration to 4
+//! constructors: `0..50`, `50..=100`, `101..=150` and `151..=200`. That is enough and infinitely
+//! more tractable.
+//!
+//! We capture this idea in a function `split(p_1 ... p_n, c)` which returns a list of constructors
+//! `c'` covered by `c`. Given such a `c'`, we require that all value ctors `c''` covered by `c'`
+//! return an equivalent set of witnesses after specializing and computing usefulness.
+//! In the example above, witnesses for specializing by `c''` covered by `0..50` will only differ
+//! in their first element.
+//!
+//! We usually also ask that the `c'` together cover all of the original `c`. However we allow
+//! skipping some constructors as long as it doesn't change whether the resulting list of witnesses
+//! is empty of not. We use this in the wildcard `_` case.
+//!
+//! Splitting is implemented in the [`Constructor::split`] function. We don't do splitting for
+//! or-patterns; instead we just try the alternatives one-by-one. For details on splitting
+//! wildcards, see [`SplitWildcard`]; for integer ranges, see [`SplitIntRange`]; for slices, see
+//! [`SplitVarLenSlice`].
+
 use self::Constructor::*;
 use self::SliceKind::*;
 
@@ -24,7 +65,7 @@
 
 use smallvec::{smallvec, SmallVec};
 use std::cmp::{self, max, min, Ordering};
-use std::iter::IntoIterator;
+use std::iter::{once, IntoIterator};
 use std::ops::RangeInclusive;
 
 /// An inclusive interval, used for precise integer exhaustiveness checking.
@@ -161,7 +202,7 @@ fn suspicious_intersection(&self, other: &Self) -> bool {
         // 2       --------   // 2 -------
         let (lo, hi) = self.boundaries();
         let (other_lo, other_hi) = other.boundaries();
-        lo == other_hi || hi == other_lo
+        (lo == other_hi || hi == other_lo) && !self.is_singleton() && !other.is_singleton()
     }
 
     fn to_pat<'tcx>(&self, tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Pat<'tcx> {
@@ -183,143 +224,56 @@ fn to_pat<'tcx>(&self, tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Pat<'tcx> {
         Pat { ty, span: DUMMY_SP, kind: Box::new(kind) }
     }
 
-    /// For exhaustive integer matching, some constructors are grouped within other constructors
-    /// (namely integer typed values are grouped within ranges). However, when specialising these
-    /// constructors, we want to be specialising for the underlying constructors (the integers), not
-    /// the groups (the ranges). Thus we need to split the groups up. Splitting them up naïvely would
-    /// mean creating a separate constructor for every single value in the range, which is clearly
-    /// impractical. However, observe that for some ranges of integers, the specialisation will be
-    /// identical across all values in that range (i.e., there are equivalence classes of ranges of
-    /// constructors based on their `U(S(c, P), S(c, p))` outcome). These classes are grouped by
-    /// the patterns that apply to them (in the matrix `P`). We can split the range whenever the
-    /// patterns that apply to that range (specifically: the patterns that *intersect* with that range)
-    /// change.
-    /// Our solution, therefore, is to split the range constructor into subranges at every single point
-    /// the group of intersecting patterns changes (using the method described below).
-    /// And voilà! We're testing precisely those ranges that we need to, without any exhaustive matching
-    /// on actual integers. The nice thing about this is that the number of subranges is linear in the
-    /// number of rows in the matrix (i.e., the number of cases in the `match` statement), so we don't
-    /// need to be worried about matching over gargantuan ranges.
-    ///
-    /// Essentially, given the first column of a matrix representing ranges, looking like the following:
-    ///
-    /// |------|  |----------| |-------|    ||
-    ///    |-------| |-------|            |----| ||
-    ///       |---------|
-    ///
-    /// We split the ranges up into equivalence classes so the ranges are no longer overlapping:
-    ///
-    /// |--|--|||-||||--||---|||-------|  |-|||| ||
-    ///
-    /// The logic for determining how to split the ranges is fairly straightforward: we calculate
-    /// boundaries for each interval range, sort them, then create constructors for each new interval
-    /// between every pair of boundary points. (This essentially sums up to performing the intuitive
-    /// merging operation depicted above.)
-    fn split<'p, 'tcx>(
+    /// Lint on likely incorrect range patterns (#63987)
+    pub(super) fn lint_overlapping_range_endpoints<'a, 'tcx: 'a>(
         &self,
-        pcx: PatCtxt<'_, 'p, 'tcx>,
-        hir_id: Option<HirId>,
-    ) -> SmallVec<[Constructor<'tcx>; 1]> {
-        /// Represents a border between 2 integers. Because the intervals spanning borders
-        /// must be able to cover every integer, we need to be able to represent
-        /// 2^128 + 1 such borders.
-        #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
-        enum Border {
-            JustBefore(u128),
-            AfterMax,
+        pcx: PatCtxt<'_, '_, 'tcx>,
+        ctors: impl Iterator<Item = (&'a Constructor<'tcx>, Span)>,
+        column_count: usize,
+        hir_id: HirId,
+    ) {
+        if self.is_singleton() {
+            return;
         }
 
-        // A function for extracting the borders of an integer interval.
-        fn range_borders(r: IntRange) -> impl Iterator<Item = Border> {
-            let (lo, hi) = r.range.into_inner();
-            let from = Border::JustBefore(lo);
-            let to = match hi.checked_add(1) {
-                Some(m) => Border::JustBefore(m),
-                None => Border::AfterMax,
-            };
-            vec![from, to].into_iter()
+        if column_count != 1 {
+            // FIXME: for now, only check for overlapping ranges on simple range
+            // patterns. Otherwise with the current logic the following is detected
+            // as overlapping:
+            // ```
+            // match (0u8, true) {
+            //   (0 ..= 125, false) => {}
+            //   (125 ..= 255, true) => {}
+            //   _ => {}
+            // }
+            // ```
+            return;
         }
 
-        // Collect the span and range of all the intersecting ranges to lint on likely
-        // incorrect range patterns. (#63987)
-        let mut overlaps = vec![];
-        let row_len = pcx.matrix.column_count().unwrap_or(0);
-        // `borders` is the set of borders between equivalence classes: each equivalence
-        // class lies between 2 borders.
-        let row_borders = pcx
-            .matrix
-            .head_ctors_and_spans(pcx.cx)
+        let overlaps: Vec<_> = ctors
             .filter_map(|(ctor, span)| Some((ctor.as_int_range()?, span)))
-            .filter_map(|(range, span)| {
-                let intersection = self.intersection(&range);
-                let should_lint = self.suspicious_intersection(&range);
-                if let (Some(range), 1, true) = (&intersection, row_len, should_lint) {
-                    // FIXME: for now, only check for overlapping ranges on simple range
-                    // patterns. Otherwise with the current logic the following is detected
-                    // as overlapping:
-                    // ```
-                    // match (0u8, true) {
-                    //   (0 ..= 125, false) => {}
-                    //   (125 ..= 255, true) => {}
-                    //   _ => {}
-                    // }
-                    // ```
-                    overlaps.push((range.clone(), span));
-                }
-                intersection
-            })
-            .flat_map(range_borders);
-        let self_borders = range_borders(self.clone());
-        let mut borders: Vec<_> = row_borders.chain(self_borders).collect();
-        borders.sort_unstable();
-
-        self.lint_overlapping_patterns(pcx, hir_id, overlaps);
-
-        // We're going to iterate through every adjacent pair of borders, making sure that
-        // each represents an interval of nonnegative length, and convert each such
-        // interval into a constructor.
-        borders
-            .array_windows()
-            .filter_map(|&pair| match pair {
-                [Border::JustBefore(n), Border::JustBefore(m)] => {
-                    if n < m {
-                        Some(n..=(m - 1))
-                    } else {
-                        None
-                    }
-                }
-                [Border::JustBefore(n), Border::AfterMax] => Some(n..=u128::MAX),
-                [Border::AfterMax, _] => None,
-            })
-            .map(|range| IntRange { range })
-            .map(IntRange)
-            .collect()
-    }
+            .filter(|(range, _)| self.suspicious_intersection(range))
+            .map(|(range, span)| (self.intersection(&range).unwrap(), span))
+            .collect();
 
-    fn lint_overlapping_patterns(
-        &self,
-        pcx: PatCtxt<'_, '_, '_>,
-        hir_id: Option<HirId>,
-        overlaps: Vec<(IntRange, Span)>,
-    ) {
-        if let (true, Some(hir_id)) = (!overlaps.is_empty(), hir_id) {
+        if !overlaps.is_empty() {
             pcx.cx.tcx.struct_span_lint_hir(
-                lint::builtin::OVERLAPPING_PATTERNS,
+                lint::builtin::OVERLAPPING_RANGE_ENDPOINTS,
                 hir_id,
                 pcx.span,
                 |lint| {
-                    let mut err = lint.build("multiple patterns covering the same range");
-                    err.span_label(pcx.span, "overlapping patterns");
+                    let mut err = lint.build("multiple patterns overlap on their endpoints");
                     for (int_range, span) in overlaps {
-                        // Use the real type for user display of the ranges:
                         err.span_label(
                             span,
                             &format!(
-                                "this range overlaps on `{}`",
-                                int_range.to_pat(pcx.cx.tcx, pcx.ty),
+                                "this range overlaps on `{}`...",
+                                int_range.to_pat(pcx.cx.tcx, pcx.ty)
                             ),
                         );
                     }
+                    err.span_label(pcx.span, "... with this range");
+                    err.note("you likely meant to write mutually exclusive ranges");
                     err.emit();
                 },
             );
@@ -339,6 +293,101 @@ fn is_covered_by(&self, other: &Self) -> bool {
     }
 }
 
+/// Represents a border between 2 integers. Because the intervals spanning borders must be able to
+/// cover every integer, we need to be able to represent 2^128 + 1 such borders.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
+enum IntBorder {
+    JustBefore(u128),
+    AfterMax,
+}
+
+/// A range of integers that is partitioned into disjoint subranges. This does constructor
+/// splitting for integer ranges as explained at the top of the file.
+///
+/// This is fed multiple ranges, and returns an output that covers the input, but is split so that
+/// the only intersections between an output range and a seen range are inclusions. No output range
+/// straddles the boundary of one of the inputs.
+///
+/// The following input:
+/// ```
+///   |-------------------------| // `self`
+/// |------|  |----------|   |----|
+///    |-------| |-------|
+/// ```
+/// would be iterated over as follows:
+/// ```
+///   ||---|--||-|---|---|---|--|
+/// ```
+#[derive(Debug, Clone)]
+struct SplitIntRange {
+    /// The range we are splitting
+    range: IntRange,
+    /// The borders of ranges we have seen. They are all contained within `range`. This is kept
+    /// sorted.
+    borders: Vec<IntBorder>,
+}
+
+impl SplitIntRange {
+    fn new(range: IntRange) -> Self {
+        SplitIntRange { range, borders: Vec::new() }
+    }
+
+    /// Internal use
+    fn to_borders(r: IntRange) -> [IntBorder; 2] {
+        use IntBorder::*;
+        let (lo, hi) = r.boundaries();
+        let lo = JustBefore(lo);
+        let hi = match hi.checked_add(1) {
+            Some(m) => JustBefore(m),
+            None => AfterMax,
+        };
+        [lo, hi]
+    }
+
+    /// Add ranges relative to which we split.
+    fn split(&mut self, ranges: impl Iterator<Item = IntRange>) {
+        let this_range = &self.range;
+        let included_ranges = ranges.filter_map(|r| this_range.intersection(&r));
+        let included_borders = included_ranges.flat_map(|r| {
+            let borders = Self::to_borders(r);
+            once(borders[0]).chain(once(borders[1]))
+        });
+        self.borders.extend(included_borders);
+        self.borders.sort_unstable();
+    }
+
+    /// Iterate over the contained ranges.
+    fn iter<'a>(&'a self) -> impl Iterator<Item = IntRange> + Captures<'a> {
+        use IntBorder::*;
+
+        let self_range = Self::to_borders(self.range.clone());
+        // Start with the start of the range.
+        let mut prev_border = self_range[0];
+        self.borders
+            .iter()
+            .copied()
+            // End with the end of the range.
+            .chain(once(self_range[1]))
+            // List pairs of adjacent borders.
+            .map(move |border| {
+                let ret = (prev_border, border);
+                prev_border = border;
+                ret
+            })
+            // Skip duplicates.
+            .filter(|(prev_border, border)| prev_border != border)
+            // Finally, convert to ranges.
+            .map(|(prev_border, border)| {
+                let range = match (prev_border, border) {
+                    (JustBefore(n), JustBefore(m)) if n < m => n..=(m - 1),
+                    (JustBefore(n), AfterMax) => n..=u128::MAX,
+                    _ => unreachable!(), // Ruled out by the sorting and filtering we did
+                };
+                IntRange { range }
+            })
+    }
+}
+
 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
 enum SliceKind {
     /// Patterns of length `n` (`[x, y]`).
@@ -391,129 +440,141 @@ fn arity(self) -> u64 {
         self.kind.arity()
     }
 
-    /// The exhaustiveness-checking paper does not include any details on
-    /// checking variable-length slice patterns. However, they may be
-    /// matched by an infinite collection of fixed-length array patterns.
-    ///
-    /// Checking the infinite set directly would take an infinite amount
-    /// of time. However, it turns out that for each finite set of
-    /// patterns `P`, all sufficiently large array lengths are equivalent:
-    ///
-    /// Each slice `s` with a "sufficiently-large" length `l â‰¥ L` that applies
-    /// to exactly the subset `Pâ‚œ` of `P` can be transformed to a slice
-    /// `sₘ` for each sufficiently-large length `m` that applies to exactly
-    /// the same subset of `P`.
-    ///
-    /// Because of that, each witness for reachability-checking of one
-    /// of the sufficiently-large lengths can be transformed to an
-    /// equally-valid witness of any other length, so we only have
-    /// to check slices of the "minimal sufficiently-large length"
-    /// and less.
-    ///
-    /// Note that the fact that there is a *single* `sₘ` for each `m`
-    /// not depending on the specific pattern in `P` is important: if
-    /// you look at the pair of patterns
-    ///     `[true, ..]`
-    ///     `[.., false]`
-    /// Then any slice of length â‰¥1 that matches one of these two
-    /// patterns can be trivially turned to a slice of any
-    /// other length â‰¥1 that matches them and vice-versa,
-    /// but the slice of length 2 `[false, true]` that matches neither
-    /// of these patterns can't be turned to a slice from length 1 that
-    /// matches neither of these patterns, so we have to consider
-    /// slices from length 2 there.
-    ///
-    /// Now, to see that that length exists and find it, observe that slice
-    /// patterns are either "fixed-length" patterns (`[_, _, _]`) or
-    /// "variable-length" patterns (`[_, .., _]`).
-    ///
-    /// For fixed-length patterns, all slices with lengths *longer* than
-    /// the pattern's length have the same outcome (of not matching), so
-    /// as long as `L` is greater than the pattern's length we can pick
-    /// any `sₘ` from that length and get the same result.
-    ///
-    /// For variable-length patterns, the situation is more complicated,
-    /// because as seen above the precise value of `sₘ` matters.
-    ///
-    /// However, for each variable-length pattern `p` with a prefix of length
-    /// `plâ‚š` and suffix of length `slâ‚š`, only the first `plâ‚š` and the last
-    /// `slâ‚š` elements are examined.
-    ///
-    /// Therefore, as long as `L` is positive (to avoid concerns about empty
-    /// types), all elements after the maximum prefix length and before
-    /// the maximum suffix length are not examined by any variable-length
-    /// pattern, and therefore can be added/removed without affecting
-    /// them - creating equivalent patterns from any sufficiently-large
-    /// length.
-    ///
-    /// Of course, if fixed-length patterns exist, we must be sure
-    /// that our length is large enough to miss them all, so
-    /// we can pick `L = max(max(FIXED_LEN)+1, max(PREFIX_LEN) + max(SUFFIX_LEN))`
-    ///
-    /// for example, with the above pair of patterns, all elements
-    /// but the first and last can be added/removed, so any
-    /// witness of length â‰¥2 (say, `[false, false, true]`) can be
-    /// turned to a witness from any other length â‰¥2.
-    fn split<'p, 'tcx>(self, pcx: PatCtxt<'_, 'p, 'tcx>) -> SmallVec<[Constructor<'tcx>; 1]> {
-        let (self_prefix, self_suffix) = match self.kind {
-            VarLen(self_prefix, self_suffix) => (self_prefix, self_suffix),
-            _ => return smallvec![Slice(self)],
-        };
+    /// See `Constructor::is_covered_by`
+    fn is_covered_by(self, other: Self) -> bool {
+        other.kind.covers_length(self.arity())
+    }
+}
+
+/// This computes constructor splitting for variable-length slices, as explained at the top of the
+/// file.
+///
+/// A slice pattern `[x, .., y]` behaves like the infinite or-pattern `[x, y] | [x, _, y] | [x, _,
+/// _, y] | ...`. The corresponding value constructors are fixed-length array constructors above a
+/// given minimum length. We obviously can't list this infinitude of constructors. Thankfully,
+/// it turns out that for each finite set of slice patterns, all sufficiently large array lengths
+/// are equivalent.
+///
+/// Let's look at an example, where we are trying to split the last pattern:
+/// ```
+/// match x {
+///     [true, true, ..] => {}
+///     [.., false, false] => {}
+///     [..] => {}
+/// }
+/// ```
+/// Here are the results of specialization for the first few lengths:
+/// ```
+/// // length 0
+/// [] => {}
+/// // length 1
+/// [_] => {}
+/// // length 2
+/// [true, true] => {}
+/// [false, false] => {}
+/// [_, _] => {}
+/// // length 3
+/// [true, true,  _    ] => {}
+/// [_,    false, false] => {}
+/// [_,    _,     _    ] => {}
+/// // length 4
+/// [true, true, _,     _    ] => {}
+/// [_,    _,    false, false] => {}
+/// [_,    _,    _,     _    ] => {}
+/// // length 5
+/// [true, true, _, _,     _    ] => {}
+/// [_,    _,    _, false, false] => {}
+/// [_,    _,    _, _,     _    ] => {}
+/// ```
+///
+/// If we went above length 5, we would simply be inserting more columns full of wildcards in the
+/// middle. This means that the set of witnesses for length `l >= 5` if equivalent to the set for
+/// any other `l' >= 5`: simply add or remove wildcards in the middle to convert between them.
+///
+/// This applies to any set of slice patterns: there will be a length `L` above which all lengths
+/// behave the same. This is exactly what we need for constructor splitting. Therefore a
+/// variable-length slice can be split into a variable-length slice of minimal length `L`, and many
+/// fixed-length slices of lengths `< L`.
+///
+/// For each variable-length pattern `p` with a prefix of length `plâ‚š` and suffix of length `slâ‚š`,
+/// only the first `plâ‚š` and the last `slâ‚š` elements are examined. Therefore, as long as `L` is
+/// positive (to avoid concerns about empty types), all elements after the maximum prefix length
+/// and before the maximum suffix length are not examined by any variable-length pattern, and
+/// therefore can be added/removed without affecting them - creating equivalent patterns from any
+/// sufficiently-large length.
+///
+/// Of course, if fixed-length patterns exist, we must be sure that our length is large enough to
+/// miss them all, so we can pick `L = max(max(FIXED_LEN)+1, max(PREFIX_LEN) + max(SUFFIX_LEN))`
+///
+/// `max_slice` below will be made to have arity `L`.
+#[derive(Debug)]
+struct SplitVarLenSlice {
+    /// If the type is an array, this is its size.
+    array_len: Option<u64>,
+    /// The arity of the input slice.
+    arity: u64,
+    /// The smallest slice bigger than any slice seen. `max_slice.arity()` is the length `L`
+    /// described above.
+    max_slice: SliceKind,
+}
 
-        let head_ctors = pcx.matrix.head_ctors(pcx.cx).filter(|c| !c.is_wildcard());
+impl SplitVarLenSlice {
+    fn new(prefix: u64, suffix: u64, array_len: Option<u64>) -> Self {
+        SplitVarLenSlice { array_len, arity: prefix + suffix, max_slice: VarLen(prefix, suffix) }
+    }
 
-        let mut max_prefix_len = self_prefix;
-        let mut max_suffix_len = self_suffix;
+    /// Pass a set of slices relative to which to split this one.
+    fn split(&mut self, slices: impl Iterator<Item = SliceKind>) {
+        let (max_prefix_len, max_suffix_len) = match &mut self.max_slice {
+            VarLen(prefix, suffix) => (prefix, suffix),
+            FixedLen(_) => return, // No need to split
+        };
+        // We grow `self.max_slice` to be larger than all slices encountered, as described above.
+        // For diagnostics, we keep the prefix and suffix lengths separate, but grow them so that
+        // `L = max_prefix_len + max_suffix_len`.
         let mut max_fixed_len = 0;
-
-        for ctor in head_ctors {
-            if let Slice(slice) = ctor {
-                match slice.kind {
-                    FixedLen(len) => {
-                        max_fixed_len = cmp::max(max_fixed_len, len);
-                    }
-                    VarLen(prefix, suffix) => {
-                        max_prefix_len = cmp::max(max_prefix_len, prefix);
-                        max_suffix_len = cmp::max(max_suffix_len, suffix);
-                    }
+        for slice in slices {
+            match slice {
+                FixedLen(len) => {
+                    max_fixed_len = cmp::max(max_fixed_len, len);
+                }
+                VarLen(prefix, suffix) => {
+                    *max_prefix_len = cmp::max(*max_prefix_len, prefix);
+                    *max_suffix_len = cmp::max(*max_suffix_len, suffix);
                 }
-            } else {
-                bug!("unexpected ctor for slice type: {:?}", ctor);
             }
         }
-
-        // For diagnostics, we keep the prefix and suffix lengths separate, so in the case
-        // where `max_fixed_len + 1` is the largest, we adapt `max_prefix_len` accordingly,
-        // so that `L = max_prefix_len + max_suffix_len`.
-        if max_fixed_len + 1 >= max_prefix_len + max_suffix_len {
+        // We want `L = max(L, max_fixed_len + 1)`, modulo the fact that we keep prefix and
+        // suffix separate.
+        if max_fixed_len + 1 >= *max_prefix_len + *max_suffix_len {
             // The subtraction can't overflow thanks to the above check.
-            // The new `max_prefix_len` is also guaranteed to be larger than its previous
-            // value.
-            max_prefix_len = max_fixed_len + 1 - max_suffix_len;
+            // The new `max_prefix_len` is larger than its previous value.
+            *max_prefix_len = max_fixed_len + 1 - *max_suffix_len;
         }
 
-        let final_slice = VarLen(max_prefix_len, max_suffix_len);
-        let final_slice = Slice::new(self.array_len, final_slice);
+        // We cap the arity of `max_slice` at the array size.
         match self.array_len {
-            Some(_) => smallvec![Slice(final_slice)],
-            None => {
-                // `self` originally covered the range `(self.arity()..infinity)`. We split that
-                // range into two: lengths smaller than `final_slice.arity()` are treated
-                // independently as fixed-lengths slices, and lengths above are captured by
-                // `final_slice`.
-                let smaller_lengths = (self.arity()..final_slice.arity()).map(FixedLen);
-                smaller_lengths
-                    .map(|kind| Slice::new(self.array_len, kind))
-                    .chain(Some(final_slice))
-                    .map(Slice)
-                    .collect()
-            }
+            Some(len) if self.max_slice.arity() >= len => self.max_slice = FixedLen(len),
+            _ => {}
         }
     }
 
-    /// See `Constructor::is_covered_by`
-    fn is_covered_by(self, other: Self) -> bool {
-        other.kind.covers_length(self.arity())
+    /// Iterate over the partition of this slice.
+    fn iter<'a>(&'a self) -> impl Iterator<Item = Slice> + Captures<'a> {
+        let smaller_lengths = match self.array_len {
+            // The only admissible fixed-length slice is one of the array size. Whether `max_slice`
+            // is fixed-length or variable-length, it will be the only relevant slice to output
+            // here.
+            Some(_) => (0..0), // empty range
+            // We cover all arities in the range `(self.arity..infinity)`. We split that range into
+            // two: lengths smaller than `max_slice.arity()` are treated independently as
+            // fixed-lengths slices, and lengths above are captured by `max_slice`.
+            None => self.arity..self.max_slice.arity(),
+        };
+        smaller_lengths
+            .map(FixedLen)
+            .chain(once(self.max_slice))
+            .map(move |kind| Slice::new(self.array_len, kind))
     }
 }
 
@@ -546,6 +607,9 @@ pub(super) enum Constructor<'tcx> {
     /// Fake extra constructor for enums that aren't allowed to be matched exhaustively. Also used
     /// for those types for which we cannot list constructors explicitly, like `f64` and `str`.
     NonExhaustive,
+    /// Stands for constructors that are not seen in the matrix, as explained in the documentation
+    /// for [`SplitWildcard`].
+    Missing,
     /// Wildcard pattern.
     Wildcard,
 }
@@ -652,48 +716,41 @@ pub(super) fn from_pat<'p>(cx: &MatchCheckCtxt<'p, 'tcx>, pat: &'p Pat<'tcx>) ->
     /// This function may discard some irrelevant constructors if this preserves behavior and
     /// diagnostics. Eg. for the `_` case, we ignore the constructors already present in the
     /// matrix, unless all of them are.
-    ///
-    /// `hir_id` is `None` when we're evaluating the wildcard pattern. In that case we do not want
-    /// to lint for overlapping ranges.
-    pub(super) fn split<'p>(
+    pub(super) fn split<'a>(
         &self,
-        pcx: PatCtxt<'_, 'p, 'tcx>,
-        hir_id: Option<HirId>,
-    ) -> SmallVec<[Self; 1]> {
-        debug!("Constructor::split({:#?}, {:#?})", self, pcx.matrix);
+        pcx: PatCtxt<'_, '_, 'tcx>,
+        ctors: impl Iterator<Item = &'a Constructor<'tcx>> + Clone,
+    ) -> SmallVec<[Self; 1]>
+    where
+        'tcx: 'a,
+    {
+        debug!("Constructor::split({:#?})", self);
 
         match self {
-            Wildcard => Constructor::split_wildcard(pcx),
+            Wildcard => {
+                let mut split_wildcard = SplitWildcard::new(pcx);
+                split_wildcard.split(pcx, ctors);
+                split_wildcard.into_ctors(pcx)
+            }
             // Fast-track if the range is trivial. In particular, we don't do the overlapping
             // ranges check.
-            IntRange(ctor_range) if !ctor_range.is_singleton() => ctor_range.split(pcx, hir_id),
-            Slice(slice @ Slice { kind: VarLen(..), .. }) => slice.split(pcx),
+            IntRange(ctor_range) if !ctor_range.is_singleton() => {
+                let mut split_range = SplitIntRange::new(ctor_range.clone());
+                let int_ranges = ctors.filter_map(|ctor| ctor.as_int_range());
+                split_range.split(int_ranges.cloned());
+                split_range.iter().map(IntRange).collect()
+            }
+            &Slice(Slice { kind: VarLen(self_prefix, self_suffix), array_len }) => {
+                let mut split_self = SplitVarLenSlice::new(self_prefix, self_suffix, array_len);
+                let slices = ctors.filter_map(|c| c.as_slice()).map(|s| s.kind);
+                split_self.split(slices);
+                split_self.iter().map(Slice).collect()
+            }
             // Any other constructor can be used unchanged.
             _ => smallvec![self.clone()],
         }
     }
 
-    /// For wildcards, there are two groups of constructors: there are the constructors actually
-    /// present in the matrix (`head_ctors`), and the constructors not present (`missing_ctors`).
-    /// Two constructors that are not in the matrix will either both be caught (by a wildcard), or
-    /// both not be caught. Therefore we can keep the missing constructors grouped together.
-    fn split_wildcard<'p>(pcx: PatCtxt<'_, 'p, 'tcx>) -> SmallVec<[Self; 1]> {
-        // Missing constructors are those that are not matched by any non-wildcard patterns in the
-        // current column. We only fully construct them on-demand, because they're rarely used and
-        // can be big.
-        let missing_ctors = MissingConstructors::new(pcx);
-        if missing_ctors.is_empty(pcx) {
-            // All the constructors are present in the matrix, so we just go through them all.
-            // We must also split them first.
-            missing_ctors.all_ctors
-        } else {
-            // Some constructors are missing, thus we can specialize with the wildcard constructor,
-            // which will stand for those constructors that are missing, and behaves like any of
-            // them.
-            smallvec![Wildcard]
-        }
-    }
-
     /// Returns whether `self` is covered by `other`, i.e. whether `self` is a subset of `other`.
     /// For the simple cases, this is simply checking for equality. For the "grouped" constructors,
     /// this checks for inclusion.
@@ -704,8 +761,8 @@ pub(super) fn is_covered_by<'p>(&self, pcx: PatCtxt<'_, 'p, 'tcx>, other: &Self)
         match (self, other) {
             // Wildcards cover anything
             (_, Wildcard) => true,
-            // Wildcards are only covered by wildcards
-            (Wildcard, _) => false,
+            // The missing ctors are not covered by anything in the matrix except wildcards.
+            (Missing | Wildcard, _) => false,
 
             (Single, Single) => true,
             (Variant(self_id), Variant(other_id)) => self_id == other_id,
@@ -778,247 +835,253 @@ fn is_covered_by_any<'p>(
                 .any(|other| slice.is_covered_by(other)),
             // This constructor is never covered by anything else
             NonExhaustive => false,
-            Str(..) | FloatRange(..) | Opaque | Wildcard => {
+            Str(..) | FloatRange(..) | Opaque | Missing | Wildcard => {
                 span_bug!(pcx.span, "found unexpected ctor in all_ctors: {:?}", self)
             }
         }
     }
 }
 
-/// This determines the set of all possible constructors of a pattern matching
-/// values of type `left_ty`. For vectors, this would normally be an infinite set
-/// but is instead bounded by the maximum fixed length of slice patterns in
-/// the column of patterns being analyzed.
+/// A wildcard constructor that we split relative to the constructors in the matrix, as explained
+/// at the top of the file.
 ///
-/// We make sure to omit constructors that are statically impossible. E.g., for
-/// `Option<!>`, we do not include `Some(_)` in the returned list of constructors.
-/// Invariant: this returns an empty `Vec` if and only if the type is uninhabited (as determined by
-/// `cx.is_uninhabited()`).
-fn all_constructors<'p, 'tcx>(pcx: PatCtxt<'_, 'p, 'tcx>) -> Vec<Constructor<'tcx>> {
-    debug!("all_constructors({:?})", pcx.ty);
-    let cx = pcx.cx;
-    let make_range = |start, end| {
-        IntRange(
-            // `unwrap()` is ok because we know the type is an integer.
-            IntRange::from_range(cx.tcx, start, end, pcx.ty, &RangeEnd::Included).unwrap(),
-        )
-    };
-    match pcx.ty.kind() {
-        ty::Bool => vec![make_range(0, 1)],
-        ty::Array(sub_ty, len) if len.try_eval_usize(cx.tcx, cx.param_env).is_some() => {
-            let len = len.eval_usize(cx.tcx, cx.param_env);
-            if len != 0 && cx.is_uninhabited(sub_ty) {
-                vec![]
-            } else {
-                vec![Slice(Slice::new(Some(len), VarLen(0, 0)))]
-            }
-        }
-        // Treat arrays of a constant but unknown length like slices.
-        ty::Array(sub_ty, _) | ty::Slice(sub_ty) => {
-            let kind = if cx.is_uninhabited(sub_ty) { FixedLen(0) } else { VarLen(0, 0) };
-            vec![Slice(Slice::new(None, kind))]
-        }
-        ty::Adt(def, substs) if def.is_enum() => {
-            // If the enum is declared as `#[non_exhaustive]`, we treat it as if it had an
-            // additional "unknown" constructor.
-            // There is no point in enumerating all possible variants, because the user can't
-            // actually match against them all themselves. So we always return only the fictitious
-            // constructor.
-            // E.g., in an example like:
-            //
-            // ```
-            //     let err: io::ErrorKind = ...;
-            //     match err {
-            //         io::ErrorKind::NotFound => {},
-            //     }
-            // ```
-            //
-            // we don't want to show every possible IO error, but instead have only `_` as the
-            // witness.
-            let is_declared_nonexhaustive = cx.is_foreign_non_exhaustive_enum(pcx.ty);
-
-            // If `exhaustive_patterns` is disabled and our scrutinee is an empty enum, we treat it
-            // as though it had an "unknown" constructor to avoid exposing its emptiness. The
-            // exception is if the pattern is at the top level, because we want empty matches to be
-            // considered exhaustive.
-            let is_secretly_empty = def.variants.is_empty()
-                && !cx.tcx.features().exhaustive_patterns
-                && !pcx.is_top_level;
-
-            if is_secretly_empty || is_declared_nonexhaustive {
-                vec![NonExhaustive]
-            } else if cx.tcx.features().exhaustive_patterns {
-                // If `exhaustive_patterns` is enabled, we exclude variants known to be
-                // uninhabited.
-                def.variants
-                    .iter()
-                    .filter(|v| {
-                        !v.uninhabited_from(cx.tcx, substs, def.adt_kind(), cx.param_env)
-                            .contains(cx.tcx, cx.module)
-                    })
-                    .map(|v| Variant(v.def_id))
-                    .collect()
-            } else {
-                def.variants.iter().map(|v| Variant(v.def_id)).collect()
-            }
-        }
-        ty::Char => {
-            vec![
-                // The valid Unicode Scalar Value ranges.
-                make_range('\u{0000}' as u128, '\u{D7FF}' as u128),
-                make_range('\u{E000}' as u128, '\u{10FFFF}' as u128),
-            ]
-        }
-        ty::Int(_) | ty::Uint(_)
-            if pcx.ty.is_ptr_sized_integral()
-                && !cx.tcx.features().precise_pointer_size_matching =>
-        {
-            // `usize`/`isize` are not allowed to be matched exhaustively unless the
-            // `precise_pointer_size_matching` feature is enabled. So we treat those types like
-            // `#[non_exhaustive]` enums by returning a special unmatcheable constructor.
-            vec![NonExhaustive]
-        }
-        &ty::Int(ity) => {
-            let bits = Integer::from_attr(&cx.tcx, SignedInt(ity)).size().bits() as u128;
-            let min = 1u128 << (bits - 1);
-            let max = min - 1;
-            vec![make_range(min, max)]
-        }
-        &ty::Uint(uty) => {
-            let size = Integer::from_attr(&cx.tcx, UnsignedInt(uty)).size();
-            let max = size.truncate(u128::MAX);
-            vec![make_range(0, max)]
-        }
-        // If `exhaustive_patterns` is disabled and our scrutinee is the never type, we cannot
-        // expose its emptiness. The exception is if the pattern is at the top level, because we
-        // want empty matches to be considered exhaustive.
-        ty::Never if !cx.tcx.features().exhaustive_patterns && !pcx.is_top_level => {
-            vec![NonExhaustive]
-        }
-        ty::Never => vec![],
-        _ if cx.is_uninhabited(pcx.ty) => vec![],
-        ty::Adt(..) | ty::Tuple(..) | ty::Ref(..) => vec![Single],
-        // This type is one for which we cannot list constructors, like `str` or `f64`.
-        _ => vec![NonExhaustive],
-    }
-}
-
-// A struct to compute a set of constructors equivalent to `all_ctors \ used_ctors`.
+/// A constructor that is not present in the matrix rows will only be covered by the rows that have
+/// wildcards. Thus we can group all of those constructors together; we call them "missing
+/// constructors". Splitting a wildcard would therefore list all present constructors individually
+/// (or grouped if they are integers or slices), and then all missing constructors together as a
+/// group.
+///
+/// However we can go further: since any constructor will match the wildcard rows, and having more
+/// rows can only reduce the amount of usefulness witnesses, we can skip the present constructors
+/// and only try the missing ones.
+/// This will not preserve the whole list of witnesses, but will preserve whether the list is empty
+/// or not. In fact this is quite natural from the point of view of diagnostics too. This is done
+/// in `to_ctors`: in some cases we only return `Missing`.
 #[derive(Debug)]
-pub(super) struct MissingConstructors<'tcx> {
+pub(super) struct SplitWildcard<'tcx> {
+    /// Constructors seen in the matrix.
+    matrix_ctors: Vec<Constructor<'tcx>>,
+    /// All the constructors for this type
     all_ctors: SmallVec<[Constructor<'tcx>; 1]>,
-    used_ctors: Vec<Constructor<'tcx>>,
 }
 
-impl<'tcx> MissingConstructors<'tcx> {
+impl<'tcx> SplitWildcard<'tcx> {
     pub(super) fn new<'p>(pcx: PatCtxt<'_, 'p, 'tcx>) -> Self {
-        let used_ctors: Vec<Constructor<'_>> =
-            pcx.matrix.head_ctors(pcx.cx).cloned().filter(|c| !c.is_wildcard()).collect();
-        // Since `all_ctors` never contains wildcards, this won't recurse further.
-        let all_ctors =
-            all_constructors(pcx).into_iter().flat_map(|ctor| ctor.split(pcx, None)).collect();
+        debug!("SplitWildcard::new({:?})", pcx.ty);
+        let cx = pcx.cx;
+        let make_range = |start, end| {
+            IntRange(
+                // `unwrap()` is ok because we know the type is an integer.
+                IntRange::from_range(cx.tcx, start, end, pcx.ty, &RangeEnd::Included).unwrap(),
+            )
+        };
+        // This determines the set of all possible constructors for the type `pcx.ty`. For numbers,
+        // arrays and slices we use ranges and variable-length slices when appropriate.
+        //
+        // If the `exhaustive_patterns` feature is enabled, we make sure to omit constructors that
+        // are statically impossible. E.g., for `Option<!>`, we do not include `Some(_)` in the
+        // returned list of constructors.
+        // Invariant: this is empty if and only if the type is uninhabited (as determined by
+        // `cx.is_uninhabited()`).
+        let all_ctors = match pcx.ty.kind() {
+            ty::Bool => smallvec![make_range(0, 1)],
+            ty::Array(sub_ty, len) if len.try_eval_usize(cx.tcx, cx.param_env).is_some() => {
+                let len = len.eval_usize(cx.tcx, cx.param_env);
+                if len != 0 && cx.is_uninhabited(sub_ty) {
+                    smallvec![]
+                } else {
+                    smallvec![Slice(Slice::new(Some(len), VarLen(0, 0)))]
+                }
+            }
+            // Treat arrays of a constant but unknown length like slices.
+            ty::Array(sub_ty, _) | ty::Slice(sub_ty) => {
+                let kind = if cx.is_uninhabited(sub_ty) { FixedLen(0) } else { VarLen(0, 0) };
+                smallvec![Slice(Slice::new(None, kind))]
+            }
+            ty::Adt(def, substs) if def.is_enum() => {
+                // If the enum is declared as `#[non_exhaustive]`, we treat it as if it had an
+                // additional "unknown" constructor.
+                // There is no point in enumerating all possible variants, because the user can't
+                // actually match against them all themselves. So we always return only the fictitious
+                // constructor.
+                // E.g., in an example like:
+                //
+                // ```
+                //     let err: io::ErrorKind = ...;
+                //     match err {
+                //         io::ErrorKind::NotFound => {},
+                //     }
+                // ```
+                //
+                // we don't want to show every possible IO error, but instead have only `_` as the
+                // witness.
+                let is_declared_nonexhaustive = cx.is_foreign_non_exhaustive_enum(pcx.ty);
+
+                // If `exhaustive_patterns` is disabled and our scrutinee is an empty enum, we treat it
+                // as though it had an "unknown" constructor to avoid exposing its emptiness. The
+                // exception is if the pattern is at the top level, because we want empty matches to be
+                // considered exhaustive.
+                let is_secretly_empty = def.variants.is_empty()
+                    && !cx.tcx.features().exhaustive_patterns
+                    && !pcx.is_top_level;
+
+                if is_secretly_empty || is_declared_nonexhaustive {
+                    smallvec![NonExhaustive]
+                } else if cx.tcx.features().exhaustive_patterns {
+                    // If `exhaustive_patterns` is enabled, we exclude variants known to be
+                    // uninhabited.
+                    def.variants
+                        .iter()
+                        .filter(|v| {
+                            !v.uninhabited_from(cx.tcx, substs, def.adt_kind(), cx.param_env)
+                                .contains(cx.tcx, cx.module)
+                        })
+                        .map(|v| Variant(v.def_id))
+                        .collect()
+                } else {
+                    def.variants.iter().map(|v| Variant(v.def_id)).collect()
+                }
+            }
+            ty::Char => {
+                smallvec![
+                    // The valid Unicode Scalar Value ranges.
+                    make_range('\u{0000}' as u128, '\u{D7FF}' as u128),
+                    make_range('\u{E000}' as u128, '\u{10FFFF}' as u128),
+                ]
+            }
+            ty::Int(_) | ty::Uint(_)
+                if pcx.ty.is_ptr_sized_integral()
+                    && !cx.tcx.features().precise_pointer_size_matching =>
+            {
+                // `usize`/`isize` are not allowed to be matched exhaustively unless the
+                // `precise_pointer_size_matching` feature is enabled. So we treat those types like
+                // `#[non_exhaustive]` enums by returning a special unmatcheable constructor.
+                smallvec![NonExhaustive]
+            }
+            &ty::Int(ity) => {
+                let bits = Integer::from_attr(&cx.tcx, SignedInt(ity)).size().bits() as u128;
+                let min = 1u128 << (bits - 1);
+                let max = min - 1;
+                smallvec![make_range(min, max)]
+            }
+            &ty::Uint(uty) => {
+                let size = Integer::from_attr(&cx.tcx, UnsignedInt(uty)).size();
+                let max = size.truncate(u128::MAX);
+                smallvec![make_range(0, max)]
+            }
+            // If `exhaustive_patterns` is disabled and our scrutinee is the never type, we cannot
+            // expose its emptiness. The exception is if the pattern is at the top level, because we
+            // want empty matches to be considered exhaustive.
+            ty::Never if !cx.tcx.features().exhaustive_patterns && !pcx.is_top_level => {
+                smallvec![NonExhaustive]
+            }
+            ty::Never => smallvec![],
+            _ if cx.is_uninhabited(pcx.ty) => smallvec![],
+            ty::Adt(..) | ty::Tuple(..) | ty::Ref(..) => smallvec![Single],
+            // This type is one for which we cannot list constructors, like `str` or `f64`.
+            _ => smallvec![NonExhaustive],
+        };
+        SplitWildcard { matrix_ctors: Vec::new(), all_ctors }
+    }
 
-        MissingConstructors { all_ctors, used_ctors }
+    /// Pass a set of constructors relative to which to split this one. Don't call twice, it won't
+    /// do what you want.
+    pub(super) fn split<'a>(
+        &mut self,
+        pcx: PatCtxt<'_, '_, 'tcx>,
+        ctors: impl Iterator<Item = &'a Constructor<'tcx>> + Clone,
+    ) where
+        'tcx: 'a,
+    {
+        // Since `all_ctors` never contains wildcards, this won't recurse further.
+        self.all_ctors =
+            self.all_ctors.iter().flat_map(|ctor| ctor.split(pcx, ctors.clone())).collect();
+        self.matrix_ctors = ctors.filter(|c| !c.is_wildcard()).cloned().collect();
     }
 
-    fn is_empty<'p>(&self, pcx: PatCtxt<'_, 'p, 'tcx>) -> bool {
-        self.iter(pcx).next().is_none()
+    /// Whether there are any value constructors for this type that are not present in the matrix.
+    fn any_missing(&self, pcx: PatCtxt<'_, '_, 'tcx>) -> bool {
+        self.iter_missing(pcx).next().is_some()
     }
 
-    /// Iterate over all_ctors \ used_ctors
-    fn iter<'a, 'p>(
+    /// Iterate over the constructors for this type that are not present in the matrix.
+    pub(super) fn iter_missing<'a, 'p>(
         &'a self,
         pcx: PatCtxt<'a, 'p, 'tcx>,
     ) -> impl Iterator<Item = &'a Constructor<'tcx>> + Captures<'p> {
-        self.all_ctors.iter().filter(move |ctor| !ctor.is_covered_by_any(pcx, &self.used_ctors))
+        self.all_ctors.iter().filter(move |ctor| !ctor.is_covered_by_any(pcx, &self.matrix_ctors))
     }
 
-    /// List the patterns corresponding to the missing constructors. In some cases, instead of
-    /// listing all constructors of a given type, we prefer to simply report a wildcard.
-    pub(super) fn report_patterns<'p>(
-        &self,
-        pcx: PatCtxt<'_, 'p, 'tcx>,
-    ) -> SmallVec<[Pat<'tcx>; 1]> {
-        // There are 2 ways we can report a witness here.
-        // Commonly, we can report all the "free"
-        // constructors as witnesses, e.g., if we have:
-        //
-        // ```
-        //     enum Direction { N, S, E, W }
-        //     let Direction::N = ...;
-        // ```
-        //
-        // we can report 3 witnesses: `S`, `E`, and `W`.
-        //
-        // However, there is a case where we don't want
-        // to do this and instead report a single `_` witness:
-        // if the user didn't actually specify a constructor
-        // in this arm, e.g., in
-        //
-        // ```
-        //     let x: (Direction, Direction, bool) = ...;
-        //     let (_, _, false) = x;
-        // ```
-        //
-        // we don't want to show all 16 possible witnesses
-        // `(<direction-1>, <direction-2>, true)` - we are
-        // satisfied with `(_, _, true)`. In this case,
-        // `used_ctors` is empty.
-        // The exception is: if we are at the top-level, for example in an empty match, we
-        // sometimes prefer reporting the list of constructors instead of just `_`.
-        let report_when_all_missing = pcx.is_top_level && !IntRange::is_integral(pcx.ty);
-        if self.used_ctors.is_empty() && !report_when_all_missing {
-            // All constructors are unused. Report only a wildcard
-            // rather than each individual constructor.
-            smallvec![Pat::wildcard_from_ty(pcx.ty)]
-        } else {
-            // Construct for each missing constructor a "wild" version of this
-            // constructor, that matches everything that can be built with
-            // it. For example, if `ctor` is a `Constructor::Variant` for
-            // `Option::Some`, we get the pattern `Some(_)`.
-            self.iter(pcx)
-                .map(|missing_ctor| Fields::wildcards(pcx, &missing_ctor).apply(pcx, missing_ctor))
-                .collect()
+    /// Return the set of constructors resulting from splitting the wildcard. As explained at the
+    /// top of the file, if any constructors are missing we can ignore the present ones.
+    fn into_ctors(self, pcx: PatCtxt<'_, '_, 'tcx>) -> SmallVec<[Constructor<'tcx>; 1]> {
+        if self.any_missing(pcx) {
+            // Some constructors are missing, thus we can specialize with the special `Missing`
+            // constructor, which stands for those constructors that are not seen in the matrix,
+            // and matches the same rows as any of them (namely the wildcard rows). See the top of
+            // the file for details.
+            // However, when all constructors are missing we can also specialize with the full
+            // `Wildcard` constructor. The difference will depend on what we want in diagnostics.
+
+            // If some constructors are missing, we typically want to report those constructors,
+            // e.g.:
+            // ```
+            //     enum Direction { N, S, E, W }
+            //     let Direction::N = ...;
+            // ```
+            // we can report 3 witnesses: `S`, `E`, and `W`.
+            //
+            // However, if the user didn't actually specify a constructor
+            // in this arm, e.g., in
+            // ```
+            //     let x: (Direction, Direction, bool) = ...;
+            //     let (_, _, false) = x;
+            // ```
+            // we don't want to show all 16 possible witnesses `(<direction-1>, <direction-2>,
+            // true)` - we are satisfied with `(_, _, true)`. So if all constructors are missing we
+            // prefer to report just a wildcard `_`.
+            //
+            // The exception is: if we are at the top-level, for example in an empty match, we
+            // sometimes prefer reporting the list of constructors instead of just `_`.
+            let report_when_all_missing = pcx.is_top_level && !IntRange::is_integral(pcx.ty);
+            let ctor = if !self.matrix_ctors.is_empty() || report_when_all_missing {
+                Missing
+            } else {
+                Wildcard
+            };
+            return smallvec![ctor];
         }
+
+        // All the constructors are present in the matrix, so we just go through them all.
+        self.all_ctors
     }
 }
 
 /// Some fields need to be explicitly hidden away in certain cases; see the comment above the
-/// `Fields` struct. This struct represents such a potentially-hidden field. When a field is hidden
-/// we still keep its type around.
+/// `Fields` struct. This struct represents such a potentially-hidden field.
 #[derive(Debug, Copy, Clone)]
 pub(super) enum FilteredField<'p, 'tcx> {
     Kept(&'p Pat<'tcx>),
-    Hidden(Ty<'tcx>),
+    Hidden,
 }
 
 impl<'p, 'tcx> FilteredField<'p, 'tcx> {
     fn kept(self) -> Option<&'p Pat<'tcx>> {
         match self {
             FilteredField::Kept(p) => Some(p),
-            FilteredField::Hidden(_) => None,
-        }
-    }
-
-    fn to_pattern(self) -> Pat<'tcx> {
-        match self {
-            FilteredField::Kept(p) => p.clone(),
-            FilteredField::Hidden(ty) => Pat::wildcard_from_ty(ty),
+            FilteredField::Hidden => None,
         }
     }
 }
 
 /// A value can be decomposed into a constructor applied to some fields. This struct represents
 /// those fields, generalized to allow patterns in each field. See also `Constructor`.
+/// This is constructed from a constructor using [`Fields::wildcards()`].
 ///
 /// If a private or `non_exhaustive` field is uninhabited, the code mustn't observe that it is
-/// uninhabited. For that, we filter these fields out of the matrix. This is subtle because we
-/// still need to have those fields back when going to/from a `Pat`. Most of this is handled
-/// automatically in `Fields`, but when constructing or deconstructing `Fields` you need to be
-/// careful. As a rule, when going to/from the matrix, use the filtered field list; when going
-/// to/from `Pat`, use the full field list.
-/// This filtering is uncommon in practice, because uninhabited fields are rarely used, so we avoid
-/// it when possible to preserve performance.
+/// uninhabited. For that, we filter these fields out of the matrix. This is handled automatically
+/// in `Fields`. This filtering is uncommon in practice, because uninhabited fields are rarely used,
+/// so we avoid it when possible to preserve performance.
 #[derive(Debug, Clone)]
 pub(super) enum Fields<'p, 'tcx> {
     /// Lists of patterns that don't contain any filtered fields.
@@ -1027,21 +1090,19 @@ pub(super) enum Fields<'p, 'tcx> {
     /// have not measured if it really made a difference.
     Slice(&'p [Pat<'tcx>]),
     Vec(SmallVec<[&'p Pat<'tcx>; 2]>),
-    /// Patterns where some of the fields need to be hidden. `kept_count` caches the number of
-    /// non-hidden fields.
+    /// Patterns where some of the fields need to be hidden. For all intents and purposes we only
+    /// care about the non-hidden fields. We need to keep the real field index for those fields;
+    /// we're morally storing a `Vec<(usize, &Pat)>` but what we do is more convenient.
+    /// `len` counts the number of non-hidden fields
     Filtered {
         fields: SmallVec<[FilteredField<'p, 'tcx>; 2]>,
-        kept_count: usize,
+        len: usize,
     },
 }
 
 impl<'p, 'tcx> Fields<'p, 'tcx> {
-    fn empty() -> Self {
-        Fields::Slice(&[])
-    }
-
-    /// Construct a new `Fields` from the given pattern. Must not be used if the pattern is a field
-    /// of a struct/tuple/variant.
+    /// Internal use. Use `Fields::wildcards()` instead.
+    /// Must not be used if the pattern is a field of a struct/tuple/variant.
     fn from_single_pattern(pat: &'p Pat<'tcx>) -> Self {
         Fields::Slice(std::slice::from_ref(pat))
     }
@@ -1086,7 +1147,7 @@ pub(super) fn wildcards(pcx: PatCtxt<'_, 'p, 'tcx>, constructor: &Constructor<'t
                         if has_no_hidden_fields {
                             Fields::wildcards_from_tys(cx, field_tys)
                         } else {
-                            let mut kept_count = 0;
+                            let mut len = 0;
                             let fields = variant
                                 .fields
                                 .iter()
@@ -1101,14 +1162,14 @@ pub(super) fn wildcards(pcx: PatCtxt<'_, 'p, 'tcx>, constructor: &Constructor<'t
                                     // order not to reveal the uninhabitedness of the whole
                                     // variant.
                                     if is_uninhabited && (!is_visible || is_non_exhaustive) {
-                                        FilteredField::Hidden(ty)
+                                        FilteredField::Hidden
                                     } else {
-                                        kept_count += 1;
+                                        len += 1;
                                         FilteredField::Kept(wildcard_from_ty(ty))
                                     }
                                 })
                                 .collect();
-                            Fields::Filtered { fields, kept_count }
+                            Fields::Filtered { fields, len }
                         }
                     }
                 }
@@ -1121,9 +1182,8 @@ pub(super) fn wildcards(pcx: PatCtxt<'_, 'p, 'tcx>, constructor: &Constructor<'t
                 }
                 _ => bug!("bad slice pattern {:?} {:?}", constructor, ty),
             },
-            Str(..) | FloatRange(..) | IntRange(..) | NonExhaustive | Opaque | Wildcard => {
-                Fields::empty()
-            }
+            Str(..) | FloatRange(..) | IntRange(..) | NonExhaustive | Opaque | Missing
+            | Wildcard => Fields::Slice(&[]),
         };
         debug!("Fields::wildcards({:?}, {:?}) = {:#?}", constructor, ty, ret);
         ret
@@ -1145,14 +1205,16 @@ pub(super) fn wildcards(pcx: PatCtxt<'_, 'p, 'tcx>, constructor: &Constructor<'t
     /// `self`: `[false]`
     /// returns `Some(false)`
     pub(super) fn apply(self, pcx: PatCtxt<'_, 'p, 'tcx>, ctor: &Constructor<'tcx>) -> Pat<'tcx> {
-        let mut subpatterns = self.all_patterns();
+        let subpatterns_and_indices = self.patterns_and_indices();
+        let mut subpatterns = subpatterns_and_indices.iter().map(|&(_, p)| p).cloned();
 
         let pat = match ctor {
             Single | Variant(_) => match pcx.ty.kind() {
                 ty::Adt(..) | ty::Tuple(..) => {
-                    let subpatterns = subpatterns
-                        .enumerate()
-                        .map(|(i, p)| FieldPat { field: Field::new(i), pattern: p })
+                    // We want the real indices here.
+                    let subpatterns = subpatterns_and_indices
+                        .iter()
+                        .map(|&(field, p)| FieldPat { field, pattern: p.clone() })
                         .collect();
 
                     if let ty::Adt(adt, substs) = pcx.ty.kind() {
@@ -1207,48 +1269,52 @@ pub(super) fn apply(self, pcx: PatCtxt<'_, 'p, 'tcx>, ctor: &Constructor<'tcx>)
             &FloatRange(lo, hi, end) => PatKind::Range(PatRange { lo, hi, end }),
             IntRange(range) => return range.to_pat(pcx.cx.tcx, pcx.ty),
             NonExhaustive => PatKind::Wild,
+            Wildcard => return Pat::wildcard_from_ty(pcx.ty),
             Opaque => bug!("we should not try to apply an opaque constructor"),
-            Wildcard => bug!(
-                "trying to apply a wildcard constructor; this should have been done in `apply_constructors`"
+            Missing => bug!(
+                "trying to apply the `Missing` constructor; this should have been done in `apply_constructors`"
             ),
         };
 
         Pat { ty: pcx.ty, span: DUMMY_SP, kind: Box::new(pat) }
     }
 
-    /// Returns the number of patterns from the viewpoint of match-checking, i.e. excluding hidden
-    /// fields. This is what we want in most cases in this file, the only exception being
-    /// conversion to/from `Pat`.
+    /// Returns the number of patterns. This is the same as the arity of the constructor used to
+    /// construct `self`.
     pub(super) fn len(&self) -> usize {
         match self {
             Fields::Slice(pats) => pats.len(),
             Fields::Vec(pats) => pats.len(),
-            Fields::Filtered { kept_count, .. } => *kept_count,
+            Fields::Filtered { len, .. } => *len,
         }
     }
 
-    /// Returns the complete list of patterns, including hidden fields.
-    fn all_patterns(self) -> impl Iterator<Item = Pat<'tcx>> {
-        let pats: SmallVec<[_; 2]> = match self {
-            Fields::Slice(pats) => pats.iter().cloned().collect(),
-            Fields::Vec(pats) => pats.into_iter().cloned().collect(),
+    /// Returns the list of patterns along with the corresponding field indices.
+    fn patterns_and_indices(&self) -> SmallVec<[(Field, &'p Pat<'tcx>); 2]> {
+        match self {
+            Fields::Slice(pats) => {
+                pats.iter().enumerate().map(|(i, p)| (Field::new(i), p)).collect()
+            }
+            Fields::Vec(pats) => {
+                pats.iter().copied().enumerate().map(|(i, p)| (Field::new(i), p)).collect()
+            }
             Fields::Filtered { fields, .. } => {
-                // We don't skip any fields here.
-                fields.into_iter().map(|p| p.to_pattern()).collect()
+                // Indices must be relative to the full list of patterns
+                fields
+                    .iter()
+                    .enumerate()
+                    .filter_map(|(i, p)| Some((Field::new(i), p.kept()?)))
+                    .collect()
             }
-        };
-        pats.into_iter()
+        }
     }
 
-    /// Returns the filtered list of patterns, not including hidden fields.
-    pub(super) fn filtered_patterns(self) -> SmallVec<[&'p Pat<'tcx>; 2]> {
+    /// Returns the list of patterns.
+    pub(super) fn into_patterns(self) -> SmallVec<[&'p Pat<'tcx>; 2]> {
         match self {
             Fields::Slice(pats) => pats.iter().collect(),
             Fields::Vec(pats) => pats,
-            Fields::Filtered { fields, .. } => {
-                // We skip hidden fields here
-                fields.into_iter().filter_map(|p| p.kept()).collect()
-            }
+            Fields::Filtered { fields, .. } => fields.iter().filter_map(|p| p.kept()).collect(),
         }
     }
 
@@ -1264,10 +1330,10 @@ fn replace_with_fieldpats(
     }
 
     /// Overrides some of the fields with the provided patterns. This is used when a pattern
-    /// defines some fields but not all, for example `Foo { field1: Some(_), .. }`: here we start with a
-    /// `Fields` that is just one wildcard per field of the `Foo` struct, and override the entry
-    /// corresponding to `field1` with the pattern `Some(_)`. This is also used for slice patterns
-    /// for the same reason.
+    /// defines some fields but not all, for example `Foo { field1: Some(_), .. }`: here we start
+    /// with a `Fields` that is just one wildcard per field of the `Foo` struct, and override the
+    /// entry corresponding to `field1` with the pattern `Some(_)`. This is also used for slice
+    /// patterns for the same reason.
     fn replace_fields_indexed(
         &self,
         new_pats: impl IntoIterator<Item = (usize, &'p Pat<'tcx>)>,
@@ -1295,8 +1361,8 @@ fn replace_fields_indexed(
         fields
     }
 
-    /// Replaces contained fields with the given filtered list of patterns, e.g. taken from the
-    /// matrix. There must be `len()` patterns in `pats`.
+    /// Replaces contained fields with the given list of patterns. There must be `len()` patterns
+    /// in `pats`.
     pub(super) fn replace_fields(
         &self,
         cx: &MatchCheckCtxt<'p, 'tcx>,
@@ -1305,7 +1371,7 @@ pub(super) fn replace_fields(
         let pats: &[_] = cx.pattern_arena.alloc_from_iter(pats);
 
         match self {
-            Fields::Filtered { fields, kept_count } => {
+            Fields::Filtered { fields, len } => {
                 let mut pats = pats.iter();
                 let mut fields = fields.clone();
                 for f in &mut fields {
@@ -1314,7 +1380,7 @@ pub(super) fn replace_fields(
                         *p = pats.next().unwrap();
                     }
                 }
-                Fields::Filtered { fields, kept_count: *kept_count }
+                Fields::Filtered { fields, len: *len }
             }
             _ => Fields::Slice(pats),
         }
index 0ecc034ac0ba9336c7fd23ec7c75172e33faf9b8..83fee380ccce7196038d4e1d438596990112cb9f 100644 (file)
 //!
 //! -----
 //!
-//! This file includes the logic for exhaustiveness and usefulness checking for
-//! pattern-matching. Specifically, given a list of patterns for a type, we can
-//! tell whether:
-//! (a) the patterns cover every possible constructor for the type (exhaustiveness)
-//! (b) each pattern is necessary (usefulness)
+//! This file includes the logic for exhaustiveness and reachability checking for pattern-matching.
+//! Specifically, given a list of patterns for a type, we can tell whether:
+//! (a) each pattern is reachable (reachability)
+//! (b) the patterns cover every possible value for the type (exhaustiveness)
 //!
-//! The algorithm implemented here is a modified version of the one described in
-//! [this paper](http://moscova.inria.fr/~maranget/papers/warn/index.html).
-//! However, to save future implementors from reading the original paper, we
-//! summarise the algorithm here to hopefully save time and be a little clearer
-//! (without being so rigorous).
+//! The algorithm implemented here is a modified version of the one described in [this
+//! paper](http://moscova.inria.fr/~maranget/papers/warn/index.html). We have however generalized
+//! it to accommodate the variety of patterns that Rust supports. We thus explain our version here,
+//! without being as rigorous.
 //!
-//! # Premise
 //!
-//! The core of the algorithm revolves about a "usefulness" check. In particular, we
-//! are trying to compute a predicate `U(P, p)` where `P` is a list of patterns (we refer to this as
-//! a matrix). `U(P, p)` represents whether, given an existing list of patterns
-//! `P_1 ..= P_m`, adding a new pattern `p` will be "useful" (that is, cover previously-
-//! uncovered values of the type).
+//! # Summary
 //!
-//! If we have this predicate, then we can easily compute both exhaustiveness of an
-//! entire set of patterns and the individual usefulness of each one.
-//! (a) the set of patterns is exhaustive iff `U(P, _)` is false (i.e., adding a wildcard
-//! match doesn't increase the number of values we're matching)
-//! (b) a pattern `P_i` is not useful if `U(P[0..=(i-1), P_i)` is false (i.e., adding a
-//! pattern to those that have come before it doesn't increase the number of values
-//! we're matching).
+//! The core of the algorithm is the notion of "usefulness". A pattern `q` is said to be *useful*
+//! relative to another pattern `p` of the same type if there is a value that is matched by `q` and
+//! not matched by `p`. This generalizes to many `p`s: `q` is useful w.r.t. a list of patterns
+//! `p_1 .. p_n` if there is a value that is matched by `q` and by none of the `p_i`. We write
+//! `usefulness(p_1 .. p_n, q)` for a function that returns a list of such values. The aim of this
+//! file is to compute it efficiently.
 //!
-//! # Core concept
+//! This is enough to compute reachability: a pattern in a `match` expression is reachable iff it
+//! is useful w.r.t. the patterns above it:
+//! ```rust
+//! match x {
+//!     Some(_) => ...,
+//!     None => ..., // reachable: `None` is matched by this but not the branch above
+//!     Some(0) => ..., // unreachable: all the values this matches are already matched by
+//!                     // `Some(_)` above
+//! }
+//! ```
+//!
+//! This is also enough to compute exhaustiveness: a match is exhaustive iff the wildcard `_`
+//! pattern is _not_ useful w.r.t. the patterns in the match. The values returned by `usefulness`
+//! are used to tell the user which values are missing.
+//! ```rust
+//! match x {
+//!     Some(0) => ...,
+//!     None => ...,
+//!     // not exhaustive: `_` is useful because it matches `Some(1)`
+//! }
+//! ```
 //!
-//! The idea that powers everything that is done in this file is the following: a value is made
-//! from a constructor applied to some fields. Examples of constructors are `Some`, `None`, `(,)`
-//! (the 2-tuple constructor), `Foo {..}` (the constructor for a struct `Foo`), and `2` (the
-//! constructor for the number `2`). Fields are just a (possibly empty) list of values.
+//! The entrypoint of this file is the [`compute_match_usefulness`] function, which computes
+//! reachability for each match branch and exhaustiveness for the whole match.
 //!
-//! Some of the constructors listed above might feel weird: `None` and `2` don't take any
-//! arguments. This is part of what makes constructors so general: we will consider plain values
-//! like numbers and string literals to be constructors that take no arguments, also called "0-ary
-//! constructors"; they are the simplest case of constructors. This allows us to see any value as
-//! made up from a tree of constructors, each having a given number of children. For example:
-//! `(None, Ok(0))` is made from 4 different constructors.
 //!
-//! This idea can be extended to patterns: a pattern captures a set of possible values, and we can
-//! describe this set using constructors. For example, `Err(_)` captures all values of the type
-//! `Result<T, E>` that start with the `Err` constructor (for some choice of `T` and `E`). The
-//! wildcard `_` captures all values of the given type starting with any of the constructors for
-//! that type.
+//! # Constructors and fields
 //!
-//! We use this to compute whether different patterns might capture a same value. Do the patterns
-//! `Ok("foo")` and `Err(_)` capture a common value? The answer is no, because the first pattern
-//! captures only values starting with the `Ok` constructor and the second only values starting
-//! with the `Err` constructor. Do the patterns `Some(42)` and `Some(1..10)` intersect? They might,
-//! since they both capture values starting with `Some`. To be certain, we need to dig under the
-//! `Some` constructor and continue asking the question. This is the main idea behind the
-//! exhaustiveness algorithm: by looking at patterns constructor-by-constructor, we can efficiently
-//! figure out if some new pattern might capture a value that hadn't been captured by previous
-//! patterns.
+//! Note: we will often abbreviate "constructor" as "ctor".
 //!
-//! Constructors are represented by the `Constructor` enum, and its fields by the `Fields` enum.
-//! Most of the complexity of this file resides in transforming between patterns and
-//! (`Constructor`, `Fields`) pairs, handling all the special cases correctly.
+//! The idea that powers everything that is done in this file is the following: a (matcheable)
+//! value is made from a constructor applied to a number of subvalues. Examples of constructors are
+//! `Some`, `None`, `(,)` (the 2-tuple constructor), `Foo {..}` (the constructor for a struct
+//! `Foo`), and `2` (the constructor for the number `2`). This is natural when we think of
+//! pattern-matching, and this is the basis for what follows.
 //!
-//! Caveat: this constructors/fields distinction doesn't quite cover every Rust value. For example
-//! a value of type `Rc<u64>` doesn't fit this idea very well, nor do various other things.
-//! However, this idea covers most of the cases that are relevant to exhaustiveness checking.
+//! Some of the ctors listed above might feel weird: `None` and `2` don't take any arguments.
+//! That's ok: those are ctors that take a list of 0 arguments; they are the simplest case of
+//! ctors. We treat `2` as a ctor because `u64` and other number types behave exactly like a huge
+//! `enum`, with one variant for each number. This allows us to see any matcheable value as made up
+//! from a tree of ctors, each having a set number of children. For example: `Foo { bar: None,
+//! baz: Ok(0) }` is made from 4 different ctors, namely `Foo{..}`, `None`, `Ok` and `0`.
 //!
+//! This idea can be extended to patterns: they are also made from constructors applied to fields.
+//! A pattern for a given type is allowed to use all the ctors for values of that type (which we
+//! call "value constructors"), but there are also pattern-only ctors. The most important one is
+//! the wildcard (`_`), and the others are integer ranges (`0..=10`), variable-length slices (`[x,
+//! ..]`), and or-patterns (`Ok(0) | Err(_)`). Examples of valid patterns are `42`, `Some(_)`, `Foo
+//! { bar: Some(0) | None, baz: _ }`. Note that a binder in a pattern (e.g. `Some(x)`) matches the
+//! same values as a wildcard (e.g. `Some(_)`), so we treat both as wildcards.
 //!
-//! # Algorithm
+//! From this deconstruction we can compute whether a given value matches a given pattern; we
+//! simply look at ctors one at a time. Given a pattern `p` and a value `v`, we want to compute
+//! `matches!(v, p)`. It's mostly straightforward: we compare the head ctors and when they match
+//! we compare their fields recursively. A few representative examples:
 //!
-//! Recall that `U(P, p)` represents whether, given an existing list of patterns (aka matrix) `P`,
-//! adding a new pattern `p` will cover previously-uncovered values of the type.
-//! During the course of the algorithm, the rows of the matrix won't just be individual patterns,
-//! but rather partially-deconstructed patterns in the form of a list of fields. The paper
-//! calls those pattern-vectors, and we will call them pattern-stacks. The same holds for the
-//! new pattern `p`.
+//! - `matches!(v, _) := true`
+//! - `matches!((v0,  v1), (p0,  p1)) := matches!(v0, p0) && matches!(v1, p1)`
+//! - `matches!(Foo { bar: v0, baz: v1 }, Foo { bar: p0, baz: p1 }) := matches!(v0, p0) && matches!(v1, p1)`
+//! - `matches!(Ok(v0), Ok(p0)) := matches!(v0, p0)`
+//! - `matches!(Ok(v0), Err(p0)) := false` (incompatible variants)
+//! - `matches!(v, 1..=100) := matches!(v, 1) || ... || matches!(v, 100)`
+//! - `matches!([v0], [p0, .., p1]) := false` (incompatible lengths)
+//! - `matches!([v0, v1, v2], [p0, .., p1]) := matches!(v0, p0) && matches!(v2, p1)`
+//! - `matches!(v, p0 | p1) := matches!(v, p0) || matches!(v, p1)`
 //!
-//! For example, say we have the following:
+//! Constructors, fields and relevant operations are defined in the [`super::deconstruct_pat`] module.
 //!
+//! Note: this constructors/fields distinction may not straightforwardly apply to every Rust type.
+//! For example a value of type `Rc<u64>` can't be deconstructed that way, and `&str` has an
+//! infinitude of constructors. There are also subtleties with visibility of fields and
+//! uninhabitedness and various other things. The constructors idea can be extended to handle most
+//! of these subtleties though; caveats are documented where relevant throughout the code.
+//!
+//! Whether constructors cover each other is computed by [`Constructor::is_covered_by`].
+//!
+//!
+//! # Specialization
+//!
+//! Recall that we wish to compute `usefulness(p_1 .. p_n, q)`: given a list of patterns `p_1 ..
+//! p_n` and a pattern `q`, all of the same type, we want to find a list of values (called
+//! "witnesses") that are matched by `q` and by none of the `p_i`. We obviously don't just
+//! enumerate all possible values. From the discussion above we see that we can proceed
+//! ctor-by-ctor: for each value ctor of the given type, we ask "is there a value that starts with
+//! this constructor and matches `q` and none of the `p_i`?". As we saw above, there's a lot we can
+//! say from knowing only the first constructor of our candidate value.
+//!
+//! Let's take the following example:
 //! ```
-//! // x: (Option<bool>, Result<()>)
 //! match x {
-//!     (Some(true), _) => {}
-//!     (None, Err(())) => {}
-//!     (None, Err(_)) => {}
+//!     Enum::Variant1(_) => {} // `p1`
+//!     Enum::Variant2(None, 0) => {} // `p2`
+//!     Enum::Variant2(Some(_), 0) => {} // `q`
 //! }
 //! ```
 //!
-//! Here, the matrix `P` starts as:
+//! We can easily see that if our candidate value `v` starts with `Variant1` it will not match `q`.
+//! If `v = Variant2(v0, v1)` however, whether or not it matches `p2` and `q` will depend on `v0`
+//! and `v1`. In fact, such a `v` will be a witness of usefulness of `q` exactly when the tuple
+//! `(v0, v1)` is a witness of usefulness of `q'` in the following reduced match:
 //!
 //! ```
-//! [
-//!     [(Some(true), _)],
-//!     [(None, Err(()))],
-//!     [(None, Err(_))],
-//! ]
+//! match x {
+//!     (None, 0) => {} // `p2'`
+//!     (Some(_), 0) => {} // `q'`
+//! }
 //! ```
 //!
-//! We can tell it's not exhaustive, because `U(P, _)` is true (we're not covering
-//! `[(Some(false), _)]`, for instance). In addition, row 3 is not useful, because
-//! all the values it covers are already covered by row 2.
+//! This motivates a new step in computing usefulness, that we call _specialization_.
+//! Specialization consist of filtering a list of patterns for those that match a constructor, and
+//! then looking into the constructor's fields. This enables usefulness to be computed recursively.
 //!
-//! A list of patterns can be thought of as a stack, because we are mainly interested in the top of
-//! the stack at any given point, and we can pop or apply constructors to get new pattern-stacks.
-//! To match the paper, the top of the stack is at the beginning / on the left.
+//! Instead of acting on a single pattern in each row, we will consider a list of patterns for each
+//! row, and we call such a list a _pattern-stack_. The idea is that we will specialize the
+//! leftmost pattern, which amounts to popping the constructor and pushing its fields, which feels
+//! like a stack. We note a pattern-stack simply with `[p_1 ... p_n]`.
+//! Here's a sequence of specializations of a list of pattern-stacks, to illustrate what's
+//! happening:
+//! ```
+//! [Enum::Variant1(_)]
+//! [Enum::Variant2(None, 0)]
+//! [Enum::Variant2(Some(_), 0)]
+//! //==>> specialize with `Variant2`
+//! [None, 0]
+//! [Some(_), 0]
+//! //==>> specialize with `Some`
+//! [_, 0]
+//! //==>> specialize with `true` (say the type was `bool`)
+//! [0]
+//! //==>> specialize with `0`
+//! []
+//! ```
 //!
-//! There are two important operations on pattern-stacks necessary to understand the algorithm:
+//! The function `specialize(c, p)` takes a value constructor `c` and a pattern `p`, and returns 0
+//! or more pattern-stacks. If `c` does not match the head constructor of `p`, it returns nothing;
+//! otherwise if returns the fields of the constructor. This only returns more than one
+//! pattern-stack if `p` has a pattern-only constructor.
 //!
-//! 1. We can pop a given constructor off the top of a stack. This operation is called
-//!    `specialize`, and is denoted `S(c, p)` where `c` is a constructor (like `Some` or
-//!    `None`) and `p` a pattern-stack.
-//!    If the pattern on top of the stack can cover `c`, this removes the constructor and
-//!    pushes its arguments onto the stack. It also expands OR-patterns into distinct patterns.
-//!    Otherwise the pattern-stack is discarded.
-//!    This essentially filters those pattern-stacks whose top covers the constructor `c` and
-//!    discards the others.
+//! - Specializing for the wrong constructor returns nothing
 //!
-//!    For example, the first pattern above initially gives a stack `[(Some(true), _)]`. If we
-//!    pop the tuple constructor, we are left with `[Some(true), _]`, and if we then pop the
-//!    `Some` constructor we get `[true, _]`. If we had popped `None` instead, we would get
-//!    nothing back.
+//!   `specialize(None, Some(p0)) := []`
 //!
-//!    This returns zero or more new pattern-stacks, as follows. We look at the pattern `p_1`
-//!    on top of the stack, and we have four cases:
+//! - Specializing for the correct constructor returns a single row with the fields
 //!
-//!      1.1. `p_1 = c(r_1, .., r_a)`, i.e. the top of the stack has constructor `c`. We
-//!           push onto the stack the arguments of this constructor, and return the result:
-//!              `r_1, .., r_a, p_2, .., p_n`
+//!   `specialize(Variant1, Variant1(p0, p1, p2)) := [[p0, p1, p2]]`
 //!
-//!      1.2. `p_1 = c'(r_1, .., r_a')` where `c â‰  c'`. We discard the current stack and
-//!           return nothing.
+//!   `specialize(Foo{..}, Foo { bar: p0, baz: p1 }) := [[p0, p1]]`
 //!
-//!         1.3. `p_1 = _`. We push onto the stack as many wildcards as the constructor `c` has
-//!              arguments (its arity), and return the resulting stack:
-//!                 `_, .., _, p_2, .., p_n`
+//! - For or-patterns, we specialize each branch and concatenate the results
 //!
-//!         1.4. `p_1 = r_1 | r_2`. We expand the OR-pattern and then recurse on each resulting
-//!              stack:
-//!                 - `S(c, (r_1, p_2, .., p_n))`
-//!                 - `S(c, (r_2, p_2, .., p_n))`
+//!   `specialize(c, p0 | p1) := specialize(c, p0) ++ specialize(c, p1)`
 //!
-//! 2. We can pop a wildcard off the top of the stack. This is called `S(_, p)`, where `p` is
-//!    a pattern-stack. Note: the paper calls this `D(p)`.
-//!    This is used when we know there are missing constructor cases, but there might be
-//!    existing wildcard patterns, so to check the usefulness of the matrix, we have to check
-//!    all its *other* components.
+//! - We treat the other pattern constructors as if they were a large or-pattern of all the
+//!   possibilities:
 //!
-//!    It is computed as follows. We look at the pattern `p_1` on top of the stack,
-//!    and we have three cases:
-//!         2.1. `p_1 = c(r_1, .., r_a)`. We discard the current stack and return nothing.
-//!         2.2. `p_1 = _`. We return the rest of the stack:
-//!                 p_2, .., p_n
-//!         2.3. `p_1 = r_1 | r_2`. We expand the OR-pattern and then recurse on each resulting
-//!           stack.
-//!                 - `S(_, (r_1, p_2, .., p_n))`
-//!                 - `S(_, (r_2, p_2, .., p_n))`
+//!   `specialize(c, _) := specialize(c, Variant1(_) | Variant2(_, _) | ...)`
 //!
-//! Note that the OR-patterns are not always used directly in Rust, but are used to derive the
-//! exhaustive integer matching rules, so they're written here for posterity.
+//!   `specialize(c, 1..=100) := specialize(c, 1 | ... | 100)`
 //!
-//! Both those operations extend straightforwardly to a list or pattern-stacks, i.e. a matrix, by
-//! working row-by-row. Popping a constructor ends up keeping only the matrix rows that start with
-//! the given constructor, and popping a wildcard keeps those rows that start with a wildcard.
+//!   `specialize(c, [p0, .., p1]) := specialize(c, [p0, p1] | [p0, _, p1] | [p0, _, _, p1] | ...)`
 //!
+//! - If `c` is a pattern-only constructor, `specialize` is defined on a case-by-case basis. See
+//!   the discussion about constructor splitting in [`super::deconstruct_pat`].
 //!
-//! The algorithm for computing `U`
-//! -------------------------------
-//! The algorithm is inductive (on the number of columns: i.e., components of tuple patterns).
-//! That means we're going to check the components from left-to-right, so the algorithm
-//! operates principally on the first component of the matrix and new pattern-stack `p`.
-//! This algorithm is realised in the `is_useful` function.
 //!
-//! Base case. (`n = 0`, i.e., an empty tuple pattern)
-//!     - If `P` already contains an empty pattern (i.e., if the number of patterns `m > 0`),
-//!       then `U(P, p)` is false.
-//!     - Otherwise, `P` must be empty, so `U(P, p)` is true.
+//! We then extend this function to work with pattern-stacks as input, by acting on the first
+//! column and keeping the other columns untouched.
 //!
-//! Inductive step. (`n > 0`, i.e., whether there's at least one column
-//!                  [which may then be expanded into further columns later])
-//! We're going to match on the top of the new pattern-stack, `p_1`.
-//!     - If `p_1 == c(r_1, .., r_a)`, i.e. we have a constructor pattern.
-//! Then, the usefulness of `p_1` can be reduced to whether it is useful when
-//! we ignore all the patterns in the first column of `P` that involve other constructors.
-//! This is where `S(c, P)` comes in:
-//! `U(P, p) := U(S(c, P), S(c, p))`
+//! Specialization for the whole matrix is done in [`Matrix::specialize_constructor`]. Note that
+//! or-patterns in the first column are expanded before being stored in the matrix. Specialization
+//! for a single patstack is done from a combination of [`Constructor::is_covered_by`] and
+//! [`PatStack::pop_head_constructor`]. The internals of how it's done mostly live in the
+//! [`Fields`] struct.
 //!
-//! For example, if `P` is:
 //!
-//! ```
-//! [
-//!     [Some(true), _],
-//!     [None, 0],
-//! ]
-//! ```
+//! # Computing usefulness
 //!
-//! and `p` is `[Some(false), 0]`, then we don't care about row 2 since we know `p` only
-//! matches values that row 2 doesn't. For row 1 however, we need to dig into the
-//! arguments of `Some` to know whether some new value is covered. So we compute
-//! `U([[true, _]], [false, 0])`.
+//! We now have all we need to compute usefulness. The inputs to usefulness are a list of
+//! pattern-stacks `p_1 ... p_n` (one per row), and a new pattern_stack `q`. The paper and this
+//! file calls the list of patstacks a _matrix_. They must all have the same number of columns and
+//! the patterns in a given column must all have the same type. `usefulness` returns a (possibly
+//! empty) list of witnesses of usefulness. These witnesses will also be pattern-stacks.
 //!
-//!   - If `p_1 == _`, then we look at the list of constructors that appear in the first
-//! component of the rows of `P`:
-//!   + If there are some constructors that aren't present, then we might think that the
-//! wildcard `_` is useful, since it covers those constructors that weren't covered
-//! before.
-//! That's almost correct, but only works if there were no wildcards in those first
-//! components. So we need to check that `p` is useful with respect to the rows that
-//! start with a wildcard, if there are any. This is where `S(_, x)` comes in:
-//! `U(P, p) := U(S(_, P), S(_, p))`
+//! - base case: `n_columns == 0`.
+//!     Since a pattern-stack functions like a tuple of patterns, an empty one functions like the
+//!     unit type. Thus `q` is useful iff there are no rows above it, i.e. if `n == 0`.
 //!
-//! For example, if `P` is:
+//! - inductive case: `n_columns > 0`.
+//!     We need a way to list the constructors we want to try. We will be more clever in the next
+//!     section but for now assume we list all value constructors for the type of the first column.
 //!
-//! ```
-//! [
-//!     [_, true, _],
-//!     [None, false, 1],
-//! ]
-//! ```
+//!     - for each such ctor `c`:
+//!
+//!         - for each `q'` returned by `specialize(c, q)`:
 //!
-//! and `p` is `[_, false, _]`, the `Some` constructor doesn't appear in `P`. So if we
-//! only had row 2, we'd know that `p` is useful. However row 1 starts with a
-//! wildcard, so we need to check whether `U([[true, _]], [false, 1])`.
+//!             - we compute `usefulness(specialize(c, p_1) ... specialize(c, p_n), q')`
 //!
-//!   + Otherwise, all possible constructors (for the relevant type) are present. In this
-//! case we must check whether the wildcard pattern covers any unmatched value. For
-//! that, we can think of the `_` pattern as a big OR-pattern that covers all
-//! possible constructors. For `Option`, that would mean `_ = None | Some(_)` for
-//! example. The wildcard pattern is useful in this case if it is useful when
-//! specialized to one of the possible constructors. So we compute:
-//! `U(P, p) := âˆƒ(k Ïµ constructors) U(S(k, P), S(k, p))`
+//!         - for each witness found, we revert specialization by pushing the constructor `c` on top.
 //!
-//! For example, if `P` is:
+//!     - We return the concatenation of all the witnesses found, if any.
 //!
+//! Example:
 //! ```
-//! [
-//!     [Some(true), _],
-//!     [None, false],
-//! ]
+//! [Some(true)] // p_1
+//! [None] // p_2
+//! [Some(_)] // q
+//! //==>> try `None`: `specialize(None, q)` returns nothing
+//! //==>> try `Some`: `specialize(Some, q)` returns a single row
+//! [true] // p_1'
+//! [_] // q'
+//! //==>> try `true`: `specialize(true, q')` returns a single row
+//! [] // p_1''
+//! [] // q''
+//! //==>> base case; `n != 0` so `q''` is not useful.
+//! //==>> go back up a step
+//! [true] // p_1'
+//! [_] // q'
+//! //==>> try `false`: `specialize(false, q')` returns a single row
+//! [] // q''
+//! //==>> base case; `n == 0` so `q''` is useful. We return the single witness `[]`
+//! witnesses:
+//! []
+//! //==>> undo the specialization with `false`
+//! witnesses:
+//! [false]
+//! //==>> undo the specialization with `Some`
+//! witnesses:
+//! [Some(false)]
+//! //==>> we have tried all the constructors. The output is the single witness `[Some(false)]`.
 //! ```
 //!
-//! and `p` is `[_, false]`, both `None` and `Some` constructors appear in the first
-//! components of `P`. We will therefore try popping both constructors in turn: we
-//! compute `U([[true, _]], [_, false])` for the `Some` constructor, and `U([[false]],
-//! [false])` for the `None` constructor. The first case returns true, so we know that
-//! `p` is useful for `P`. Indeed, it matches `[Some(false), _]` that wasn't matched
-//! before.
+//! This computation is done in [`is_useful`]. In practice we don't care about the list of
+//! witnesses when computing reachability; we only need to know whether any exist. We do keep the
+//! witnesses when computing exhaustiveness to report them to the user.
+//!
 //!
-//!   - If `p_1 == r_1 | r_2`, then the usefulness depends on each `r_i` separately:
-//! `U(P, p) := U(P, (r_1, p_2, .., p_n))
-//!  || U(P, (r_2, p_2, .., p_n))`
+//! # Making usefulness tractable: constructor splitting
 //!
-//! Modifications to the algorithm
-//! ------------------------------
-//! The algorithm in the paper doesn't cover some of the special cases that arise in Rust, for
-//! example uninhabited types and variable-length slice patterns. These are drawn attention to
-//! throughout the code below. I'll make a quick note here about how exhaustive integer matching is
-//! accounted for, though.
+//! We're missing one last detail: which constructors do we list? Naively listing all value
+//! constructors cannot work for types like `u64` or `&str`, so we need to be more clever. The
+//! first obvious insight is that we only want to list constructors that are covered by the head
+//! constructor of `q`. If it's a value constructor, we only try that one. If it's a pattern-only
+//! constructor, we use the final clever idea for this algorithm: _constructor splitting_, where we
+//! group together constructors that behave the same.
 //!
-//! Exhaustive integer matching
-//! ---------------------------
-//! An integer type can be thought of as a (huge) sum type: 1 | 2 | 3 | ...
-//! So to support exhaustive integer matching, we can make use of the logic in the paper for
-//! OR-patterns. However, we obviously can't just treat ranges x..=y as individual sums, because
-//! they are likely gigantic. So we instead treat ranges as constructors of the integers. This means
-//! that we have a constructor *of* constructors (the integers themselves). We then need to work
-//! through all the inductive step rules above, deriving how the ranges would be treated as
-//! OR-patterns, and making sure that they're treated in the same way even when they're ranges.
-//! There are really only four special cases here:
-//! - When we match on a constructor that's actually a range, we have to treat it as if we would
-//!   an OR-pattern.
-//!     + It turns out that we can simply extend the case for single-value patterns in
-//!      `specialize` to either be *equal* to a value constructor, or *contained within* a range
-//!      constructor.
-//!     + When the pattern itself is a range, you just want to tell whether any of the values in
-//!       the pattern range coincide with values in the constructor range, which is precisely
-//!       intersection.
-//!   Since when encountering a range pattern for a value constructor, we also use inclusion, it
-//!   means that whenever the constructor is a value/range and the pattern is also a value/range,
-//!   we can simply use intersection to test usefulness.
-//! - When we're testing for usefulness of a pattern and the pattern's first component is a
-//!   wildcard.
-//!     + If all the constructors appear in the matrix, we have a slight complication. By default,
-//!       the behaviour (i.e., a disjunction over specialised matrices for each constructor) is
-//!       invalid, because we want a disjunction over every *integer* in each range, not just a
-//!       disjunction over every range. This is a bit more tricky to deal with: essentially we need
-//!       to form equivalence classes of subranges of the constructor range for which the behaviour
-//!       of the matrix `P` and new pattern `p` are the same. This is described in more
-//!       detail in `Constructor::split`.
-//!     + If some constructors are missing from the matrix, it turns out we don't need to do
-//!       anything special (because we know none of the integers are actually wildcards: i.e., we
-//!       can't span wildcards using ranges).
+//! The details are not necessary to understand this file, so we explain them in
+//! [`super::deconstruct_pat`]. Splitting is done by the [`Constructor::split`] function.
 
 use self::Usefulness::*;
 use self::WitnessPreference::*;
 
-use super::deconstruct_pat::{Constructor, Fields, MissingConstructors};
+use super::deconstruct_pat::{Constructor, Fields, SplitWildcard};
 use super::{Pat, PatKind};
 use super::{PatternFoldable, PatternFolder};
 
@@ -358,8 +335,6 @@ pub(super) fn is_foreign_non_exhaustive_enum(&self, ty: Ty<'tcx>) -> bool {
 #[derive(Copy, Clone)]
 pub(super) struct PatCtxt<'a, 'p, 'tcx> {
     pub(super) cx: &'a MatchCheckCtxt<'p, 'tcx>,
-    /// Current state of the matrix.
-    pub(super) matrix: &'a Matrix<'p, 'tcx>,
     /// Type of the current column under investigation.
     pub(super) ty: Ty<'tcx>,
     /// Span of the current pattern under investigation.
@@ -473,7 +448,7 @@ fn pop_head_constructor(&self, ctor_wild_subpatterns: &Fields<'p, 'tcx>) -> PatS
         // We pop the head pattern and push the new fields extracted from the arguments of
         // `self.head()`.
         let mut new_fields =
-            ctor_wild_subpatterns.replace_with_pattern_arguments(self.head()).filtered_patterns();
+            ctor_wild_subpatterns.replace_with_pattern_arguments(self.head()).into_patterns();
         new_fields.extend_from_slice(&self.pats[1..]);
         PatStack::from_vec(new_fields)
     }
@@ -538,7 +513,7 @@ fn heads<'a>(&'a self) -> impl Iterator<Item = &'a Pat<'tcx>> + Captures<'p> {
     pub(super) fn head_ctors<'a>(
         &'a self,
         cx: &'a MatchCheckCtxt<'p, 'tcx>,
-    ) -> impl Iterator<Item = &'a Constructor<'tcx>> + Captures<'p> {
+    ) -> impl Iterator<Item = &'a Constructor<'tcx>> + Captures<'p> + Clone {
         self.patterns.iter().map(move |r| r.head_ctor(cx))
     }
 
@@ -804,14 +779,25 @@ fn unsplit_or_pat(self, this_span: Span, or_pat_spans: &[Span]) -> Self {
     fn apply_constructor<'p>(
         self,
         pcx: PatCtxt<'_, 'p, 'tcx>,
+        matrix: &Matrix<'p, 'tcx>, // used to compute missing ctors
         ctor: &Constructor<'tcx>,
         ctor_wild_subpatterns: &Fields<'p, 'tcx>,
     ) -> Self {
         match self {
             UsefulWithWitness(witnesses) => {
-                let new_witnesses = if ctor.is_wildcard() {
-                    let missing_ctors = MissingConstructors::new(pcx);
-                    let new_patterns = missing_ctors.report_patterns(pcx);
+                let new_witnesses = if matches!(ctor, Constructor::Missing) {
+                    let mut split_wildcard = SplitWildcard::new(pcx);
+                    split_wildcard.split(pcx, matrix.head_ctors(pcx.cx));
+                    // Construct for each missing constructor a "wild" version of this
+                    // constructor, that matches everything that can be built with
+                    // it. For example, if `ctor` is a `Constructor::Variant` for
+                    // `Option::Some`, we get the pattern `Some(_)`.
+                    let new_patterns: Vec<_> = split_wildcard
+                        .iter_missing(pcx)
+                        .map(|missing_ctor| {
+                            Fields::wildcards(pcx, missing_ctor).apply(pcx, missing_ctor)
+                        })
+                        .collect();
                     witnesses
                         .into_iter()
                         .flat_map(|witness| {
@@ -866,10 +852,10 @@ enum WitnessPreference {
 /// We'll perform the following steps:
 /// 1. Start with an empty witness
 ///     `Witness(vec![])`
-/// 2. Push a witness `Some(_)` against the `None`
-///     `Witness(vec![Some(_)])`
-/// 3. Push a witness `true` against the `false`
-///     `Witness(vec![Some(_), true])`
+/// 2. Push a witness `true` against the `false`
+///     `Witness(vec![true])`
+/// 3. Push a witness `Some(_)` against the `None`
+///     `Witness(vec![true, Some(_)])`
 /// 4. Apply the `Pair` constructor to the witnesses
 ///     `Witness(vec![Pair(Some(_), true)])`
 ///
@@ -967,7 +953,7 @@ fn is_useful<'p, 'tcx>(
 
     // FIXME(Nadrieril): Hack to work around type normalization issues (see #72476).
     let ty = matrix.heads().next().map(|r| r.ty).unwrap_or(v.head().ty);
-    let pcx = PatCtxt { cx, matrix, ty, span: v.head().span, is_top_level };
+    let pcx = PatCtxt { cx, ty, span: v.head().span, is_top_level };
 
     debug!("is_useful_expand_first_col: ty={:#?}, expanding {:#?}", pcx.ty, v.head());
 
@@ -991,18 +977,30 @@ fn is_useful<'p, 'tcx>(
         });
         Usefulness::merge(usefulnesses)
     } else {
+        let v_ctor = v.head_ctor(cx);
+        if let Constructor::IntRange(ctor_range) = &v_ctor {
+            // Lint on likely incorrect range patterns (#63987)
+            ctor_range.lint_overlapping_range_endpoints(
+                pcx,
+                matrix.head_ctors_and_spans(cx),
+                matrix.column_count().unwrap_or(0),
+                hir_id,
+            )
+        }
         // We split the head constructor of `v`.
-        let ctors = v.head_ctor(cx).split(pcx, Some(hir_id));
+        let split_ctors = v_ctor.split(pcx, matrix.head_ctors(cx));
         // For each constructor, we compute whether there's a value that starts with it that would
         // witness the usefulness of `v`.
-        let usefulnesses = ctors.into_iter().map(|ctor| {
+        let start_matrix = &matrix;
+        let usefulnesses = split_ctors.into_iter().map(|ctor| {
             // We cache the result of `Fields::wildcards` because it is used a lot.
             let ctor_wild_subpatterns = Fields::wildcards(pcx, &ctor);
-            let matrix = pcx.matrix.specialize_constructor(pcx, &ctor, &ctor_wild_subpatterns);
+            let spec_matrix =
+                start_matrix.specialize_constructor(pcx, &ctor, &ctor_wild_subpatterns);
             let v = v.pop_head_constructor(&ctor_wild_subpatterns);
             let usefulness =
-                is_useful(pcx.cx, &matrix, &v, witness_preference, hir_id, is_under_guard, false);
-            usefulness.apply_constructor(pcx, &ctor, &ctor_wild_subpatterns)
+                is_useful(cx, &spec_matrix, &v, witness_preference, hir_id, is_under_guard, false);
+            usefulness.apply_constructor(pcx, start_matrix, &ctor, &ctor_wild_subpatterns)
         });
         Usefulness::merge(usefulnesses)
     };
@@ -1013,7 +1011,7 @@ fn is_useful<'p, 'tcx>(
 /// The arm of a match expression.
 #[derive(Clone, Copy)]
 crate struct MatchArm<'p, 'tcx> {
-    /// The pattern must have been lowered through `MatchVisitor::lower_pattern`.
+    /// The pattern must have been lowered through `check_match::MatchVisitor::lower_pattern`.
     crate pat: &'p super::Pat<'tcx>,
     crate hir_id: HirId,
     crate has_guard: bool,
@@ -1031,7 +1029,8 @@ fn is_useful<'p, 'tcx>(
 /// The entrypoint for the usefulness algorithm. Computes whether a match is exhaustive and which
 /// of its arms are reachable.
 ///
-/// Note: the input patterns must have been lowered through `MatchVisitor::lower_pattern`.
+/// Note: the input patterns must have been lowered through
+/// `check_match::MatchVisitor::lower_pattern`.
 crate fn compute_match_usefulness<'p, 'tcx>(
     cx: &MatchCheckCtxt<'p, 'tcx>,
     arms: &[MatchArm<'p, 'tcx>],
index 44999c9b63ab6c2c428475f38ec6fe9fd3c2b232..9abffbacfc3b3671b92182e3b6b04bcc0c6f2ad6 100644 (file)
@@ -7,22 +7,18 @@
 
 use rustc_ast as ast;
 use rustc_ast::attr::HasAttrs;
-use rustc_ast::token::{self, DelimToken, Nonterminal, Token, TokenKind};
-use rustc_ast::tokenstream::{self, LazyTokenStream, TokenStream, TokenTree};
+use rustc_ast::token::{self, Nonterminal};
+use rustc_ast::tokenstream::{self, CanSynthesizeMissingTokens, LazyTokenStream, TokenStream};
 use rustc_ast_pretty::pprust;
-use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::{Diagnostic, FatalError, Level, PResult};
 use rustc_session::parse::ParseSess;
-use rustc_span::{symbol::kw, FileName, SourceFile, Span, DUMMY_SP};
+use rustc_span::{FileName, SourceFile, Span};
 
-use smallvec::SmallVec;
-use std::cell::RefCell;
-use std::mem;
 use std::path::Path;
 use std::str;
 
-use tracing::{debug, info};
+use tracing::debug;
 
 pub const MACRO_ARGUMENTS: Option<&str> = Some("macro arguments");
 
@@ -237,7 +233,12 @@ pub fn parse_in<'a, T>(
 // NOTE(Centril): The following probably shouldn't be here but it acknowledges the
 // fact that architecturally, we are using parsing (read on below to understand why).
 
-pub fn nt_to_tokenstream(nt: &Nonterminal, sess: &ParseSess, span: Span) -> TokenStream {
+pub fn nt_to_tokenstream(
+    nt: &Nonterminal,
+    sess: &ParseSess,
+    span: Span,
+    synthesize_tokens: CanSynthesizeMissingTokens,
+) -> TokenStream {
     // A `Nonterminal` is often a parsed AST item. At this point we now
     // need to convert the parsed AST to an actual token stream, e.g.
     // un-parse it basically.
@@ -255,9 +256,11 @@ pub fn nt_to_tokenstream(nt: &Nonterminal, sess: &ParseSess, span: Span) -> Toke
         |tokens: Option<&LazyTokenStream>| tokens.as_ref().map(|t| t.create_token_stream());
 
     let tokens = match *nt {
-        Nonterminal::NtItem(ref item) => prepend_attrs(&item.attrs, item.tokens.as_ref()),
+        Nonterminal::NtItem(ref item) => {
+            prepend_attrs(sess, &item.attrs, nt, span, item.tokens.as_ref())
+        }
         Nonterminal::NtBlock(ref block) => convert_tokens(block.tokens.as_ref()),
-        Nonterminal::NtStmt(ref stmt) => prepend_attrs(stmt.attrs(), stmt.tokens()),
+        Nonterminal::NtStmt(ref stmt) => prepend_attrs(sess, stmt.attrs(), nt, span, stmt.tokens()),
         Nonterminal::NtPat(ref pat) => convert_tokens(pat.tokens.as_ref()),
         Nonterminal::NtTy(ref ty) => convert_tokens(ty.tokens.as_ref()),
         Nonterminal::NtIdent(ident, is_raw) => {
@@ -274,376 +277,45 @@ pub fn nt_to_tokenstream(nt: &Nonterminal, sess: &ParseSess, span: Span) -> Toke
             if expr.tokens.is_none() {
                 debug!("missing tokens for expr {:?}", expr);
             }
-            prepend_attrs(&expr.attrs, expr.tokens.as_ref())
+            prepend_attrs(sess, &expr.attrs, nt, span, expr.tokens.as_ref())
         }
     };
 
-    // Caches the stringification of 'good' `TokenStreams` which passed
-    // `tokenstream_probably_equal_for_proc_macro`. This allows us to avoid
-    // repeatedly stringifying and comparing the same `TokenStream` for deeply
-    // nested nonterminals.
-    //
-    // We cache by the strinification instead of the `TokenStream` to avoid
-    // needing to implement `Hash` for `TokenStream`. Note that it's possible to
-    // have two distinct `TokenStream`s that stringify to the same result
-    // (e.g. if they differ only in hygiene information). However, any
-    // information lost during the stringification process is also intentionally
-    // ignored by `tokenstream_probably_equal_for_proc_macro`, so it's fine
-    // that a single cache entry may 'map' to multiple distinct `TokenStream`s.
-    //
-    // This is a temporary hack to prevent compilation blowup on certain inputs.
-    // The entire pretty-print/retokenize process will be removed soon.
-    thread_local! {
-        static GOOD_TOKEN_CACHE: RefCell<FxHashSet<String>> = Default::default();
-    }
-
-    // FIXME(#43081): Avoid this pretty-print + reparse hack
-    // Pretty-print the AST struct without inserting any parenthesis
-    // beyond those explicitly written by the user (e.g. `ExpnKind::Paren`).
-    // The resulting stream may have incorrect precedence, but it's only
-    // ever used for a comparison against the capture tokenstream.
-    let source = pprust::nonterminal_to_string_no_extra_parens(nt);
-    let filename = FileName::macro_expansion_source_code(&source);
-    let reparsed_tokens = parse_stream_from_source_str(filename, source.clone(), sess, Some(span));
-
-    // During early phases of the compiler the AST could get modified
-    // directly (e.g., attributes added or removed) and the internal cache
-    // of tokens my not be invalidated or updated. Consequently if the
-    // "lossless" token stream disagrees with our actual stringification
-    // (which has historically been much more battle-tested) then we go
-    // with the lossy stream anyway (losing span information).
-    //
-    // Note that the comparison isn't `==` here to avoid comparing spans,
-    // but it *also* is a "probable" equality which is a pretty weird
-    // definition. We mostly want to catch actual changes to the AST
-    // like a `#[cfg]` being processed or some weird `macro_rules!`
-    // expansion.
-    //
-    // What we *don't* want to catch is the fact that a user-defined
-    // literal like `0xf` is stringified as `15`, causing the cached token
-    // stream to not be literal `==` token-wise (ignoring spans) to the
-    // token stream we got from stringification.
-    //
-    // Instead the "probably equal" check here is "does each token
-    // recursively have the same discriminant?" We basically don't look at
-    // the token values here and assume that such fine grained token stream
-    // modifications, including adding/removing typically non-semantic
-    // tokens such as extra braces and commas, don't happen.
     if let Some(tokens) = tokens {
-        if GOOD_TOKEN_CACHE.with(|cache| cache.borrow().contains(&source)) {
-            return tokens;
-        }
-
-        // Compare with a non-relaxed delim match to start.
-        if tokenstream_probably_equal_for_proc_macro(&tokens, &reparsed_tokens, sess, false) {
-            GOOD_TOKEN_CACHE.with(|cache| cache.borrow_mut().insert(source.clone()));
-            return tokens;
-        }
-
-        // The check failed. This time, we pretty-print the AST struct with parenthesis
-        // inserted to preserve precedence. This may cause `None`-delimiters in the captured
-        // token stream to match up with inserted parenthesis in the reparsed stream.
-        let source_with_parens = pprust::nonterminal_to_string(nt);
-        let filename_with_parens = FileName::macro_expansion_source_code(&source_with_parens);
-
-        if GOOD_TOKEN_CACHE.with(|cache| cache.borrow().contains(&source_with_parens)) {
-            return tokens;
-        }
-
-        let reparsed_tokens_with_parens = parse_stream_from_source_str(
-            filename_with_parens,
-            source_with_parens,
-            sess,
-            Some(span),
-        );
-
-        // Compare with a relaxed delim match - we want inserted parenthesis in the
-        // reparsed stream to match `None`-delimiters in the original stream.
-        if tokenstream_probably_equal_for_proc_macro(
-            &tokens,
-            &reparsed_tokens_with_parens,
-            sess,
-            true,
-        ) {
-            GOOD_TOKEN_CACHE.with(|cache| cache.borrow_mut().insert(source.clone()));
-            return tokens;
-        }
-
-        info!(
-            "cached tokens found, but they're not \"probably equal\", \
-                going with stringified version"
-        );
-        info!("cached   tokens: {}", pprust::tts_to_string(&tokens));
-        info!("reparsed tokens: {}", pprust::tts_to_string(&reparsed_tokens_with_parens));
-
-        info!("cached   tokens debug: {:?}", tokens);
-        info!("reparsed tokens debug: {:?}", reparsed_tokens_with_parens);
-    }
-    reparsed_tokens
-}
-
-// See comments in `Nonterminal::to_tokenstream` for why we care about
-// *probably* equal here rather than actual equality
-//
-// This is otherwise the same as `eq_unspanned`, only recursing with a
-// different method.
-pub fn tokenstream_probably_equal_for_proc_macro(
-    tokens: &TokenStream,
-    reparsed_tokens: &TokenStream,
-    sess: &ParseSess,
-    relaxed_delim_match: bool,
-) -> bool {
-    // When checking for `probably_eq`, we ignore certain tokens that aren't
-    // preserved in the AST. Because they are not preserved, the pretty
-    // printer arbitrarily adds or removes them when printing as token
-    // streams, making a comparison between a token stream generated from an
-    // AST and a token stream which was parsed into an AST more reliable.
-    fn semantic_tree(tree: &TokenTree) -> bool {
-        if let TokenTree::Token(token) = tree {
-            if let
-                // The pretty printer tends to add trailing commas to
-                // everything, and in particular, after struct fields.
-                | token::Comma
-                // The pretty printer collapses many semicolons into one.
-                | token::Semi
-                // We don't preserve leading `|` tokens in patterns, so
-                // we ignore them entirely
-                | token::BinOp(token::BinOpToken::Or)
-                // We don't preserve trailing '+' tokens in trait bounds,
-                // so we ignore them entirely
-                | token::BinOp(token::BinOpToken::Plus)
-                // The pretty printer can turn `$crate` into `::crate_name`
-                | token::ModSep = token.kind {
-                return false;
-            }
-        }
-        true
-    }
-
-    // When comparing two `TokenStream`s, we ignore the `IsJoint` information.
-    //
-    // However, `rustc_parse::lexer::tokentrees::TokenStreamBuilder` will
-    // use `Token.glue` on adjacent tokens with the proper `IsJoint`.
-    // Since we are ignoreing `IsJoint`, a 'glued' token (e.g. `BinOp(Shr)`)
-    // and its 'split'/'unglued' compoenents (e.g. `Gt, Gt`) are equivalent
-    // when determining if two `TokenStream`s are 'probably equal'.
-    //
-    // Therefore, we use `break_two_token_op` to convert all tokens
-    // to the 'unglued' form (if it exists). This ensures that two
-    // `TokenStream`s which differ only in how their tokens are glued
-    // will be considered 'probably equal', which allows us to keep spans.
-    //
-    // This is important when the original `TokenStream` contained
-    // extra spaces (e.g. `f :: < Vec < _ > > ( ) ;'). These extra spaces
-    // will be omitted when we pretty-print, which can cause the original
-    // and reparsed `TokenStream`s to differ in the assignment of `IsJoint`,
-    // leading to some tokens being 'glued' together in one stream but not
-    // the other. See #68489 for more details.
-    fn break_tokens(tree: TokenTree) -> impl Iterator<Item = TokenTree> {
-        // In almost all cases, we should have either zero or one levels
-        // of 'unglueing'. However, in some unusual cases, we may need
-        // to iterate breaking tokens mutliple times. For example:
-        // '[BinOpEq(Shr)] => [Gt, Ge] -> [Gt, Gt, Eq]'
-        let mut token_trees: SmallVec<[_; 2]>;
-        if let TokenTree::Token(token) = tree {
-            let mut out = SmallVec::<[_; 2]>::new();
-            out.push(token);
-            // Iterate to fixpoint:
-            // * We start off with 'out' containing our initial token, and `temp` empty
-            // * If we are able to break any tokens in `out`, then `out` will have
-            //   at least one more element than 'temp', so we will try to break tokens
-            //   again.
-            // * If we cannot break any tokens in 'out', we are done
-            loop {
-                let mut temp = SmallVec::<[_; 2]>::new();
-                let mut changed = false;
-
-                for token in out.into_iter() {
-                    if let Some((first, second)) = token.kind.break_two_token_op() {
-                        temp.push(Token::new(first, DUMMY_SP));
-                        temp.push(Token::new(second, DUMMY_SP));
-                        changed = true;
-                    } else {
-                        temp.push(token);
-                    }
-                }
-                out = temp;
-                if !changed {
-                    break;
-                }
-            }
-            token_trees = out.into_iter().map(TokenTree::Token).collect();
-        } else {
-            token_trees = SmallVec::new();
-            token_trees.push(tree);
-        }
-        token_trees.into_iter()
-    }
-
-    fn expand_token(tree: TokenTree, sess: &ParseSess) -> impl Iterator<Item = TokenTree> {
-        // When checking tokenstreams for 'probable equality', we are comparing
-        // a captured (from parsing) `TokenStream` to a reparsed tokenstream.
-        // The reparsed Tokenstream will never have `None`-delimited groups,
-        // since they are only ever inserted as a result of macro expansion.
-        // Therefore, inserting a `None`-delimtied group here (when we
-        // convert a nested `Nonterminal` to a tokenstream) would cause
-        // a mismatch with the reparsed tokenstream.
-        //
-        // Note that we currently do not handle the case where the
-        // reparsed stream has a `Parenthesis`-delimited group
-        // inserted. This will cause a spurious mismatch:
-        // issue #75734 tracks resolving this.
-
-        let expanded: SmallVec<[_; 1]> =
-            if let TokenTree::Token(Token { kind: TokenKind::Interpolated(nt), span }) = &tree {
-                nt_to_tokenstream(nt, sess, *span)
-                    .into_trees()
-                    .flat_map(|t| expand_token(t, sess))
-                    .collect()
-            } else {
-                // Filter before and after breaking tokens,
-                // since we may want to ignore both glued and unglued tokens.
-                std::iter::once(tree)
-                    .filter(semantic_tree)
-                    .flat_map(break_tokens)
-                    .filter(semantic_tree)
-                    .collect()
-            };
-        expanded.into_iter()
-    }
-
-    // Break tokens after we expand any nonterminals, so that we break tokens
-    // that are produced as a result of nonterminal expansion.
-    let tokens = tokens.trees().flat_map(|t| expand_token(t, sess));
-    let reparsed_tokens = reparsed_tokens.trees().flat_map(|t| expand_token(t, sess));
-
-    tokens.eq_by(reparsed_tokens, |t, rt| {
-        tokentree_probably_equal_for_proc_macro(&t, &rt, sess, relaxed_delim_match)
-    })
-}
-
-// See comments in `Nonterminal::to_tokenstream` for why we care about
-// *probably* equal here rather than actual equality
-//
-// This is otherwise the same as `eq_unspanned`, only recursing with a
-// different method.
-pub fn tokentree_probably_equal_for_proc_macro(
-    token: &TokenTree,
-    reparsed_token: &TokenTree,
-    sess: &ParseSess,
-    relaxed_delim_match: bool,
-) -> bool {
-    match (token, reparsed_token) {
-        (TokenTree::Token(token), TokenTree::Token(reparsed_token)) => {
-            token_probably_equal_for_proc_macro(token, reparsed_token)
-        }
-        (
-            TokenTree::Delimited(_, delim, tokens),
-            TokenTree::Delimited(_, reparsed_delim, reparsed_tokens),
-        ) if delim == reparsed_delim => tokenstream_probably_equal_for_proc_macro(
-            tokens,
-            reparsed_tokens,
-            sess,
-            relaxed_delim_match,
-        ),
-        (TokenTree::Delimited(_, DelimToken::NoDelim, tokens), reparsed_token) => {
-            if relaxed_delim_match {
-                if let TokenTree::Delimited(_, DelimToken::Paren, reparsed_tokens) = reparsed_token
-                {
-                    if tokenstream_probably_equal_for_proc_macro(
-                        tokens,
-                        reparsed_tokens,
-                        sess,
-                        relaxed_delim_match,
-                    ) {
-                        return true;
-                    }
-                }
-            }
-            tokens.len() == 1
-                && tokentree_probably_equal_for_proc_macro(
-                    &tokens.trees().next().unwrap(),
-                    reparsed_token,
-                    sess,
-                    relaxed_delim_match,
-                )
-        }
-        _ => false,
+        return tokens;
+    } else if matches!(synthesize_tokens, CanSynthesizeMissingTokens::Yes) {
+        return fake_token_stream(sess, nt, span);
+    } else {
+        let pretty = rustc_ast_pretty::pprust::nonterminal_to_string_no_extra_parens(&nt);
+        panic!("Missing tokens at {:?} for nt {:?}", span, pretty);
     }
 }
 
-// See comments in `Nonterminal::to_tokenstream` for why we care about
-// *probably* equal here rather than actual equality
-fn token_probably_equal_for_proc_macro(first: &Token, other: &Token) -> bool {
-    if mem::discriminant(&first.kind) != mem::discriminant(&other.kind) {
-        return false;
-    }
-    use rustc_ast::token::TokenKind::*;
-    match (&first.kind, &other.kind) {
-        (&Eq, &Eq)
-        | (&Lt, &Lt)
-        | (&Le, &Le)
-        | (&EqEq, &EqEq)
-        | (&Ne, &Ne)
-        | (&Ge, &Ge)
-        | (&Gt, &Gt)
-        | (&AndAnd, &AndAnd)
-        | (&OrOr, &OrOr)
-        | (&Not, &Not)
-        | (&Tilde, &Tilde)
-        | (&At, &At)
-        | (&Dot, &Dot)
-        | (&DotDot, &DotDot)
-        | (&DotDotDot, &DotDotDot)
-        | (&DotDotEq, &DotDotEq)
-        | (&Comma, &Comma)
-        | (&Semi, &Semi)
-        | (&Colon, &Colon)
-        | (&ModSep, &ModSep)
-        | (&RArrow, &RArrow)
-        | (&LArrow, &LArrow)
-        | (&FatArrow, &FatArrow)
-        | (&Pound, &Pound)
-        | (&Dollar, &Dollar)
-        | (&Question, &Question)
-        | (&Eof, &Eof) => true,
-
-        (&BinOp(a), &BinOp(b)) | (&BinOpEq(a), &BinOpEq(b)) => a == b,
-
-        (&OpenDelim(a), &OpenDelim(b)) | (&CloseDelim(a), &CloseDelim(b)) => a == b,
-
-        (&DocComment(a1, a2, a3), &DocComment(b1, b2, b3)) => a1 == b1 && a2 == b2 && a3 == b3,
-
-        (&Literal(a), &Literal(b)) => a == b,
-
-        (&Lifetime(a), &Lifetime(b)) => a == b,
-        (&Ident(a, b), &Ident(c, d)) => {
-            b == d && (a == c || a == kw::DollarCrate || c == kw::DollarCrate)
-        }
-
-        (&Interpolated(..), &Interpolated(..)) => panic!("Unexpanded Interpolated!"),
-
-        _ => panic!("forgot to add a token?"),
-    }
+pub fn fake_token_stream(sess: &ParseSess, nt: &Nonterminal, span: Span) -> TokenStream {
+    let source = pprust::nonterminal_to_string(nt);
+    let filename = FileName::macro_expansion_source_code(&source);
+    parse_stream_from_source_str(filename, source, sess, Some(span))
 }
 
 fn prepend_attrs(
+    sess: &ParseSess,
     attrs: &[ast::Attribute],
+    nt: &Nonterminal,
+    span: Span,
     tokens: Option<&tokenstream::LazyTokenStream>,
 ) -> Option<tokenstream::TokenStream> {
-    let tokens = tokens?.create_token_stream();
     if attrs.is_empty() {
-        return Some(tokens);
+        return Some(tokens?.create_token_stream());
     }
     let mut builder = tokenstream::TokenStreamBuilder::new();
     for attr in attrs {
         // FIXME: Correctly handle tokens for inner attributes.
         // For now, we fall back to reparsing the original AST node
         if attr.style == ast::AttrStyle::Inner {
-            return None;
+            return Some(fake_token_stream(sess, nt, span));
         }
         builder.push(attr.tokens());
     }
-    builder.push(tokens);
+    builder.push(tokens?.create_token_stream());
     Some(builder.build())
 }
index 350a372a684cc5e7b6f829f1e13026c0f61a37c7..98c7b9a63a55f60d8f54c0933e0bebdebd04bde8 100644 (file)
@@ -1912,4 +1912,22 @@ pub fn recover_const_arg(
         *self = snapshot;
         Err(err)
     }
+
+    /// Get the diagnostics for the cases where `move async` is found.
+    ///
+    /// `move_async_span` starts at the 'm' of the move keyword and ends with the 'c' of the async keyword
+    pub(super) fn incorrect_move_async_order_found(
+        &self,
+        move_async_span: Span,
+    ) -> DiagnosticBuilder<'a> {
+        let mut err =
+            self.struct_span_err(move_async_span, "the order of `move` and `async` is incorrect");
+        err.span_suggestion_verbose(
+            move_async_span,
+            "try switching the order",
+            "async move".to_owned(),
+            Applicability::MaybeIncorrect,
+        );
+        err
+    }
 }
index eed3e9947b2aa3a3b9cff81f7a1f5149983b4694..b147f42fada25bfdf368c1ad27e66bba6d280cd5 100644 (file)
@@ -1603,7 +1603,7 @@ fn parse_closure_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
             self.sess.gated_spans.gate(sym::async_closure, span);
         }
 
-        let capture_clause = self.parse_capture_clause();
+        let capture_clause = self.parse_capture_clause()?;
         let decl = self.parse_fn_block_decl()?;
         let decl_hi = self.prev_token.span;
         let body = match decl.output {
@@ -1626,8 +1626,18 @@ fn parse_closure_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
     }
 
     /// Parses an optional `move` prefix to a closure-like construct.
-    fn parse_capture_clause(&mut self) -> CaptureBy {
-        if self.eat_keyword(kw::Move) { CaptureBy::Value } else { CaptureBy::Ref }
+    fn parse_capture_clause(&mut self) -> PResult<'a, CaptureBy> {
+        if self.eat_keyword(kw::Move) {
+            // Check for `move async` and recover
+            if self.check_keyword(kw::Async) {
+                let move_async_span = self.token.span.with_lo(self.prev_token.span.data().lo);
+                Err(self.incorrect_move_async_order_found(move_async_span))
+            } else {
+                Ok(CaptureBy::Value)
+            }
+        } else {
+            Ok(CaptureBy::Ref)
+        }
     }
 
     /// Parses the `|arg, arg|` header of a closure.
@@ -2019,7 +2029,7 @@ fn is_try_block(&self) -> bool {
     fn parse_async_block(&mut self, mut attrs: AttrVec) -> PResult<'a, P<Expr>> {
         let lo = self.token.span;
         self.expect_keyword(kw::Async)?;
-        let capture_clause = self.parse_capture_clause();
+        let capture_clause = self.parse_capture_clause()?;
         let (iattrs, body) = self.parse_inner_attrs_and_block()?;
         attrs.extend(iattrs);
         let kind = ExprKind::Async(capture_clause, DUMMY_NODE_ID, body);
index ed8d4f78426ac7a242c46952fe03f4ec0ea39a96..860e63020bb0644715d485160dbbdb1d79e8bb92 100644 (file)
@@ -5,7 +5,7 @@
     self as ast, Attribute, GenericBounds, GenericParam, GenericParamKind, WhereClause,
 };
 use rustc_errors::PResult;
-use rustc_span::symbol::{kw, sym};
+use rustc_span::symbol::kw;
 
 impl<'a> Parser<'a> {
     /// Parses bounds of a lifetime parameter `BOUND + BOUND + BOUND`, possibly with trailing `+`.
@@ -56,8 +56,6 @@ fn parse_const_param(&mut self, preceding_attrs: Vec<Attribute>) -> PResult<'a,
         self.expect(&token::Colon)?;
         let ty = self.parse_ty()?;
 
-        self.sess.gated_spans.gate(sym::min_const_generics, const_span.to(self.prev_token.span));
-
         Ok(GenericParam {
             ident,
             id: ast::DUMMY_NODE_ID,
index 634cce403df96f86ef20e36a2d9055d48a57044b..c6669f0468296cb3217fdf2ed1c083f422b26ac6 100644 (file)
@@ -494,7 +494,7 @@ fn parse_item_impl(
         let polarity = self.parse_polarity();
 
         // Parse both types and traits as a type, then reinterpret if necessary.
-        let err_path = |span| ast::Path::from_ident(Ident::new(kw::Invalid, span));
+        let err_path = |span| ast::Path::from_ident(Ident::new(kw::Empty, span));
         let ty_first = if self.token.is_keyword(kw::For) && self.look_ahead(1, |t| t != &token::Lt)
         {
             let span = self.prev_token.span.between(self.token.span);
@@ -1699,7 +1699,7 @@ fn parse_fn_params(&mut self, req_name: ReqName) -> PResult<'a, Vec<Param>> {
                 // Skip every token until next possible arg or end.
                 p.eat_to_tokens(&[&token::Comma, &token::CloseDelim(token::Paren)]);
                 // Create a placeholder argument for proper arg count (issue #34264).
-                Ok(dummy_arg(Ident::new(kw::Invalid, lo.to(p.prev_token.span))))
+                Ok(dummy_arg(Ident::new(kw::Empty, lo.to(p.prev_token.span))))
             });
             // ...now that we've parsed the first argument, `self` is no longer allowed.
             first_param = false;
@@ -1759,7 +1759,7 @@ fn parse_param_general(&mut self, req_name: ReqName, first_param: bool) -> PResu
             }
             match ty {
                 Ok(ty) => {
-                    let ident = Ident::new(kw::Invalid, self.prev_token.span);
+                    let ident = Ident::new(kw::Empty, self.prev_token.span);
                     let bm = BindingMode::ByValue(Mutability::Not);
                     let pat = self.mk_pat_ident(ty.span, bm, ident);
                     (pat, ty)
index e19ebb8fd2fbc3bb9d881a8d1fb24f0a3543a9a4..1062000fede9b264b7dbe9a1c6f1aa2d9c1a1ff9 100644 (file)
@@ -721,13 +721,9 @@ fn parse_seq_to_before_tokens<T>(
                                 Ok(t) => {
                                     // Parsed successfully, therefore most probably the code only
                                     // misses a separator.
-                                    let mut exp_span = self.sess.source_map().next_point(sp);
-                                    if self.sess.source_map().is_multiline(exp_span) {
-                                        exp_span = sp;
-                                    }
                                     expect_err
                                         .span_suggestion_short(
-                                            exp_span,
+                                            sp,
                                             &format!("missing `{}`", token_str),
                                             token_str,
                                             Applicability::MaybeIncorrect,
index 4510e86e0341fd899e8240eddb8884906acba5b3..60a47ca12b868c4958880e84c5bb0ee0b13c84a6 100644 (file)
@@ -501,10 +501,9 @@ fn parse_assoc_equality_term(&mut self, ident: Ident, eq: Span) -> PResult<'a, P
     pub(super) fn expr_is_valid_const_arg(&self, expr: &P<rustc_ast::Expr>) -> bool {
         match &expr.kind {
             ast::ExprKind::Block(_, _) | ast::ExprKind::Lit(_) => true,
-            ast::ExprKind::Unary(ast::UnOp::Neg, expr) => match &expr.kind {
-                ast::ExprKind::Lit(_) => true,
-                _ => false,
-            },
+            ast::ExprKind::Unary(ast::UnOp::Neg, expr) => {
+                matches!(expr.kind, ast::ExprKind::Lit(_))
+            }
             // We can only resolve single-segment paths at the moment, because multi-segment paths
             // require type-checking: see `visit_generic_arg` in `src/librustc_resolve/late.rs`.
             ast::ExprKind::Path(None, path)
index 00152878d6d9bef999b1cb685d0d20fa44c85c2d..c4fb0cf5b28dc6bdb5bfc98eeee6ea5852034fbb 100644 (file)
 // function, then we should explore its block to check for codes that
 // may need to be marked as live.
 fn should_explore(tcx: TyCtxt<'_>, hir_id: hir::HirId) -> bool {
-    match tcx.hir().find(hir_id) {
+    matches!(
+        tcx.hir().find(hir_id),
         Some(
             Node::Item(..)
-            | Node::ImplItem(..)
-            | Node::ForeignItem(..)
-            | Node::TraitItem(..)
-            | Node::Variant(..)
-            | Node::AnonConst(..)
-            | Node::Pat(..),
-        ) => true,
-        _ => false,
-    }
+                | Node::ImplItem(..)
+                | Node::ForeignItem(..)
+                | Node::TraitItem(..)
+                | Node::Variant(..)
+                | Node::AnonConst(..)
+                | Node::Pat(..),
+        )
+    )
 }
 
 struct MarkSymbolVisitor<'tcx> {
@@ -500,16 +500,16 @@ struct DeadVisitor<'tcx> {
 
 impl DeadVisitor<'tcx> {
     fn should_warn_about_item(&mut self, item: &hir::Item<'_>) -> bool {
-        let should_warn = match item.kind {
+        let should_warn = matches!(
+            item.kind,
             hir::ItemKind::Static(..)
-            | hir::ItemKind::Const(..)
-            | hir::ItemKind::Fn(..)
-            | hir::ItemKind::TyAlias(..)
-            | hir::ItemKind::Enum(..)
-            | hir::ItemKind::Struct(..)
-            | hir::ItemKind::Union(..) => true,
-            _ => false,
-        };
+                | hir::ItemKind::Const(..)
+                | hir::ItemKind::Fn(..)
+                | hir::ItemKind::TyAlias(..)
+                | hir::ItemKind::Enum(..)
+                | hir::ItemKind::Struct(..)
+                | hir::ItemKind::Union(..)
+        );
         should_warn && !self.symbol_is_live(item.hir_id)
     }
 
index 86ce35c6d9909df219c04dd705e187d41c02704f..fcea1b29ec367528f47b0d429bd3694caa1a47b8 100644 (file)
@@ -367,10 +367,7 @@ fn visit_arm(&mut self, arm: &'tcx hir::Arm<'tcx>) {
     }
 
     fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) {
-        let is_shorthand = match param.pat.kind {
-            rustc_hir::PatKind::Struct(..) => true,
-            _ => false,
-        };
+        let is_shorthand = matches!(param.pat.kind, rustc_hir::PatKind::Struct(..));
         param.pat.each_binding(|_bm, hir_id, _x, ident| {
             let var = if is_shorthand {
                 Local(LocalInfo { id: hir_id, name: ident.name, is_shorthand: true })
@@ -1385,7 +1382,7 @@ fn check_place(&mut self, expr: &'tcx Expr<'tcx>) {
 
     fn should_warn(&self, var: Variable) -> Option<String> {
         let name = self.ir.variable_name(var);
-        if name == kw::Invalid {
+        if name == kw::Empty {
             return None;
         }
         let name: &str = &name.as_str();
index 3b4249a93e1fbc79f18b9a247015e4bacf37d8d7..1bcfdf0faf66a8850000c99443a9daf909090507 100644 (file)
@@ -842,11 +842,9 @@ fn visit_macro_def(&mut self, md: &'tcx hir::MacroDef<'tcx>) {
         let macro_module_def_id =
             ty::DefIdTree::parent(self.tcx, self.tcx.hir().local_def_id(md.hir_id).to_def_id())
                 .unwrap();
-        // FIXME(#71104) Should really be using just `as_local_hir_id` but
-        // some `DefId` do not seem to have a corresponding HirId.
         let hir_id = macro_module_def_id
             .as_local()
-            .and_then(|def_id| self.tcx.hir().opt_local_def_id_to_hir_id(def_id));
+            .map(|def_id| self.tcx.hir().local_def_id_to_hir_id(def_id));
         let mut module_id = match hir_id {
             Some(module_id) if self.tcx.hir().is_hir_id_module(module_id) => module_id,
             // `module_id` doesn't correspond to a `mod`, return early (#63164, #65252).
@@ -959,7 +957,7 @@ fn check_field(
         in_update_syntax: bool,
     ) {
         // definition of the field
-        let ident = Ident::new(kw::Invalid, use_ctxt);
+        let ident = Ident::new(kw::Empty, use_ctxt);
         let current_hir = self.current_item.unwrap();
         let def_id = self.tcx.adjust_ident_and_get_scope(ident, def.did, current_hir).1;
         if !def.is_enum() && !field.vis.is_accessible_from(def_id, self.tcx) {
index 09e5dc857a7511320e552b7f5c40ade65b0b1636..ff52fdab19c50775f25b8e763faa5aff2c8d4732 100644 (file)
@@ -60,9 +60,8 @@ pub struct DepNode<K> {
     // * When a `DepNode::construct` is called, `arg.to_fingerprint()`
     //   is responsible for calling `OnDiskCache::store_foreign_def_id_hash`
     //   if needed
-    // * When a `DepNode` is loaded from the `PreviousDepGraph`,
-    //   then `PreviousDepGraph::index_to_node` is responsible for calling
-    //   `tcx.register_reused_dep_path_hash`
+    // * When we serialize the on-disk cache, `OnDiskCache::serialize` is
+    //   responsible for calling `DepGraph::register_reused_dep_nodes`.
     //
     // FIXME: Enforce this by preventing manual construction of `DefNode`
     // (e.g. add a `_priv: ()` field)
index 956d476d973ef89013c342efb5d44b3bc4267f9d..605d7ae4af67832eae5f495fad624add4ce0811f 100644 (file)
@@ -3,7 +3,7 @@
 use rustc_data_structures::profiling::QueryInvocationId;
 use rustc_data_structures::sharded::{self, Sharded};
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
-use rustc_data_structures::sync::{AtomicU32, AtomicU64, Lock, Lrc, Ordering};
+use rustc_data_structures::sync::{AtomicU32, AtomicU64, Lock, LockGuard, Lrc, Ordering};
 use rustc_data_structures::unlikely;
 use rustc_errors::Diagnostic;
 use rustc_index::vec::{Idx, IndexVec};
@@ -15,6 +15,7 @@
 use std::hash::Hash;
 use std::marker::PhantomData;
 use std::mem;
+use std::ops::Range;
 use std::sync::atomic::Ordering::Relaxed;
 
 use super::debug::EdgeFilter;
@@ -68,7 +69,7 @@ struct DepGraphData<K: DepKind> {
     /// The new encoding of the dependency graph, optimized for red/green
     /// tracking. The `current` field is the dependency graph of only the
     /// current compilation session: We don't merge the previous dep-graph into
-    /// current one anymore.
+    /// current one anymore, but we do reference shared data to save space.
     current: CurrentDepGraph<K>,
 
     /// The dep-graph from the previous compilation session. It contains all
@@ -134,17 +135,61 @@ pub fn is_fully_enabled(&self) -> bool {
     }
 
     pub fn query(&self) -> DepGraphQuery<K> {
-        let data = self.data.as_ref().unwrap().current.data.lock();
-        let nodes: Vec<_> = data.iter().map(|n| n.node).collect();
-        let mut edges = Vec::new();
-        for (from, edge_targets) in data.iter().map(|d| (d.node, &d.edges)) {
-            for &edge_target in edge_targets.iter() {
-                let to = data[edge_target].node;
-                edges.push((from, to));
+        let data = self.data.as_ref().unwrap();
+        let previous = &data.previous;
+
+        // Note locking order: `prev_index_to_index`, then `data`.
+        let prev_index_to_index = data.current.prev_index_to_index.lock();
+        let data = data.current.data.lock();
+        let node_count = data.hybrid_indices.len();
+        let edge_count = self.edge_count(&data);
+
+        let mut nodes = Vec::with_capacity(node_count);
+        let mut edge_list_indices = Vec::with_capacity(node_count);
+        let mut edge_list_data = Vec::with_capacity(edge_count);
+
+        // See `serialize` for notes on the approach used here.
+
+        edge_list_data.extend(data.unshared_edges.iter().map(|i| i.index()));
+
+        for &hybrid_index in data.hybrid_indices.iter() {
+            match hybrid_index.into() {
+                HybridIndex::New(new_index) => {
+                    nodes.push(data.new.nodes[new_index]);
+                    let edges = &data.new.edges[new_index];
+                    edge_list_indices.push((edges.start.index(), edges.end.index()));
+                }
+                HybridIndex::Red(red_index) => {
+                    nodes.push(previous.index_to_node(data.red.node_indices[red_index]));
+                    let edges = &data.red.edges[red_index];
+                    edge_list_indices.push((edges.start.index(), edges.end.index()));
+                }
+                HybridIndex::LightGreen(lg_index) => {
+                    nodes.push(previous.index_to_node(data.light_green.node_indices[lg_index]));
+                    let edges = &data.light_green.edges[lg_index];
+                    edge_list_indices.push((edges.start.index(), edges.end.index()));
+                }
+                HybridIndex::DarkGreen(prev_index) => {
+                    nodes.push(previous.index_to_node(prev_index));
+
+                    let edges_iter = previous
+                        .edge_targets_from(prev_index)
+                        .iter()
+                        .map(|&dst| prev_index_to_index[dst].unwrap().index());
+
+                    let start = edge_list_data.len();
+                    edge_list_data.extend(edges_iter);
+                    let end = edge_list_data.len();
+                    edge_list_indices.push((start, end));
+                }
             }
         }
 
-        DepGraphQuery::new(&nodes[..], &edges[..])
+        debug_assert_eq!(nodes.len(), node_count);
+        debug_assert_eq!(edge_list_indices.len(), node_count);
+        debug_assert_eq!(edge_list_data.len(), edge_count);
+
+        DepGraphQuery::new(&nodes[..], &edge_list_indices[..], &edge_list_data[..])
     }
 
     pub fn assert_ignored(&self) {
@@ -201,7 +246,6 @@ pub fn with_task<Ctxt: DepContext<DepKind = K>, A, R>(
             key,
             cx,
             arg,
-            false,
             task,
             |_key| {
                 Some(TaskDeps {
@@ -212,7 +256,6 @@ pub fn with_task<Ctxt: DepContext<DepKind = K>, A, R>(
                     phantom_data: PhantomData,
                 })
             },
-            |data, key, fingerprint, task| data.complete_task(key, task.unwrap(), fingerprint),
             hash_result,
         )
     }
@@ -222,66 +265,69 @@ fn with_task_impl<Ctxt: DepContext<DepKind = K>, A, R>(
         key: DepNode<K>,
         cx: Ctxt,
         arg: A,
-        no_tcx: bool,
         task: fn(Ctxt, A) -> R,
         create_task: fn(DepNode<K>) -> Option<TaskDeps<K>>,
-        finish_task_and_alloc_depnode: fn(
-            &CurrentDepGraph<K>,
-            DepNode<K>,
-            Fingerprint,
-            Option<TaskDeps<K>>,
-        ) -> DepNodeIndex,
         hash_result: impl FnOnce(&mut Ctxt::StableHashingContext, &R) -> Option<Fingerprint>,
     ) -> (R, DepNodeIndex) {
         if let Some(ref data) = self.data {
             let task_deps = create_task(key).map(Lock::new);
+            let result = K::with_deps(task_deps.as_ref(), || task(cx, arg));
+            let edges = task_deps.map_or_else(|| smallvec![], |lock| lock.into_inner().reads);
 
-            // In incremental mode, hash the result of the task. We don't
-            // do anything with the hash yet, but we are computing it
-            // anyway so that
-            //  - we make sure that the infrastructure works and
-            //  - we can get an idea of the runtime cost.
             let mut hcx = cx.create_stable_hashing_context();
-
-            let result = if no_tcx {
-                task(cx, arg)
-            } else {
-                K::with_deps(task_deps.as_ref(), || task(cx, arg))
-            };
-
             let current_fingerprint = hash_result(&mut hcx, &result);
 
-            let dep_node_index = finish_task_and_alloc_depnode(
-                &data.current,
-                key,
-                current_fingerprint.unwrap_or(Fingerprint::ZERO),
-                task_deps.map(|lock| lock.into_inner()),
-            );
-
             let print_status = cfg!(debug_assertions) && cx.debug_dep_tasks();
 
-            // Determine the color of the new DepNode.
-            if let Some(prev_index) = data.previous.node_to_index_opt(&key) {
-                let prev_fingerprint = data.previous.fingerprint_by_index(prev_index);
-
-                let color = if let Some(current_fingerprint) = current_fingerprint {
-                    if current_fingerprint == prev_fingerprint {
+            // Intern the new `DepNode`.
+            let dep_node_index = if let Some(prev_index) = data.previous.node_to_index_opt(&key) {
+                // Determine the color and index of the new `DepNode`.
+                let (color, dep_node_index) = if let Some(current_fingerprint) = current_fingerprint
+                {
+                    if current_fingerprint == data.previous.fingerprint_by_index(prev_index) {
                         if print_status {
                             eprintln!("[task::green] {:?}", key);
                         }
-                        DepNodeColor::Green(dep_node_index)
+
+                        // This is a light green node: it existed in the previous compilation,
+                        // its query was re-executed, and it has the same result as before.
+                        let dep_node_index =
+                            data.current.intern_light_green_node(&data.previous, prev_index, edges);
+
+                        (DepNodeColor::Green(dep_node_index), dep_node_index)
                     } else {
                         if print_status {
                             eprintln!("[task::red] {:?}", key);
                         }
-                        DepNodeColor::Red
+
+                        // This is a red node: it existed in the previous compilation, its query
+                        // was re-executed, but it has a different result from before.
+                        let dep_node_index = data.current.intern_red_node(
+                            &data.previous,
+                            prev_index,
+                            edges,
+                            current_fingerprint,
+                        );
+
+                        (DepNodeColor::Red, dep_node_index)
                     }
                 } else {
                     if print_status {
                         eprintln!("[task::unknown] {:?}", key);
                     }
-                    // Mark the node as Red if we can't hash the result
-                    DepNodeColor::Red
+
+                    // This is a red node, effectively: it existed in the previous compilation
+                    // session, its query was re-executed, but it doesn't compute a result hash
+                    // (i.e. it represents a `no_hash` query), so we have no way of determining
+                    // whether or not the result was the same as before.
+                    let dep_node_index = data.current.intern_red_node(
+                        &data.previous,
+                        prev_index,
+                        edges,
+                        Fingerprint::ZERO,
+                    );
+
+                    (DepNodeColor::Red, dep_node_index)
                 };
 
                 debug_assert!(
@@ -292,12 +338,27 @@ fn with_task_impl<Ctxt: DepContext<DepKind = K>, A, R>(
                 );
 
                 data.colors.insert(prev_index, color);
-            } else if print_status {
-                eprintln!("[task::new] {:?}", key);
-            }
+                dep_node_index
+            } else {
+                if print_status {
+                    eprintln!("[task::new] {:?}", key);
+                }
+
+                // This is a new node: it didn't exist in the previous compilation session.
+                data.current.intern_new_node(
+                    &data.previous,
+                    key,
+                    edges,
+                    current_fingerprint.unwrap_or(Fingerprint::ZERO),
+                )
+            };
 
             (result, dep_node_index)
         } else {
+            // Incremental compilation is turned off. We just execute the task
+            // without tracking. We still provide a dep-node index that uniquely
+            // identifies the task so that we have a cheap way of referring to
+            // the query for self-profiling.
             (task(cx, arg), self.next_virtual_depnode_index())
         }
     }
@@ -308,13 +369,36 @@ pub fn with_anon_task<OP, R>(&self, dep_kind: K, op: OP) -> (R, DepNodeIndex)
     where
         OP: FnOnce() -> R,
     {
+        debug_assert!(!dep_kind.is_eval_always());
+
         if let Some(ref data) = self.data {
             let task_deps = Lock::new(TaskDeps::default());
-
             let result = K::with_deps(Some(&task_deps), op);
             let task_deps = task_deps.into_inner();
 
-            let dep_node_index = data.current.complete_anon_task(dep_kind, task_deps);
+            // The dep node indices are hashed here instead of hashing the dep nodes of the
+            // dependencies. These indices may refer to different nodes per session, but this isn't
+            // a problem here because we that ensure the final dep node hash is per session only by
+            // combining it with the per session random number `anon_id_seed`. This hash only need
+            // to map the dependencies to a single value on a per session basis.
+            let mut hasher = StableHasher::new();
+            task_deps.reads.hash(&mut hasher);
+
+            let target_dep_node = DepNode {
+                kind: dep_kind,
+                // Fingerprint::combine() is faster than sending Fingerprint
+                // through the StableHasher (at least as long as StableHasher
+                // is so slow).
+                hash: data.current.anon_id_seed.combine(hasher.finish()).into(),
+            };
+
+            let dep_node_index = data.current.intern_new_node(
+                &data.previous,
+                target_dep_node,
+                task_deps.reads,
+                Fingerprint::ZERO,
+            );
+
             (result, dep_node_index)
         } else {
             (op(), self.next_virtual_depnode_index())
@@ -331,69 +415,106 @@ pub fn with_eval_always_task<Ctxt: DepContext<DepKind = K>, A, R>(
         task: fn(Ctxt, A) -> R,
         hash_result: impl FnOnce(&mut Ctxt::StableHashingContext, &R) -> Option<Fingerprint>,
     ) -> (R, DepNodeIndex) {
-        self.with_task_impl(
-            key,
-            cx,
-            arg,
-            false,
-            task,
-            |_| None,
-            |data, key, fingerprint, _| data.alloc_node(key, smallvec![], fingerprint),
-            hash_result,
-        )
+        self.with_task_impl(key, cx, arg, task, |_| None, hash_result)
     }
 
     #[inline]
-    pub fn read(&self, v: DepNode<K>) {
+    pub fn read_index(&self, dep_node_index: DepNodeIndex) {
         if let Some(ref data) = self.data {
-            let map = data.current.node_to_node_index.get_shard_by_value(&v).lock();
-            if let Some(dep_node_index) = map.get(&v).copied() {
-                std::mem::drop(map);
-                data.read_index(dep_node_index);
-            } else {
-                panic!("DepKind {:?} should be pre-allocated but isn't.", v.kind)
-            }
+            K::read_deps(|task_deps| {
+                if let Some(task_deps) = task_deps {
+                    let mut task_deps = task_deps.lock();
+                    let task_deps = &mut *task_deps;
+                    if cfg!(debug_assertions) {
+                        data.current.total_read_count.fetch_add(1, Relaxed);
+                    }
+
+                    // As long as we only have a low number of reads we can avoid doing a hash
+                    // insert and potentially allocating/reallocating the hashmap
+                    let new_read = if task_deps.reads.len() < TASK_DEPS_READS_CAP {
+                        task_deps.reads.iter().all(|other| *other != dep_node_index)
+                    } else {
+                        task_deps.read_set.insert(dep_node_index)
+                    };
+                    if new_read {
+                        task_deps.reads.push(dep_node_index);
+                        if task_deps.reads.len() == TASK_DEPS_READS_CAP {
+                            // Fill `read_set` with what we have so far so we can use the hashset
+                            // next time
+                            task_deps.read_set.extend(task_deps.reads.iter().copied());
+                        }
+
+                        #[cfg(debug_assertions)]
+                        {
+                            if let Some(target) = task_deps.node {
+                                if let Some(ref forbidden_edge) = data.current.forbidden_edge {
+                                    let src = self.dep_node_of(dep_node_index);
+                                    if forbidden_edge.test(&src, &target) {
+                                        panic!("forbidden edge {:?} -> {:?} created", src, target)
+                                    }
+                                }
+                            }
+                        }
+                    } else if cfg!(debug_assertions) {
+                        data.current.total_duplicate_read_count.fetch_add(1, Relaxed);
+                    }
+                }
+            })
         }
     }
 
     #[inline]
-    pub fn read_index(&self, dep_node_index: DepNodeIndex) {
-        if let Some(ref data) = self.data {
-            data.read_index(dep_node_index);
-        }
+    pub fn dep_node_index_of(&self, dep_node: &DepNode<K>) -> DepNodeIndex {
+        self.dep_node_index_of_opt(dep_node).unwrap()
     }
 
     #[inline]
-    pub fn dep_node_index_of(&self, dep_node: &DepNode<K>) -> DepNodeIndex {
-        self.data
-            .as_ref()
-            .unwrap()
-            .current
-            .node_to_node_index
-            .get_shard_by_value(dep_node)
-            .lock()
-            .get(dep_node)
-            .cloned()
-            .unwrap()
+    pub fn dep_node_index_of_opt(&self, dep_node: &DepNode<K>) -> Option<DepNodeIndex> {
+        let data = self.data.as_ref().unwrap();
+        let current = &data.current;
+
+        if let Some(prev_index) = data.previous.node_to_index_opt(dep_node) {
+            current.prev_index_to_index.lock()[prev_index]
+        } else {
+            current.new_node_to_index.get_shard_by_value(dep_node).lock().get(dep_node).copied()
+        }
     }
 
     #[inline]
     pub fn dep_node_exists(&self, dep_node: &DepNode<K>) -> bool {
-        if let Some(ref data) = self.data {
-            data.current
-                .node_to_node_index
-                .get_shard_by_value(&dep_node)
-                .lock()
-                .contains_key(dep_node)
-        } else {
-            false
+        self.data.is_some() && self.dep_node_index_of_opt(dep_node).is_some()
+    }
+
+    #[inline]
+    pub fn dep_node_of(&self, dep_node_index: DepNodeIndex) -> DepNode<K> {
+        let data = self.data.as_ref().unwrap();
+        let previous = &data.previous;
+        let data = data.current.data.lock();
+
+        match data.hybrid_indices[dep_node_index].into() {
+            HybridIndex::New(new_index) => data.new.nodes[new_index],
+            HybridIndex::Red(red_index) => previous.index_to_node(data.red.node_indices[red_index]),
+            HybridIndex::LightGreen(light_green_index) => {
+                previous.index_to_node(data.light_green.node_indices[light_green_index])
+            }
+            HybridIndex::DarkGreen(prev_index) => previous.index_to_node(prev_index),
         }
     }
 
     #[inline]
     pub fn fingerprint_of(&self, dep_node_index: DepNodeIndex) -> Fingerprint {
-        let data = self.data.as_ref().expect("dep graph enabled").current.data.lock();
-        data[dep_node_index].fingerprint
+        let data = self.data.as_ref().unwrap();
+        let previous = &data.previous;
+        let data = data.current.data.lock();
+
+        match data.hybrid_indices[dep_node_index].into() {
+            HybridIndex::New(new_index) => data.new.fingerprints[new_index],
+            HybridIndex::Red(red_index) => data.red.fingerprints[red_index],
+            HybridIndex::LightGreen(light_green_index) => {
+                previous.fingerprint_by_index(data.light_green.node_indices[light_green_index])
+            }
+            HybridIndex::DarkGreen(prev_index) => previous.fingerprint_by_index(prev_index),
+        }
     }
 
     pub fn prev_fingerprint_of(&self, dep_node: &DepNode<K>) -> Option<Fingerprint> {
@@ -443,30 +564,95 @@ pub fn edge_deduplication_data(&self) -> Option<(u64, u64)> {
         }
     }
 
-    pub fn serialize(&self) -> SerializedDepGraph<K> {
-        let data = self.data.as_ref().unwrap().current.data.lock();
+    fn edge_count(&self, node_data: &LockGuard<'_, DepNodeData<K>>) -> usize {
+        let data = self.data.as_ref().unwrap();
+        let previous = &data.previous;
 
-        let fingerprints: IndexVec<SerializedDepNodeIndex, _> =
-            data.iter().map(|d| d.fingerprint).collect();
-        let nodes: IndexVec<SerializedDepNodeIndex, _> = data.iter().map(|d| d.node).collect();
+        let mut edge_count = node_data.unshared_edges.len();
 
-        let total_edge_count: usize = data.iter().map(|d| d.edges.len()).sum();
+        for &hybrid_index in node_data.hybrid_indices.iter() {
+            if let HybridIndex::DarkGreen(prev_index) = hybrid_index.into() {
+                edge_count += previous.edge_targets_from(prev_index).len()
+            }
+        }
 
-        let mut edge_list_indices = IndexVec::with_capacity(nodes.len());
-        let mut edge_list_data = Vec::with_capacity(total_edge_count);
+        edge_count
+    }
 
-        for (current_dep_node_index, edges) in data.iter_enumerated().map(|(i, d)| (i, &d.edges)) {
-            let start = edge_list_data.len() as u32;
-            // This should really just be a memcpy :/
-            edge_list_data.extend(edges.iter().map(|i| SerializedDepNodeIndex::new(i.index())));
-            let end = edge_list_data.len() as u32;
+    pub fn serialize(&self) -> SerializedDepGraph<K> {
+        type SDNI = SerializedDepNodeIndex;
 
-            debug_assert_eq!(current_dep_node_index.index(), edge_list_indices.len());
-            edge_list_indices.push((start, end));
+        let data = self.data.as_ref().unwrap();
+        let previous = &data.previous;
+
+        // Note locking order: `prev_index_to_index`, then `data`.
+        let prev_index_to_index = data.current.prev_index_to_index.lock();
+        let data = data.current.data.lock();
+        let node_count = data.hybrid_indices.len();
+        let edge_count = self.edge_count(&data);
+
+        let mut nodes = IndexVec::with_capacity(node_count);
+        let mut fingerprints = IndexVec::with_capacity(node_count);
+        let mut edge_list_indices = IndexVec::with_capacity(node_count);
+        let mut edge_list_data = Vec::with_capacity(edge_count);
+
+        // `rustc_middle::ty::query::OnDiskCache` expects nodes to be in
+        // `DepNodeIndex` order. The edges in `edge_list_data`, on the other
+        // hand, don't need to be in a particular order, as long as each node
+        // can reference its edges as a contiguous range within it. This is why
+        // we're able to copy `unshared_edges` directly into `edge_list_data`.
+        // It meets the above requirements, and each non-dark-green node already
+        // knows the range of edges to reference within it, which they'll push
+        // onto `edge_list_indices`. Dark green nodes, however, don't have their
+        // edges in `unshared_edges`, so need to add them to `edge_list_data`.
+
+        edge_list_data.extend(data.unshared_edges.iter().map(|i| SDNI::new(i.index())));
+
+        for &hybrid_index in data.hybrid_indices.iter() {
+            match hybrid_index.into() {
+                HybridIndex::New(i) => {
+                    let new = &data.new;
+                    nodes.push(new.nodes[i]);
+                    fingerprints.push(new.fingerprints[i]);
+                    let edges = &new.edges[i];
+                    edge_list_indices.push((edges.start.as_u32(), edges.end.as_u32()));
+                }
+                HybridIndex::Red(i) => {
+                    let red = &data.red;
+                    nodes.push(previous.index_to_node(red.node_indices[i]));
+                    fingerprints.push(red.fingerprints[i]);
+                    let edges = &red.edges[i];
+                    edge_list_indices.push((edges.start.as_u32(), edges.end.as_u32()));
+                }
+                HybridIndex::LightGreen(i) => {
+                    let lg = &data.light_green;
+                    nodes.push(previous.index_to_node(lg.node_indices[i]));
+                    fingerprints.push(previous.fingerprint_by_index(lg.node_indices[i]));
+                    let edges = &lg.edges[i];
+                    edge_list_indices.push((edges.start.as_u32(), edges.end.as_u32()));
+                }
+                HybridIndex::DarkGreen(prev_index) => {
+                    nodes.push(previous.index_to_node(prev_index));
+                    fingerprints.push(previous.fingerprint_by_index(prev_index));
+
+                    let edges_iter = previous
+                        .edge_targets_from(prev_index)
+                        .iter()
+                        .map(|&dst| prev_index_to_index[dst].as_ref().unwrap());
+
+                    let start = edge_list_data.len() as u32;
+                    edge_list_data.extend(edges_iter.map(|i| SDNI::new(i.index())));
+                    let end = edge_list_data.len() as u32;
+                    edge_list_indices.push((start, end));
+                }
+            }
         }
 
+        debug_assert_eq!(nodes.len(), node_count);
+        debug_assert_eq!(fingerprints.len(), node_count);
+        debug_assert_eq!(edge_list_indices.len(), node_count);
+        debug_assert_eq!(edge_list_data.len(), edge_count);
         debug_assert!(edge_list_data.len() <= u32::MAX as usize);
-        debug_assert_eq!(edge_list_data.len(), total_edge_count);
 
         SerializedDepGraph { nodes, fingerprints, edge_list_indices, edge_list_data }
     }
@@ -540,31 +726,22 @@ fn try_mark_previous_green<Ctxt: DepContext<DepKind = K>>(
 
         #[cfg(not(parallel_compiler))]
         {
-            debug_assert!(
-                !data
-                    .current
-                    .node_to_node_index
-                    .get_shard_by_value(dep_node)
-                    .lock()
-                    .contains_key(dep_node)
-            );
+            debug_assert!(!self.dep_node_exists(dep_node));
             debug_assert!(data.colors.get(prev_dep_node_index).is_none());
         }
 
         // We never try to mark eval_always nodes as green
         debug_assert!(!dep_node.kind.is_eval_always());
 
-        data.previous.debug_assert_eq(prev_dep_node_index, *dep_node);
+        debug_assert_eq!(data.previous.index_to_node(prev_dep_node_index), *dep_node);
 
         let prev_deps = data.previous.edge_targets_from(prev_dep_node_index);
 
-        let mut current_deps = SmallVec::new();
-
         for &dep_dep_node_index in prev_deps {
             let dep_dep_node_color = data.colors.get(dep_dep_node_index);
 
             match dep_dep_node_color {
-                Some(DepNodeColor::Green(node_index)) => {
+                Some(DepNodeColor::Green(_)) => {
                     // This dependency has been marked as green before, we are
                     // still fine and can continue with checking the other
                     // dependencies.
@@ -572,9 +749,8 @@ fn try_mark_previous_green<Ctxt: DepContext<DepKind = K>>(
                         "try_mark_previous_green({:?}) --- found dependency {:?} to \
                             be immediately green",
                         dep_node,
-                        data.previous.debug_dep_node(dep_dep_node_index),
+                        data.previous.index_to_node(dep_dep_node_index)
                     );
-                    current_deps.push(node_index);
                 }
                 Some(DepNodeColor::Red) => {
                     // We found a dependency the value of which has changed
@@ -585,12 +761,12 @@ fn try_mark_previous_green<Ctxt: DepContext<DepKind = K>>(
                         "try_mark_previous_green({:?}) - END - dependency {:?} was \
                             immediately red",
                         dep_node,
-                        data.previous.debug_dep_node(dep_dep_node_index)
+                        data.previous.index_to_node(dep_dep_node_index)
                     );
                     return None;
                 }
                 None => {
-                    let dep_dep_node = &data.previous.index_to_node(dep_dep_node_index, tcx);
+                    let dep_dep_node = &data.previous.index_to_node(dep_dep_node_index);
 
                     // We don't know the state of this dependency. If it isn't
                     // an eval_always node, let's try to mark it green recursively.
@@ -607,13 +783,12 @@ fn try_mark_previous_green<Ctxt: DepContext<DepKind = K>>(
                             dep_dep_node_index,
                             dep_dep_node,
                         );
-                        if let Some(node_index) = node_index {
+                        if node_index.is_some() {
                             debug!(
                                 "try_mark_previous_green({:?}) --- managed to MARK \
                                     dependency {:?} as green",
                                 dep_node, dep_dep_node
                             );
-                            current_deps.push(node_index);
                             continue;
                         }
                     }
@@ -628,13 +803,12 @@ fn try_mark_previous_green<Ctxt: DepContext<DepKind = K>>(
                         let dep_dep_node_color = data.colors.get(dep_dep_node_index);
 
                         match dep_dep_node_color {
-                            Some(DepNodeColor::Green(node_index)) => {
+                            Some(DepNodeColor::Green(_)) => {
                                 debug!(
                                     "try_mark_previous_green({:?}) --- managed to \
                                         FORCE dependency {:?} to green",
                                     dep_node, dep_dep_node
                                 );
-                                current_deps.push(node_index);
                             }
                             Some(DepNodeColor::Red) => {
                                 debug!(
@@ -690,13 +864,9 @@ fn try_mark_previous_green<Ctxt: DepContext<DepKind = K>>(
         // There may be multiple threads trying to mark the same dep node green concurrently
 
         let dep_node_index = {
-            // Copy the fingerprint from the previous graph,
-            // so we don't have to recompute it
-            let fingerprint = data.previous.fingerprint_by_index(prev_dep_node_index);
-
             // We allocating an entry for the node in the current dependency graph and
             // adding all the appropriate edges imported from the previous graph
-            data.current.intern_node(*dep_node, current_deps, fingerprint)
+            data.current.intern_dark_green_node(&data.previous, prev_dep_node_index)
         };
 
         // ... emitting any stored diagnostic ...
@@ -801,7 +971,7 @@ pub fn exec_cache_promotions<Ctxt: DepContext<DepKind = K>>(&self, tcx: Ctxt) {
         for prev_index in data.colors.values.indices() {
             match data.colors.get(prev_index) {
                 Some(DepNodeColor::Green(_)) => {
-                    let dep_node = data.previous.index_to_node(prev_index, tcx);
+                    let dep_node = data.previous.index_to_node(prev_index);
                     tcx.try_load_from_on_disk_cache(&dep_node);
                 }
                 None | Some(DepNodeColor::Red) => {
@@ -813,6 +983,20 @@ pub fn exec_cache_promotions<Ctxt: DepContext<DepKind = K>>(&self, tcx: Ctxt) {
         }
     }
 
+    // Register reused dep nodes (i.e. nodes we've marked red or green) with the context.
+    pub fn register_reused_dep_nodes<Ctxt: DepContext<DepKind = K>>(&self, tcx: Ctxt) {
+        let data = self.data.as_ref().unwrap();
+        for prev_index in data.colors.values.indices() {
+            match data.colors.get(prev_index) {
+                Some(DepNodeColor::Red) | Some(DepNodeColor::Green(_)) => {
+                    let dep_node = data.previous.index_to_node(prev_index);
+                    tcx.register_reused_dep_node(&dep_node);
+                }
+                None => {}
+            }
+        }
+    }
+
     fn next_virtual_depnode_index(&self) -> DepNodeIndex {
         let index = self.virtual_dep_node_index.fetch_add(1, Relaxed);
         DepNodeIndex::from_u32(index)
@@ -857,31 +1041,234 @@ pub struct WorkProduct {
     pub saved_file: Option<String>,
 }
 
-#[derive(Clone)]
+// The maximum value of the follow index types leaves the upper two bits unused
+// so that we can store multiple index types in `CompressedHybridIndex`, and use
+// those bits to encode which index type it contains.
+
+// Index type for `NewDepNodeData`.
+rustc_index::newtype_index! {
+    struct NewDepNodeIndex {
+        MAX = 0x7FFF_FFFF
+    }
+}
+
+// Index type for `RedDepNodeData`.
+rustc_index::newtype_index! {
+    struct RedDepNodeIndex {
+        MAX = 0x7FFF_FFFF
+    }
+}
+
+// Index type for `LightGreenDepNodeData`.
+rustc_index::newtype_index! {
+    struct LightGreenDepNodeIndex {
+        MAX = 0x7FFF_FFFF
+    }
+}
+
+/// Compressed representation of `HybridIndex` enum. Bits unused by the
+/// contained index types are used to encode which index type it contains.
+#[derive(Copy, Clone)]
+struct CompressedHybridIndex(u32);
+
+impl CompressedHybridIndex {
+    const NEW_TAG: u32 = 0b0000_0000_0000_0000_0000_0000_0000_0000;
+    const RED_TAG: u32 = 0b0100_0000_0000_0000_0000_0000_0000_0000;
+    const LIGHT_GREEN_TAG: u32 = 0b1000_0000_0000_0000_0000_0000_0000_0000;
+    const DARK_GREEN_TAG: u32 = 0b1100_0000_0000_0000_0000_0000_0000_0000;
+
+    const TAG_MASK: u32 = 0b1100_0000_0000_0000_0000_0000_0000_0000;
+    const INDEX_MASK: u32 = !Self::TAG_MASK;
+}
+
+impl From<NewDepNodeIndex> for CompressedHybridIndex {
+    #[inline]
+    fn from(index: NewDepNodeIndex) -> Self {
+        CompressedHybridIndex(Self::NEW_TAG | index.as_u32())
+    }
+}
+
+impl From<RedDepNodeIndex> for CompressedHybridIndex {
+    #[inline]
+    fn from(index: RedDepNodeIndex) -> Self {
+        CompressedHybridIndex(Self::RED_TAG | index.as_u32())
+    }
+}
+
+impl From<LightGreenDepNodeIndex> for CompressedHybridIndex {
+    #[inline]
+    fn from(index: LightGreenDepNodeIndex) -> Self {
+        CompressedHybridIndex(Self::LIGHT_GREEN_TAG | index.as_u32())
+    }
+}
+
+impl From<SerializedDepNodeIndex> for CompressedHybridIndex {
+    #[inline]
+    fn from(index: SerializedDepNodeIndex) -> Self {
+        CompressedHybridIndex(Self::DARK_GREEN_TAG | index.as_u32())
+    }
+}
+
+/// Contains an index into one of several node data collections. Elsewhere, we
+/// store `CompressedHyridIndex` instead of this to save space, but convert to
+/// this type during processing to take advantage of the enum match ergonomics.
+enum HybridIndex {
+    New(NewDepNodeIndex),
+    Red(RedDepNodeIndex),
+    LightGreen(LightGreenDepNodeIndex),
+    DarkGreen(SerializedDepNodeIndex),
+}
+
+impl From<CompressedHybridIndex> for HybridIndex {
+    #[inline]
+    fn from(hybrid_index: CompressedHybridIndex) -> Self {
+        let index = hybrid_index.0 & CompressedHybridIndex::INDEX_MASK;
+
+        match hybrid_index.0 & CompressedHybridIndex::TAG_MASK {
+            CompressedHybridIndex::NEW_TAG => HybridIndex::New(NewDepNodeIndex::from_u32(index)),
+            CompressedHybridIndex::RED_TAG => HybridIndex::Red(RedDepNodeIndex::from_u32(index)),
+            CompressedHybridIndex::LIGHT_GREEN_TAG => {
+                HybridIndex::LightGreen(LightGreenDepNodeIndex::from_u32(index))
+            }
+            CompressedHybridIndex::DARK_GREEN_TAG => {
+                HybridIndex::DarkGreen(SerializedDepNodeIndex::from_u32(index))
+            }
+            _ => unreachable!(),
+        }
+    }
+}
+
+// Index type for `DepNodeData`'s edges.
+rustc_index::newtype_index! {
+    struct EdgeIndex { .. }
+}
+
+/// Data for nodes in the current graph, divided into different collections
+/// based on their presence in the previous graph, and if present, their color.
+/// We divide nodes this way because different types of nodes are able to share
+/// more or less data with the previous graph.
+///
+/// To enable more sharing, we distinguish between two kinds of green nodes.
+/// Light green nodes are nodes in the previous graph that have been marked
+/// green because we re-executed their queries and the results were the same as
+/// in the previous session. Dark green nodes are nodes in the previous graph
+/// that have been marked green because we were able to mark all of their
+/// dependencies green.
+///
+/// Both light and dark green nodes can share the dep node and fingerprint with
+/// the previous graph, but for light green nodes, we can't be sure that the
+/// edges may be shared without comparing them against the previous edges, so we
+/// store them directly (an approach in which we compare edges with the previous
+/// edges to see if they can be shared was evaluated, but was not found to be
+/// very profitable).
+///
+/// For dark green nodes, we can share everything with the previous graph, which
+/// is why the `HybridIndex::DarkGreen` enum variant contains the index of the
+/// node in the previous graph, and why we don't have a separate collection for
+/// dark green node data--the collection is the `PreviousDepGraph` itself.
+///
+/// (Note that for dark green nodes, the edges in the previous graph
+/// (`SerializedDepNodeIndex`s) must be converted to edges in the current graph
+/// (`DepNodeIndex`s). `CurrentDepGraph` contains `prev_index_to_index`, which
+/// can perform this conversion. It should always be possible, as by definition,
+/// a dark green node is one whose dependencies from the previous session have
+/// all been marked green--which means `prev_index_to_index` contains them.)
+///
+/// Node data is stored in parallel vectors to eliminate the padding between
+/// elements that would be needed to satisfy alignment requirements of the
+/// structure that would contain all of a node's data. We could group tightly
+/// packing subsets of node data together and use fewer vectors, but for
+/// consistency's sake, we use separate vectors for each piece of data.
 struct DepNodeData<K> {
-    node: DepNode<K>,
-    edges: EdgesVec,
-    fingerprint: Fingerprint,
+    /// Data for nodes not in previous graph.
+    new: NewDepNodeData<K>,
+
+    /// Data for nodes in previous graph that have been marked red.
+    red: RedDepNodeData,
+
+    /// Data for nodes in previous graph that have been marked light green.
+    light_green: LightGreenDepNodeData,
+
+    // Edges for all nodes other than dark-green ones. Edges for each node
+    // occupy a contiguous region of this collection, which a node can reference
+    // using two indices. Storing edges this way rather than using an `EdgesVec`
+    // for each node reduces memory consumption by a not insignificant amount
+    // when compiling large crates. The downside is that we have to copy into
+    // this collection the edges from the `EdgesVec`s that are built up during
+    // query execution. But this is mostly balanced out by the more efficient
+    // implementation of `DepGraph::serialize` enabled by this representation.
+    unshared_edges: IndexVec<EdgeIndex, DepNodeIndex>,
+
+    /// Mapping from `DepNodeIndex` to an index into a collection above.
+    /// Indicates which of the above collections contains a node's data.
+    ///
+    /// This collection is wasteful in time and space during incr-full builds,
+    /// because for those, all nodes are new. However, the waste is relatively
+    /// small, and the maintenance cost of avoiding using this for incr-full
+    /// builds is somewhat high and prone to bugginess. It does not seem worth
+    /// it at the time of this writing, but we may want to revisit the idea.
+    hybrid_indices: IndexVec<DepNodeIndex, CompressedHybridIndex>,
+}
+
+/// Data for nodes not in previous graph. Since we cannot share any data with
+/// the previous graph, so we must store all of such a node's data here.
+struct NewDepNodeData<K> {
+    nodes: IndexVec<NewDepNodeIndex, DepNode<K>>,
+    edges: IndexVec<NewDepNodeIndex, Range<EdgeIndex>>,
+    fingerprints: IndexVec<NewDepNodeIndex, Fingerprint>,
 }
 
-/// `CurrentDepGraph` stores the dependency graph for the current session.
-/// It will be populated as we run queries or tasks.
+/// Data for nodes in previous graph that have been marked red. We can share the
+/// dep node with the previous graph, but the edges may be different, and the
+/// fingerprint is known to be different, so we store the latter two directly.
+struct RedDepNodeData {
+    node_indices: IndexVec<RedDepNodeIndex, SerializedDepNodeIndex>,
+    edges: IndexVec<RedDepNodeIndex, Range<EdgeIndex>>,
+    fingerprints: IndexVec<RedDepNodeIndex, Fingerprint>,
+}
+
+/// Data for nodes in previous graph that have been marked green because we
+/// re-executed their queries and the results were the same as in the previous
+/// session. We can share the dep node and the fingerprint with the previous
+/// graph, but the edges may be different, so we store them directly.
+struct LightGreenDepNodeData {
+    node_indices: IndexVec<LightGreenDepNodeIndex, SerializedDepNodeIndex>,
+    edges: IndexVec<LightGreenDepNodeIndex, Range<EdgeIndex>>,
+}
+
+/// `CurrentDepGraph` stores the dependency graph for the current session. It
+/// will be populated as we run queries or tasks. We never remove nodes from the
+/// graph: they are only added.
 ///
-/// The nodes in it are identified by an index (`DepNodeIndex`).
-/// The data for each node is stored in its `DepNodeData`, found in the `data` field.
+/// The nodes in it are identified by a `DepNodeIndex`. Internally, this maps to
+/// a `HybridIndex`, which identifies which collection in the `data` field
+/// contains a node's data. Which collection is used for a node depends on
+/// whether the node was present in the `PreviousDepGraph`, and if so, the color
+/// of the node. Each type of node can share more or less data with the previous
+/// graph. When possible, we can store just the index of the node in the
+/// previous graph, rather than duplicating its data in our own collections.
+/// This is important, because these graph structures are some of the largest in
+/// the compiler.
 ///
-/// We never remove nodes from the graph: they are only added.
+/// For the same reason, we also avoid storing `DepNode`s more than once as map
+/// keys. The `new_node_to_index` map only contains nodes not in the previous
+/// graph, and we map nodes in the previous graph to indices via a two-step
+/// mapping. `PreviousDepGraph` maps from `DepNode` to `SerializedDepNodeIndex`,
+/// and the `prev_index_to_index` vector (which is more compact and faster than
+/// using a map) maps from `SerializedDepNodeIndex` to `DepNodeIndex`.
 ///
-/// This struct uses two locks internally. The `data` and `node_to_node_index` fields are
-/// locked separately. Operations that take a `DepNodeIndex` typically just access
-/// the data field.
+/// This struct uses three locks internally. The `data`, `new_node_to_index`,
+/// and `prev_index_to_index` fields are locked separately. Operations that take
+/// a `DepNodeIndex` typically just access the `data` field.
 ///
-/// The only operation that must manipulate both locks is adding new nodes, in which case
-/// we first acquire the `node_to_node_index` lock and then, once a new node is to be inserted,
-/// acquire the lock on `data.`
+/// We only need to manipulate at most two locks simultaneously:
+/// `new_node_to_index` and `data`, or `prev_index_to_index` and `data`. When
+/// manipulating both, we acquire `new_node_to_index` or `prev_index_to_index`
+/// first, and `data` second.
 pub(super) struct CurrentDepGraph<K> {
-    data: Lock<IndexVec<DepNodeIndex, DepNodeData<K>>>,
-    node_to_node_index: Sharded<FxHashMap<DepNode<K>, DepNodeIndex>>,
+    data: Lock<DepNodeData<K>>,
+    new_node_to_index: Sharded<FxHashMap<DepNode<K>, DepNodeIndex>>,
+    prev_index_to_index: Lock<IndexVec<SerializedDepNodeIndex, Option<DepNodeIndex>>>,
 
     /// Used to trap when a specific edge is added to the graph.
     /// This is used for debug purposes and is only active with `debug_assertions`.
@@ -930,18 +1317,63 @@ fn new(prev_graph_node_count: usize) -> CurrentDepGraph<K> {
 
         // Pre-allocate the dep node structures. We over-allocate a little so
         // that we hopefully don't have to re-allocate during this compilation
-        // session. The over-allocation is 2% plus a small constant to account
-        // for the fact that in very small crates 2% might not be enough.
-        let new_node_count_estimate = (prev_graph_node_count * 102) / 100 + 200;
+        // session. The over-allocation for new nodes is 2% plus a small
+        // constant to account for the fact that in very small crates 2% might
+        // not be enough. The allocation for red and green node data doesn't
+        // include a constant, as we don't want to allocate anything for these
+        // structures during full incremental builds, where they aren't used.
+        //
+        // These estimates are based on the distribution of node and edge counts
+        // seen in rustc-perf benchmarks, adjusted somewhat to account for the
+        // fact that these benchmarks aren't perfectly representative.
+        //
+        // FIXME Use a collection type that doesn't copy node and edge data and
+        // grow multiplicatively on reallocation. Without such a collection or
+        // solution having the same effect, there is a performance hazard here
+        // in both time and space, as growing these collections means copying a
+        // large amount of data and doubling already large buffer capacities. A
+        // solution for this will also mean that it's less important to get
+        // these estimates right.
+        let new_node_count_estimate = (prev_graph_node_count * 2) / 100 + 200;
+        let red_node_count_estimate = (prev_graph_node_count * 3) / 100;
+        let light_green_node_count_estimate = (prev_graph_node_count * 25) / 100;
+        let total_node_count_estimate = prev_graph_node_count + new_node_count_estimate;
+
+        let average_edges_per_node_estimate = 6;
+        let unshared_edge_count_estimate = average_edges_per_node_estimate
+            * (new_node_count_estimate + red_node_count_estimate + light_green_node_count_estimate);
+
+        // We store a large collection of these in `prev_index_to_index` during
+        // non-full incremental builds, and want to ensure that the element size
+        // doesn't inadvertently increase.
+        static_assert_size!(Option<DepNodeIndex>, 4);
 
         CurrentDepGraph {
-            data: Lock::new(IndexVec::with_capacity(new_node_count_estimate)),
-            node_to_node_index: Sharded::new(|| {
+            data: Lock::new(DepNodeData {
+                new: NewDepNodeData {
+                    nodes: IndexVec::with_capacity(new_node_count_estimate),
+                    edges: IndexVec::with_capacity(new_node_count_estimate),
+                    fingerprints: IndexVec::with_capacity(new_node_count_estimate),
+                },
+                red: RedDepNodeData {
+                    node_indices: IndexVec::with_capacity(red_node_count_estimate),
+                    edges: IndexVec::with_capacity(red_node_count_estimate),
+                    fingerprints: IndexVec::with_capacity(red_node_count_estimate),
+                },
+                light_green: LightGreenDepNodeData {
+                    node_indices: IndexVec::with_capacity(light_green_node_count_estimate),
+                    edges: IndexVec::with_capacity(light_green_node_count_estimate),
+                },
+                unshared_edges: IndexVec::with_capacity(unshared_edge_count_estimate),
+                hybrid_indices: IndexVec::with_capacity(total_node_count_estimate),
+            }),
+            new_node_to_index: Sharded::new(|| {
                 FxHashMap::with_capacity_and_hasher(
                     new_node_count_estimate / sharded::SHARDS,
                     Default::default(),
                 )
             }),
+            prev_index_to_index: Lock::new(IndexVec::from_elem_n(None, prev_graph_node_count)),
             anon_id_seed: stable_hasher.finish(),
             forbidden_edge,
             total_read_count: AtomicU64::new(0),
@@ -949,116 +1381,127 @@ fn new(prev_graph_node_count: usize) -> CurrentDepGraph<K> {
         }
     }
 
-    fn complete_task(
+    fn intern_new_node(
         &self,
-        node: DepNode<K>,
-        task_deps: TaskDeps<K>,
+        prev_graph: &PreviousDepGraph<K>,
+        dep_node: DepNode<K>,
+        edges: EdgesVec,
         fingerprint: Fingerprint,
     ) -> DepNodeIndex {
-        self.alloc_node(node, task_deps.reads, fingerprint)
-    }
-
-    fn complete_anon_task(&self, kind: K, task_deps: TaskDeps<K>) -> DepNodeIndex {
-        debug_assert!(!kind.is_eval_always());
-
-        let mut hasher = StableHasher::new();
-
-        // The dep node indices are hashed here instead of hashing the dep nodes of the
-        // dependencies. These indices may refer to different nodes per session, but this isn't
-        // a problem here because we that ensure the final dep node hash is per session only by
-        // combining it with the per session random number `anon_id_seed`. This hash only need
-        // to map the dependencies to a single value on a per session basis.
-        task_deps.reads.hash(&mut hasher);
-
-        let target_dep_node = DepNode {
-            kind,
-
-            // Fingerprint::combine() is faster than sending Fingerprint
-            // through the StableHasher (at least as long as StableHasher
-            // is so slow).
-            hash: self.anon_id_seed.combine(hasher.finish()).into(),
-        };
+        debug_assert!(
+            prev_graph.node_to_index_opt(&dep_node).is_none(),
+            "node in previous graph should be interned using one \
+            of `intern_red_node`, `intern_light_green_node`, etc."
+        );
 
-        self.intern_node(target_dep_node, task_deps.reads, Fingerprint::ZERO)
+        match self.new_node_to_index.get_shard_by_value(&dep_node).lock().entry(dep_node) {
+            Entry::Occupied(entry) => *entry.get(),
+            Entry::Vacant(entry) => {
+                let data = &mut *self.data.lock();
+                let new_index = data.new.nodes.push(dep_node);
+                add_edges(&mut data.unshared_edges, &mut data.new.edges, edges);
+                data.new.fingerprints.push(fingerprint);
+                let dep_node_index = data.hybrid_indices.push(new_index.into());
+                entry.insert(dep_node_index);
+                dep_node_index
+            }
+        }
     }
 
-    fn alloc_node(
+    fn intern_red_node(
         &self,
-        dep_node: DepNode<K>,
+        prev_graph: &PreviousDepGraph<K>,
+        prev_index: SerializedDepNodeIndex,
         edges: EdgesVec,
         fingerprint: Fingerprint,
     ) -> DepNodeIndex {
-        debug_assert!(
-            !self.node_to_node_index.get_shard_by_value(&dep_node).lock().contains_key(&dep_node)
-        );
-        self.intern_node(dep_node, edges, fingerprint)
+        self.debug_assert_not_in_new_nodes(prev_graph, prev_index);
+
+        let mut prev_index_to_index = self.prev_index_to_index.lock();
+
+        match prev_index_to_index[prev_index] {
+            Some(dep_node_index) => dep_node_index,
+            None => {
+                let data = &mut *self.data.lock();
+                let red_index = data.red.node_indices.push(prev_index);
+                add_edges(&mut data.unshared_edges, &mut data.red.edges, edges);
+                data.red.fingerprints.push(fingerprint);
+                let dep_node_index = data.hybrid_indices.push(red_index.into());
+                prev_index_to_index[prev_index] = Some(dep_node_index);
+                dep_node_index
+            }
+        }
     }
 
-    fn intern_node(
+    fn intern_light_green_node(
         &self,
-        dep_node: DepNode<K>,
+        prev_graph: &PreviousDepGraph<K>,
+        prev_index: SerializedDepNodeIndex,
         edges: EdgesVec,
-        fingerprint: Fingerprint,
     ) -> DepNodeIndex {
-        match self.node_to_node_index.get_shard_by_value(&dep_node).lock().entry(dep_node) {
-            Entry::Occupied(entry) => *entry.get(),
-            Entry::Vacant(entry) => {
-                let mut data = self.data.lock();
-                let dep_node_index = DepNodeIndex::new(data.len());
-                data.push(DepNodeData { node: dep_node, edges, fingerprint });
-                entry.insert(dep_node_index);
+        self.debug_assert_not_in_new_nodes(prev_graph, prev_index);
+
+        let mut prev_index_to_index = self.prev_index_to_index.lock();
+
+        match prev_index_to_index[prev_index] {
+            Some(dep_node_index) => dep_node_index,
+            None => {
+                let data = &mut *self.data.lock();
+                let light_green_index = data.light_green.node_indices.push(prev_index);
+                add_edges(&mut data.unshared_edges, &mut data.light_green.edges, edges);
+                let dep_node_index = data.hybrid_indices.push(light_green_index.into());
+                prev_index_to_index[prev_index] = Some(dep_node_index);
                 dep_node_index
             }
         }
     }
-}
 
-impl<K: DepKind> DepGraphData<K> {
-    #[inline(never)]
-    fn read_index(&self, source: DepNodeIndex) {
-        K::read_deps(|task_deps| {
-            if let Some(task_deps) = task_deps {
-                let mut task_deps = task_deps.lock();
-                let task_deps = &mut *task_deps;
-                if cfg!(debug_assertions) {
-                    self.current.total_read_count.fetch_add(1, Relaxed);
-                }
+    fn intern_dark_green_node(
+        &self,
+        prev_graph: &PreviousDepGraph<K>,
+        prev_index: SerializedDepNodeIndex,
+    ) -> DepNodeIndex {
+        self.debug_assert_not_in_new_nodes(prev_graph, prev_index);
 
-                // As long as we only have a low number of reads we can avoid doing a hash
-                // insert and potentially allocating/reallocating the hashmap
-                let new_read = if task_deps.reads.len() < TASK_DEPS_READS_CAP {
-                    task_deps.reads.iter().all(|other| *other != source)
-                } else {
-                    task_deps.read_set.insert(source)
-                };
-                if new_read {
-                    task_deps.reads.push(source);
-                    if task_deps.reads.len() == TASK_DEPS_READS_CAP {
-                        // Fill `read_set` with what we have so far so we can use the hashset next
-                        // time
-                        task_deps.read_set.extend(task_deps.reads.iter().copied());
-                    }
+        let mut prev_index_to_index = self.prev_index_to_index.lock();
 
-                    #[cfg(debug_assertions)]
-                    {
-                        if let Some(target) = task_deps.node {
-                            let data = self.current.data.lock();
-                            if let Some(ref forbidden_edge) = self.current.forbidden_edge {
-                                let source = data[source].node;
-                                if forbidden_edge.test(&source, &target) {
-                                    panic!("forbidden edge {:?} -> {:?} created", source, target)
-                                }
-                            }
-                        }
-                    }
-                } else if cfg!(debug_assertions) {
-                    self.current.total_duplicate_read_count.fetch_add(1, Relaxed);
-                }
+        match prev_index_to_index[prev_index] {
+            Some(dep_node_index) => dep_node_index,
+            None => {
+                let mut data = self.data.lock();
+                let dep_node_index = data.hybrid_indices.push(prev_index.into());
+                prev_index_to_index[prev_index] = Some(dep_node_index);
+                dep_node_index
             }
-        })
+        }
+    }
+
+    #[inline]
+    fn debug_assert_not_in_new_nodes(
+        &self,
+        prev_graph: &PreviousDepGraph<K>,
+        prev_index: SerializedDepNodeIndex,
+    ) {
+        let node = &prev_graph.index_to_node(prev_index);
+        debug_assert!(
+            !self.new_node_to_index.get_shard_by_value(node).lock().contains_key(node),
+            "node from previous graph present in new node collection"
+        );
     }
 }
 
+#[inline]
+fn add_edges<I: Idx>(
+    edges: &mut IndexVec<EdgeIndex, DepNodeIndex>,
+    edge_indices: &mut IndexVec<I, Range<EdgeIndex>>,
+    new_edges: EdgesVec,
+) {
+    let start = edges.next_index();
+    edges.extend(new_edges);
+    let end = edges.next_index();
+    edge_indices.push(start..end);
+}
+
 /// The capacity of the `reads` field `SmallVec`
 const TASK_DEPS_READS_CAP: usize = 8;
 type EdgesVec = SmallVec<[DepNodeIndex; TASK_DEPS_READS_CAP]>;
index 3b4b62ad6be88982f9320efeabc800de2ff8732d..da0b5aad6c811493e3a7954925f11469c76eee4a 100644 (file)
@@ -15,7 +15,6 @@
 use rustc_data_structures::sync::Lock;
 use rustc_data_structures::thin_vec::ThinVec;
 use rustc_errors::Diagnostic;
-use rustc_span::def_id::DefPathHash;
 
 use std::fmt;
 use std::hash::Hash;
@@ -33,7 +32,7 @@ pub trait DepContext: Copy {
     /// Try to force a dep node to execute and see if it's green.
     fn try_force_from_dep_node(&self, dep_node: &DepNode<Self::DepKind>) -> bool;
 
-    fn register_reused_dep_path_hash(&self, hash: DefPathHash);
+    fn register_reused_dep_node(&self, dep_node: &DepNode<Self::DepKind>);
 
     /// Return whether the current session is tainted by errors.
     fn has_errors_or_delayed_span_bugs(&self) -> bool;
index 9298b652da2d04c142105701271106c24a7ab93b..29357ce9449ce26f48df11c3ac0c12c743efa0a2 100644 (file)
@@ -1,9 +1,7 @@
 use super::serialized::{SerializedDepGraph, SerializedDepNodeIndex};
 use super::{DepKind, DepNode};
-use crate::dep_graph::DepContext;
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::fx::FxHashMap;
-use rustc_span::def_id::DefPathHash;
 
 #[derive(Debug, Encodable, Decodable)]
 pub struct PreviousDepGraph<K: DepKind> {
@@ -33,44 +31,7 @@ pub fn edge_targets_from(
     }
 
     #[inline]
-    pub fn index_to_node<CTX: DepContext<DepKind = K>>(
-        &self,
-        dep_node_index: SerializedDepNodeIndex,
-        tcx: CTX,
-    ) -> DepNode<K> {
-        let dep_node = self.data.nodes[dep_node_index];
-        // We have just loaded a deserialized `DepNode` from the previous
-        // compilation session into the current one. If this was a foreign `DefId`,
-        // then we stored additional information in the incr comp cache when we
-        // initially created its fingerprint (see `DepNodeParams::to_fingerprint`)
-        // We won't be calling `to_fingerprint` again for this `DepNode` (we no longer
-        // have the original value), so we need to copy over this additional information
-        // from the old incremental cache into the new cache that we serialize
-        // and the end of this compilation session.
-        if dep_node.kind.can_reconstruct_query_key() {
-            tcx.register_reused_dep_path_hash(DefPathHash(dep_node.hash.into()));
-        }
-        dep_node
-    }
-
-    /// When debug assertions are enabled, asserts that the dep node at `dep_node_index` is equal to `dep_node`.
-    /// This method should be preferred over manually calling `index_to_node`.
-    /// Calls to `index_to_node` may affect global state, so gating a call
-    /// to `index_to_node` on debug assertions could cause behavior changes when debug assertions
-    /// are enabled.
-    #[inline]
-    pub fn debug_assert_eq(&self, dep_node_index: SerializedDepNodeIndex, dep_node: DepNode<K>) {
-        debug_assert_eq!(self.data.nodes[dep_node_index], dep_node);
-    }
-
-    /// Obtains a debug-printable version of the `DepNode`.
-    /// See `debug_assert_eq` for why this should be preferred over manually
-    /// calling `dep_node_index`
-    pub fn debug_dep_node(&self, dep_node_index: SerializedDepNodeIndex) -> impl std::fmt::Debug {
-        // We're returning the `DepNode` without calling `register_reused_dep_path_hash`,
-        // but `impl Debug` return type means that it can only be used for debug printing.
-        // So, there's no risk of calls trying to create new dep nodes that have this
-        // node as a dependency
+    pub fn index_to_node(&self, dep_node_index: SerializedDepNodeIndex) -> DepNode<K> {
         self.data.nodes[dep_node_index]
     }
 
index a27b716b95aee5fcbc0e84ef11676c6b71e9db0c..cc25d08cb54f43797fe4f526ed772db7b3e8c833 100644 (file)
@@ -9,17 +9,23 @@ pub struct DepGraphQuery<K> {
 }
 
 impl<K: DepKind> DepGraphQuery<K> {
-    pub fn new(nodes: &[DepNode<K>], edges: &[(DepNode<K>, DepNode<K>)]) -> DepGraphQuery<K> {
-        let mut graph = Graph::with_capacity(nodes.len(), edges.len());
+    pub fn new(
+        nodes: &[DepNode<K>],
+        edge_list_indices: &[(usize, usize)],
+        edge_list_data: &[usize],
+    ) -> DepGraphQuery<K> {
+        let mut graph = Graph::with_capacity(nodes.len(), edge_list_data.len());
         let mut indices = FxHashMap::default();
         for node in nodes {
             indices.insert(*node, graph.add_node(*node));
         }
 
-        for &(ref source, ref target) in edges {
-            let source = indices[source];
-            let target = indices[target];
-            graph.add_edge(source, target, ());
+        for (source, &(start, end)) in edge_list_indices.iter().enumerate() {
+            for &target in &edge_list_data[start..end] {
+                let source = indices[&nodes[source]];
+                let target = indices[&nodes[target]];
+                graph.add_edge(source, target, ());
+            }
         }
 
         DepGraphQuery { graph, indices }
index 932c6d2a2f184260434bf38989fa5d9626f88dff..28e074069185206d840ae103d25930c1fe10defc 100644 (file)
@@ -4,8 +4,13 @@
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_index::vec::IndexVec;
 
+// The maximum value of `SerializedDepNodeIndex` leaves the upper two bits
+// unused so that we can store multiple index types in `CompressedHybridIndex`,
+// and use those bits to encode which index type it contains.
 rustc_index::newtype_index! {
-    pub struct SerializedDepNodeIndex { .. }
+    pub struct SerializedDepNodeIndex {
+        MAX = 0x7FFF_FFFF
+    }
 }
 
 /// Data for use when recompiling the **current crate**.
index 06e9969697d09b835ec3364255e6b61f22d83833..c5f783e84a91ec610c20166c8ccba9c13ac7242e 100644 (file)
@@ -185,15 +185,15 @@ fn nearest_mod_parent(&mut self, def_id: DefId) -> Module<'a> {
 
     crate fn get_macro(&mut self, res: Res) -> Option<Lrc<SyntaxExtension>> {
         match res {
-            Res::Def(DefKind::Macro(..), def_id) => self.get_macro_by_def_id(def_id),
+            Res::Def(DefKind::Macro(..), def_id) => Some(self.get_macro_by_def_id(def_id)),
             Res::NonMacroAttr(attr_kind) => Some(self.non_macro_attr(attr_kind.is_used())),
             _ => None,
         }
     }
 
-    crate fn get_macro_by_def_id(&mut self, def_id: DefId) -> Option<Lrc<SyntaxExtension>> {
+    crate fn get_macro_by_def_id(&mut self, def_id: DefId) -> Lrc<SyntaxExtension> {
         if let Some(ext) = self.macro_map.get(&def_id) {
-            return Some(ext.clone());
+            return ext.clone();
         }
 
         let ext = Lrc::new(match self.cstore().load_macro_untracked(def_id, &self.session) {
@@ -202,7 +202,7 @@ fn nearest_mod_parent(&mut self, def_id: DefId) -> Module<'a> {
         });
 
         self.macro_map.insert(def_id, ext.clone());
-        Some(ext)
+        ext
     }
 
     crate fn build_reduced_graph(
@@ -342,7 +342,7 @@ fn insert_field_names_local(&mut self, def_id: DefId, vdata: &ast::VariantData)
         let field_names = vdata
             .fields()
             .iter()
-            .map(|field| respan(field.span, field.ident.map_or(kw::Invalid, |ident| ident.name)))
+            .map(|field| respan(field.span, field.ident.map_or(kw::Empty, |ident| ident.name)))
             .collect();
         self.insert_field_names(def_id, field_names);
     }
@@ -525,9 +525,9 @@ fn build_reduced_graph_for_use_tree(
                             ModuleKind::Block(..) => unreachable!(),
                         };
                         // HACK(eddyb) unclear how good this is, but keeping `$crate`
-                        // in `source` breaks `src/test/compile-fail/import-crate-var.rs`,
+                        // in `source` breaks `src/test/ui/imports/import-crate-var.rs`,
                         // while the current crate doesn't have a valid `crate_name`.
-                        if crate_name != kw::Invalid {
+                        if crate_name != kw::Empty {
                             // `crate_name` should not be interpreted as relative.
                             module_path.push(Segment {
                                 ident: Ident { name: kw::PathRoot, span: source.ident.span },
@@ -656,7 +656,7 @@ fn build_reduced_graph_for_use_tree(
 
     /// Constructs the reduced graph for one item.
     fn build_reduced_graph_for_item(&mut self, item: &'b Item) {
-        if matches!(item.kind, ItemKind::Mod(..)) && item.ident.name == kw::Invalid {
+        if matches!(item.kind, ItemKind::Mod(..)) && item.ident.name == kw::Empty {
             // Fake crate root item from expand.
             return;
         }
index 69773ba1d72215b1139483c81a436ad840412524..48bce88439424524a678b10dd90abe0c60a6893e 100644 (file)
@@ -74,7 +74,7 @@ fn visit_item(&mut self, i: &'a Item) {
         // information we encapsulate into, the better
         let def_data = match &i.kind {
             ItemKind::Impl { .. } => DefPathData::Impl,
-            ItemKind::Mod(..) if i.ident.name == kw::Invalid => {
+            ItemKind::Mod(..) if i.ident.name == kw::Empty => {
                 // Fake crate root item from expand.
                 return visit::walk_item(self, i);
             }
index b13462587bc618ef55762577dd16a818ebb424a1..dd1874debbd96afe9a2c55def400e5925c084371 100644 (file)
@@ -1151,13 +1151,11 @@ fn with_current_self_item<T>(&mut self, self_item: &Item, f: impl FnOnce(&mut Se
     /// When evaluating a `trait` use its associated types' idents for suggestions in E0412.
     fn with_trait_items<T>(
         &mut self,
-        trait_items: &'ast Vec<P<AssocItem>>,
+        trait_items: &'ast [P<AssocItem>],
         f: impl FnOnce(&mut Self) -> T,
     ) -> T {
-        let trait_assoc_items = replace(
-            &mut self.diagnostic_metadata.current_trait_assoc_items,
-            Some(&trait_items[..]),
-        );
+        let trait_assoc_items =
+            replace(&mut self.diagnostic_metadata.current_trait_assoc_items, Some(&trait_items));
         let result = f(self);
         self.diagnostic_metadata.current_trait_assoc_items = trait_assoc_items;
         result
@@ -1641,7 +1639,7 @@ fn fresh_binding(
         }
 
         // Record as bound if it's valid:
-        let ident_valid = ident.name != kw::Invalid;
+        let ident_valid = ident.name != kw::Empty;
         if ident_valid {
             bindings.last_mut().unwrap().1.insert(ident);
         }
index 68f59baffce1787ecd3a10bef915063c51c44643..7d8f112af8a51d46696dc1bb27658d2b01746bce 100644 (file)
@@ -1653,17 +1653,14 @@ impl<'tcx> LifetimeContext<'_, 'tcx> {
         for missing in &self.missing_named_lifetime_spots {
             match missing {
                 MissingLifetimeSpot::Generics(generics) => {
-                    let (span, sugg) = if let Some(param) =
-                        generics.params.iter().find(|p| match p.kind {
-                            hir::GenericParamKind::Type {
-                                synthetic: Some(hir::SyntheticTyParamKind::ImplTrait),
-                                ..
-                            } => false,
-                            hir::GenericParamKind::Lifetime {
-                                kind: hir::LifetimeParamKind::Elided,
-                            } => false,
-                            _ => true,
-                        }) {
+                    let (span, sugg) = if let Some(param) = generics.params.iter().find(|p| {
+                        !matches!(p.kind, hir::GenericParamKind::Type {
+                            synthetic: Some(hir::SyntheticTyParamKind::ImplTrait),
+                            ..
+                        } | hir::GenericParamKind::Lifetime {
+                            kind: hir::LifetimeParamKind::Elided,
+                        })
+                    }) {
                         (param.span.shrink_to_lo(), format!("{}, ", lifetime_ref))
                     } else {
                         suggests_in_band = true;
@@ -1985,8 +1982,8 @@ impl<'tcx> LifetimeContext<'_, 'tcx> {
         }
     }
 
-    /// Non-static lifetimes are prohibited in anonymous constants under `min_const_generics` so
-    /// this function will emit an error if `min_const_generics` is enabled, the body identified by
+    /// Non-static lifetimes are prohibited in anonymous constants under `min_const_generics`.
+    /// This function will emit an error if `const_generics` is not enabled, the body identified by
     /// `body_id` is an anonymous constant and `lifetime_ref` is non-static.
     crate fn maybe_emit_forbidden_non_static_lifetime_error(
         &self,
@@ -2002,7 +1999,7 @@ impl<'tcx> LifetimeContext<'_, 'tcx> {
             hir::LifetimeName::Implicit | hir::LifetimeName::Static | hir::LifetimeName::Underscore
         );
 
-        if self.tcx.features().min_const_generics && is_anon_const && !is_allowed_lifetime {
+        if !self.tcx.lazy_normalization() && is_anon_const && !is_allowed_lifetime {
             feature_err(
                 &self.tcx.sess.parse_sess,
                 sym::const_generics,
index 69f28045bb5bdff01bbbf33c63c8424156072652..d5ba6f3b53b211b968a4600c86262a7a1903dbf0 100644 (file)
@@ -1769,8 +1769,8 @@ fn resolve_lifetime_ref(&mut self, lifetime_ref: &'tcx hir::Lifetime) {
         let result = loop {
             match *scope {
                 Scope::Body { id, s } => {
-                    // Non-static lifetimes are prohibited in anonymous constants under
-                    // `min_const_generics`.
+                    // Non-static lifetimes are prohibited in anonymous constants without
+                    // `const_generics`.
                     self.maybe_emit_forbidden_non_static_lifetime_error(id, lifetime_ref);
 
                     outermost_body = Some(id);
index f764fbc3f8dac83c9cbcacfd6912f7ddfbcf78ca..ca30d90e6ad1d6a9c228ebe172d8e3030e3a08aa 100644 (file)
@@ -1182,12 +1182,12 @@ pub fn new(
     ) -> Resolver<'a> {
         let root_local_def_id = LocalDefId { local_def_index: CRATE_DEF_INDEX };
         let root_def_id = root_local_def_id.to_def_id();
-        let root_module_kind = ModuleKind::Def(DefKind::Mod, root_def_id, kw::Invalid);
+        let root_module_kind = ModuleKind::Def(DefKind::Mod, root_def_id, kw::Empty);
         let graph_root = arenas.alloc_module(ModuleData {
             no_implicit_prelude: session.contains_name(&krate.attrs, sym::no_implicit_prelude),
             ..ModuleData::new(None, root_module_kind, root_def_id, ExpnId::root(), krate.span)
         });
-        let empty_module_kind = ModuleKind::Def(DefKind::Mod, root_def_id, kw::Invalid);
+        let empty_module_kind = ModuleKind::Def(DefKind::Mod, root_def_id, kw::Empty);
         let empty_module = arenas.alloc_module(ModuleData {
             no_implicit_prelude: true,
             ..ModuleData::new(
@@ -1797,7 +1797,7 @@ fn resolve_ident_in_lexical_scope(
         ribs: &[Rib<'a>],
     ) -> Option<LexicalScopeBinding<'a>> {
         assert!(ns == TypeNS || ns == ValueNS);
-        if ident.name == kw::Invalid {
+        if ident.name == kw::Empty {
             return Some(LexicalScopeBinding::Res(Res::Err));
         }
         let (general_span, normalized_span) = if ident.name == kw::SelfUpper {
@@ -1991,14 +1991,13 @@ fn hygienic_lexical_parent_with_compatibility_fallback(
             {
                 // The macro is a proc macro derive
                 if let Some(def_id) = module.expansion.expn_data().macro_def_id {
-                    if let Some(ext) = self.get_macro_by_def_id(def_id) {
-                        if !ext.is_builtin
-                            && ext.macro_kind() == MacroKind::Derive
-                            && parent.expansion.outer_expn_is_descendant_of(span.ctxt())
-                        {
-                            *poisoned = Some(node_id);
-                            return module.parent;
-                        }
+                    let ext = self.get_macro_by_def_id(def_id);
+                    if !ext.is_builtin
+                        && ext.macro_kind() == MacroKind::Derive
+                        && parent.expansion.outer_expn_is_descendant_of(span.ctxt())
+                    {
+                        *poisoned = Some(node_id);
+                        return module.parent;
                     }
                 }
             }
@@ -2416,7 +2415,10 @@ enum FindBindingResult<'a> {
                     } else if i == 0 {
                         if ident
                             .name
-                            .with(|n| n.chars().next().map_or(false, |c| c.is_ascii_uppercase()))
+                            .as_str()
+                            .chars()
+                            .next()
+                            .map_or(false, |c| c.is_ascii_uppercase())
                         {
                             (format!("use of undeclared type `{}`", ident), None)
                         } else {
@@ -2624,8 +2626,12 @@ fn validate_res_from_ribs(
                             continue;
                         }
                         ConstantItemRibKind(trivial) => {
+                            let features = self.session.features_untracked();
                             // HACK(min_const_generics): We currently only allow `N` or `{ N }`.
-                            if !trivial && self.session.features_untracked().min_const_generics {
+                            if !(trivial
+                                || features.const_generics
+                                || features.lazy_normalization_consts)
+                            {
                                 // 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.
@@ -2713,8 +2719,12 @@ fn validate_res_from_ribs(
                             continue;
                         }
                         ConstantItemRibKind(trivial) => {
+                            let features = self.session.features_untracked();
                             // HACK(min_const_generics): We currently only allow `N` or `{ N }`.
-                            if !trivial && self.session.features_untracked().min_const_generics {
+                            if !(trivial
+                                || features.const_generics
+                                || features.lazy_normalization_consts)
+                            {
                                 if record_used {
                                     self.report_error(
                                         span,
index c8dbe685128576951283a9de01dbbb19265d5ed9..5ad7c83ca36afd8b140730a2640bf503632e84d7 100644 (file)
@@ -160,7 +160,7 @@ fn resolve_dollar_crates(&mut self) {
         hygiene::update_dollar_crate_names(|ctxt| {
             let ident = Ident::new(kw::DollarCrate, DUMMY_SP.with_ctxt(ctxt));
             match self.resolve_crate_root(ident).kind {
-                ModuleKind::Def(.., name) if name != kw::Invalid => name,
+                ModuleKind::Def(.., name) if name != kw::Empty => name,
                 _ => kw::Crate,
             }
         });
index eed9f2eb74d4f727545e7104735738f6eeafd242..056c0b3d9d513f8fa5813f76af3dae424f9e44ae 100644 (file)
@@ -825,7 +825,7 @@ fn docs_for_attrs(&self, attrs: &[ast::Attribute]) -> String {
         for attr in attrs {
             if let Some(val) = attr.doc_str() {
                 // FIXME: Should save-analysis beautify doc strings itself or leave it to users?
-                result.push_str(&beautify_doc_string(val));
+                result.push_str(&beautify_doc_string(val).as_str());
                 result.push('\n');
             } else if self.tcx.sess.check_name(attr, sym::doc) {
                 if let Some(meta_list) = attr.meta_item_list() {
index fab29f29e8730fd8db67d00b5f36140e08f3a253..ac1cdc6ad45f20338a8ad3ba8d55bed26304ab11 100644 (file)
@@ -13,7 +13,7 @@
 #![feature(never_type)]
 #![feature(nll)]
 #![feature(associated_type_bounds)]
-#![feature(min_const_generics)]
+#![cfg_attr(bootstrap, feature(min_const_generics))]
 #![cfg_attr(test, feature(test))]
 #![allow(rustc::internal)]
 
index 55ee4e52082e51e3b10c57e4fc7dd2db3126b391..3a757e5f0075d468b77e1f5d02873231d0e51a0c 100644 (file)
@@ -76,7 +76,7 @@ fn is_rlib(spf: &SearchPathFile) -> bool {
     pub fn new(
         sysroot: &'a Path,
         triple: &'a str,
-        search_paths: &'a Vec<SearchPath>,
+        search_paths: &'a [SearchPath],
         tlib_path: &'a SearchPath,
         kind: PathKind,
     ) -> FileSearch<'a> {
index 66c3738fb5b5ae1716205deadbab597c9a8d6460..b1a48342417308dae140af911f2f8491c396db34 100644 (file)
@@ -119,6 +119,7 @@ pub struct ParseSess {
     pub unstable_features: UnstableFeatures,
     pub config: CrateConfig,
     pub edition: Edition,
+    pub missing_fragment_specifiers: Lock<FxHashMap<Span, NodeId>>,
     /// Places where raw identifiers were used. This is used for feature-gating raw identifiers.
     pub raw_identifier_spans: Lock<Vec<Span>>,
     /// Used to determine and report recursive module inclusions.
@@ -152,6 +153,7 @@ pub fn with_span_handler(handler: Handler, source_map: Lrc<SourceMap>) -> Self {
             unstable_features: UnstableFeatures::from_environment(None),
             config: FxHashSet::default(),
             edition: ExpnId::root().expn_data().edition,
+            missing_fragment_specifiers: Default::default(),
             raw_identifier_spans: Lock::new(Vec::new()),
             included_mod_stack: Lock::new(vec![]),
             source_map,
index 4d0c92f51d7ca7063c934486a78c7947e2b4b511..efbb0a23a6f012a679f80ed764775d90c1bf9b7e 100644 (file)
@@ -4,24 +4,25 @@
 
 use rustc_macros::HashStable_Generic;
 
-/// The edition of the compiler (RFC 2052)
+/// The edition of the compiler. (See [RFC 2052](https://github.com/rust-lang/rfcs/blob/master/text/2052-epochs.md).)
 #[derive(Clone, Copy, Hash, PartialEq, PartialOrd, Debug, Encodable, Decodable, Eq)]
 #[derive(HashStable_Generic)]
 pub enum Edition {
-    // editions must be kept in order, oldest to newest
+    // When adding new editions, be sure to do the following:
+    //
+    // - update the `ALL_EDITIONS` const
+    // - update the `EDITION_NAME_LIST` const
+    // - add a `rust_####()` function to the session
+    // - update the enum in Cargo's sources as well
+    //
+    // Editions *must* be kept in order, oldest to newest.
     /// The 2015 edition
     Edition2015,
     /// The 2018 edition
     Edition2018,
-    // when adding new editions, be sure to update:
-    //
-    // - Update the `ALL_EDITIONS` const
-    // - Update the EDITION_NAME_LIST const
-    // - add a `rust_####()` function to the session
-    // - update the enum in Cargo's sources as well
 }
 
-// must be in order from oldest to newest
+// Must be in order from oldest to newest.
 pub const ALL_EDITIONS: &[Edition] = &[Edition::Edition2015, Edition::Edition2018];
 
 pub const EDITION_NAME_LIST: &str = "2015|2018";
index 0f82db1d05aa12991f5ad3975ef1f3ac12c811dd..fdc0d225bb82d9f1f98b06cfc5052a5a5a88b500 100644 (file)
@@ -1065,7 +1065,7 @@ pub fn decode_syntax_context<
             parent: SyntaxContext::root(),
             opaque: SyntaxContext::root(),
             opaque_and_semitransparent: SyntaxContext::root(),
-            dollar_crate_name: kw::Invalid,
+            dollar_crate_name: kw::Empty,
         });
         let mut ctxts = outer_ctxts.lock();
         let new_len = raw_id as usize + 1;
@@ -1092,7 +1092,7 @@ pub fn decode_syntax_context<
             ctxt_data,
         );
         // Make sure nothing weird happening while `decode_data` was running
-        assert_eq!(dummy.dollar_crate_name, kw::Invalid);
+        assert_eq!(dummy.dollar_crate_name, kw::Empty);
     });
 
     Ok(new_ctxt)
index edc6625a6ead7a94fcac4da8c5bb54f52e726e52..cea7871923bc689dc44ca295518c64f8c502eeac 100644 (file)
@@ -1,10 +1,16 @@
+//! Levenshtein distances.
+//!
+//! The [Levenshtein distance] is a metric for measuring the difference between two strings.
+//!
+//! [Levenshtein distance]: https://en.wikipedia.org/wiki/Levenshtein_distance
+
 use crate::symbol::Symbol;
 use std::cmp;
 
 #[cfg(test)]
 mod tests;
 
-/// Finds the Levenshtein distance between two strings
+/// Finds the Levenshtein distance between two strings.
 pub fn lev_distance(a: &str, b: &str) -> usize {
     // cases which don't require further computation
     if a.is_empty() {
@@ -35,14 +41,14 @@ pub fn lev_distance(a: &str, b: &str) -> usize {
     dcol[t_last + 1]
 }
 
-/// Finds the best match for a given word in the given iterator
+/// Finds the best match for a given word in the given iterator.
 ///
 /// As a loose rule to avoid the obviously incorrect suggestions, it takes
 /// an optional limit for the maximum allowable edit distance, which defaults
 /// to one-third of the given word.
 ///
-/// Besides Levenshtein, we use case insensitive comparison to improve accuracy on an edge case with
-/// a lower(upper)case letters mismatch.
+/// Besides Levenshtein, we use case insensitive comparison to improve accuracy
+/// on an edge case with a lower(upper)case letters mismatch.
 #[cold]
 pub fn find_best_match_for_name(
     name_vec: &[Symbol],
@@ -98,7 +104,7 @@ fn find_match_by_sorted_words(iter_names: &[Symbol], lookup: &str) -> Option<Sym
 
 fn sort_by_words(name: &str) -> String {
     let mut split_words: Vec<&str> = name.split('_').collect();
-    // We are sorting primitive &strs and can use unstable sort here
+    // We are sorting primitive &strs and can use unstable sort here.
     split_words.sort_unstable();
     split_words.join("_")
 }
index f63a73acbf4ba164c5130eaaa41e9e015f3be718..8009530717566370f18e0d2448af299c5c769469 100644 (file)
@@ -1,4 +1,13 @@
-//! The source positions and related helper functions.
+//! Source positions and related helper functions.
+//!
+//! Important concepts in this module include:
+//!
+//! - the *span*, represented by [`SpanData`] and related types;
+//! - source code as represented by a [`SourceMap`]; and
+//! - interned strings, represented by [`Symbol`]s, with some common symbols available statically in the [`sym`] module.
+//!
+//! Unlike most compilers, the span contains not only the position in the source code, but also various other metadata,
+//! such as the edition and macro hygiene. This metadata is stored in [`SyntaxContext`] and [`ExpnData`].
 //!
 //! ## Note
 //!
@@ -124,7 +133,7 @@ pub enum RealFileName {
 
 impl RealFileName {
     /// Returns the path suitable for reading from the file system on the local host.
-    /// Avoid embedding this in build artifacts; see `stable_name` for that.
+    /// Avoid embedding this in build artifacts; see `stable_name()` for that.
     pub fn local_path(&self) -> &Path {
         match self {
             RealFileName::Named(p)
@@ -133,7 +142,7 @@ pub fn local_path(&self) -> &Path {
     }
 
     /// Returns the path suitable for reading from the file system on the local host.
-    /// Avoid embedding this in build artifacts; see `stable_name` for that.
+    /// Avoid embedding this in build artifacts; see `stable_name()` for that.
     pub fn into_local_path(self) -> PathBuf {
         match self {
             RealFileName::Named(p)
@@ -143,7 +152,7 @@ pub fn into_local_path(self) -> PathBuf {
 
     /// Returns the path suitable for embedding into build artifacts. Note that
     /// a virtualized path will not correspond to a valid file system path; see
-    /// `local_path` for something that is more likely to return paths into the
+    /// `local_path()` for something that is more likely to return paths into the
     /// local host file system.
     pub fn stable_name(&self) -> &Path {
         match self {
@@ -173,7 +182,7 @@ pub enum FileName {
     /// Custom sources for explicit parser calls from plugins and drivers.
     Custom(String),
     DocTest(PathBuf, isize),
-    /// Post-substitution inline assembly from LLVM
+    /// Post-substitution inline assembly from LLVM.
     InlineAsm(u64),
 }
 
@@ -182,7 +191,7 @@ fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         use FileName::*;
         match *self {
             Real(RealFileName::Named(ref path)) => write!(fmt, "{}", path.display()),
-            // FIXME: might be nice to display both compoments of Devirtualized.
+            // FIXME: might be nice to display both components of Devirtualized.
             // But for now (to backport fix for issue #70924), best to not
             // perturb diagnostics so its obvious test suite still works.
             Real(RealFileName::Devirtualized { ref local_path, virtual_name: _ }) => {
@@ -266,14 +275,17 @@ pub fn inline_asm_source_code(src: &str) -> FileName {
     }
 }
 
+/// Represents a span.
+///
 /// Spans represent a region of code, used for error reporting. Positions in spans
-/// are *absolute* positions from the beginning of the source_map, not positions
-/// relative to `SourceFile`s. Methods on the `SourceMap` can be used to relate spans back
+/// are *absolute* positions from the beginning of the [`SourceMap`], not positions
+/// relative to [`SourceFile`]s. Methods on the `SourceMap` can be used to relate spans back
 /// to the original source.
-/// You must be careful if the span crosses more than one file - you will not be
+///
+/// You must be careful if the span crosses more than one file, since you will not be
 /// able to use many of the functions on spans in source_map and you cannot assume
-/// that the length of the `span = hi - lo`; there may be space in the `BytePos`
-/// range between files.
+/// that the length of the span is equal to `span.hi - span.lo`; there may be space in the
+/// [`BytePos`] range between files.
 ///
 /// `SpanData` is public because `Span` uses a thread-local interner and can't be
 /// sent to other threads, but some pieces of performance infra run in a separate thread.
@@ -384,7 +396,7 @@ pub fn with_root_ctxt(lo: BytePos, hi: BytePos) -> Span {
         Span::new(lo, hi, SyntaxContext::root())
     }
 
-    /// Returns a new span representing an empty span at the beginning of this span
+    /// Returns a new span representing an empty span at the beginning of this span.
     #[inline]
     pub fn shrink_to_lo(self) -> Span {
         let span = self.data();
@@ -398,7 +410,7 @@ pub fn shrink_to_hi(self) -> Span {
     }
 
     #[inline]
-    /// Returns true if hi == lo
+    /// Returns `true` if `hi == lo`.
     pub fn is_empty(&self) -> bool {
         let span = self.data();
         span.hi == span.lo
@@ -512,7 +524,7 @@ pub fn desugaring_kind(&self) -> Option<DesugaringKind> {
     }
 
     /// Checks if a span is "internal" to a macro in which `unsafe`
-    /// can be used without triggering the `unsafe_code` lint
+    /// can be used without triggering the `unsafe_code` lint.
     //  (that is, a macro marked with `#[allow_internal_unsafe]`).
     pub fn allows_unsafe(&self) -> bool {
         self.ctxt().outer_expn_data().allow_internal_unsafe
@@ -700,6 +712,7 @@ pub fn normalize_to_macro_rules(self) -> Span {
     }
 }
 
+/// A span together with some additional data.
 #[derive(Clone, Debug)]
 pub struct SpanLabel {
     /// The span we are going to include in the final snippet.
@@ -743,7 +756,7 @@ impl<D: Decoder> Decodable<D> for Span {
 /// any spans that are debug-printed during the closure's execution.
 ///
 /// Normally, the global `TyCtxt` is used to retrieve the `SourceMap`
-/// (see `rustc_interface::callbacks::span_debug1). However, some parts
+/// (see `rustc_interface::callbacks::span_debug1`). However, some parts
 /// of the compiler (e.g. `rustc_parse`) may debug-print `Span`s before
 /// a `TyCtxt` is available. In this case, we fall back to
 /// the `SourceMap` provided to this function. If that is not available,
@@ -994,9 +1007,9 @@ pub enum ExternalSource {
     Unneeded,
     Foreign {
         kind: ExternalSourceKind,
-        /// This SourceFile's byte-offset within the source_map of its original crate
+        /// This SourceFile's byte-offset within the source_map of its original crate.
         original_start_pos: BytePos,
-        /// The end of this SourceFile within the source_map of its original crate
+        /// The end of this SourceFile within the source_map of its original crate.
         original_end_pos: BytePos,
     },
 }
@@ -1099,7 +1112,7 @@ fn hash_len(&self) -> usize {
     }
 }
 
-/// A single source in the `SourceMap`.
+/// A single source in the [`SourceMap`].
 #[derive(Clone)]
 pub struct SourceFile {
     /// The name of the file that the source came from. Source that doesn't
@@ -1580,7 +1593,7 @@ fn remove_bom(src: &mut String, normalized_pos: &mut Vec<NormalizedPos>) {
 
 /// Replaces `\r\n` with `\n` in-place in `src`.
 ///
-/// Returns error if there's a lone `\r` in the string
+/// Returns error if there's a lone `\r` in the string.
 fn normalize_newlines(src: &mut String, normalized_pos: &mut Vec<NormalizedPos>) {
     if !src.as_bytes().contains(&b'\r') {
         return;
@@ -1705,13 +1718,16 @@ fn sub(self, rhs: $ident) -> $ident {
 }
 
 impl_pos! {
-    /// A byte offset. Keep this small (currently 32-bits), as AST contains
-    /// a lot of them.
+    /// A byte offset.
+    ///
+    /// Keep this small (currently 32-bits), as AST contains a lot of them.
     #[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
     pub struct BytePos(pub u32);
 
-    /// A character offset. Because of multibyte UTF-8 characters, a byte offset
-    /// is not equivalent to a character offset. The `SourceMap` will convert `BytePos`
+    /// A character offset.
+    ///
+    /// Because of multibyte UTF-8 characters, a byte offset
+    /// is not equivalent to a character offset. The [`SourceMap`] will convert [`BytePos`]
     /// values to `CharPos` values as necessary.
     #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
     pub struct CharPos(pub usize);
@@ -1835,8 +1851,9 @@ fn lookup_line(lines: &[BytePos], pos: BytePos) -> isize {
 }
 
 /// Requirements for a `StableHashingContext` to be used in this crate.
-/// This is a hack to allow using the `HashStable_Generic` derive macro
-/// instead of implementing everything in librustc_middle.
+///
+/// This is a hack to allow using the [`HashStable_Generic`] derive macro
+/// instead of implementing everything in rustc_middle.
 pub trait HashStableContext {
     fn hash_def_id(&mut self, _: DefId, hasher: &mut StableHasher);
     fn hash_crate_num(&mut self, _: CrateNum, hasher: &mut StableHasher);
@@ -1856,6 +1873,7 @@ impl<CTX> HashStable<CTX> for Span
     /// offsets into the `SourceMap`). Instead, we hash the (file name, line, column)
     /// triple, which stays the same even if the containing `SourceFile` has moved
     /// within the `SourceMap`.
+    ///
     /// Also note that we are hashing byte offsets for the column, not unicode
     /// codepoint offsets. For the purpose of the hash that's sufficient.
     /// Also, hashing filenames is expensive so we avoid doing it twice when the
index e9b4eb6e4abe0357a144b17a6e42dcde2cc6e8a7..fefc0cb48ddd8efea9b86f5346d4b2555ebcd75c 100644 (file)
@@ -1,9 +1,11 @@
-//! The `SourceMap` tracks all the source code used within a single crate, mapping
+//! Types for tracking pieces of source code within a crate.
+//!
+//! The [`SourceMap`] tracks all the source code used within a single crate, mapping
 //! from integer byte positions to the original source code location. Each bit
 //! of source parsed during crate parsing (typically files, in-memory strings,
 //! or various bits of macro expansion) cover a continuous range of bytes in the
-//! `SourceMap` and are represented by `SourceFile`s. Byte positions are stored in
-//! `Span` and used pervasively in the compiler. They are absolute positions
+//! `SourceMap` and are represented by [`SourceFile`]s. Byte positions are stored in
+//! [`Span`] and used pervasively in the compiler. They are absolute positions
 //! within the `SourceMap`, which upon request can be converted to line and column
 //! information, source code snippets, etc.
 
index b05e01d666bd6917e32f4451640c4c4748a7f0ce..ceb9b59b13ad1609489eab9cd8ef03307a42b25f 100644 (file)
@@ -12,7 +12,7 @@
 
 /// A compressed span.
 ///
-/// `SpanData` is 12 bytes, which is a bit too big to stick everywhere. `Span`
+/// Whereas [`SpanData`] is 12 bytes, which is a bit too big to stick everywhere, `Span`
 /// is a form that only takes up 8 bytes, with less space for the length and
 /// context. The vast majority (99.9%+) of `SpanData` instances will fit within
 /// those 8 bytes; any `SpanData` whose fields don't fit into a `Span` are
 /// - `base` is 32 bits in both `Span` and `SpanData`, which means that `base`
 ///   values never cause interning. The number of bits needed for `base`
 ///   depends on the crate size. 32 bits allows up to 4 GiB of code in a crate.
-///   `script-servo` is the largest crate in `rustc-perf`, requiring 26 bits
-///   for some spans.
 /// - `len` is 15 bits in `Span` (a u16, minus 1 bit for the tag) and 32 bits
 ///   in `SpanData`, which means that large `len` values will cause interning.
 ///   The number of bits needed for `len` does not depend on the crate size.
-///   The most common number of bits for `len` are 0--7, with a peak usually at
-///   3 or 4, and then it drops off quickly from 8 onwards. 15 bits is enough
+///   The most common numbers of bits for `len` are from 0 to 7, with a peak usually
+///   at 3 or 4, and then it drops off quickly from 8 onwards. 15 bits is enough
 ///   for 99.99%+ of cases, but larger values (sometimes 20+ bits) might occur
 ///   dozens of times in a typical crate.
 /// - `ctxt` is 16 bits in `Span` and 32 bits in `SpanData`, which means that
index 4d14763825caa5b58b1b3fcb823ee5b60d72e6d1..7ca2ff4f1fb7177144a6f63b656d612b6b4f2556 100644 (file)
@@ -13,7 +13,7 @@
 use std::hash::{Hash, Hasher};
 use std::str;
 
-use crate::{Span, DUMMY_SP, SESSION_GLOBALS};
+use crate::{Edition, Span, DUMMY_SP, SESSION_GLOBALS};
 
 #[cfg(test)]
 mod tests;
@@ -25,7 +25,7 @@
     Keywords {
         // Special reserved identifiers used internally for elided lifetimes,
         // unnamed method parameters, crate root module, error recovery etc.
-        Invalid:            "",
+        Empty:              "",
         PathRoot:           "{{root}}",
         DollarCrate:        "$crate",
         Underscore:         "_",
@@ -1273,7 +1273,7 @@ pub const fn with_dummy_span(name: Symbol) -> Ident {
 
     #[inline]
     pub fn invalid() -> Ident {
-        Ident::with_dummy_span(kw::Invalid)
+        Ident::with_dummy_span(kw::Empty)
     }
 
     /// Maps a string to an identifier with a dummy span.
@@ -1451,12 +1451,6 @@ pub fn intern(string: &str) -> Self {
         with_interner(|interner| interner.intern(string))
     }
 
-    /// Access the symbol's chars. This is a slowish operation because it
-    /// requires locking the symbol interner.
-    pub fn with<F: FnOnce(&str) -> R, R>(self, f: F) -> R {
-        with_interner(|interner| f(interner.get(self)))
-    }
-
     /// Convert to a `SymbolStr`. This is a slowish operation because it
     /// requires locking the symbol interner.
     pub fn as_str(self) -> SymbolStr {
@@ -1470,7 +1464,7 @@ pub fn as_u32(self) -> u32 {
     }
 
     pub fn is_empty(self) -> bool {
-        self == kw::Invalid
+        self == kw::Empty
     }
 
     /// This method is supposed to be used in error messages, so it's expected to be
@@ -1484,19 +1478,19 @@ pub fn to_ident_string(self) -> String {
 
 impl fmt::Debug for Symbol {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        self.with(|str| fmt::Debug::fmt(&str, f))
+        fmt::Debug::fmt(&self.as_str(), f)
     }
 }
 
 impl fmt::Display for Symbol {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        self.with(|str| fmt::Display::fmt(&str, f))
+        fmt::Display::fmt(&self.as_str(), f)
     }
 }
 
 impl<S: Encoder> Encodable<S> for Symbol {
     fn encode(&self, s: &mut S) -> Result<(), S::Error> {
-        self.with(|string| s.emit_str(string))
+        s.emit_str(&self.as_str())
     }
 }
 
@@ -1609,12 +1603,32 @@ pub fn integer<N: TryInto<usize> + Copy + ToString>(n: N) -> Symbol {
 }
 
 impl Symbol {
-    fn is_used_keyword_2018(self) -> bool {
-        self >= kw::Async && self <= kw::Dyn
+    fn is_special(self) -> bool {
+        self <= kw::Underscore
+    }
+
+    fn is_used_keyword_always(self) -> bool {
+        self >= kw::As && self <= kw::While
+    }
+
+    fn is_used_keyword_conditional(self, edition: impl FnOnce() -> Edition) -> bool {
+        (self >= kw::Async && self <= kw::Dyn) && edition() >= Edition::Edition2018
+    }
+
+    fn is_unused_keyword_always(self) -> bool {
+        self >= kw::Abstract && self <= kw::Yield
     }
 
-    fn is_unused_keyword_2018(self) -> bool {
-        self == kw::Try
+    fn is_unused_keyword_conditional(self, edition: impl FnOnce() -> Edition) -> bool {
+        self == kw::Try && edition() >= Edition::Edition2018
+    }
+
+    pub fn is_reserved(self, edition: impl Copy + FnOnce() -> Edition) -> bool {
+        self.is_special()
+            || self.is_used_keyword_always()
+            || self.is_unused_keyword_always()
+            || self.is_used_keyword_conditional(edition)
+            || self.is_unused_keyword_conditional(edition)
     }
 
     /// A keyword or reserved identifier that can be used as a path segment.
@@ -1634,7 +1648,7 @@ pub fn is_bool_lit(self) -> bool {
 
     /// Returns `true` if this symbol can be a raw identifier.
     pub fn can_be_raw(self) -> bool {
-        self != kw::Invalid && self != kw::Underscore && !self.is_path_segment_keyword()
+        self != kw::Empty && self != kw::Underscore && !self.is_path_segment_keyword()
     }
 }
 
@@ -1642,26 +1656,27 @@ impl Ident {
     // Returns `true` for reserved identifiers used internally for elided lifetimes,
     // unnamed method parameters, crate root module, error recovery etc.
     pub fn is_special(self) -> bool {
-        self.name <= kw::Underscore
+        self.name.is_special()
     }
 
     /// Returns `true` if the token is a keyword used in the language.
     pub fn is_used_keyword(self) -> bool {
         // Note: `span.edition()` is relatively expensive, don't call it unless necessary.
-        self.name >= kw::As && self.name <= kw::While
-            || self.name.is_used_keyword_2018() && self.span.rust_2018()
+        self.name.is_used_keyword_always()
+            || self.name.is_used_keyword_conditional(|| self.span.edition())
     }
 
     /// Returns `true` if the token is a keyword reserved for possible future use.
     pub fn is_unused_keyword(self) -> bool {
         // Note: `span.edition()` is relatively expensive, don't call it unless necessary.
-        self.name >= kw::Abstract && self.name <= kw::Yield
-            || self.name.is_unused_keyword_2018() && self.span.rust_2018()
+        self.name.is_unused_keyword_always()
+            || self.name.is_unused_keyword_conditional(|| self.span.edition())
     }
 
     /// Returns `true` if the token is either a special identifier or a keyword.
     pub fn is_reserved(self) -> bool {
-        self.is_special() || self.is_used_keyword() || self.is_unused_keyword()
+        // Note: `span.edition()` is relatively expensive, don't call it unless necessary.
+        self.name.is_reserved(|| self.span.edition())
     }
 
     /// A keyword or reserved identifier that can be used as a path segment.
@@ -1681,7 +1696,7 @@ fn with_interner<T, F: FnOnce(&mut Interner) -> T>(f: F) -> T {
     SESSION_GLOBALS.with(|session_globals| f(&mut *session_globals.symbol_interner.lock()))
 }
 
-/// An alternative to `Symbol`, useful when the chars within the symbol need to
+/// An alternative to [`Symbol`], useful when the chars within the symbol need to
 /// be accessed. It deliberately has limited functionality and should only be
 /// used for temporary values.
 ///
index 41184ce21168666cdadbe07ed6bde04a950e72dd..da66fbc8587d7ac498a6d6b92ec8d27e12df07d5 100644 (file)
@@ -162,7 +162,7 @@ impl<'tcx> OutlivesEnvironmentExt<'tcx> for OutlivesEnvironment<'tcx> {
     /// 'b` (and hence, transitively, that `T: 'a`). This method would
     /// add those assumptions into the outlives-environment.
     ///
-    /// Tests: `src/test/compile-fail/regions-free-region-ordering-*.rs`
+    /// Tests: `src/test/ui/regions/regions-free-region-ordering-*.rs`
     fn add_implied_bounds(
         &mut self,
         infcx: &InferCtxt<'a, 'tcx>,
index 6ab16886ed2377ec7ef46137832844274183c9b6..fc6a9a7f20972ffe1fd1c4695c202ebbcfee63f7 100644 (file)
@@ -35,10 +35,7 @@ pub enum AutoTraitResult<A> {
 #[allow(dead_code)]
 impl<A> AutoTraitResult<A> {
     fn is_auto(&self) -> bool {
-        match *self {
-            AutoTraitResult::PositiveImpl(_) | AutoTraitResult::NegativeImpl => true,
-            _ => false,
-        }
+        matches!(self, AutoTraitResult::PositiveImpl(_) | AutoTraitResult::NegativeImpl)
     }
 }
 
@@ -601,10 +598,7 @@ pub fn is_of_param(&self, ty: Ty<'_>) -> bool {
     }
 
     fn is_self_referential_projection(&self, p: ty::PolyProjectionPredicate<'_>) -> bool {
-        match *p.ty().skip_binder().kind() {
-            ty::Projection(proj) if proj == p.skip_binder().projection_ty => true,
-            _ => false,
-        }
+        matches!(*p.ty().skip_binder().kind(), ty::Projection(proj) if proj == p.skip_binder().projection_ty)
     }
 
     fn evaluate_nested_obligations(
index 9324d55ac1b2d2e5e5c4ab235d909e60f79ea4d6..99b96f609647687bb7c4da8155a3c3aa1372e177 100644 (file)
@@ -193,10 +193,8 @@ fn overlap_within_probe(
     let intercrate_ambiguity_causes = selcx.take_intercrate_ambiguity_causes();
     debug!("overlap: intercrate_ambiguity_causes={:#?}", intercrate_ambiguity_causes);
 
-    let involves_placeholder = match selcx.infcx().region_constraints_added_in_snapshot(snapshot) {
-        Some(true) => true,
-        _ => false,
-    };
+    let involves_placeholder =
+        matches!(selcx.infcx().region_constraints_added_in_snapshot(snapshot), Some(true));
 
     Some(OverlapResult { impl_header, intercrate_ambiguity_causes, involves_placeholder })
 }
index 9feba7bfc492f5523653a0a1f4ba1f44dda1dc87..1d82e732907ba29ee31320c39891169f885aca0f 100644 (file)
@@ -861,10 +861,7 @@ fn report_arg_count_mismatch(
 
         let args_str = |arguments: &[ArgKind], other: &[ArgKind]| {
             let arg_length = arguments.len();
-            let distinct = match &other[..] {
-                &[ArgKind::Tuple(..)] => true,
-                _ => false,
-            };
+            let distinct = matches!(other, &[ArgKind::Tuple(..)]);
             match (arg_length, arguments.get(0)) {
                 (1, Some(&ArgKind::Tuple(_, ref fields))) => {
                     format!("a single {}-tuple as argument", fields.len())
@@ -1201,12 +1198,9 @@ fn report_projection_error(
                     normalized_ty, data.ty
                 );
 
-                let is_normalized_ty_expected = match &obligation.cause.code {
-                    ObligationCauseCode::ItemObligation(_)
+                let is_normalized_ty_expected = !matches!(obligation.cause.code, ObligationCauseCode::ItemObligation(_)
                     | ObligationCauseCode::BindingObligation(_, _)
-                    | ObligationCauseCode::ObjectCastObligation(_) => false,
-                    _ => true,
-                };
+                    | ObligationCauseCode::ObjectCastObligation(_));
 
                 if let Err(error) = self.at(&obligation.cause, obligation.param_env).eq_exp(
                     is_normalized_ty_expected,
index 2fb9b3cd5d30547f03ac3d1ce6caa4cd744704f1..9c894e99a389a684b4106447e78cdc47f7d48205 100644 (file)
@@ -323,9 +323,8 @@ pub fn normalize_param_env_or_error<'tcx>(
     // This works fairly well because trait matching  does not actually care about param-env
     // TypeOutlives predicates - these are normally used by regionck.
     let outlives_predicates: Vec<_> = predicates
-        .drain_filter(|predicate| match predicate.skip_binders() {
-            ty::PredicateAtom::TypeOutlives(..) => true,
-            _ => false,
+        .drain_filter(|predicate| {
+            matches!(predicate.skip_binders(), ty::PredicateAtom::TypeOutlives(..))
         })
         .collect();
 
index a11499e43209f662817d43141924363663485002..fa0526445c194042aab483cfbd76a87f5c8b46ce 100644 (file)
@@ -496,12 +496,6 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>(
             return Ok(None);
         }
         Err(ProjectionCacheEntry::InProgress) => {
-            // If while normalized A::B, we are asked to normalize
-            // A::B, just return A::B itself. This is a conservative
-            // answer, in the sense that A::B *is* clearly equivalent
-            // to A::B, though there may be a better value we can
-            // find.
-
             // Under lazy normalization, this can arise when
             // bootstrapping.  That is, imagine an environment with a
             // where-clause like `A::B == u32`. Now, if we are asked
@@ -512,6 +506,14 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>(
 
             debug!("found cache entry: in-progress");
 
+            // Cache that normalizing this projection resulted in a cycle. This
+            // should ensure that, unless this happens within a snapshot that's
+            // rolled back, fulfillment or evaluation will notice the cycle.
+
+            infcx.inner.borrow_mut().projection_cache().recur(cache_key);
+            return Err(InProgress);
+        }
+        Err(ProjectionCacheEntry::Recur) => {
             return Err(InProgress);
         }
         Err(ProjectionCacheEntry::NormalizedTy(ty)) => {
@@ -734,7 +736,14 @@ fn project_type<'cx, 'tcx>(
 
     if !selcx.tcx().sess.recursion_limit().value_within_limit(obligation.recursion_depth) {
         debug!("project: overflow!");
-        return Err(ProjectionTyError::TraitSelectionError(SelectionError::Overflow));
+        match selcx.query_mode() {
+            super::TraitQueryMode::Standard => {
+                selcx.infcx().report_overflow_error(&obligation, true);
+            }
+            super::TraitQueryMode::Canonical => {
+                return Err(ProjectionTyError::TraitSelectionError(SelectionError::Overflow));
+            }
+        }
     }
 
     let obligation_trait_ref = &obligation.predicate.trait_ref(selcx.tcx());
index ca3369b8f1e9d2d2c313f16d3d782faa6efdd752..f09ce8d64ed5e1b5bba37d3d21b8df6d8b508dc1 100644 (file)
@@ -247,7 +247,7 @@ pub(super) fn assemble_candidates<'o>(
 
         let mut candidates = SelectionCandidateSet { vec: Vec::new(), ambiguous: false };
 
-        self.assemble_candidates_for_trait_alias(obligation, &mut candidates)?;
+        self.assemble_candidates_for_trait_alias(obligation, &mut candidates);
 
         // Other bounds. Consider both in-scope bounds from fn decl
         // and applicable impls. There is a certain set of precedence rules here.
@@ -259,11 +259,11 @@ pub(super) fn assemble_candidates<'o>(
 
             // User-defined copy impls are permitted, but only for
             // structs and enums.
-            self.assemble_candidates_from_impls(obligation, &mut candidates)?;
+            self.assemble_candidates_from_impls(obligation, &mut candidates);
 
             // For other types, we'll use the builtin rules.
             let copy_conditions = self.copy_clone_conditions(obligation);
-            self.assemble_builtin_bound_candidates(copy_conditions, &mut candidates)?;
+            self.assemble_builtin_bound_candidates(copy_conditions, &mut candidates);
         } else if lang_items.discriminant_kind_trait() == Some(def_id) {
             // `DiscriminantKind` is automatically implemented for every type.
             candidates.vec.push(DiscriminantKindCandidate);
@@ -271,7 +271,7 @@ pub(super) fn assemble_candidates<'o>(
             // Sized is never implementable by end-users, it is
             // always automatically computed.
             let sized_conditions = self.sized_conditions(obligation);
-            self.assemble_builtin_bound_candidates(sized_conditions, &mut candidates)?;
+            self.assemble_builtin_bound_candidates(sized_conditions, &mut candidates);
         } else if lang_items.unsize_trait() == Some(def_id) {
             self.assemble_candidates_for_unsizing(obligation, &mut candidates);
         } else {
@@ -280,13 +280,13 @@ pub(super) fn assemble_candidates<'o>(
                 // for `Copy` also has builtin support for `Clone`, and tuples/arrays of `Clone`
                 // types have builtin support for `Clone`.
                 let clone_conditions = self.copy_clone_conditions(obligation);
-                self.assemble_builtin_bound_candidates(clone_conditions, &mut candidates)?;
+                self.assemble_builtin_bound_candidates(clone_conditions, &mut candidates);
             }
 
-            self.assemble_generator_candidates(obligation, &mut candidates)?;
-            self.assemble_closure_candidates(obligation, &mut candidates)?;
-            self.assemble_fn_pointer_candidates(obligation, &mut candidates)?;
-            self.assemble_candidates_from_impls(obligation, &mut candidates)?;
+            self.assemble_generator_candidates(obligation, &mut candidates);
+            self.assemble_closure_candidates(obligation, &mut candidates);
+            self.assemble_fn_pointer_candidates(obligation, &mut candidates);
+            self.assemble_candidates_from_impls(obligation, &mut candidates);
             self.assemble_candidates_from_object_ty(obligation, &mut candidates);
         }
 
@@ -295,7 +295,7 @@ pub(super) fn assemble_candidates<'o>(
         // Auto implementations have lower priority, so we only
         // consider triggering a default if there is no other impl that can apply.
         if candidates.vec.is_empty() {
-            self.assemble_candidates_from_auto_impls(obligation, &mut candidates)?;
+            self.assemble_candidates_from_auto_impls(obligation, &mut candidates);
         }
         debug!("candidate list size: {}", candidates.vec.len());
         Ok(candidates)
@@ -367,9 +367,9 @@ fn assemble_generator_candidates(
         &mut self,
         obligation: &TraitObligation<'tcx>,
         candidates: &mut SelectionCandidateSet<'tcx>,
-    ) -> Result<(), SelectionError<'tcx>> {
+    ) {
         if self.tcx().lang_items().gen_trait() != Some(obligation.predicate.def_id()) {
-            return Ok(());
+            return;
         }
 
         // Okay to skip binder because the substs on generator types never
@@ -388,8 +388,6 @@ fn assemble_generator_candidates(
             }
             _ => {}
         }
-
-        Ok(())
     }
 
     /// Checks for the artificial impl that the compiler will create for an obligation like `X :
@@ -402,11 +400,11 @@ fn assemble_closure_candidates(
         &mut self,
         obligation: &TraitObligation<'tcx>,
         candidates: &mut SelectionCandidateSet<'tcx>,
-    ) -> Result<(), SelectionError<'tcx>> {
+    ) {
         let kind = match self.tcx().fn_trait_kind_from_lang_item(obligation.predicate.def_id()) {
             Some(k) => k,
             None => {
-                return Ok(());
+                return;
             }
         };
 
@@ -435,8 +433,6 @@ fn assemble_closure_candidates(
             }
             _ => {}
         }
-
-        Ok(())
     }
 
     /// Implements one of the `Fn()` family for a fn pointer.
@@ -444,10 +440,10 @@ fn assemble_fn_pointer_candidates(
         &mut self,
         obligation: &TraitObligation<'tcx>,
         candidates: &mut SelectionCandidateSet<'tcx>,
-    ) -> Result<(), SelectionError<'tcx>> {
+    ) {
         // We provide impl of all fn traits for fn pointers.
         if self.tcx().fn_trait_kind_from_lang_item(obligation.predicate.def_id()).is_none() {
-            return Ok(());
+            return;
         }
 
         // Okay to skip binder because what we are inspecting doesn't involve bound regions.
@@ -485,8 +481,6 @@ fn assemble_fn_pointer_candidates(
             }
             _ => {}
         }
-
-        Ok(())
     }
 
     /// Searches for impls that might apply to `obligation`.
@@ -494,7 +488,7 @@ fn assemble_candidates_from_impls(
         &mut self,
         obligation: &TraitObligation<'tcx>,
         candidates: &mut SelectionCandidateSet<'tcx>,
-    ) -> Result<(), SelectionError<'tcx>> {
+    ) {
         debug!(?obligation, "assemble_candidates_from_impls");
 
         // Essentially any user-written impl will match with an error type,
@@ -504,7 +498,7 @@ fn assemble_candidates_from_impls(
         // Since compilation is already guaranteed to fail, this is just
         // to try to show the 'nicest' possible errors to the user.
         if obligation.references_error() {
-            return Ok(());
+            return;
         }
 
         self.tcx().for_each_relevant_impl(
@@ -518,15 +512,13 @@ fn assemble_candidates_from_impls(
                 });
             },
         );
-
-        Ok(())
     }
 
     fn assemble_candidates_from_auto_impls(
         &mut self,
         obligation: &TraitObligation<'tcx>,
         candidates: &mut SelectionCandidateSet<'tcx>,
-    ) -> Result<(), SelectionError<'tcx>> {
+    ) {
         // Okay to skip binder here because the tests we do below do not involve bound regions.
         let self_ty = obligation.self_ty().skip_binder();
         debug!(?self_ty, "assemble_candidates_from_auto_impls");
@@ -558,7 +550,7 @@ fn assemble_candidates_from_auto_impls(
                     // where-clause or, in the case of an object type,
                     // it could be that the object type lists the
                     // trait (e.g., `Foo+Send : Send`). See
-                    // `compile-fail/typeck-default-trait-impl-send-param.rs`
+                    // `ui/typeck/typeck-default-trait-impl-send-param.rs`
                     // for an example of a test case that exercises
                     // this path.
                 }
@@ -585,8 +577,6 @@ fn assemble_candidates_from_auto_impls(
                 _ => candidates.vec.push(AutoImplCandidate(def_id)),
             }
         }
-
-        Ok(())
     }
 
     /// Searches for impls that might apply to `obligation`.
@@ -753,7 +743,7 @@ fn assemble_candidates_for_trait_alias(
         &mut self,
         obligation: &TraitObligation<'tcx>,
         candidates: &mut SelectionCandidateSet<'tcx>,
-    ) -> Result<(), SelectionError<'tcx>> {
+    ) {
         // Okay to skip binder here because the tests we do below do not involve bound regions.
         let self_ty = obligation.self_ty().skip_binder();
         debug!(?self_ty, "assemble_candidates_for_trait_alias");
@@ -763,8 +753,6 @@ fn assemble_candidates_for_trait_alias(
         if self.tcx().is_trait_alias(def_id) {
             candidates.vec.push(TraitAliasCandidate(def_id));
         }
-
-        Ok(())
     }
 
     /// Assembles the trait which are built-in to the language itself:
@@ -773,7 +761,7 @@ fn assemble_builtin_bound_candidates(
         &mut self,
         conditions: BuiltinImplConditions<'tcx>,
         candidates: &mut SelectionCandidateSet<'tcx>,
-    ) -> Result<(), SelectionError<'tcx>> {
+    ) {
         match conditions {
             BuiltinImplConditions::Where(nested) => {
                 debug!(?nested, "builtin_bound");
@@ -787,7 +775,5 @@ fn assemble_builtin_bound_candidates(
                 candidates.ambiguous = true;
             }
         }
-
-        Ok(())
     }
 }
index f1c86eab0956e3c76fe9d7a46e7b8db2d28676fe..a8f81445b03979dab77ed6411eb60292639f368b 100644 (file)
@@ -291,6 +291,10 @@ pub fn tcx(&self) -> TyCtxt<'tcx> {
         self.infcx.tcx
     }
 
+    pub(super) fn query_mode(&self) -> TraitQueryMode {
+        self.query_mode
+    }
+
     ///////////////////////////////////////////////////////////////////////////
     // Selection
     //
index f3a55fec9e4627dd049efd1f25164e27ab0e9382..bd2f87f70a2f1f983aaa197591f5798e36acb80f 100644 (file)
@@ -98,7 +98,7 @@
     let mut solver = chalk_engine::solve::SLGSolver::new(32, None);
     let db = ChalkRustIrDatabase { interner, reempty_placeholder };
     let solution = solver.solve(&db, &lowered_goal);
-    debug!(?obligation, ?solution, "evaluatate goal");
+    debug!(?obligation, ?solution, "evaluate goal");
 
     // Ideally, the code to convert *back* to rustc types would live close to
     // the code to convert *from* rustc types. Right now though, we don't
index b7e77f389f8575c9500156ed57eebeef00e5b64c..0feac036f00265a90a5d4093ad8fdd139f5cd137 100644 (file)
@@ -526,18 +526,16 @@ pub(crate) fn check_impl_trait(
         generics: &ty::Generics,
     ) -> bool {
         let explicit = !seg.infer_args;
-        let impl_trait =
-            generics.params.iter().any(|param| match param.kind {
-                ty::GenericParamDefKind::Type {
-                    synthetic:
-                        Some(
-                            hir::SyntheticTyParamKind::ImplTrait
-                            | hir::SyntheticTyParamKind::FromAttr,
-                        ),
-                    ..
-                } => true,
-                _ => false,
-            });
+        let impl_trait = generics.params.iter().any(|param| {
+            matches!(param.kind, ty::GenericParamDefKind::Type {
+                synthetic:
+                    Some(
+                        hir::SyntheticTyParamKind::ImplTrait
+                        | hir::SyntheticTyParamKind::FromAttr,
+                    ),
+                ..
+            })
+        });
 
         if explicit && impl_trait {
             let spans = seg
index ec7369fd3e8ee6c96329ae849e36438a9244843d..9c60e8933d4dbf4bf242a050f785c823a01a3714 100644 (file)
@@ -543,10 +543,9 @@ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
 
         if let Some(ty) = prohibit_opaque.break_value() {
             let is_async = match item.kind {
-                ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => match origin {
-                    hir::OpaqueTyOrigin::AsyncFn => true,
-                    _ => false,
-                },
+                ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => {
+                    matches!(origin, hir::OpaqueTyOrigin::AsyncFn)
+                }
                 _ => unreachable!(),
             };
 
@@ -1321,10 +1320,7 @@ pub fn check_enum<'tcx>(
     }
 
     if tcx.adt_def(def_id).repr.int.is_none() && tcx.features().arbitrary_enum_discriminant {
-        let is_unit = |var: &hir::Variant<'_>| match var.data {
-            hir::VariantData::Unit(..) => true,
-            _ => false,
-        };
+        let is_unit = |var: &hir::Variant<'_>| matches!(var.data, hir::VariantData::Unit(..));
 
         let has_disr = |var: &hir::Variant<'_>| var.disr_expr.is_some();
         let has_non_units = vs.iter().any(|var| !is_unit(var));
index aa4d57f7e1d97ef55b90a850a877de8fcda6d27c..2728e03171a75df207825ecfa5c56049ae050c87 100644 (file)
@@ -360,10 +360,6 @@ fn can_use_as_ref(&self, expr: &hir::Expr<'_>) -> Option<(Span, &'static str, St
         false
     }
 
-    fn replace_prefix(&self, s: &str, old: &str, new: &str) -> Option<String> {
-        s.strip_prefix(old).map(|stripped| new.to_string() + stripped)
-    }
-
     /// This function is used to determine potential "simple" improvements or users' errors and
     /// provide them useful help. For example:
     ///
@@ -394,6 +390,10 @@ pub fn check_ref(
             return None;
         }
 
+        let replace_prefix = |s: &str, old: &str, new: &str| {
+            s.strip_prefix(old).map(|stripped| new.to_string() + stripped)
+        };
+
         let is_struct_pat_shorthand_field =
             self.is_hir_id_from_struct_pattern_shorthand_field(expr.hir_id, sp);
 
@@ -409,7 +409,7 @@ pub fn check_ref(
                 (&ty::Str, &ty::Array(arr, _) | &ty::Slice(arr)) if arr == self.tcx.types.u8 => {
                     if let hir::ExprKind::Lit(_) = expr.kind {
                         if let Ok(src) = sm.span_to_snippet(sp) {
-                            if let Some(src) = self.replace_prefix(&src, "b\"", "\"") {
+                            if let Some(src) = replace_prefix(&src, "b\"", "\"") {
                                 return Some((
                                     sp,
                                     "consider removing the leading `b`",
@@ -423,7 +423,7 @@ pub fn check_ref(
                 (&ty::Array(arr, _) | &ty::Slice(arr), &ty::Str) if arr == self.tcx.types.u8 => {
                     if let hir::ExprKind::Lit(_) = expr.kind {
                         if let Ok(src) = sm.span_to_snippet(sp) {
-                            if let Some(src) = self.replace_prefix(&src, "\"", "b\"") {
+                            if let Some(src) = replace_prefix(&src, "\"", "b\"") {
                                 return Some((
                                     sp,
                                     "consider adding a leading `b`",
@@ -583,23 +583,27 @@ pub fn check_ref(
                                 hir::Mutability::Mut => {
                                     let new_prefix = "&mut ".to_owned() + derefs;
                                     match mutbl_a {
-                                        hir::Mutability::Mut => self
-                                            .replace_prefix(&src, "&mut ", &new_prefix)
-                                            .map(|s| (s, Applicability::MachineApplicable)),
-                                        hir::Mutability::Not => self
-                                            .replace_prefix(&src, "&", &new_prefix)
-                                            .map(|s| (s, Applicability::Unspecified)),
+                                        hir::Mutability::Mut => {
+                                            replace_prefix(&src, "&mut ", &new_prefix)
+                                                .map(|s| (s, Applicability::MachineApplicable))
+                                        }
+                                        hir::Mutability::Not => {
+                                            replace_prefix(&src, "&", &new_prefix)
+                                                .map(|s| (s, Applicability::Unspecified))
+                                        }
                                     }
                                 }
                                 hir::Mutability::Not => {
                                     let new_prefix = "&".to_owned() + derefs;
                                     match mutbl_a {
-                                        hir::Mutability::Mut => self
-                                            .replace_prefix(&src, "&mut ", &new_prefix)
-                                            .map(|s| (s, Applicability::MachineApplicable)),
-                                        hir::Mutability::Not => self
-                                            .replace_prefix(&src, "&", &new_prefix)
-                                            .map(|s| (s, Applicability::MachineApplicable)),
+                                        hir::Mutability::Mut => {
+                                            replace_prefix(&src, "&mut ", &new_prefix)
+                                                .map(|s| (s, Applicability::MachineApplicable))
+                                        }
+                                        hir::Mutability::Not => {
+                                            replace_prefix(&src, "&", &new_prefix)
+                                                .map(|s| (s, Applicability::MachineApplicable))
+                                        }
                                     }
                                 }
                             } {
index ad675f1e3833e229bb511c28755d6e796d15cd84..be19919c0ea1f6be8cc20aa99cb6405a583b52f6 100644 (file)
@@ -267,15 +267,13 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>(
     ty: Ty<'tcx>,
     span: Span,
     body_id: hir::HirId,
-) -> Result<(), ErrorReported> {
+) {
     debug!("check_drop_obligations typ: {:?}", ty);
 
     let cause = &ObligationCause::misc(span, body_id);
     let infer_ok = rcx.infcx.at(cause, rcx.fcx.param_env).dropck_outlives(ty);
     debug!("dropck_outlives = {:#?}", infer_ok);
     rcx.fcx.register_infer_ok_obligations(infer_ok);
-
-    Ok(())
 }
 
 // This is an implementation of the TypeRelation trait with the
index ec0e039b5d29d99867fa0672f3104a6421f41129..93eb2cfc72a8059d903db58ec5b0bf81f223a764 100644 (file)
@@ -883,7 +883,7 @@ fn check_method_call(
                 Ok(method)
             }
             Err(error) => {
-                if segment.ident.name != kw::Invalid {
+                if segment.ident.name != kw::Empty {
                     self.report_extended_method_error(segment, span, args, rcvr_t, error);
                 }
                 Err(())
@@ -1547,7 +1547,7 @@ fn check_field(
             return field_ty;
         }
 
-        if field.name == kw::Invalid {
+        if field.name == kw::Empty {
         } else if self.method_exists(field, expr_t, expr.hir_id, true) {
             self.ban_take_value_of_method(expr, expr_t, field);
         } else if !expr_t.is_primitive_ty() {
index 41a403a010ee698b1fa840dd2e88e0e445a40682..2a8b77da44fc461530d769aae82aa143b53dff93 100644 (file)
@@ -914,7 +914,7 @@ pub fn resolve_ty_and_res_ufcs<'b>(
                 method::MethodError::PrivateMatch(kind, def_id, _) => Ok((kind, def_id)),
                 _ => Err(ErrorReported),
             };
-            if item_name.name != kw::Invalid {
+            if item_name.name != kw::Empty {
                 if let Some(mut e) = self.report_method_error(
                     span,
                     ty,
index 333bda00dbe817f4fefe808d68898bffbcec5ed4..3e60924d6fcf889b22af1fa83ec86956c3f8e9c6 100644 (file)
@@ -325,10 +325,7 @@ pub(in super::super) fn check_argument_types(
                     self.warn_if_unreachable(arg.hir_id, arg.span, "expression");
                 }
 
-                let is_closure = match arg.kind {
-                    ExprKind::Closure(..) => true,
-                    _ => false,
-                };
+                let is_closure = matches!(arg.kind, ExprKind::Closure(..));
 
                 if is_closure != check_closures {
                     continue;
index c3b0fc60b97058cda6c49f92a797f74d081a53e6..673dec6c7f9a74b81abe70d5cd8e19e8fcfea593 100644 (file)
@@ -92,6 +92,7 @@ pub fn intrinsic_operation_unsafety(intrinsic: Symbol) -> hir::Unsafety {
         | sym::rustc_peek
         | sym::maxnumf64
         | sym::type_name
+        | sym::forget
         | sym::variant_count => hir::Unsafety::Normal,
         _ => hir::Unsafety::Unsafe,
     }
index 891dd8b2f0228f98b44b75ae8d1bf59df41707a0..d4631c465a3a7c8c81a0fbb7e906f2e789070502 100644 (file)
@@ -423,9 +423,9 @@ fn probe_op<OP, R>(
             probe_cx.assemble_inherent_candidates();
             match scope {
                 ProbeScope::TraitsInScope => {
-                    probe_cx.assemble_extension_candidates_for_traits_in_scope(scope_expr_id)?
+                    probe_cx.assemble_extension_candidates_for_traits_in_scope(scope_expr_id)
                 }
-                ProbeScope::AllTraits => probe_cx.assemble_extension_candidates_for_all_traits()?,
+                ProbeScope::AllTraits => probe_cx.assemble_extension_candidates_for_all_traits(),
             };
             op(probe_cx)
         })
@@ -866,35 +866,29 @@ fn elaborate_bounds<F>(
         }
     }
 
-    fn assemble_extension_candidates_for_traits_in_scope(
-        &mut self,
-        expr_hir_id: hir::HirId,
-    ) -> Result<(), MethodError<'tcx>> {
+    fn assemble_extension_candidates_for_traits_in_scope(&mut self, expr_hir_id: hir::HirId) {
         let mut duplicates = FxHashSet::default();
         let opt_applicable_traits = self.tcx.in_scope_traits(expr_hir_id);
         if let Some(applicable_traits) = opt_applicable_traits {
             for trait_candidate in applicable_traits.iter() {
                 let trait_did = trait_candidate.def_id;
                 if duplicates.insert(trait_did) {
-                    let result = self.assemble_extension_candidates_for_trait(
+                    self.assemble_extension_candidates_for_trait(
                         &trait_candidate.import_ids,
                         trait_did,
                     );
-                    result?;
                 }
             }
         }
-        Ok(())
     }
 
-    fn assemble_extension_candidates_for_all_traits(&mut self) -> Result<(), MethodError<'tcx>> {
+    fn assemble_extension_candidates_for_all_traits(&mut self) {
         let mut duplicates = FxHashSet::default();
         for trait_info in suggest::all_traits(self.tcx) {
             if duplicates.insert(trait_info.def_id) {
-                self.assemble_extension_candidates_for_trait(&smallvec![], trait_info.def_id)?;
+                self.assemble_extension_candidates_for_trait(&smallvec![], trait_info.def_id);
             }
         }
-        Ok(())
     }
 
     pub fn matches_return_type(
@@ -932,7 +926,7 @@ fn assemble_extension_candidates_for_trait(
         &mut self,
         import_ids: &SmallVec<[LocalDefId; 1]>,
         trait_def_id: DefId,
-    ) -> Result<(), MethodError<'tcx>> {
+    ) {
         debug!("assemble_extension_candidates_for_trait(trait_def_id={:?})", trait_def_id);
         let trait_substs = self.fresh_item_substs(trait_def_id);
         let trait_ref = ty::TraitRef::new(trait_def_id, trait_substs);
@@ -980,7 +974,6 @@ fn assemble_extension_candidates_for_trait(
                 );
             }
         }
-        Ok(())
     }
 
     fn candidate_method_names(&self) -> Vec<Ident> {
@@ -1027,7 +1020,7 @@ fn pick(mut self) -> PickResult<'tcx> {
         let span = self.span;
         let tcx = self.tcx;
 
-        self.assemble_extension_candidates_for_all_traits()?;
+        self.assemble_extension_candidates_for_all_traits();
 
         let out_of_scope_traits = match self.pick_core() {
             Some(Ok(p)) => vec![p.item.container.id()],
index b8b98cef7637a849c2f00e79c04f9cda0cd9b376..88e8dd3cb129aa1ac39358c81274c6e0ab41fbea 100644 (file)
@@ -325,7 +325,7 @@ fn constrain_bindings_in_pat(&mut self, pat: &hir::Pat<'_>) {
         pat.each_binding(|_, hir_id, span, _| {
             let typ = self.resolve_node_type(hir_id);
             let body_id = self.body_id;
-            let _ = dropck::check_drop_obligations(self, typ, span, body_id);
+            dropck::check_drop_obligations(self, typ, span, body_id);
         })
     }
 }
@@ -354,10 +354,7 @@ fn visit_fn(
         hir_id: hir::HirId,
     ) {
         assert!(
-            match fk {
-                intravisit::FnKind::Closure(..) => true,
-                _ => false,
-            },
+            matches!(fk, intravisit::FnKind::Closure(..)),
             "visit_fn invoked for something other than a closure"
         );
 
@@ -491,7 +488,7 @@ fn check_safety_of_rvalue_destructor_if_necessary(
             if place_with_id.place.projections.is_empty() {
                 let typ = self.resolve_type(place_with_id.place.ty());
                 let body_id = self.body_id;
-                let _ = dropck::check_drop_obligations(self, typ, span, body_id);
+                dropck::check_drop_obligations(self, typ, span, body_id);
             }
         }
     }
index 0f084c5c11f399ce2badd708da29eb2fa3f62f24..e8cbefd44ee6d842477c1c4dc905e9bd5930dc79 100644 (file)
@@ -390,7 +390,7 @@ fn compute_min_captures(
 
             let min_cap_list = match root_var_min_capture_list.get_mut(&var_hir_id) {
                 None => {
-                    let min_cap_list = vec![ty::CapturedPlace { place: place, info: capture_info }];
+                    let min_cap_list = vec![ty::CapturedPlace { place, info: capture_info }];
                     root_var_min_capture_list.insert(var_hir_id, min_cap_list);
                     continue;
                 }
index c09f8cce5b44de9d8eb3bae178c27fb6ed9848fc..cd871a4da979f4786c10abba07a88e6ea0c4adb2 100644 (file)
@@ -293,7 +293,13 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) {
 
             let err_ty_str;
             let mut is_ptr = true;
-            let err = if tcx.features().min_const_generics {
+            let err = if tcx.features().const_generics {
+                match ty.peel_refs().kind() {
+                    ty::FnPtr(_) => Some("function pointers"),
+                    ty::RawPtr(_) => Some("raw pointers"),
+                    _ => None,
+                }
+            } else {
                 match ty.kind() {
                     ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Error(_) => None,
                     ty::FnPtr(_) => Some("function pointers"),
@@ -304,12 +310,6 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) {
                         Some(err_ty_str.as_str())
                     }
                 }
-            } else {
-                match ty.peel_refs().kind() {
-                    ty::FnPtr(_) => Some("function pointers"),
-                    ty::RawPtr(_) => Some("raw pointers"),
-                    _ => None,
-                }
             };
             if let Some(unsupported_type) = err {
                 if is_ptr {
index d5643fcca873e57702724a938ee3bf83e38aa817..3e40f5ba28a7eec224c92da7a071aace8f7e5564 100644 (file)
@@ -156,10 +156,10 @@ struct CollectItemTypesVisitor<'tcx> {
         if let Some(span) = span {
             sugg.push((span, format!("<{}>", type_name)));
         }
-    } else if let Some(arg) = generics.iter().find(|arg| match arg.name {
-        hir::ParamName::Plain(Ident { name: kw::Underscore, .. }) => true,
-        _ => false,
-    }) {
+    } else if let Some(arg) = generics
+        .iter()
+        .find(|arg| matches!(arg.name, hir::ParamName::Plain(Ident { name: kw::Underscore, .. })))
+    {
         // Account for `_` already present in cases like `struct S<_>(_);` and suggest
         // `struct S<T>(T);` instead of `struct S<_, T>(T);`.
         sugg.push((arg.span, (*type_name).to_string()));
@@ -1260,7 +1260,7 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
                 // used with const generics, e.g. `Foo<{N+1}>`, can work at all.
                 //
                 // Note that we do not supply the parent generics when using
-                // `feature(min_const_generics)`.
+                // `min_const_generics`.
                 Some(parent_def_id.to_def_id())
             } else {
                 let parent_node = tcx.hir().get(tcx.hir().get_parent_node(hir_id));
@@ -1369,7 +1369,11 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
         generics.parent_count + generics.params.len()
     });
 
-    let mut params: Vec<_> = opt_self.into_iter().collect();
+    let mut params: Vec<_> = Vec::with_capacity(ast_generics.params.len() + has_self as usize);
+
+    if let Some(opt_self) = opt_self {
+        params.push(opt_self);
+    }
 
     let early_lifetimes = early_bound_lifetimes_from_generics(tcx, ast_generics);
     params.extend(early_lifetimes.enumerate().map(|(i, param)| ty::GenericParamDef {
@@ -1540,12 +1544,27 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> {
                     let mut diag = bad_placeholder_type(tcx, visitor.0);
                     let ret_ty = fn_sig.output();
                     if ret_ty != tcx.ty_error() {
-                        diag.span_suggestion(
-                            ty.span,
-                            "replace with the correct return type",
-                            ret_ty.to_string(),
-                            Applicability::MaybeIncorrect,
-                        );
+                        if !ret_ty.is_closure() {
+                            let ret_ty_str = match ret_ty.kind() {
+                                // Suggest a function pointer return type instead of a unique function definition
+                                // (e.g. `fn() -> i32` instead of `fn() -> i32 { f }`, the latter of which is invalid
+                                // syntax)
+                                ty::FnDef(..) => ret_ty.fn_sig(tcx).to_string(),
+                                _ => ret_ty.to_string(),
+                            };
+                            diag.span_suggestion(
+                                ty.span,
+                                "replace with the correct return type",
+                                ret_ty_str,
+                                Applicability::MaybeIncorrect,
+                            );
+                        } else {
+                            // We're dealing with a closure, so we should suggest using `impl Fn` or trait bounds
+                            // to prevent the user from getting a papercut while trying to use the unique closure
+                            // syntax (e.g. `[closure@src/lib.rs:2:5: 2:9]`).
+                            diag.help("consider using an `Fn`, `FnMut`, or `FnOnce` trait bound");
+                            diag.note("for more information on `Fn` traits and closure types, see https://doc.rust-lang.org/book/ch13-01-closures.html");
+                        }
                     }
                     diag.emit();
                     ty::Binder::bind(fn_sig)
@@ -1748,8 +1767,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
     const NO_GENERICS: &hir::Generics<'_> = &hir::Generics::empty();
 
     // We use an `IndexSet` to preserves order of insertion.
-    // Preserving the order of insertion is important here so as not to break
-    // compile-fail UI tests.
+    // Preserving the order of insertion is important here so as not to break UI tests.
     let mut predicates: FxIndexSet<(ty::Predicate<'_>, Span)> = FxIndexSet::default();
 
     let ast_generics = match node {
index ce9fd5575cf957ff71ad7df3230c628fdcf18c86..3ce244e11bf453dd391db7aa0ae28ffb68c20eca 100644 (file)
@@ -595,10 +595,10 @@ fn walk_captures(&mut self, closure_expr: &hir::Expr<'_>) {
         let upvars = self.tcx().upvars_mentioned(self.body_owner);
 
         // For purposes of this function, generator and closures are equivalent.
-        let body_owner_is_closure = match self.tcx().type_of(self.body_owner.to_def_id()).kind() {
-            ty::Closure(..) | ty::Generator(..) => true,
-            _ => false,
-        };
+        let body_owner_is_closure = matches!(
+            self.tcx().type_of(self.body_owner.to_def_id()).kind(),
+            ty::Closure(..) | ty::Generator(..)
+        );
 
         if let Some(min_captures) = self.mc.typeck_results.closure_min_captures.get(&closure_def_id)
         {
index 9992094117dfc847c9f32e5540bcf5866c6fa776..a601123c8d0555a8acf5c0277beb54af279dd391 100644 (file)
@@ -459,7 +459,7 @@ fn cat_upvar(&self, hir_id: hir::HirId, var_id: hir::HirId) -> McResult<PlaceWit
         kind: ProjectionKind,
     ) -> PlaceWithHirId<'tcx> {
         let mut projections = base_place.place.projections;
-        projections.push(Projection { kind: kind, ty: ty });
+        projections.push(Projection { kind, ty });
         let ret = PlaceWithHirId::new(
             node.hir_id(),
             base_place.place.base_ty,
index b1fb8904ca9889779d0b94d637dd6b9707e42168..9e08ce9b27e0cdf7e0d41171162a58a60234ffb3 100644 (file)
@@ -669,3 +669,7 @@ changelog-seen = 2
 
 # Whether to allow failures when building tools
 #missing-tools = false
+
+# List of compression formats to use when generating dist tarballs. The list of
+# formats is provided to rust-installer, which must support all of them.
+#compression-formats = ["gz", "xz"]
index 97ebc12175f73c6149a0b49189636b9d74cd2651..76051d9e1dffdc149d2c3344d55d53fc3629a516 100644 (file)
@@ -915,6 +915,7 @@ pub fn into_vec(self) -> Vec<T> {
     ///
     /// assert_eq!(heap.len(), 2);
     /// ```
+    #[doc(alias = "length")]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn len(&self) -> usize {
         self.data.len()
index bd99c4ed2f14e7e24bc21fd61efa22d7b6e7a3d2..1d6488dd2dfe32b44de7e70f43f890d71d316862 100644 (file)
@@ -30,7 +30,7 @@ pub fn append_from_sorted_iters<I>(&mut self, left: I, right: I, length: &mut us
     /// Pushes all key-value pairs to the end of the tree, incrementing a
     /// `length` variable along the way. The latter makes it easier for the
     /// caller to avoid a leak when the iterator panicks.
-    fn bulk_push<I>(&mut self, iter: I, length: &mut usize)
+    pub fn bulk_push<I>(&mut self, iter: I, length: &mut usize)
     where
         I: Iterator<Item = (K, V)>,
     {
@@ -81,15 +81,18 @@ fn bulk_push<I>(&mut self, iter: I, length: &mut usize)
             // the appended elements even if advancing the iterator panicks.
             *length += 1;
         }
-        self.fix_right_edge();
+        self.fix_right_border_of_plentiful();
     }
 
-    fn fix_right_edge(&mut self) {
-        // Handle underfull nodes, start from the top.
+    /// Stock up any underfull nodes on the right border of the tree.
+    /// The other nodes, those that are not the root nor a rightmost edge,
+    /// must have MIN_LEN elements to spare.
+    fn fix_right_border_of_plentiful(&mut self) {
         let mut cur_node = self.borrow_mut();
         while let Internal(internal) = cur_node.force() {
             // Check if right-most child is underfull.
             let mut last_kv = internal.last_kv().consider_for_balancing();
+            debug_assert!(last_kv.left_child_len() >= MIN_LEN * 2);
             let right_child_len = last_kv.right_child_len();
             if right_child_len < MIN_LEN {
                 // We need to steal.
index bd2ad257402fa6511069015fe56382ab72ff7b33..944e0e65cf7c111e061d3fd94a5105254120df3d 100644 (file)
@@ -248,7 +248,7 @@ fn replace(&mut self, key: K) -> Option<K> {
         let (map, dormant_map) = DormantMutRef::new(self);
         let root_node = Self::ensure_is_owned(&mut map.root).borrow_mut();
         match search::search_tree::<marker::Mut<'_>, K, (), K>(root_node, &key) {
-            Found(handle) => Some(mem::replace(handle.into_key_mut(), key)),
+            Found(mut kv) => Some(mem::replace(kv.key_mut(), key)),
             GoDown(handle) => {
                 VacantEntry { key, handle, dormant_map, _marker: PhantomData }.insert(());
                 None
@@ -2132,6 +2132,7 @@ pub fn values_mut(&mut self) -> ValuesMut<'_, K, V> {
     /// a.insert(1, "a");
     /// assert_eq!(a.len(), 1);
     /// ```
+    #[doc(alias = "length")]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_const_unstable(feature = "const_btree_new", issue = "71835")]
     pub const fn len(&self) -> usize {
index 97df8ea07d23ed88c728a130292cfa60a54dbd24..f92aed8ce15bf8b10397ed9e2a77f79fbdfb5853 100644 (file)
@@ -111,11 +111,23 @@ fn assert_strictly_ascending(&self)
             }
         }
     }
+
+    // Transform the tree to minimize wasted space, obtaining fewer nodes that
+    // are mostly filled up to their capacity. The same compact tree could have
+    // been obtained by inserting keys in a shrewd order.
+    fn compact(&mut self)
+    where
+        K: Ord,
+    {
+        let iter = mem::take(self).into_iter();
+        let root = BTreeMap::ensure_is_owned(&mut self.root);
+        root.bulk_push(iter, &mut self.length);
+    }
 }
 
 impl<'a, K: 'a, V: 'a> NodeRef<marker::Immut<'a>, K, V, marker::LeafOrInternal> {
     fn assert_min_len(self, min_len: usize) {
-        assert!(self.len() >= min_len, "{} < {}", self.len(), min_len);
+        assert!(self.len() >= min_len, "node len {} < {}", self.len(), min_len);
         if let node::ForceResult::Internal(node) = self.force() {
             for idx in 0..=node.len() {
                 let edge = unsafe { Handle::new_edge(node, idx) };
@@ -1679,17 +1691,29 @@ fn test_first_last_entry() {
 }
 
 #[test]
-fn test_insert_into_full_left() {
-    let mut map: BTreeMap<_, _> = (0..NODE_CAPACITY).map(|i| (i * 2, ())).collect();
-    assert!(map.insert(NODE_CAPACITY, ()).is_none());
-    map.check();
+fn test_insert_into_full_height_0() {
+    let size = NODE_CAPACITY;
+    for pos in 0..=size {
+        let mut map: BTreeMap<_, _> = (0..size).map(|i| (i * 2 + 1, ())).collect();
+        assert!(map.insert(pos * 2, ()).is_none());
+        map.check();
+    }
 }
 
 #[test]
-fn test_insert_into_full_right() {
-    let mut map: BTreeMap<_, _> = (0..NODE_CAPACITY).map(|i| (i * 2, ())).collect();
-    assert!(map.insert(NODE_CAPACITY + 2, ()).is_none());
-    map.check();
+fn test_insert_into_full_height_1() {
+    let size = NODE_CAPACITY + 1 + NODE_CAPACITY;
+    for pos in 0..=size {
+        let mut map: BTreeMap<_, _> = (0..size).map(|i| (i * 2 + 1, ())).collect();
+        map.compact();
+        let root_node = map.root.as_ref().unwrap().reborrow();
+        assert_eq!(root_node.len(), 1);
+        assert_eq!(root_node.first_leaf_edge().into_node().len(), NODE_CAPACITY);
+        assert_eq!(root_node.last_leaf_edge().into_node().len(), NODE_CAPACITY);
+
+        assert!(map.insert(pos * 2, ()).is_none());
+        map.check();
+    }
 }
 
 macro_rules! create_append_test {
@@ -1797,7 +1821,6 @@ fn test_append_ord_chaos() {
 }
 
 fn rand_data(len: usize) -> Vec<(u32, u32)> {
-    assert!(len * 2 <= 70029); // from that point on numbers repeat
     let mut rng = DeterministicRng::new();
     Vec::from_iter((0..len).map(|_| (rng.next(), rng.next())))
 }
@@ -1862,6 +1885,25 @@ fn test_split_off_tiny_right_height_2() {
     assert_eq!(*right.last_key_value().unwrap().0, last);
 }
 
+#[test]
+fn test_split_off_halfway() {
+    let mut rng = DeterministicRng::new();
+    for &len in &[NODE_CAPACITY, 25, 50, 75, 100] {
+        let mut data = Vec::from_iter((0..len).map(|_| (rng.next(), ())));
+        // Insertion in non-ascending order creates some variation in node length.
+        let mut map = BTreeMap::from_iter(data.iter().copied());
+        data.sort();
+        let small_keys = data.iter().take(len / 2).map(|kv| kv.0);
+        let large_keys = data.iter().skip(len / 2).map(|kv| kv.0);
+        let split_key = large_keys.clone().next().unwrap();
+        let right = map.split_off(&split_key);
+        map.check();
+        right.check();
+        assert!(map.keys().copied().eq(small_keys));
+        assert!(right.keys().copied().eq(large_keys));
+    }
+}
+
 #[test]
 fn test_split_off_large_random_sorted() {
     // Miri is too slow
index ebcbb0e467c467b1cb95879bda8328301ec0b908..cdb39104047f0db0472e7a08757e9cfe9a180ed2 100644 (file)
@@ -38,6 +38,7 @@ pub unsafe fn unwrap_unchecked<T>(val: Option<T>) -> T {
 #[cfg(test)]
 /// XorShiftRng
 struct DeterministicRng {
+    count: usize,
     x: u32,
     y: u32,
     z: u32,
@@ -47,11 +48,13 @@ struct DeterministicRng {
 #[cfg(test)]
 impl DeterministicRng {
     fn new() -> Self {
-        DeterministicRng { x: 0x193a6754, y: 0xa8a7d469, z: 0x97830e05, w: 0x113ba7bb }
+        DeterministicRng { count: 0, x: 0x193a6754, y: 0xa8a7d469, z: 0x97830e05, w: 0x113ba7bb }
     }
 
-    /// Guarantees that the first 70029 results are unique.
+    /// Guarantees that each returned number is unique.
     fn next(&mut self) -> u32 {
+        self.count += 1;
+        assert!(self.count <= 70029);
         let x = self.x;
         let t = x ^ (x << 11);
         self.x = self.y;
index 22e179af4a93289f7537c243d63e9fa195f0e1e3..b3641a7a0c6973a8cd52e2dd2a9a6645d1e6f06d 100644 (file)
@@ -35,6 +35,7 @@
 use core::marker::PhantomData;
 use core::mem::{self, MaybeUninit};
 use core::ptr::{self, NonNull};
+use core::slice::SliceIndex;
 
 use crate::alloc::{Allocator, Global, Layout};
 use crate::boxed::Box;
@@ -239,17 +240,16 @@ pub fn pop_internal_level(&mut self) {
 /// - We cannot get implicit coercion from say `Mut<'a>` to `Immut<'a>`.
 ///   Therefore, we have to explicitly call `reborrow` on a more powerfull
 ///   `NodeRef` in order to reach a method like `key_at`.
-/// - All methods on `NodeRef` that return some kind of reference, except
-///   `reborrow` and `reborrow_mut`, take `self` by value and not by reference.
-///   This avoids silently returning a second reference somewhere in the tree.
-///   That is irrelevant when `BorrowType` is `Immut<'a>`, but the rule does
-///   no harm because we make those `NodeRef` implicitly `Copy`.
-///   The rule also avoids implicitly returning the lifetime of `&self`,
-///   instead of the lifetime carried by `BorrowType`.
-///   An exception to this rule are the insert functions.
-/// - Given the above, we need a `reborrow_mut` to explicitly copy a `Mut<'a>`
-///   `NodeRef` whenever we want to invoke a method returning an extra reference
-///   somewhere in the tree.
+///
+/// All methods on `NodeRef` that return some kind of reference, either:
+/// - Take `self` by value, and return the lifetime carried by `BorrowType`.
+///   Sometimes, to invoke such a method, we need to call `reborrow_mut`.
+/// - Take `self` by reference, and (implicitly) return that reference's
+///   lifetime, instead of the lifetime carried by `BorrowType`. That way,
+///   the borrow checker guarantees that the `NodeRef` remains borrowed as long
+///   as the returned reference is used.
+///   The methods supporting insert bend this rule by returning a raw pointer,
+///   i.e., a reference without any lifetime.
 pub struct NodeRef<BorrowType, K, V, Type> {
     /// The number of levels that the node and the level of leaves are apart, a
     /// constant of the node that cannot be entirely described by `Type`, and that
@@ -295,19 +295,10 @@ fn as_internal_ptr(this: &Self) -> *mut InternalNode<K, V> {
     }
 }
 
-impl<'a, K, V> NodeRef<marker::Immut<'a>, K, V, marker::Internal> {
-    /// Exposes the data of an internal node in an immutable tree.
-    fn as_internal(this: &Self) -> &'a InternalNode<K, V> {
-        let ptr = Self::as_internal_ptr(this);
-        // SAFETY: there can be no mutable references into this tree borrowed as `Immut`.
-        unsafe { &*ptr }
-    }
-}
-
 impl<'a, K, V> NodeRef<marker::Mut<'a>, K, V, marker::Internal> {
-    /// Offers exclusive access to the data of an internal node.
-    fn as_internal_mut(this: &mut Self) -> &'a mut InternalNode<K, V> {
-        let ptr = Self::as_internal_ptr(this);
+    /// Borrows exclusive access to the data of an internal node.
+    fn as_internal_mut(&mut self) -> &mut InternalNode<K, V> {
+        let ptr = Self::as_internal_ptr(self);
         unsafe { &mut *ptr }
     }
 }
@@ -355,7 +346,7 @@ impl<'a, K: 'a, V: 'a, Type> NodeRef<marker::Immut<'a>, K, V, Type> {
     /// The node has more than `idx` initialized elements.
     pub unsafe fn key_at(self, idx: usize) -> &'a K {
         debug_assert!(idx < self.len());
-        unsafe { Self::as_leaf(&self).keys.get_unchecked(idx).assume_init_ref() }
+        unsafe { self.into_leaf().keys.get_unchecked(idx).assume_init_ref() }
     }
 
     /// Exposes one of the values stored in the node.
@@ -364,18 +355,7 @@ pub unsafe fn key_at(self, idx: usize) -> &'a K {
     /// The node has more than `idx` initialized elements.
     unsafe fn val_at(self, idx: usize) -> &'a V {
         debug_assert!(idx < self.len());
-        unsafe { Self::as_leaf(&self).vals.get_unchecked(idx).assume_init_ref() }
-    }
-}
-
-impl<'a, K, V> NodeRef<marker::Immut<'a>, K, V, marker::Internal> {
-    /// Exposes the contents of one of the edges in the node.
-    ///
-    /// # Safety
-    /// The node has more than `idx` initialized elements.
-    unsafe fn edge_at(self, idx: usize) -> &'a BoxedNode<K, V> {
-        debug_assert!(idx <= self.len());
-        unsafe { Self::as_internal(&self).edges.get_unchecked(idx).assume_init_ref() }
+        unsafe { self.into_leaf().vals.get_unchecked(idx).assume_init_ref() }
     }
 }
 
@@ -431,8 +411,8 @@ pub fn last_kv(self) -> Handle<Self, marker::KV> {
 
 impl<'a, K: 'a, V: 'a, Type> NodeRef<marker::Immut<'a>, K, V, Type> {
     /// Exposes the leaf portion of any leaf or internal node in an immutable tree.
-    fn as_leaf(this: &Self) -> &'a LeafNode<K, V> {
-        let ptr = Self::as_leaf_ptr(this);
+    fn into_leaf(self) -> &'a LeafNode<K, V> {
+        let ptr = Self::as_leaf_ptr(&self);
         // SAFETY: there can be no mutable references into this tree borrowed as `Immut`.
         unsafe { &*ptr }
     }
@@ -489,98 +469,64 @@ unsafe fn reborrow_mut(&mut self) -> NodeRef<marker::Mut<'_>, K, V, Type> {
         NodeRef { height: self.height, node: self.node, _marker: PhantomData }
     }
 
-    /// Offers exclusive access to the leaf portion of any leaf or internal node.
-    fn as_leaf_mut(this: &mut Self) -> &'a mut LeafNode<K, V> {
-        let ptr = Self::as_leaf_ptr(this);
+    /// Borrows exclusive access to the leaf portion of any leaf or internal node.
+    fn as_leaf_mut(&mut self) -> &mut LeafNode<K, V> {
+        let ptr = Self::as_leaf_ptr(self);
         // SAFETY: we have exclusive access to the entire node.
         unsafe { &mut *ptr }
     }
-}
 
-impl<'a, K: 'a, V: 'a, Type> NodeRef<marker::Mut<'a>, K, V, Type> {
-    /// Offers exclusive access to a part of the key storage area.
-    ///
-    /// # Safety
-    /// The node has more than `idx` initialized elements.
-    unsafe fn into_key_area_mut_at(mut self, idx: usize) -> &'a mut MaybeUninit<K> {
-        debug_assert!(idx < self.len());
-        unsafe { Self::as_leaf_mut(&mut self).keys.get_unchecked_mut(idx) }
-    }
-
-    /// Offers exclusive access to a part of the value storage area.
-    ///
-    /// # Safety
-    /// The node has more than `idx` initialized elements.
-    unsafe fn into_val_area_mut_at(mut self, idx: usize) -> &'a mut MaybeUninit<V> {
-        debug_assert!(idx < self.len());
-        unsafe { Self::as_leaf_mut(&mut self).vals.get_unchecked_mut(idx) }
+    /// Offers exclusive access to the leaf portion of any leaf or internal node.
+    fn into_leaf_mut(mut self) -> &'a mut LeafNode<K, V> {
+        let ptr = Self::as_leaf_ptr(&mut self);
+        // SAFETY: we have exclusive access to the entire node.
+        unsafe { &mut *ptr }
     }
 }
 
-impl<'a, K: 'a, V: 'a> NodeRef<marker::Mut<'a>, K, V, marker::Internal> {
-    /// Offers exclusive access to a part of the storage area for edge contents.
+impl<'a, K: 'a, V: 'a, Type> NodeRef<marker::Mut<'a>, K, V, Type> {
+    /// Borrows exclusive access to an element of the key storage area.
     ///
     /// # Safety
-    /// The node has at least `idx` initialized elements.
-    unsafe fn into_edge_area_mut_at(mut self, idx: usize) -> &'a mut MaybeUninit<BoxedNode<K, V>> {
-        debug_assert!(idx <= self.len());
-        unsafe { Self::as_internal_mut(&mut self).edges.get_unchecked_mut(idx) }
-    }
-}
-
-impl<'a, K: 'a, V: 'a, Type> NodeRef<marker::Immut<'a>, K, V, Type> {
-    /// Exposes the entire key storage area in the node,
-    /// regardless of the node's current length,
-    /// having exclusive access to the entire node.
-    unsafe fn key_area(self) -> &'a [MaybeUninit<K>] {
-        Self::as_leaf(&self).keys.as_slice()
-    }
-
-    /// Exposes the entire value storage area in the node,
-    /// regardless of the node's current length,
-    /// having exclusive access to the entire node.
-    unsafe fn val_area(self) -> &'a [MaybeUninit<V>] {
-        Self::as_leaf(&self).vals.as_slice()
-    }
-}
-
-impl<'a, K: 'a, V: 'a> NodeRef<marker::Immut<'a>, K, V, marker::Internal> {
-    /// Exposes the entire storage area for edge contents in the node,
-    /// regardless of the node's current length,
-    /// having exclusive access to the entire node.
-    unsafe fn edge_area(self) -> &'a [MaybeUninit<BoxedNode<K, V>>] {
-        Self::as_internal(&self).edges.as_slice()
-    }
-}
-
-impl<'a, K: 'a, V: 'a, Type> NodeRef<marker::Mut<'a>, K, V, Type> {
-    /// Offers exclusive access to a sized slice of key storage area in the node.
-    unsafe fn into_key_area_slice(mut self) -> &'a mut [MaybeUninit<K>] {
-        let len = self.len();
+    /// `index` is in bounds of 0..CAPACITY
+    unsafe fn key_area_mut<I, Output: ?Sized>(&mut self, index: I) -> &mut Output
+    where
+        I: SliceIndex<[MaybeUninit<K>], Output = Output>,
+    {
         // SAFETY: the caller will not be able to call further methods on self
         // until the key slice reference is dropped, as we have unique access
         // for the lifetime of the borrow.
-        unsafe { Self::as_leaf_mut(&mut self).keys.get_unchecked_mut(..len) }
+        unsafe { self.as_leaf_mut().keys.as_mut_slice().get_unchecked_mut(index) }
     }
 
-    /// Offers exclusive access to a sized slice of value storage area in the node.
-    unsafe fn into_val_area_slice(mut self) -> &'a mut [MaybeUninit<V>] {
-        let len = self.len();
+    /// Borrows exclusive access to an element or slice of the node's value storage area.
+    ///
+    /// # Safety
+    /// `index` is in bounds of 0..CAPACITY
+    unsafe fn val_area_mut<I, Output: ?Sized>(&mut self, index: I) -> &mut Output
+    where
+        I: SliceIndex<[MaybeUninit<V>], Output = Output>,
+    {
         // SAFETY: the caller will not be able to call further methods on self
         // until the value slice reference is dropped, as we have unique access
         // for the lifetime of the borrow.
-        unsafe { Self::as_leaf_mut(&mut self).vals.get_unchecked_mut(..len) }
+        unsafe { self.as_leaf_mut().vals.as_mut_slice().get_unchecked_mut(index) }
     }
 }
 
 impl<'a, K: 'a, V: 'a> NodeRef<marker::Mut<'a>, K, V, marker::Internal> {
-    /// Offers exclusive access to a sized slice of storage area for edge contents in the node.
-    unsafe fn into_edge_area_slice(mut self) -> &'a mut [MaybeUninit<BoxedNode<K, V>>] {
-        let len = self.len();
+    /// Borrows exclusive access to an element or slice of the node's storage area for edge contents.
+    ///
+    /// # Safety
+    /// `index` is in bounds of 0..CAPACITY + 1
+    unsafe fn edge_area_mut<I, Output: ?Sized>(&mut self, index: I) -> &mut Output
+    where
+        I: SliceIndex<[MaybeUninit<BoxedNode<K, V>>], Output = Output>,
+    {
         // SAFETY: the caller will not be able to call further methods on self
         // until the edge slice reference is dropped, as we have unique access
         // for the lifetime of the borrow.
-        unsafe { Self::as_internal_mut(&mut self).edges.get_unchecked_mut(..len + 1) }
+        unsafe { self.as_internal_mut().edges.as_mut_slice().get_unchecked_mut(index) }
     }
 }
 
@@ -604,9 +550,9 @@ unsafe fn into_key_val_mut_at(mut self, idx: usize) -> (&'a K, &'a mut V) {
 }
 
 impl<'a, K: 'a, V: 'a, Type> NodeRef<marker::Mut<'a>, K, V, Type> {
-    /// Exposes exclusive access to the length of the node.
-    pub fn into_len_mut(mut self) -> &'a mut u16 {
-        &mut (*Self::as_leaf_mut(&mut self)).len
+    /// Borrows exclusive access to the length of the node.
+    pub fn len_mut(&mut self) -> &mut u16 {
+        &mut self.as_leaf_mut().len
     }
 }
 
@@ -623,7 +569,8 @@ fn set_parent_link(&mut self, parent: NonNull<InternalNode<K, V>>, parent_idx: u
 impl<K, V> NodeRef<marker::Owned, K, V, marker::LeafOrInternal> {
     /// Clears the root's link to its parent edge.
     fn clear_parent_link(&mut self) {
-        let leaf = NodeRef::as_leaf_mut(&mut self.borrow_mut());
+        let mut root_node = self.borrow_mut();
+        let leaf = root_node.as_leaf_mut();
         leaf.parent = None;
     }
 }
@@ -631,24 +578,24 @@ fn clear_parent_link(&mut self) {
 impl<'a, K: 'a, V: 'a> NodeRef<marker::Mut<'a>, K, V, marker::Leaf> {
     /// Adds a key-value pair to the end of the node.
     pub fn push(&mut self, key: K, val: V) {
-        let len = unsafe { self.reborrow_mut().into_len_mut() };
+        let len = self.len_mut();
         let idx = usize::from(*len);
         assert!(idx < CAPACITY);
         *len += 1;
         unsafe {
-            self.reborrow_mut().into_key_area_mut_at(idx).write(key);
-            self.reborrow_mut().into_val_area_mut_at(idx).write(val);
+            self.key_area_mut(idx).write(key);
+            self.val_area_mut(idx).write(val);
         }
     }
 
     /// Adds a key-value pair to the beginning of the node.
     fn push_front(&mut self, key: K, val: V) {
-        assert!(self.len() < CAPACITY);
-
+        let new_len = self.len() + 1;
+        assert!(new_len <= CAPACITY);
         unsafe {
-            *self.reborrow_mut().into_len_mut() += 1;
-            slice_insert(self.reborrow_mut().into_key_area_slice(), 0, key);
-            slice_insert(self.reborrow_mut().into_val_area_slice(), 0, val);
+            slice_insert(self.key_area_mut(..new_len), 0, key);
+            slice_insert(self.val_area_mut(..new_len), 0, val);
+            *self.len_mut() = new_len as u16;
         }
     }
 }
@@ -675,14 +622,14 @@ impl<'a, K: 'a, V: 'a> NodeRef<marker::Mut<'a>, K, V, marker::Internal> {
     pub fn push(&mut self, key: K, val: V, edge: Root<K, V>) {
         assert!(edge.height == self.height - 1);
 
-        let len = unsafe { self.reborrow_mut().into_len_mut() };
+        let len = self.len_mut();
         let idx = usize::from(*len);
         assert!(idx < CAPACITY);
         *len += 1;
         unsafe {
-            self.reborrow_mut().into_key_area_mut_at(idx).write(key);
-            self.reborrow_mut().into_val_area_mut_at(idx).write(val);
-            self.reborrow_mut().into_edge_area_mut_at(idx + 1).write(edge.node);
+            self.key_area_mut(idx).write(key);
+            self.val_area_mut(idx).write(val);
+            self.edge_area_mut(idx + 1).write(edge.node);
             Handle::new_edge(self.reborrow_mut(), idx + 1).correct_parent_link();
         }
     }
@@ -690,14 +637,15 @@ pub fn push(&mut self, key: K, val: V, edge: Root<K, V>) {
     /// Adds a key-value pair, and an edge to go to the left of that pair,
     /// to the beginning of the node.
     fn push_front(&mut self, key: K, val: V, edge: Root<K, V>) {
+        let new_len = self.len() + 1;
         assert!(edge.height == self.height - 1);
-        assert!(self.len() < CAPACITY);
+        assert!(new_len <= CAPACITY);
 
         unsafe {
-            *self.reborrow_mut().into_len_mut() += 1;
-            slice_insert(self.reborrow_mut().into_key_area_slice(), 0, key);
-            slice_insert(self.reborrow_mut().into_val_area_slice(), 0, val);
-            slice_insert(self.reborrow_mut().into_edge_area_slice(), 0, edge.node);
+            slice_insert(self.key_area_mut(..new_len), 0, key);
+            slice_insert(self.val_area_mut(..new_len), 0, val);
+            slice_insert(self.edge_area_mut(..new_len + 1), 0, edge.node);
+            *self.len_mut() = new_len as u16;
         }
 
         self.correct_all_childrens_parent_links();
@@ -714,12 +662,12 @@ fn pop(&mut self) -> (K, V, Option<Root<K, V>>) {
         let idx = self.len() - 1;
 
         unsafe {
-            let key = ptr::read(self.reborrow().key_at(idx));
-            let val = ptr::read(self.reborrow().val_at(idx));
+            let key = self.key_area_mut(idx).assume_init_read();
+            let val = self.val_area_mut(idx).assume_init_read();
             let edge = match self.reborrow_mut().force() {
                 ForceResult::Leaf(_) => None,
-                ForceResult::Internal(internal) => {
-                    let node = ptr::read(internal.reborrow().edge_at(idx + 1));
+                ForceResult::Internal(mut internal) => {
+                    let node = internal.edge_area_mut(idx + 1).assume_init_read();
                     let mut edge = Root { node, height: internal.height - 1, _marker: PhantomData };
                     // Currently, clearing the parent link is superfluous, because we will
                     // insert the node elsewhere and set its parent link again.
@@ -728,7 +676,7 @@ fn pop(&mut self) -> (K, V, Option<Root<K, V>>) {
                 }
             };
 
-            *self.reborrow_mut().into_len_mut() -= 1;
+            *self.len_mut() -= 1;
             (key, val, edge)
         }
     }
@@ -742,12 +690,12 @@ fn pop_front(&mut self) -> (K, V, Option<Root<K, V>>) {
         let old_len = self.len();
 
         unsafe {
-            let key = slice_remove(self.reborrow_mut().into_key_area_slice(), 0);
-            let val = slice_remove(self.reborrow_mut().into_val_area_slice(), 0);
+            let key = slice_remove(self.key_area_mut(..old_len), 0);
+            let val = slice_remove(self.val_area_mut(..old_len), 0);
             let edge = match self.reborrow_mut().force() {
                 ForceResult::Leaf(_) => None,
                 ForceResult::Internal(mut internal) => {
-                    let node = slice_remove(internal.reborrow_mut().into_edge_area_slice(), 0);
+                    let node = slice_remove(internal.edge_area_mut(..old_len + 1), 0);
                     let mut edge = Root { node, height: internal.height - 1, _marker: PhantomData };
                     // Currently, clearing the parent link is superfluous, because we will
                     // insert the node elsewhere and set its parent link again.
@@ -759,14 +707,14 @@ fn pop_front(&mut self) -> (K, V, Option<Root<K, V>>) {
                 }
             };
 
-            *self.reborrow_mut().into_len_mut() -= 1;
+            *self.len_mut() -= 1;
 
             (key, val, edge)
         }
     }
 
     fn into_kv_pointers_mut(mut self) -> (*mut K, *mut V) {
-        let leaf = Self::as_leaf_mut(&mut self);
+        let leaf = self.as_leaf_mut();
         let keys = MaybeUninit::slice_as_mut_ptr(&mut leaf.keys);
         let vals = MaybeUninit::slice_as_mut_ptr(&mut leaf.vals);
         (keys, vals)
@@ -968,13 +916,14 @@ impl<'a, K: 'a, V: 'a> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, mark
     /// The returned pointer points to the inserted value.
     fn insert_fit(&mut self, key: K, val: V) -> *mut V {
         debug_assert!(self.node.len() < CAPACITY);
+        let new_len = self.node.len() + 1;
 
         unsafe {
-            *self.node.reborrow_mut().into_len_mut() += 1;
-            slice_insert(self.node.reborrow_mut().into_key_area_slice(), self.idx, key);
-            slice_insert(self.node.reborrow_mut().into_val_area_slice(), self.idx, val);
+            slice_insert(self.node.key_area_mut(..new_len), self.idx, key);
+            slice_insert(self.node.val_area_mut(..new_len), self.idx, val);
+            *self.node.len_mut() = new_len as u16;
 
-            self.node.reborrow_mut().into_val_area_mut_at(self.idx).assume_init_mut()
+            self.node.val_area_mut(self.idx).assume_init_mut()
         }
     }
 }
@@ -1026,14 +975,15 @@ impl<'a, K: 'a, V: 'a> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Internal>,
     fn insert_fit(&mut self, key: K, val: V, edge: Root<K, V>) {
         debug_assert!(self.node.len() < CAPACITY);
         debug_assert!(edge.height == self.node.height - 1);
+        let new_len = self.node.len() + 1;
 
         unsafe {
-            *self.node.reborrow_mut().into_len_mut() += 1;
-            slice_insert(self.node.reborrow_mut().into_key_area_slice(), self.idx, key);
-            slice_insert(self.node.reborrow_mut().into_val_area_slice(), self.idx, val);
-            slice_insert(self.node.reborrow_mut().into_edge_area_slice(), self.idx + 1, edge.node);
+            slice_insert(self.node.key_area_mut(..new_len), self.idx, key);
+            slice_insert(self.node.val_area_mut(..new_len), self.idx, val);
+            slice_insert(self.node.edge_area_mut(..new_len + 1), self.idx + 1, edge.node);
+            *self.node.len_mut() = new_len as u16;
 
-            self.node.correct_childrens_parent_links((self.idx + 1)..=self.node.len());
+            self.node.correct_childrens_parent_links(self.idx + 1..new_len + 1);
         }
     }
 
@@ -1134,12 +1084,13 @@ pub fn into_kv(self) -> (&'a K, &'a V) {
 }
 
 impl<'a, K: 'a, V: 'a, NodeType> Handle<NodeRef<marker::Mut<'a>, K, V, NodeType>, marker::KV> {
-    pub fn into_key_mut(self) -> &'a mut K {
-        unsafe { self.node.into_key_area_mut_at(self.idx).assume_init_mut() }
+    pub fn key_mut(&mut self) -> &mut K {
+        unsafe { self.node.key_area_mut(self.idx).assume_init_mut() }
     }
 
     pub fn into_val_mut(self) -> &'a mut V {
-        unsafe { self.node.into_val_area_mut_at(self.idx).assume_init_mut() }
+        let leaf = self.node.into_leaf_mut();
+        unsafe { leaf.vals.get_unchecked_mut(self.idx).assume_init_mut() }
     }
 }
 
@@ -1154,7 +1105,7 @@ pub fn kv_mut(&mut self) -> (&mut K, &mut V) {
         // We cannot call separate key and value methods, because calling the second one
         // invalidates the reference returned by the first.
         unsafe {
-            let leaf = NodeRef::as_leaf_mut(&mut self.node.reborrow_mut());
+            let leaf = self.node.as_leaf_mut();
             let key = leaf.keys.get_unchecked_mut(self.idx).assume_init_mut();
             let val = leaf.vals.get_unchecked_mut(self.idx).assume_init_mut();
             (key, val)
@@ -1169,34 +1120,28 @@ pub fn replace_kv(&mut self, k: K, v: V) -> (K, V) {
 }
 
 impl<'a, K: 'a, V: 'a, NodeType> Handle<NodeRef<marker::Mut<'a>, K, V, NodeType>, marker::KV> {
-    /// Helps implementations of `split` for a particular `NodeType`,
-    /// by calculating the length of the new node.
-    fn split_new_node_len(&self) -> usize {
-        debug_assert!(self.idx < self.node.len());
-        self.node.len() - self.idx - 1
-    }
-
     /// Helps implementations of `split` for a particular `NodeType`,
     /// by taking care of leaf data.
     fn split_leaf_data(&mut self, new_node: &mut LeafNode<K, V>) -> (K, V) {
-        let new_len = self.split_new_node_len();
+        debug_assert!(self.idx < self.node.len());
+        let new_len = self.node.len() - self.idx - 1;
         new_node.len = new_len as u16;
         unsafe {
-            let k = ptr::read(self.node.reborrow().key_at(self.idx));
-            let v = ptr::read(self.node.reborrow().val_at(self.idx));
+            let k = self.node.key_area_mut(self.idx).assume_init_read();
+            let v = self.node.val_area_mut(self.idx).assume_init_read();
 
             ptr::copy_nonoverlapping(
-                self.node.reborrow().key_area().as_ptr().add(self.idx + 1),
+                self.node.key_area_mut(self.idx + 1..).as_ptr(),
                 new_node.keys.as_mut_ptr(),
                 new_len,
             );
             ptr::copy_nonoverlapping(
-                self.node.reborrow().val_area().as_ptr().add(self.idx + 1),
+                self.node.val_area_mut(self.idx + 1..).as_ptr(),
                 new_node.vals.as_mut_ptr(),
                 new_len,
             );
 
-            *self.node.reborrow_mut().into_len_mut() = self.idx as u16;
+            *self.node.len_mut() = self.idx as u16;
             (k, v)
         }
     }
@@ -1226,10 +1171,11 @@ pub fn split(mut self) -> SplitResult<'a, K, V, marker::Leaf> {
     pub fn remove(
         mut self,
     ) -> ((K, V), Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge>) {
+        let old_len = self.node.len();
         unsafe {
-            let k = slice_remove(self.node.reborrow_mut().into_key_area_slice(), self.idx);
-            let v = slice_remove(self.node.reborrow_mut().into_val_area_slice(), self.idx);
-            *self.node.reborrow_mut().into_len_mut() -= 1;
+            let k = slice_remove(self.node.key_area_mut(..old_len), self.idx);
+            let v = slice_remove(self.node.val_area_mut(..old_len), self.idx);
+            *self.node.len_mut() = (old_len - 1) as u16;
             ((k, v), self.left_edge())
         }
     }
@@ -1246,14 +1192,13 @@ impl<'a, K: 'a, V: 'a> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Internal>,
     pub fn split(mut self) -> SplitResult<'a, K, V, marker::Internal> {
         unsafe {
             let mut new_node = Box::new(InternalNode::new());
-            let new_len = self.split_new_node_len();
-            // Move edges out before reducing length:
+            let kv = self.split_leaf_data(&mut new_node.data);
+            let new_len = usize::from(new_node.data.len);
             ptr::copy_nonoverlapping(
-                self.node.reborrow().edge_area().as_ptr().add(self.idx + 1),
+                self.node.edge_area_mut(self.idx + 1..).as_ptr(),
                 new_node.edges.as_mut_ptr(),
                 new_len + 1,
             );
-            let kv = self.split_leaf_data(&mut new_node.data);
 
             let height = self.node.height;
             let mut right = NodeRef::from_new_internal(new_node, height);
@@ -1362,7 +1307,7 @@ pub fn merge(
         let old_parent_len = parent_node.len();
         let mut left_node = self.left_child;
         let old_left_len = left_node.len();
-        let right_node = self.right_child;
+        let mut right_node = self.right_child;
         let right_len = right_node.len();
         let new_left_len = old_left_len + 1 + right_len;
 
@@ -1374,42 +1319,36 @@ pub fn merge(
         });
 
         unsafe {
-            *left_node.reborrow_mut().into_len_mut() = new_left_len as u16;
+            *left_node.len_mut() = new_left_len as u16;
 
-            let parent_key =
-                slice_remove(parent_node.reborrow_mut().into_key_area_slice(), parent_idx);
-            left_node.reborrow_mut().into_key_area_mut_at(old_left_len).write(parent_key);
+            let parent_key = slice_remove(parent_node.key_area_mut(..old_parent_len), parent_idx);
+            left_node.key_area_mut(old_left_len).write(parent_key);
             ptr::copy_nonoverlapping(
-                right_node.reborrow().key_area().as_ptr(),
-                left_node.reborrow_mut().into_key_area_slice().as_mut_ptr().add(old_left_len + 1),
+                right_node.key_area_mut(..).as_ptr(),
+                left_node.key_area_mut(old_left_len + 1..).as_mut_ptr(),
                 right_len,
             );
 
-            let parent_val =
-                slice_remove(parent_node.reborrow_mut().into_val_area_slice(), parent_idx);
-            left_node.reborrow_mut().into_val_area_mut_at(old_left_len).write(parent_val);
+            let parent_val = slice_remove(parent_node.val_area_mut(..old_parent_len), parent_idx);
+            left_node.val_area_mut(old_left_len).write(parent_val);
             ptr::copy_nonoverlapping(
-                right_node.reborrow().val_area().as_ptr(),
-                left_node.reborrow_mut().into_val_area_slice().as_mut_ptr().add(old_left_len + 1),
+                right_node.val_area_mut(..).as_ptr(),
+                left_node.val_area_mut(old_left_len + 1..).as_mut_ptr(),
                 right_len,
             );
 
-            slice_remove(&mut parent_node.reborrow_mut().into_edge_area_slice(), parent_idx + 1);
+            slice_remove(&mut parent_node.edge_area_mut(..old_parent_len + 1), parent_idx + 1);
             parent_node.correct_childrens_parent_links(parent_idx + 1..old_parent_len);
-            *parent_node.reborrow_mut().into_len_mut() -= 1;
+            *parent_node.len_mut() -= 1;
 
             if parent_node.height > 1 {
                 // SAFETY: the height of the nodes being merged is one below the height
                 // of the node of this edge, thus above zero, so they are internal.
                 let mut left_node = left_node.reborrow_mut().cast_to_internal_unchecked();
-                let right_node = right_node.cast_to_internal_unchecked();
+                let mut right_node = right_node.cast_to_internal_unchecked();
                 ptr::copy_nonoverlapping(
-                    right_node.reborrow().edge_area().as_ptr(),
-                    left_node
-                        .reborrow_mut()
-                        .into_edge_area_slice()
-                        .as_mut_ptr()
-                        .add(old_left_len + 1),
+                    right_node.edge_area_mut(..).as_ptr(),
+                    left_node.edge_area_mut(old_left_len + 1..).as_mut_ptr(),
                     right_len + 1,
                 );
 
@@ -1487,6 +1426,9 @@ pub fn bulk_steal_left(&mut self, count: usize) {
             assert!(old_left_len >= count);
 
             let new_left_len = old_left_len - count;
+            let new_right_len = old_right_len + count;
+            *left_node.len_mut() = new_left_len as u16;
+            *right_node.len_mut() = new_right_len as u16;
 
             // Move leaf data.
             {
@@ -1511,16 +1453,12 @@ pub fn bulk_steal_left(&mut self, count: usize) {
                 move_kv(left_kv, new_left_len, parent_kv, 0, 1);
             }
 
-            *left_node.reborrow_mut().into_len_mut() -= count as u16;
-            *right_node.reborrow_mut().into_len_mut() += count as u16;
-
             match (left_node.reborrow_mut().force(), right_node.reborrow_mut().force()) {
                 (ForceResult::Internal(left), ForceResult::Internal(mut right)) => {
                     // Make room for stolen edges.
-                    let left = left.reborrow();
-                    let right_edges = right.reborrow_mut().into_edge_area_slice().as_mut_ptr();
+                    let right_edges = right.edge_area_mut(..).as_mut_ptr();
                     ptr::copy(right_edges, right_edges.add(count), old_right_len + 1);
-                    right.correct_childrens_parent_links(count..count + old_right_len + 1);
+                    right.correct_childrens_parent_links(count..new_right_len + 1);
 
                     // Steal edges.
                     move_edges(left, new_left_len + 1, right, 0, count);
@@ -1544,7 +1482,10 @@ pub fn bulk_steal_right(&mut self, count: usize) {
             assert!(old_left_len + count <= CAPACITY);
             assert!(old_right_len >= count);
 
+            let new_left_len = old_left_len + count;
             let new_right_len = old_right_len - count;
+            *left_node.len_mut() = new_left_len as u16;
+            *right_node.len_mut() = new_right_len as u16;
 
             // Move leaf data.
             {
@@ -1569,16 +1510,13 @@ pub fn bulk_steal_right(&mut self, count: usize) {
                 ptr::copy(right_kv.1.add(count), right_kv.1, new_right_len);
             }
 
-            *left_node.reborrow_mut().into_len_mut() += count as u16;
-            *right_node.reborrow_mut().into_len_mut() -= count as u16;
-
             match (left_node.reborrow_mut().force(), right_node.reborrow_mut().force()) {
                 (ForceResult::Internal(left), ForceResult::Internal(mut right)) => {
                     // Steal edges.
-                    move_edges(right.reborrow(), 0, left, old_left_len + 1, count);
+                    move_edges(right.reborrow_mut(), 0, left, old_left_len + 1, count);
 
                     // Fill gap where stolen edges used to be.
-                    let right_edges = right.reborrow_mut().into_edge_area_slice().as_mut_ptr();
+                    let right_edges = right.edge_area_mut(..).as_mut_ptr();
                     ptr::copy(right_edges.add(count), right_edges, new_right_len + 1);
                     right.correct_childrens_parent_links(0..=new_right_len);
                 }
@@ -1604,16 +1542,16 @@ unsafe fn move_kv<K, V>(
 
 // Source and destination must have the same height.
 unsafe fn move_edges<'a, K: 'a, V: 'a>(
-    source: NodeRef<marker::Immut<'a>, K, V, marker::Internal>,
+    mut source: NodeRef<marker::Mut<'a>, K, V, marker::Internal>,
     source_offset: usize,
     mut dest: NodeRef<marker::Mut<'a>, K, V, marker::Internal>,
     dest_offset: usize,
     count: usize,
 ) {
     unsafe {
-        let source_ptr = source.edge_area().as_ptr();
-        let dest_ptr = dest.reborrow_mut().into_edge_area_slice().as_mut_ptr();
-        ptr::copy_nonoverlapping(source_ptr.add(source_offset), dest_ptr.add(dest_offset), count);
+        let source_ptr = source.edge_area_mut(..).as_ptr();
+        let dest_ptr = dest.edge_area_mut(dest_offset..).as_mut_ptr();
+        ptr::copy_nonoverlapping(source_ptr.add(source_offset), dest_ptr, count);
         dest.correct_childrens_parent_links(dest_offset..dest_offset + count);
     }
 }
@@ -1708,12 +1646,11 @@ pub fn move_suffix(
 
                 move_kv(left_kv, new_left_len, right_kv, 0, new_right_len);
 
-                *left_node.reborrow_mut().into_len_mut() = new_left_len as u16;
-                *right_node.reborrow_mut().into_len_mut() = new_right_len as u16;
+                *left_node.len_mut() = new_left_len as u16;
+                *right_node.len_mut() = new_right_len as u16;
 
                 match (left_node.force(), right_node.force()) {
                     (ForceResult::Internal(left), ForceResult::Internal(right)) => {
-                        let left = left.reborrow();
                         move_edges(left, new_left_len + 1, right, 1, new_right_len);
                     }
                     (ForceResult::Leaf(_), ForceResult::Leaf(_)) => {}
index 6886962106b02ea5dfd20c3df28f70c68a7af984..7fe8ff743c040546870a1da810c2fd5352346917 100644 (file)
@@ -30,11 +30,15 @@ pub fn dump_keys(self) -> String
                 let depth = self.height();
                 let indent = "  ".repeat(depth);
                 result += &format!("\n{}", indent);
-                for idx in 0..leaf.len() {
-                    if idx > 0 {
-                        result += ", ";
+                if leaf.len() == 0 {
+                    result += "(empty node)";
+                } else {
+                    for idx in 0..leaf.len() {
+                        if idx > 0 {
+                            result += ", ";
+                        }
+                        result += &format!("{:?}", unsafe { leaf.key_at(idx) });
                     }
-                    result += &format!("{:?}", unsafe { leaf.key_at(idx) });
                 }
             }
             navigate::Position::Internal(_) => {}
index f63c3dd58040866339c66f66ad4914a2c03899be..c72e305a1f9470334f641ed77fb1361aed103199 100644 (file)
@@ -975,6 +975,7 @@ pub fn iter(&self) -> Iter<'_, T> {
     /// v.insert(1);
     /// assert_eq!(v.len(), 1);
     /// ```
+    #[doc(alias = "length")]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_const_unstable(feature = "const_btree_new", issue = "71835")]
     pub const fn len(&self) -> usize {
index 4d05bc4ebfa1e9aa5255d60f5103b123496f6504..fd19c0078a7487ef4af93cf9cc7287cbf97914a8 100644 (file)
@@ -696,8 +696,10 @@ fn test_first_last() {
     assert_eq!(a.pop_last(), None);
 }
 
+// Unlike the function with the same name in map/tests, returns no values.
+// Which also means it returns different predetermined pseudo-random keys,
+// and the test cases using this function explore slightly different trees.
 fn rand_data(len: usize) -> Vec<u32> {
-    assert!(len <= 70029); // from that point on numbers repeat
     let mut rng = DeterministicRng::new();
     Vec::from_iter((0..len).map(|_| rng.next()))
 }
index 6108c139bb3a62d3cfde162dedbb0849308c2d02..4561c8eaf47fb135bea1bd4194ee5a234ac3440e 100644 (file)
@@ -53,6 +53,9 @@ fn fix_top(&mut self) {
         }
     }
 
+    /// Stock up or merge away any underfull nodes on the right border of the
+    /// tree. The other nodes, those that are not the root nor a rightmost edge,
+    /// must already have at least MIN_LEN elements.
     fn fix_right_border(&mut self) {
         self.fix_top();
 
@@ -72,6 +75,7 @@ fn fix_right_border(&mut self) {
                     }
                     cur_node = last_kv.into_right_child();
                 }
+                debug_assert!(cur_node.len() > MIN_LEN);
             }
         }
 
@@ -98,6 +102,7 @@ fn fix_left_border(&mut self) {
                     }
                     cur_node = first_kv.into_left_child();
                 }
+                debug_assert!(cur_node.len() > MIN_LEN);
             }
         }
 
index 4707f12940171105ec41b55547dc0737b5dc09b8..397e774f1a03da6f6f615ff5cdf066c9c48c65af 100644 (file)
@@ -593,6 +593,7 @@ pub fn is_empty(&self) -> bool {
     /// dl.push_back(3);
     /// assert_eq!(dl.len(), 3);
     /// ```
+    #[doc(alias = "length")]
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn len(&self) -> usize {
index 9e54c15ea6a0b3a5f2bfed00d985187600801889..f8fad6de1a3cc567be060543fa9f4d3e2234f5ca 100644 (file)
@@ -1038,6 +1038,7 @@ pub fn as_mut_slices(&mut self) -> (&mut [T], &mut [T]) {
     /// v.push_back(1);
     /// assert_eq!(v.len(), 1);
     /// ```
+    #[doc(alias = "length")]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn len(&self) -> usize {
         count(self.tail, self.head, self.cap())
@@ -1080,8 +1081,6 @@ fn range_tail_head<R>(&self, range: R) -> (usize, usize)
     /// # Examples
     ///
     /// ```
-    /// #![feature(deque_range)]
-    ///
     /// use std::collections::VecDeque;
     ///
     /// let v: VecDeque<_> = vec![1, 2, 3].into_iter().collect();
@@ -1093,7 +1092,7 @@ fn range_tail_head<R>(&self, range: R) -> (usize, usize)
     /// assert_eq!(all.len(), 3);
     /// ```
     #[inline]
-    #[unstable(feature = "deque_range", issue = "74217")]
+    #[stable(feature = "deque_range", since = "1.51.0")]
     pub fn range<R>(&self, range: R) -> Iter<'_, T>
     where
         R: RangeBounds<usize>,
@@ -1117,8 +1116,6 @@ pub fn range<R>(&self, range: R) -> Iter<'_, T>
     /// # Examples
     ///
     /// ```
-    /// #![feature(deque_range)]
-    ///
     /// use std::collections::VecDeque;
     ///
     /// let mut v: VecDeque<_> = vec![1, 2, 3].into_iter().collect();
@@ -1134,7 +1131,7 @@ pub fn range<R>(&self, range: R) -> Iter<'_, T>
     /// assert_eq!(v, vec![2, 4, 12]);
     /// ```
     #[inline]
-    #[unstable(feature = "deque_range", issue = "74217")]
+    #[stable(feature = "deque_range", since = "1.51.0")]
     pub fn range_mut<R>(&mut self, range: R) -> IterMut<'_, T>
     where
         R: RangeBounds<usize>,
index 3ac34c9ae28af271afe810bc5b357c5cd4604ddb..54b402faaeba0a765a1f59c4d4a3ccb1cd87a7ee 100644 (file)
 #![feature(never_type)]
 #![feature(nll)]
 #![feature(nonnull_slice_from_raw_parts)]
-#![cfg_attr(bootstrap, feature(optin_builtin_traits))]
-#![cfg_attr(not(bootstrap), feature(auto_traits))]
+#![feature(auto_traits)]
 #![feature(or_patterns)]
 #![feature(pattern)]
 #![feature(ptr_internals)]
index a96be57143d385cba2ace97e9e9f6a7ac5d1b1d6..57df28a15c85aa6dcdd6ecbd305c7b46c5422f61 100644 (file)
@@ -1749,7 +1749,7 @@ struct WeakInner<'a> {
     strong: &'a Cell<usize>,
 }
 
-impl<T: ?Sized> Weak<T> {
+impl<T> Weak<T> {
     /// Returns a raw pointer to the object `T` pointed to by this `Weak<T>`.
     ///
     /// The pointer is valid only if there are some strong references. The pointer may be dangling,
@@ -1882,7 +1882,9 @@ pub unsafe fn from_raw(ptr: *const T) -> Self {
         // SAFETY: we now have recovered the original Weak pointer, so can create the Weak.
         Weak { ptr: unsafe { NonNull::new_unchecked(ptr) } }
     }
+}
 
+impl<T: ?Sized> Weak<T> {
     /// Attempts to upgrade the `Weak` pointer to an [`Rc`], delaying
     /// dropping of the inner value if successful.
     ///
@@ -2040,7 +2042,7 @@ fn drop(&mut self) {
         // the strong pointers have disappeared.
         if inner.weak() == 0 {
             unsafe {
-                Global.deallocate(self.ptr.cast(), Layout::for_value(self.ptr.as_ref()));
+                Global.deallocate(self.ptr.cast(), Layout::for_value_raw(self.ptr.as_ptr()));
             }
         }
     }
index bb5c3f4f904339bb251e7c4935606220266396c1..2d183a8c88c6438144c73c72f4ea82d6d26804be 100644 (file)
@@ -208,30 +208,6 @@ fn into_from_weak_raw() {
     }
 }
 
-#[test]
-fn test_into_from_weak_raw_unsized() {
-    use std::fmt::Display;
-    use std::string::ToString;
-
-    let arc: Rc<str> = Rc::from("foo");
-    let weak: Weak<str> = Rc::downgrade(&arc);
-
-    let ptr = Weak::into_raw(weak.clone());
-    let weak2 = unsafe { Weak::from_raw(ptr) };
-
-    assert_eq!(unsafe { &*ptr }, "foo");
-    assert!(weak.ptr_eq(&weak2));
-
-    let arc: Rc<dyn Display> = Rc::new(123);
-    let weak: Weak<dyn Display> = Rc::downgrade(&arc);
-
-    let ptr = Weak::into_raw(weak.clone());
-    let weak2 = unsafe { Weak::from_raw(ptr) };
-
-    assert_eq!(unsafe { &*ptr }.to_string(), "123");
-    assert!(weak.ptr_eq(&weak2));
-}
-
 #[test]
 fn get_mut() {
     let mut x = Rc::new(3);
index 27b32b6950267ad4077b546b0ba6984caa4d5ad5..9198892859317e02e1d3214a98df477a564cc86e 100644 (file)
@@ -1388,6 +1388,7 @@ pub unsafe fn as_mut_vec(&mut self) -> &mut Vec<u8> {
     /// assert_eq!(fancy_f.len(), 4);
     /// assert_eq!(fancy_f.chars().count(), 3);
     /// ```
+    #[doc(alias = "length")]
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn len(&self) -> usize {
index 9d478a302e96c01aaa740ce0bb6128933975226e..85c0a9f085729a33b8e12d5c2147086c7a17c9ec 100644 (file)
@@ -14,7 +14,7 @@
 use core::intrinsics::abort;
 use core::iter;
 use core::marker::{PhantomData, Unpin, Unsize};
-use core::mem::{self, align_of_val, size_of_val};
+use core::mem::{self, align_of_val_raw, size_of_val};
 use core::ops::{CoerceUnsized, Deref, DispatchFromDyn, Receiver};
 use core::pin::Pin;
 use core::ptr::{self, NonNull};
@@ -1535,7 +1535,7 @@ struct WeakInner<'a> {
     strong: &'a atomic::AtomicUsize,
 }
 
-impl<T: ?Sized> Weak<T> {
+impl<T> Weak<T> {
     /// Returns a raw pointer to the object `T` pointed to by this `Weak<T>`.
     ///
     /// The pointer is valid only if there are some strong references. The pointer may be dangling,
@@ -1668,7 +1668,9 @@ pub unsafe fn from_raw(ptr: *const T) -> Self {
         // SAFETY: we now have recovered the original Weak pointer, so can create the Weak.
         unsafe { Weak { ptr: NonNull::new_unchecked(ptr) } }
     }
+}
 
+impl<T: ?Sized> Weak<T> {
     /// Attempts to upgrade the `Weak` pointer to an [`Arc`], delaying
     /// dropping of the inner value if successful.
     ///
@@ -1925,7 +1927,7 @@ fn drop(&mut self) {
 
         if inner.weak.fetch_sub(1, Release) == 1 {
             acquire!(inner.weak);
-            unsafe { Global.deallocate(self.ptr.cast(), Layout::for_value(self.ptr.as_ref())) }
+            unsafe { Global.deallocate(self.ptr.cast(), Layout::for_value_raw(self.ptr.as_ptr())) }
         }
     }
 }
@@ -2364,7 +2366,7 @@ unsafe fn data_offset<T: ?Sized>(ptr: *const T) -> isize {
     // Because it is `?Sized`, it will always be the last field in memory.
     // Note: This is a detail of the current implementation of the compiler,
     // and is not a guaranteed language detail. Do not rely on it outside of std.
-    unsafe { data_offset_align(align_of_val(&*ptr)) }
+    unsafe { data_offset_align(align_of_val_raw(ptr)) }
 }
 
 #[inline]
index 77f328d48f94d890568a658601943a9970aa97e1..e8e1e66da5ed4f7c1bf00be29bc193862fcb9562 100644 (file)
@@ -158,30 +158,6 @@ fn into_from_weak_raw() {
     }
 }
 
-#[test]
-fn test_into_from_weak_raw_unsized() {
-    use std::fmt::Display;
-    use std::string::ToString;
-
-    let arc: Arc<str> = Arc::from("foo");
-    let weak: Weak<str> = Arc::downgrade(&arc);
-
-    let ptr = Weak::into_raw(weak.clone());
-    let weak2 = unsafe { Weak::from_raw(ptr) };
-
-    assert_eq!(unsafe { &*ptr }, "foo");
-    assert!(weak.ptr_eq(&weak2));
-
-    let arc: Arc<dyn Display> = Arc::new(123);
-    let weak: Weak<dyn Display> = Arc::downgrade(&arc);
-
-    let ptr = Weak::into_raw(weak.clone());
-    let weak2 = unsafe { Weak::from_raw(ptr) };
-
-    assert_eq!(unsafe { &*ptr }.to_string(), "123");
-    assert!(weak.ptr_eq(&weak2));
-}
-
 #[test]
 fn test_cowarc_clone_make_mut() {
     let mut cow0 = Arc::new(75);
diff --git a/library/alloc/src/vec.rs b/library/alloc/src/vec.rs
deleted file mode 100644 (file)
index 2b08f1f..0000000
+++ /dev/null
@@ -1,3724 +0,0 @@
-// ignore-tidy-filelength
-//! A contiguous growable array type with heap-allocated contents, written
-//! `Vec<T>`.
-//!
-//! Vectors have `O(1)` indexing, amortized `O(1)` push (to the end) and
-//! `O(1)` pop (from the end).
-//!
-//! Vectors ensure they never allocate more than `isize::MAX` bytes.
-//!
-//! # Examples
-//!
-//! You can explicitly create a [`Vec`] with [`Vec::new`]:
-//!
-//! ```
-//! let v: Vec<i32> = Vec::new();
-//! ```
-//!
-//! ...or by using the [`vec!`] macro:
-//!
-//! ```
-//! let v: Vec<i32> = vec![];
-//!
-//! let v = vec![1, 2, 3, 4, 5];
-//!
-//! let v = vec![0; 10]; // ten zeroes
-//! ```
-//!
-//! You can [`push`] values onto the end of a vector (which will grow the vector
-//! as needed):
-//!
-//! ```
-//! let mut v = vec![1, 2];
-//!
-//! v.push(3);
-//! ```
-//!
-//! Popping values works in much the same way:
-//!
-//! ```
-//! let mut v = vec![1, 2];
-//!
-//! let two = v.pop();
-//! ```
-//!
-//! Vectors also support indexing (through the [`Index`] and [`IndexMut`] traits):
-//!
-//! ```
-//! let mut v = vec![1, 2, 3];
-//! let three = v[2];
-//! v[1] = v[1] + 5;
-//! ```
-//!
-//! [`push`]: Vec::push
-
-#![stable(feature = "rust1", since = "1.0.0")]
-
-use core::cmp::{self, Ordering};
-use core::convert::TryFrom;
-use core::fmt;
-use core::hash::{Hash, Hasher};
-use core::intrinsics::{arith_offset, assume};
-use core::iter::{
-    FromIterator, FusedIterator, InPlaceIterable, SourceIter, TrustedLen, TrustedRandomAccess,
-};
-use core::marker::PhantomData;
-use core::mem::{self, ManuallyDrop, MaybeUninit};
-use core::ops::{self, Index, IndexMut, Range, RangeBounds};
-use core::ptr::{self, NonNull};
-use core::slice::{self, SliceIndex};
-
-use crate::alloc::{Allocator, Global};
-use crate::borrow::{Cow, ToOwned};
-use crate::boxed::Box;
-use crate::collections::TryReserveError;
-use crate::raw_vec::RawVec;
-
-/// A contiguous growable array type, written `Vec<T>` but pronounced 'vector'.
-///
-/// # Examples
-///
-/// ```
-/// let mut vec = Vec::new();
-/// vec.push(1);
-/// vec.push(2);
-///
-/// assert_eq!(vec.len(), 2);
-/// assert_eq!(vec[0], 1);
-///
-/// assert_eq!(vec.pop(), Some(2));
-/// assert_eq!(vec.len(), 1);
-///
-/// vec[0] = 7;
-/// assert_eq!(vec[0], 7);
-///
-/// vec.extend([1, 2, 3].iter().copied());
-///
-/// for x in &vec {
-///     println!("{}", x);
-/// }
-/// assert_eq!(vec, [7, 1, 2, 3]);
-/// ```
-///
-/// The [`vec!`] macro is provided to make initialization more convenient:
-///
-/// ```
-/// let mut vec = vec![1, 2, 3];
-/// vec.push(4);
-/// assert_eq!(vec, [1, 2, 3, 4]);
-/// ```
-///
-/// It can also initialize each element of a `Vec<T>` with a given value.
-/// This may be more efficient than performing allocation and initialization
-/// in separate steps, especially when initializing a vector of zeros:
-///
-/// ```
-/// let vec = vec![0; 5];
-/// assert_eq!(vec, [0, 0, 0, 0, 0]);
-///
-/// // The following is equivalent, but potentially slower:
-/// let mut vec = Vec::with_capacity(5);
-/// vec.resize(5, 0);
-/// assert_eq!(vec, [0, 0, 0, 0, 0]);
-/// ```
-///
-/// For more information, see
-/// [Capacity and Reallocation](#capacity-and-reallocation).
-///
-/// Use a `Vec<T>` as an efficient stack:
-///
-/// ```
-/// let mut stack = Vec::new();
-///
-/// stack.push(1);
-/// stack.push(2);
-/// stack.push(3);
-///
-/// while let Some(top) = stack.pop() {
-///     // Prints 3, 2, 1
-///     println!("{}", top);
-/// }
-/// ```
-///
-/// # Indexing
-///
-/// The `Vec` type allows to access values by index, because it implements the
-/// [`Index`] trait. An example will be more explicit:
-///
-/// ```
-/// let v = vec![0, 2, 4, 6];
-/// println!("{}", v[1]); // it will display '2'
-/// ```
-///
-/// However be careful: if you try to access an index which isn't in the `Vec`,
-/// your software will panic! You cannot do this:
-///
-/// ```should_panic
-/// let v = vec![0, 2, 4, 6];
-/// println!("{}", v[6]); // it will panic!
-/// ```
-///
-/// Use [`get`] and [`get_mut`] if you want to check whether the index is in
-/// the `Vec`.
-///
-/// # Slicing
-///
-/// A `Vec` can be mutable. Slices, on the other hand, are read-only objects.
-/// To get a [slice], use [`&`]. Example:
-///
-/// ```
-/// fn read_slice(slice: &[usize]) {
-///     // ...
-/// }
-///
-/// let v = vec![0, 1];
-/// read_slice(&v);
-///
-/// // ... and that's all!
-/// // you can also do it like this:
-/// let u: &[usize] = &v;
-/// // or like this:
-/// let u: &[_] = &v;
-/// ```
-///
-/// In Rust, it's more common to pass slices as arguments rather than vectors
-/// when you just want to provide read access. The same goes for [`String`] and
-/// [`&str`].
-///
-/// # Capacity and reallocation
-///
-/// The capacity of a vector is the amount of space allocated for any future
-/// elements that will be added onto the vector. This is not to be confused with
-/// the *length* of a vector, which specifies the number of actual elements
-/// within the vector. If a vector's length exceeds its capacity, its capacity
-/// will automatically be increased, but its elements will have to be
-/// reallocated.
-///
-/// For example, a vector with capacity 10 and length 0 would be an empty vector
-/// with space for 10 more elements. Pushing 10 or fewer elements onto the
-/// vector will not change its capacity or cause reallocation to occur. However,
-/// if the vector's length is increased to 11, it will have to reallocate, which
-/// can be slow. For this reason, it is recommended to use [`Vec::with_capacity`]
-/// whenever possible to specify how big the vector is expected to get.
-///
-/// # Guarantees
-///
-/// Due to its incredibly fundamental nature, `Vec` makes a lot of guarantees
-/// about its design. This ensures that it's as low-overhead as possible in
-/// the general case, and can be correctly manipulated in primitive ways
-/// by unsafe code. Note that these guarantees refer to an unqualified `Vec<T>`.
-/// If additional type parameters are added (e.g., to support custom allocators),
-/// overriding their defaults may change the behavior.
-///
-/// Most fundamentally, `Vec` is and always will be a (pointer, capacity, length)
-/// triplet. No more, no less. The order of these fields is completely
-/// unspecified, and you should use the appropriate methods to modify these.
-/// The pointer will never be null, so this type is null-pointer-optimized.
-///
-/// However, the pointer may not actually point to allocated memory. In particular,
-/// if you construct a `Vec` with capacity 0 via [`Vec::new`], [`vec![]`][`vec!`],
-/// [`Vec::with_capacity(0)`][`Vec::with_capacity`], or by calling [`shrink_to_fit`]
-/// on an empty Vec, it will not allocate memory. Similarly, if you store zero-sized
-/// types inside a `Vec`, it will not allocate space for them. *Note that in this case
-/// the `Vec` may not report a [`capacity`] of 0*. `Vec` will allocate if and only
-/// if [`mem::size_of::<T>`]`() * capacity() > 0`. In general, `Vec`'s allocation
-/// details are very subtle &mdash; if you intend to allocate memory using a `Vec`
-/// and use it for something else (either to pass to unsafe code, or to build your
-/// own memory-backed collection), be sure to deallocate this memory by using
-/// `from_raw_parts` to recover the `Vec` and then dropping it.
-///
-/// If a `Vec` *has* allocated memory, then the memory it points to is on the heap
-/// (as defined by the allocator Rust is configured to use by default), and its
-/// pointer points to [`len`] initialized, contiguous elements in order (what
-/// you would see if you coerced it to a slice), followed by [`capacity`]` -
-/// `[`len`] logically uninitialized, contiguous elements.
-///
-/// `Vec` will never perform a "small optimization" where elements are actually
-/// stored on the stack for two reasons:
-///
-/// * It would make it more difficult for unsafe code to correctly manipulate
-///   a `Vec`. The contents of a `Vec` wouldn't have a stable address if it were
-///   only moved, and it would be more difficult to determine if a `Vec` had
-///   actually allocated memory.
-///
-/// * It would penalize the general case, incurring an additional branch
-///   on every access.
-///
-/// `Vec` will never automatically shrink itself, even if completely empty. This
-/// ensures no unnecessary allocations or deallocations occur. Emptying a `Vec`
-/// and then filling it back up to the same [`len`] should incur no calls to
-/// the allocator. If you wish to free up unused memory, use
-/// [`shrink_to_fit`].
-///
-/// [`push`] and [`insert`] will never (re)allocate if the reported capacity is
-/// sufficient. [`push`] and [`insert`] *will* (re)allocate if
-/// [`len`]` == `[`capacity`]. That is, the reported capacity is completely
-/// accurate, and can be relied on. It can even be used to manually free the memory
-/// allocated by a `Vec` if desired. Bulk insertion methods *may* reallocate, even
-/// when not necessary.
-///
-/// `Vec` does not guarantee any particular growth strategy when reallocating
-/// when full, nor when [`reserve`] is called. The current strategy is basic
-/// and it may prove desirable to use a non-constant growth factor. Whatever
-/// strategy is used will of course guarantee *O*(1) amortized [`push`].
-///
-/// `vec![x; n]`, `vec![a, b, c, d]`, and
-/// [`Vec::with_capacity(n)`][`Vec::with_capacity`], will all produce a `Vec`
-/// with exactly the requested capacity. If [`len`]` == `[`capacity`],
-/// (as is the case for the [`vec!`] macro), then a `Vec<T>` can be converted to
-/// and from a [`Box<[T]>`][owned slice] without reallocating or moving the elements.
-///
-/// `Vec` will not specifically overwrite any data that is removed from it,
-/// but also won't specifically preserve it. Its uninitialized memory is
-/// scratch space that it may use however it wants. It will generally just do
-/// whatever is most efficient or otherwise easy to implement. Do not rely on
-/// removed data to be erased for security purposes. Even if you drop a `Vec`, its
-/// buffer may simply be reused by another `Vec`. Even if you zero a `Vec`'s memory
-/// first, that may not actually happen because the optimizer does not consider
-/// this a side-effect that must be preserved. There is one case which we will
-/// not break, however: using `unsafe` code to write to the excess capacity,
-/// and then increasing the length to match, is always valid.
-///
-/// `Vec` does not currently guarantee the order in which elements are dropped.
-/// The order has changed in the past and may change again.
-///
-/// [`get`]: ../../std/vec/struct.Vec.html#method.get
-/// [`get_mut`]: ../../std/vec/struct.Vec.html#method.get_mut
-/// [`String`]: crate::string::String
-/// [`&str`]: type@str
-/// [`shrink_to_fit`]: Vec::shrink_to_fit
-/// [`capacity`]: Vec::capacity
-/// [`mem::size_of::<T>`]: core::mem::size_of
-/// [`len`]: Vec::len
-/// [`push`]: Vec::push
-/// [`insert`]: Vec::insert
-/// [`reserve`]: Vec::reserve
-/// [owned slice]: Box
-/// [slice]: ../../std/primitive.slice.html
-/// [`&`]: ../../std/primitive.reference.html
-#[stable(feature = "rust1", since = "1.0.0")]
-#[cfg_attr(not(test), rustc_diagnostic_item = "vec_type")]
-pub struct Vec<T, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global> {
-    buf: RawVec<T, A>,
-    len: usize,
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Inherent methods
-////////////////////////////////////////////////////////////////////////////////
-
-impl<T> Vec<T> {
-    /// Constructs a new, empty `Vec<T>`.
-    ///
-    /// The vector will not allocate until elements are pushed onto it.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// # #![allow(unused_mut)]
-    /// let mut vec: Vec<i32> = Vec::new();
-    /// ```
-    #[inline]
-    #[rustc_const_stable(feature = "const_vec_new", since = "1.39.0")]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub const fn new() -> Self {
-        Vec { buf: RawVec::NEW, len: 0 }
-    }
-
-    /// Constructs a new, empty `Vec<T>` with the specified capacity.
-    ///
-    /// The vector will be able to hold exactly `capacity` elements without
-    /// reallocating. If `capacity` is 0, the vector will not allocate.
-    ///
-    /// It is important to note that although the returned vector has the
-    /// *capacity* specified, the vector will have a zero *length*. For an
-    /// explanation of the difference between length and capacity, see
-    /// *[Capacity and reallocation]*.
-    ///
-    /// [Capacity and reallocation]: #capacity-and-reallocation
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// let mut vec = Vec::with_capacity(10);
-    ///
-    /// // The vector contains no items, even though it has capacity for more
-    /// assert_eq!(vec.len(), 0);
-    /// assert_eq!(vec.capacity(), 10);
-    ///
-    /// // These are all done without reallocating...
-    /// for i in 0..10 {
-    ///     vec.push(i);
-    /// }
-    /// assert_eq!(vec.len(), 10);
-    /// assert_eq!(vec.capacity(), 10);
-    ///
-    /// // ...but this may make the vector reallocate
-    /// vec.push(11);
-    /// assert_eq!(vec.len(), 11);
-    /// assert!(vec.capacity() >= 11);
-    /// ```
-    #[inline]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn with_capacity(capacity: usize) -> Self {
-        Self::with_capacity_in(capacity, Global)
-    }
-
-    /// Creates a `Vec<T>` directly from the raw components of another vector.
-    ///
-    /// # Safety
-    ///
-    /// This is highly unsafe, due to the number of invariants that aren't
-    /// checked:
-    ///
-    /// * `ptr` needs to have been previously allocated via [`String`]/`Vec<T>`
-    ///   (at least, it's highly likely to be incorrect if it wasn't).
-    /// * `T` needs to have the same size and alignment as what `ptr` was allocated with.
-    ///   (`T` having a less strict alignment is not sufficient, the alignment really
-    ///   needs to be equal to satisfy the [`dealloc`] requirement that memory must be
-    ///   allocated and deallocated with the same layout.)
-    /// * `length` needs to be less than or equal to `capacity`.
-    /// * `capacity` needs to be the capacity that the pointer was allocated with.
-    ///
-    /// Violating these may cause problems like corrupting the allocator's
-    /// internal data structures. For example it is **not** safe
-    /// to build a `Vec<u8>` from a pointer to a C `char` array with length `size_t`.
-    /// It's also not safe to build one from a `Vec<u16>` and its length, because
-    /// the allocator cares about the alignment, and these two types have different
-    /// alignments. The buffer was allocated with alignment 2 (for `u16`), but after
-    /// turning it into a `Vec<u8>` it'll be deallocated with alignment 1.
-    ///
-    /// The ownership of `ptr` is effectively transferred to the
-    /// `Vec<T>` which may then deallocate, reallocate or change the
-    /// contents of memory pointed to by the pointer at will. Ensure
-    /// that nothing else uses the pointer after calling this
-    /// function.
-    ///
-    /// [`String`]: crate::string::String
-    /// [`dealloc`]: crate::alloc::GlobalAlloc::dealloc
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::ptr;
-    /// use std::mem;
-    ///
-    /// let v = vec![1, 2, 3];
-    ///
-    // FIXME Update this when vec_into_raw_parts is stabilized
-    /// // Prevent running `v`'s destructor so we are in complete control
-    /// // of the allocation.
-    /// let mut v = mem::ManuallyDrop::new(v);
-    ///
-    /// // Pull out the various important pieces of information about `v`
-    /// let p = v.as_mut_ptr();
-    /// let len = v.len();
-    /// let cap = v.capacity();
-    ///
-    /// unsafe {
-    ///     // Overwrite memory with 4, 5, 6
-    ///     for i in 0..len as isize {
-    ///         ptr::write(p.offset(i), 4 + i);
-    ///     }
-    ///
-    ///     // Put everything back together into a Vec
-    ///     let rebuilt = Vec::from_raw_parts(p, len, cap);
-    ///     assert_eq!(rebuilt, [4, 5, 6]);
-    /// }
-    /// ```
-    #[inline]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub unsafe fn from_raw_parts(ptr: *mut T, length: usize, capacity: usize) -> Self {
-        unsafe { Self::from_raw_parts_in(ptr, length, capacity, Global) }
-    }
-}
-
-impl<T, A: Allocator> Vec<T, A> {
-    /// Constructs a new, empty `Vec<T, A>`.
-    ///
-    /// The vector will not allocate until elements are pushed onto it.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(allocator_api)]
-    ///
-    /// use std::alloc::System;
-    ///
-    /// # #[allow(unused_mut)]
-    /// let mut vec: Vec<i32, _> = Vec::new_in(System);
-    /// ```
-    #[inline]
-    #[unstable(feature = "allocator_api", issue = "32838")]
-    pub const fn new_in(alloc: A) -> Self {
-        Vec { buf: RawVec::new_in(alloc), len: 0 }
-    }
-
-    /// Constructs a new, empty `Vec<T, A>` with the specified capacity with the provided
-    /// allocator.
-    ///
-    /// The vector will be able to hold exactly `capacity` elements without
-    /// reallocating. If `capacity` is 0, the vector will not allocate.
-    ///
-    /// It is important to note that although the returned vector has the
-    /// *capacity* specified, the vector will have a zero *length*. For an
-    /// explanation of the difference between length and capacity, see
-    /// *[Capacity and reallocation]*.
-    ///
-    /// [Capacity and reallocation]: #capacity-and-reallocation
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(allocator_api)]
-    ///
-    /// use std::alloc::System;
-    ///
-    /// let mut vec = Vec::with_capacity_in(10, System);
-    ///
-    /// // The vector contains no items, even though it has capacity for more
-    /// assert_eq!(vec.len(), 0);
-    /// assert_eq!(vec.capacity(), 10);
-    ///
-    /// // These are all done without reallocating...
-    /// for i in 0..10 {
-    ///     vec.push(i);
-    /// }
-    /// assert_eq!(vec.len(), 10);
-    /// assert_eq!(vec.capacity(), 10);
-    ///
-    /// // ...but this may make the vector reallocate
-    /// vec.push(11);
-    /// assert_eq!(vec.len(), 11);
-    /// assert!(vec.capacity() >= 11);
-    /// ```
-    #[inline]
-    #[unstable(feature = "allocator_api", issue = "32838")]
-    pub fn with_capacity_in(capacity: usize, alloc: A) -> Self {
-        Vec { buf: RawVec::with_capacity_in(capacity, alloc), len: 0 }
-    }
-
-    /// Creates a `Vec<T, A>` directly from the raw components of another vector.
-    ///
-    /// # Safety
-    ///
-    /// This is highly unsafe, due to the number of invariants that aren't
-    /// checked:
-    ///
-    /// * `ptr` needs to have been previously allocated via [`String`]/`Vec<T>`
-    ///   (at least, it's highly likely to be incorrect if it wasn't).
-    /// * `T` needs to have the same size and alignment as what `ptr` was allocated with.
-    ///   (`T` having a less strict alignment is not sufficient, the alignment really
-    ///   needs to be equal to satisfy the [`dealloc`] requirement that memory must be
-    ///   allocated and deallocated with the same layout.)
-    /// * `length` needs to be less than or equal to `capacity`.
-    /// * `capacity` needs to be the capacity that the pointer was allocated with.
-    ///
-    /// Violating these may cause problems like corrupting the allocator's
-    /// internal data structures. For example it is **not** safe
-    /// to build a `Vec<u8>` from a pointer to a C `char` array with length `size_t`.
-    /// It's also not safe to build one from a `Vec<u16>` and its length, because
-    /// the allocator cares about the alignment, and these two types have different
-    /// alignments. The buffer was allocated with alignment 2 (for `u16`), but after
-    /// turning it into a `Vec<u8>` it'll be deallocated with alignment 1.
-    ///
-    /// The ownership of `ptr` is effectively transferred to the
-    /// `Vec<T>` which may then deallocate, reallocate or change the
-    /// contents of memory pointed to by the pointer at will. Ensure
-    /// that nothing else uses the pointer after calling this
-    /// function.
-    ///
-    /// [`String`]: crate::string::String
-    /// [`dealloc`]: crate::alloc::GlobalAlloc::dealloc
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(allocator_api)]
-    ///
-    /// use std::alloc::System;
-    ///
-    /// use std::ptr;
-    /// use std::mem;
-    ///
-    /// let mut v = Vec::with_capacity_in(3, System);
-    /// v.push(1);
-    /// v.push(2);
-    /// v.push(3);
-    ///
-    // FIXME Update this when vec_into_raw_parts is stabilized
-    /// // Prevent running `v`'s destructor so we are in complete control
-    /// // of the allocation.
-    /// let mut v = mem::ManuallyDrop::new(v);
-    ///
-    /// // Pull out the various important pieces of information about `v`
-    /// let p = v.as_mut_ptr();
-    /// let len = v.len();
-    /// let cap = v.capacity();
-    /// let alloc = v.allocator();
-    ///
-    /// unsafe {
-    ///     // Overwrite memory with 4, 5, 6
-    ///     for i in 0..len as isize {
-    ///         ptr::write(p.offset(i), 4 + i);
-    ///     }
-    ///
-    ///     // Put everything back together into a Vec
-    ///     let rebuilt = Vec::from_raw_parts_in(p, len, cap, alloc.clone());
-    ///     assert_eq!(rebuilt, [4, 5, 6]);
-    /// }
-    /// ```
-    #[inline]
-    #[unstable(feature = "allocator_api", issue = "32838")]
-    pub unsafe fn from_raw_parts_in(ptr: *mut T, length: usize, capacity: usize, alloc: A) -> Self {
-        unsafe { Vec { buf: RawVec::from_raw_parts_in(ptr, capacity, alloc), len: length } }
-    }
-
-    /// Decomposes a `Vec<T>` into its raw components.
-    ///
-    /// Returns the raw pointer to the underlying data, the length of
-    /// the vector (in elements), and the allocated capacity of the
-    /// data (in elements). These are the same arguments in the same
-    /// order as the arguments to [`from_raw_parts`].
-    ///
-    /// After calling this function, the caller is responsible for the
-    /// memory previously managed by the `Vec`. The only way to do
-    /// this is to convert the raw pointer, length, and capacity back
-    /// into a `Vec` with the [`from_raw_parts`] function, allowing
-    /// the destructor to perform the cleanup.
-    ///
-    /// [`from_raw_parts`]: Vec::from_raw_parts
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(vec_into_raw_parts)]
-    /// let v: Vec<i32> = vec![-1, 0, 1];
-    ///
-    /// let (ptr, len, cap) = v.into_raw_parts();
-    ///
-    /// let rebuilt = unsafe {
-    ///     // We can now make changes to the components, such as
-    ///     // transmuting the raw pointer to a compatible type.
-    ///     let ptr = ptr as *mut u32;
-    ///
-    ///     Vec::from_raw_parts(ptr, len, cap)
-    /// };
-    /// assert_eq!(rebuilt, [4294967295, 0, 1]);
-    /// ```
-    #[unstable(feature = "vec_into_raw_parts", reason = "new API", issue = "65816")]
-    pub fn into_raw_parts(self) -> (*mut T, usize, usize) {
-        let mut me = ManuallyDrop::new(self);
-        (me.as_mut_ptr(), me.len(), me.capacity())
-    }
-
-    /// Decomposes a `Vec<T>` into its raw components.
-    ///
-    /// Returns the raw pointer to the underlying data, the length of the vector (in elements),
-    /// the allocated capacity of the data (in elements), and the allocator. These are the same
-    /// arguments in the same order as the arguments to [`from_raw_parts_in`].
-    ///
-    /// After calling this function, the caller is responsible for the
-    /// memory previously managed by the `Vec`. The only way to do
-    /// this is to convert the raw pointer, length, and capacity back
-    /// into a `Vec` with the [`from_raw_parts_in`] function, allowing
-    /// the destructor to perform the cleanup.
-    ///
-    /// [`from_raw_parts_in`]: Vec::from_raw_parts_in
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(allocator_api, vec_into_raw_parts)]
-    ///
-    /// use std::alloc::System;
-    ///
-    /// let mut v: Vec<i32, System> = Vec::new_in(System);
-    /// v.push(-1);
-    /// v.push(0);
-    /// v.push(1);
-    ///
-    /// let (ptr, len, cap, alloc) = v.into_raw_parts_with_alloc();
-    ///
-    /// let rebuilt = unsafe {
-    ///     // We can now make changes to the components, such as
-    ///     // transmuting the raw pointer to a compatible type.
-    ///     let ptr = ptr as *mut u32;
-    ///
-    ///     Vec::from_raw_parts_in(ptr, len, cap, alloc)
-    /// };
-    /// assert_eq!(rebuilt, [4294967295, 0, 1]);
-    /// ```
-    #[unstable(feature = "allocator_api", issue = "32838")]
-    // #[unstable(feature = "vec_into_raw_parts", reason = "new API", issue = "65816")]
-    pub fn into_raw_parts_with_alloc(self) -> (*mut T, usize, usize, A) {
-        let mut me = ManuallyDrop::new(self);
-        let len = me.len();
-        let capacity = me.capacity();
-        let ptr = me.as_mut_ptr();
-        let alloc = unsafe { ptr::read(me.allocator()) };
-        (ptr, len, capacity, alloc)
-    }
-
-    /// Returns the number of elements the vector can hold without
-    /// reallocating.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// let vec: Vec<i32> = Vec::with_capacity(10);
-    /// assert_eq!(vec.capacity(), 10);
-    /// ```
-    #[inline]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn capacity(&self) -> usize {
-        self.buf.capacity()
-    }
-
-    /// Reserves capacity for at least `additional` more elements to be inserted
-    /// in the given `Vec<T>`. The collection may reserve more space to avoid
-    /// frequent reallocations. After calling `reserve`, capacity will be
-    /// greater than or equal to `self.len() + additional`. Does nothing if
-    /// capacity is already sufficient.
-    ///
-    /// # Panics
-    ///
-    /// Panics if the new capacity exceeds `isize::MAX` bytes.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// let mut vec = vec![1];
-    /// vec.reserve(10);
-    /// assert!(vec.capacity() >= 11);
-    /// ```
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn reserve(&mut self, additional: usize) {
-        self.buf.reserve(self.len, additional);
-    }
-
-    /// Reserves the minimum capacity for exactly `additional` more elements to
-    /// be inserted in the given `Vec<T>`. After calling `reserve_exact`,
-    /// capacity will be greater than or equal to `self.len() + additional`.
-    /// Does nothing if the capacity is already sufficient.
-    ///
-    /// Note that the allocator may give the collection more space than it
-    /// requests. Therefore, capacity can not be relied upon to be precisely
-    /// minimal. Prefer `reserve` if future insertions are expected.
-    ///
-    /// # Panics
-    ///
-    /// Panics if the new capacity overflows `usize`.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// let mut vec = vec![1];
-    /// vec.reserve_exact(10);
-    /// assert!(vec.capacity() >= 11);
-    /// ```
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn reserve_exact(&mut self, additional: usize) {
-        self.buf.reserve_exact(self.len, additional);
-    }
-
-    /// Tries to reserve capacity for at least `additional` more elements to be inserted
-    /// in the given `Vec<T>`. The collection may reserve more space to avoid
-    /// frequent reallocations. After calling `try_reserve`, capacity will be
-    /// greater than or equal to `self.len() + additional`. Does nothing if
-    /// capacity is already sufficient.
-    ///
-    /// # Errors
-    ///
-    /// If the capacity overflows, or the allocator reports a failure, then an error
-    /// is returned.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(try_reserve)]
-    /// use std::collections::TryReserveError;
-    ///
-    /// fn process_data(data: &[u32]) -> Result<Vec<u32>, TryReserveError> {
-    ///     let mut output = Vec::new();
-    ///
-    ///     // Pre-reserve the memory, exiting if we can't
-    ///     output.try_reserve(data.len())?;
-    ///
-    ///     // Now we know this can't OOM in the middle of our complex work
-    ///     output.extend(data.iter().map(|&val| {
-    ///         val * 2 + 5 // very complicated
-    ///     }));
-    ///
-    ///     Ok(output)
-    /// }
-    /// # process_data(&[1, 2, 3]).expect("why is the test harness OOMing on 12 bytes?");
-    /// ```
-    #[unstable(feature = "try_reserve", reason = "new API", issue = "48043")]
-    pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> {
-        self.buf.try_reserve(self.len, additional)
-    }
-
-    /// Tries to reserve the minimum capacity for exactly `additional`
-    /// elements to be inserted in the given `Vec<T>`. After calling
-    /// `try_reserve_exact`, capacity will be greater than or equal to
-    /// `self.len() + additional` if it returns `Ok(())`.
-    /// Does nothing if the capacity is already sufficient.
-    ///
-    /// Note that the allocator may give the collection more space than it
-    /// requests. Therefore, capacity can not be relied upon to be precisely
-    /// minimal. Prefer `reserve` if future insertions are expected.
-    ///
-    /// # Errors
-    ///
-    /// If the capacity overflows, or the allocator reports a failure, then an error
-    /// is returned.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(try_reserve)]
-    /// use std::collections::TryReserveError;
-    ///
-    /// fn process_data(data: &[u32]) -> Result<Vec<u32>, TryReserveError> {
-    ///     let mut output = Vec::new();
-    ///
-    ///     // Pre-reserve the memory, exiting if we can't
-    ///     output.try_reserve_exact(data.len())?;
-    ///
-    ///     // Now we know this can't OOM in the middle of our complex work
-    ///     output.extend(data.iter().map(|&val| {
-    ///         val * 2 + 5 // very complicated
-    ///     }));
-    ///
-    ///     Ok(output)
-    /// }
-    /// # process_data(&[1, 2, 3]).expect("why is the test harness OOMing on 12 bytes?");
-    /// ```
-    #[unstable(feature = "try_reserve", reason = "new API", issue = "48043")]
-    pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), TryReserveError> {
-        self.buf.try_reserve_exact(self.len, additional)
-    }
-
-    /// Shrinks the capacity of the vector as much as possible.
-    ///
-    /// It will drop down as close as possible to the length but the allocator
-    /// may still inform the vector that there is space for a few more elements.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// let mut vec = Vec::with_capacity(10);
-    /// vec.extend([1, 2, 3].iter().cloned());
-    /// assert_eq!(vec.capacity(), 10);
-    /// vec.shrink_to_fit();
-    /// assert!(vec.capacity() >= 3);
-    /// ```
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn shrink_to_fit(&mut self) {
-        // The capacity is never less than the length, and there's nothing to do when
-        // they are equal, so we can avoid the panic case in `RawVec::shrink_to_fit`
-        // by only calling it with a greater capacity.
-        if self.capacity() > self.len {
-            self.buf.shrink_to_fit(self.len);
-        }
-    }
-
-    /// Shrinks the capacity of the vector with a lower bound.
-    ///
-    /// The capacity will remain at least as large as both the length
-    /// and the supplied value.
-    ///
-    /// # Panics
-    ///
-    /// Panics if the current capacity is smaller than the supplied
-    /// minimum capacity.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(shrink_to)]
-    /// let mut vec = Vec::with_capacity(10);
-    /// vec.extend([1, 2, 3].iter().cloned());
-    /// assert_eq!(vec.capacity(), 10);
-    /// vec.shrink_to(4);
-    /// assert!(vec.capacity() >= 4);
-    /// vec.shrink_to(0);
-    /// assert!(vec.capacity() >= 3);
-    /// ```
-    #[unstable(feature = "shrink_to", reason = "new API", issue = "56431")]
-    pub fn shrink_to(&mut self, min_capacity: usize) {
-        self.buf.shrink_to_fit(cmp::max(self.len, min_capacity));
-    }
-
-    /// Converts the vector into [`Box<[T]>`][owned slice].
-    ///
-    /// Note that this will drop any excess capacity.
-    ///
-    /// [owned slice]: Box
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// let v = vec![1, 2, 3];
-    ///
-    /// let slice = v.into_boxed_slice();
-    /// ```
-    ///
-    /// Any excess capacity is removed:
-    ///
-    /// ```
-    /// let mut vec = Vec::with_capacity(10);
-    /// vec.extend([1, 2, 3].iter().cloned());
-    ///
-    /// assert_eq!(vec.capacity(), 10);
-    /// let slice = vec.into_boxed_slice();
-    /// assert_eq!(slice.into_vec().capacity(), 3);
-    /// ```
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn into_boxed_slice(mut self) -> Box<[T], A> {
-        unsafe {
-            self.shrink_to_fit();
-            let me = ManuallyDrop::new(self);
-            let buf = ptr::read(&me.buf);
-            let len = me.len();
-            buf.into_box(len).assume_init()
-        }
-    }
-
-    /// Shortens the vector, keeping the first `len` elements and dropping
-    /// the rest.
-    ///
-    /// If `len` is greater than the vector's current length, this has no
-    /// effect.
-    ///
-    /// The [`drain`] method can emulate `truncate`, but causes the excess
-    /// elements to be returned instead of dropped.
-    ///
-    /// Note that this method has no effect on the allocated capacity
-    /// of the vector.
-    ///
-    /// # Examples
-    ///
-    /// Truncating a five element vector to two elements:
-    ///
-    /// ```
-    /// let mut vec = vec![1, 2, 3, 4, 5];
-    /// vec.truncate(2);
-    /// assert_eq!(vec, [1, 2]);
-    /// ```
-    ///
-    /// No truncation occurs when `len` is greater than the vector's current
-    /// length:
-    ///
-    /// ```
-    /// let mut vec = vec![1, 2, 3];
-    /// vec.truncate(8);
-    /// assert_eq!(vec, [1, 2, 3]);
-    /// ```
-    ///
-    /// Truncating when `len == 0` is equivalent to calling the [`clear`]
-    /// method.
-    ///
-    /// ```
-    /// let mut vec = vec![1, 2, 3];
-    /// vec.truncate(0);
-    /// assert_eq!(vec, []);
-    /// ```
-    ///
-    /// [`clear`]: Vec::clear
-    /// [`drain`]: Vec::drain
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn truncate(&mut self, len: usize) {
-        // This is safe because:
-        //
-        // * the slice passed to `drop_in_place` is valid; the `len > self.len`
-        //   case avoids creating an invalid slice, and
-        // * the `len` of the vector is shrunk before calling `drop_in_place`,
-        //   such that no value will be dropped twice in case `drop_in_place`
-        //   were to panic once (if it panics twice, the program aborts).
-        unsafe {
-            if len > self.len {
-                return;
-            }
-            let remaining_len = self.len - len;
-            let s = ptr::slice_from_raw_parts_mut(self.as_mut_ptr().add(len), remaining_len);
-            self.len = len;
-            ptr::drop_in_place(s);
-        }
-    }
-
-    /// Extracts a slice containing the entire vector.
-    ///
-    /// Equivalent to `&s[..]`.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::io::{self, Write};
-    /// let buffer = vec![1, 2, 3, 5, 8];
-    /// io::sink().write(buffer.as_slice()).unwrap();
-    /// ```
-    #[inline]
-    #[stable(feature = "vec_as_slice", since = "1.7.0")]
-    pub fn as_slice(&self) -> &[T] {
-        self
-    }
-
-    /// Extracts a mutable slice of the entire vector.
-    ///
-    /// Equivalent to `&mut s[..]`.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::io::{self, Read};
-    /// let mut buffer = vec![0; 3];
-    /// io::repeat(0b101).read_exact(buffer.as_mut_slice()).unwrap();
-    /// ```
-    #[inline]
-    #[stable(feature = "vec_as_slice", since = "1.7.0")]
-    pub fn as_mut_slice(&mut self) -> &mut [T] {
-        self
-    }
-
-    /// Returns a raw pointer to the vector's buffer.
-    ///
-    /// The caller must ensure that the vector outlives the pointer this
-    /// function returns, or else it will end up pointing to garbage.
-    /// Modifying the vector may cause its buffer to be reallocated,
-    /// which would also make any pointers to it invalid.
-    ///
-    /// The caller must also ensure that the memory the pointer (non-transitively) points to
-    /// is never written to (except inside an `UnsafeCell`) using this pointer or any pointer
-    /// derived from it. If you need to mutate the contents of the slice, use [`as_mut_ptr`].
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// let x = vec![1, 2, 4];
-    /// let x_ptr = x.as_ptr();
-    ///
-    /// unsafe {
-    ///     for i in 0..x.len() {
-    ///         assert_eq!(*x_ptr.add(i), 1 << i);
-    ///     }
-    /// }
-    /// ```
-    ///
-    /// [`as_mut_ptr`]: Vec::as_mut_ptr
-    #[stable(feature = "vec_as_ptr", since = "1.37.0")]
-    #[inline]
-    pub fn as_ptr(&self) -> *const T {
-        // We shadow the slice method of the same name to avoid going through
-        // `deref`, which creates an intermediate reference.
-        let ptr = self.buf.ptr();
-        unsafe {
-            assume(!ptr.is_null());
-        }
-        ptr
-    }
-
-    /// Returns an unsafe mutable pointer to the vector's buffer.
-    ///
-    /// The caller must ensure that the vector outlives the pointer this
-    /// function returns, or else it will end up pointing to garbage.
-    /// Modifying the vector may cause its buffer to be reallocated,
-    /// which would also make any pointers to it invalid.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// // Allocate vector big enough for 4 elements.
-    /// let size = 4;
-    /// let mut x: Vec<i32> = Vec::with_capacity(size);
-    /// let x_ptr = x.as_mut_ptr();
-    ///
-    /// // Initialize elements via raw pointer writes, then set length.
-    /// unsafe {
-    ///     for i in 0..size {
-    ///         *x_ptr.add(i) = i as i32;
-    ///     }
-    ///     x.set_len(size);
-    /// }
-    /// assert_eq!(&*x, &[0, 1, 2, 3]);
-    /// ```
-    #[stable(feature = "vec_as_ptr", since = "1.37.0")]
-    #[inline]
-    pub fn as_mut_ptr(&mut self) -> *mut T {
-        // We shadow the slice method of the same name to avoid going through
-        // `deref_mut`, which creates an intermediate reference.
-        let ptr = self.buf.ptr();
-        unsafe {
-            assume(!ptr.is_null());
-        }
-        ptr
-    }
-
-    /// Returns a reference to the underlying allocator.
-    #[unstable(feature = "allocator_api", issue = "32838")]
-    #[inline]
-    pub fn allocator(&self) -> &A {
-        self.buf.allocator()
-    }
-
-    /// Forces the length of the vector to `new_len`.
-    ///
-    /// This is a low-level operation that maintains none of the normal
-    /// invariants of the type. Normally changing the length of a vector
-    /// is done using one of the safe operations instead, such as
-    /// [`truncate`], [`resize`], [`extend`], or [`clear`].
-    ///
-    /// [`truncate`]: Vec::truncate
-    /// [`resize`]: Vec::resize
-    /// [`extend`]: Extend::extend
-    /// [`clear`]: Vec::clear
-    ///
-    /// # Safety
-    ///
-    /// - `new_len` must be less than or equal to [`capacity()`].
-    /// - The elements at `old_len..new_len` must be initialized.
-    ///
-    /// [`capacity()`]: Vec::capacity
-    ///
-    /// # Examples
-    ///
-    /// This method can be useful for situations in which the vector
-    /// is serving as a buffer for other code, particularly over FFI:
-    ///
-    /// ```no_run
-    /// # #![allow(dead_code)]
-    /// # // This is just a minimal skeleton for the doc example;
-    /// # // don't use this as a starting point for a real library.
-    /// # pub struct StreamWrapper { strm: *mut std::ffi::c_void }
-    /// # const Z_OK: i32 = 0;
-    /// # extern "C" {
-    /// #     fn deflateGetDictionary(
-    /// #         strm: *mut std::ffi::c_void,
-    /// #         dictionary: *mut u8,
-    /// #         dictLength: *mut usize,
-    /// #     ) -> i32;
-    /// # }
-    /// # impl StreamWrapper {
-    /// pub fn get_dictionary(&self) -> Option<Vec<u8>> {
-    ///     // Per the FFI method's docs, "32768 bytes is always enough".
-    ///     let mut dict = Vec::with_capacity(32_768);
-    ///     let mut dict_length = 0;
-    ///     // SAFETY: When `deflateGetDictionary` returns `Z_OK`, it holds that:
-    ///     // 1. `dict_length` elements were initialized.
-    ///     // 2. `dict_length` <= the capacity (32_768)
-    ///     // which makes `set_len` safe to call.
-    ///     unsafe {
-    ///         // Make the FFI call...
-    ///         let r = deflateGetDictionary(self.strm, dict.as_mut_ptr(), &mut dict_length);
-    ///         if r == Z_OK {
-    ///             // ...and update the length to what was initialized.
-    ///             dict.set_len(dict_length);
-    ///             Some(dict)
-    ///         } else {
-    ///             None
-    ///         }
-    ///     }
-    /// }
-    /// # }
-    /// ```
-    ///
-    /// While the following example is sound, there is a memory leak since
-    /// the inner vectors were not freed prior to the `set_len` call:
-    ///
-    /// ```
-    /// let mut vec = vec![vec![1, 0, 0],
-    ///                    vec![0, 1, 0],
-    ///                    vec![0, 0, 1]];
-    /// // SAFETY:
-    /// // 1. `old_len..0` is empty so no elements need to be initialized.
-    /// // 2. `0 <= capacity` always holds whatever `capacity` is.
-    /// unsafe {
-    ///     vec.set_len(0);
-    /// }
-    /// ```
-    ///
-    /// Normally, here, one would use [`clear`] instead to correctly drop
-    /// the contents and thus not leak memory.
-    #[inline]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub unsafe fn set_len(&mut self, new_len: usize) {
-        debug_assert!(new_len <= self.capacity());
-
-        self.len = new_len;
-    }
-
-    /// Removes an element from the vector and returns it.
-    ///
-    /// The removed element is replaced by the last element of the vector.
-    ///
-    /// This does not preserve ordering, but is O(1).
-    ///
-    /// # Panics
-    ///
-    /// Panics if `index` is out of bounds.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// let mut v = vec!["foo", "bar", "baz", "qux"];
-    ///
-    /// assert_eq!(v.swap_remove(1), "bar");
-    /// assert_eq!(v, ["foo", "qux", "baz"]);
-    ///
-    /// assert_eq!(v.swap_remove(0), "foo");
-    /// assert_eq!(v, ["baz", "qux"]);
-    /// ```
-    #[inline]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn swap_remove(&mut self, index: usize) -> T {
-        #[cold]
-        #[inline(never)]
-        fn assert_failed(index: usize, len: usize) -> ! {
-            panic!("swap_remove index (is {}) should be < len (is {})", index, len);
-        }
-
-        let len = self.len();
-        if index >= len {
-            assert_failed(index, len);
-        }
-        unsafe {
-            // We replace self[index] with the last element. Note that if the
-            // bounds check above succeeds there must be a last element (which
-            // can be self[index] itself).
-            let last = ptr::read(self.as_ptr().add(len - 1));
-            let hole = self.as_mut_ptr().add(index);
-            self.set_len(len - 1);
-            ptr::replace(hole, last)
-        }
-    }
-
-    /// Inserts an element at position `index` within the vector, shifting all
-    /// elements after it to the right.
-    ///
-    /// # Panics
-    ///
-    /// Panics if `index > len`.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// let mut vec = vec![1, 2, 3];
-    /// vec.insert(1, 4);
-    /// assert_eq!(vec, [1, 4, 2, 3]);
-    /// vec.insert(4, 5);
-    /// assert_eq!(vec, [1, 4, 2, 3, 5]);
-    /// ```
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn insert(&mut self, index: usize, element: T) {
-        #[cold]
-        #[inline(never)]
-        fn assert_failed(index: usize, len: usize) -> ! {
-            panic!("insertion index (is {}) should be <= len (is {})", index, len);
-        }
-
-        let len = self.len();
-        if index > len {
-            assert_failed(index, len);
-        }
-
-        // space for the new element
-        if len == self.buf.capacity() {
-            self.reserve(1);
-        }
-
-        unsafe {
-            // infallible
-            // The spot to put the new value
-            {
-                let p = self.as_mut_ptr().add(index);
-                // Shift everything over to make space. (Duplicating the
-                // `index`th element into two consecutive places.)
-                ptr::copy(p, p.offset(1), len - index);
-                // Write it in, overwriting the first copy of the `index`th
-                // element.
-                ptr::write(p, element);
-            }
-            self.set_len(len + 1);
-        }
-    }
-
-    /// Removes and returns the element at position `index` within the vector,
-    /// shifting all elements after it to the left.
-    ///
-    /// # Panics
-    ///
-    /// Panics if `index` is out of bounds.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// let mut v = vec![1, 2, 3];
-    /// assert_eq!(v.remove(1), 2);
-    /// assert_eq!(v, [1, 3]);
-    /// ```
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn remove(&mut self, index: usize) -> T {
-        #[cold]
-        #[inline(never)]
-        fn assert_failed(index: usize, len: usize) -> ! {
-            panic!("removal index (is {}) should be < len (is {})", index, len);
-        }
-
-        let len = self.len();
-        if index >= len {
-            assert_failed(index, len);
-        }
-        unsafe {
-            // infallible
-            let ret;
-            {
-                // the place we are taking from.
-                let ptr = self.as_mut_ptr().add(index);
-                // copy it out, unsafely having a copy of the value on
-                // the stack and in the vector at the same time.
-                ret = ptr::read(ptr);
-
-                // Shift everything down to fill in that spot.
-                ptr::copy(ptr.offset(1), ptr, len - index - 1);
-            }
-            self.set_len(len - 1);
-            ret
-        }
-    }
-
-    /// Retains only the elements specified by the predicate.
-    ///
-    /// In other words, remove all elements `e` such that `f(&e)` returns `false`.
-    /// This method operates in place, visiting each element exactly once in the
-    /// original order, and preserves the order of the retained elements.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// let mut vec = vec![1, 2, 3, 4];
-    /// vec.retain(|&x| x % 2 == 0);
-    /// assert_eq!(vec, [2, 4]);
-    /// ```
-    ///
-    /// The exact order may be useful for tracking external state, like an index.
-    ///
-    /// ```
-    /// let mut vec = vec![1, 2, 3, 4, 5];
-    /// let keep = [false, true, true, false, true];
-    /// let mut i = 0;
-    /// vec.retain(|_| (keep[i], i += 1).0);
-    /// assert_eq!(vec, [2, 3, 5]);
-    /// ```
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn retain<F>(&mut self, mut f: F)
-    where
-        F: FnMut(&T) -> bool,
-    {
-        let len = self.len();
-        let mut del = 0;
-        {
-            let v = &mut **self;
-
-            for i in 0..len {
-                if !f(&v[i]) {
-                    del += 1;
-                } else if del > 0 {
-                    v.swap(i - del, i);
-                }
-            }
-        }
-        if del > 0 {
-            self.truncate(len - del);
-        }
-    }
-
-    /// Removes all but the first of consecutive elements in the vector that resolve to the same
-    /// key.
-    ///
-    /// If the vector is sorted, this removes all duplicates.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// let mut vec = vec![10, 20, 21, 30, 20];
-    ///
-    /// vec.dedup_by_key(|i| *i / 10);
-    ///
-    /// assert_eq!(vec, [10, 20, 30, 20]);
-    /// ```
-    #[stable(feature = "dedup_by", since = "1.16.0")]
-    #[inline]
-    pub fn dedup_by_key<F, K>(&mut self, mut key: F)
-    where
-        F: FnMut(&mut T) -> K,
-        K: PartialEq,
-    {
-        self.dedup_by(|a, b| key(a) == key(b))
-    }
-
-    /// Removes all but the first of consecutive elements in the vector satisfying a given equality
-    /// relation.
-    ///
-    /// The `same_bucket` function is passed references to two elements from the vector and
-    /// must determine if the elements compare equal. The elements are passed in opposite order
-    /// from their order in the slice, so if `same_bucket(a, b)` returns `true`, `a` is removed.
-    ///
-    /// If the vector is sorted, this removes all duplicates.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// let mut vec = vec!["foo", "bar", "Bar", "baz", "bar"];
-    ///
-    /// vec.dedup_by(|a, b| a.eq_ignore_ascii_case(b));
-    ///
-    /// assert_eq!(vec, ["foo", "bar", "baz", "bar"]);
-    /// ```
-    #[stable(feature = "dedup_by", since = "1.16.0")]
-    pub fn dedup_by<F>(&mut self, same_bucket: F)
-    where
-        F: FnMut(&mut T, &mut T) -> bool,
-    {
-        let len = {
-            let (dedup, _) = self.as_mut_slice().partition_dedup_by(same_bucket);
-            dedup.len()
-        };
-        self.truncate(len);
-    }
-
-    /// Appends an element to the back of a collection.
-    ///
-    /// # Panics
-    ///
-    /// Panics if the new capacity exceeds `isize::MAX` bytes.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// let mut vec = vec![1, 2];
-    /// vec.push(3);
-    /// assert_eq!(vec, [1, 2, 3]);
-    /// ```
-    #[inline]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn push(&mut self, value: T) {
-        // This will panic or abort if we would allocate > isize::MAX bytes
-        // or if the length increment would overflow for zero-sized types.
-        if self.len == self.buf.capacity() {
-            self.reserve(1);
-        }
-        unsafe {
-            let end = self.as_mut_ptr().add(self.len);
-            ptr::write(end, value);
-            self.len += 1;
-        }
-    }
-
-    /// Removes the last element from a vector and returns it, or [`None`] if it
-    /// is empty.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// let mut vec = vec![1, 2, 3];
-    /// assert_eq!(vec.pop(), Some(3));
-    /// assert_eq!(vec, [1, 2]);
-    /// ```
-    #[inline]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn pop(&mut self) -> Option<T> {
-        if self.len == 0 {
-            None
-        } else {
-            unsafe {
-                self.len -= 1;
-                Some(ptr::read(self.as_ptr().add(self.len())))
-            }
-        }
-    }
-
-    /// Moves all the elements of `other` into `Self`, leaving `other` empty.
-    ///
-    /// # Panics
-    ///
-    /// Panics if the number of elements in the vector overflows a `usize`.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// let mut vec = vec![1, 2, 3];
-    /// let mut vec2 = vec![4, 5, 6];
-    /// vec.append(&mut vec2);
-    /// assert_eq!(vec, [1, 2, 3, 4, 5, 6]);
-    /// assert_eq!(vec2, []);
-    /// ```
-    #[inline]
-    #[stable(feature = "append", since = "1.4.0")]
-    pub fn append(&mut self, other: &mut Self) {
-        unsafe {
-            self.append_elements(other.as_slice() as _);
-            other.set_len(0);
-        }
-    }
-
-    /// Appends elements to `Self` from other buffer.
-    #[inline]
-    unsafe fn append_elements(&mut self, other: *const [T]) {
-        let count = unsafe { (*other).len() };
-        self.reserve(count);
-        let len = self.len();
-        unsafe { ptr::copy_nonoverlapping(other as *const T, self.as_mut_ptr().add(len), count) };
-        self.len += count;
-    }
-
-    /// Creates a draining iterator that removes the specified range in the vector
-    /// and yields the removed items.
-    ///
-    /// When the iterator **is** dropped, all elements in the range are removed
-    /// from the vector, even if the iterator was not fully consumed. If the
-    /// iterator **is not** dropped (with [`mem::forget`] for example), it is
-    /// unspecified how many elements are removed.
-    ///
-    /// # Panics
-    ///
-    /// Panics if the starting point is greater than the end point or if
-    /// the end point is greater than the length of the vector.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// let mut v = vec![1, 2, 3];
-    /// let u: Vec<_> = v.drain(1..).collect();
-    /// assert_eq!(v, &[1]);
-    /// assert_eq!(u, &[2, 3]);
-    ///
-    /// // A full range clears the vector
-    /// v.drain(..);
-    /// assert_eq!(v, &[]);
-    /// ```
-    #[stable(feature = "drain", since = "1.6.0")]
-    pub fn drain<R>(&mut self, range: R) -> Drain<'_, T, A>
-    where
-        R: RangeBounds<usize>,
-    {
-        // Memory safety
-        //
-        // When the Drain is first created, it shortens the length of
-        // the source vector to make sure no uninitialized or moved-from elements
-        // are accessible at all if the Drain's destructor never gets to run.
-        //
-        // Drain will ptr::read out the values to remove.
-        // When finished, remaining tail of the vec is copied back to cover
-        // the hole, and the vector length is restored to the new length.
-        //
-        let len = self.len();
-        let Range { start, end } = range.assert_len(len);
-
-        unsafe {
-            // set self.vec length's to start, to be safe in case Drain is leaked
-            self.set_len(start);
-            // Use the borrow in the IterMut to indicate borrowing behavior of the
-            // whole Drain iterator (like &mut T).
-            let range_slice = slice::from_raw_parts_mut(self.as_mut_ptr().add(start), end - start);
-            Drain {
-                tail_start: end,
-                tail_len: len - end,
-                iter: range_slice.iter(),
-                vec: NonNull::from(self),
-            }
-        }
-    }
-
-    /// Clears the vector, removing all values.
-    ///
-    /// Note that this method has no effect on the allocated capacity
-    /// of the vector.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// let mut v = vec![1, 2, 3];
-    ///
-    /// v.clear();
-    ///
-    /// assert!(v.is_empty());
-    /// ```
-    #[inline]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn clear(&mut self) {
-        self.truncate(0)
-    }
-
-    /// Returns the number of elements in the vector, also referred to
-    /// as its 'length'.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// let a = vec![1, 2, 3];
-    /// assert_eq!(a.len(), 3);
-    /// ```
-    #[inline]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn len(&self) -> usize {
-        self.len
-    }
-
-    /// Returns `true` if the vector contains no elements.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// let mut v = Vec::new();
-    /// assert!(v.is_empty());
-    ///
-    /// v.push(1);
-    /// assert!(!v.is_empty());
-    /// ```
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn is_empty(&self) -> bool {
-        self.len() == 0
-    }
-
-    /// Splits the collection into two at the given index.
-    ///
-    /// Returns a newly allocated vector containing the elements in the range
-    /// `[at, len)`. After the call, the original vector will be left containing
-    /// the elements `[0, at)` with its previous capacity unchanged.
-    ///
-    /// # Panics
-    ///
-    /// Panics if `at > len`.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// let mut vec = vec![1, 2, 3];
-    /// let vec2 = vec.split_off(1);
-    /// assert_eq!(vec, [1]);
-    /// assert_eq!(vec2, [2, 3]);
-    /// ```
-    #[inline]
-    #[must_use = "use `.truncate()` if you don't need the other half"]
-    #[stable(feature = "split_off", since = "1.4.0")]
-    pub fn split_off(&mut self, at: usize) -> Self
-    where
-        A: Clone,
-    {
-        #[cold]
-        #[inline(never)]
-        fn assert_failed(at: usize, len: usize) -> ! {
-            panic!("`at` split index (is {}) should be <= len (is {})", at, len);
-        }
-
-        if at > self.len() {
-            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_in(self.capacity(), self.allocator().clone()),
-            );
-        }
-
-        let other_len = self.len - at;
-        let mut other = Vec::with_capacity_in(other_len, self.allocator().clone());
-
-        // Unsafely `set_len` and copy items to `other`.
-        unsafe {
-            self.set_len(at);
-            other.set_len(other_len);
-
-            ptr::copy_nonoverlapping(self.as_ptr().add(at), other.as_mut_ptr(), other.len());
-        }
-        other
-    }
-
-    /// Resizes the `Vec` in-place so that `len` is equal to `new_len`.
-    ///
-    /// If `new_len` is greater than `len`, the `Vec` is extended by the
-    /// difference, with each additional slot filled with the result of
-    /// calling the closure `f`. The return values from `f` will end up
-    /// in the `Vec` in the order they have been generated.
-    ///
-    /// If `new_len` is less than `len`, the `Vec` is simply truncated.
-    ///
-    /// This method uses a closure to create new values on every push. If
-    /// you'd rather [`Clone`] a given value, use [`Vec::resize`]. If you
-    /// want to use the [`Default`] trait to generate values, you can
-    /// pass [`Default::default`] as the second argument.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// let mut vec = vec![1, 2, 3];
-    /// vec.resize_with(5, Default::default);
-    /// assert_eq!(vec, [1, 2, 3, 0, 0]);
-    ///
-    /// let mut vec = vec![];
-    /// let mut p = 1;
-    /// vec.resize_with(4, || { p *= 2; p });
-    /// assert_eq!(vec, [2, 4, 8, 16]);
-    /// ```
-    #[stable(feature = "vec_resize_with", since = "1.33.0")]
-    pub fn resize_with<F>(&mut self, new_len: usize, f: F)
-    where
-        F: FnMut() -> T,
-    {
-        let len = self.len();
-        if new_len > len {
-            self.extend_with(new_len - len, ExtendFunc(f));
-        } else {
-            self.truncate(new_len);
-        }
-    }
-
-    /// Consumes and leaks the `Vec`, returning a mutable reference to the contents,
-    /// `&'a mut [T]`. Note that the type `T` must outlive the chosen lifetime
-    /// `'a`. If the type has only static references, or none at all, then this
-    /// may be chosen to be `'static`.
-    ///
-    /// This function is similar to the [`leak`][Box::leak] function on [`Box`]
-    /// except that there is no way to recover the leaked memory.
-    ///
-    /// This function is mainly useful for data that lives for the remainder of
-    /// the program's life. Dropping the returned reference will cause a memory
-    /// leak.
-    ///
-    /// # Examples
-    ///
-    /// Simple usage:
-    ///
-    /// ```
-    /// let x = vec![1, 2, 3];
-    /// let static_ref: &'static mut [usize] = x.leak();
-    /// static_ref[0] += 1;
-    /// assert_eq!(static_ref, &[2, 2, 3]);
-    /// ```
-    #[stable(feature = "vec_leak", since = "1.47.0")]
-    #[inline]
-    pub fn leak<'a>(self) -> &'a mut [T]
-    where
-        A: 'a,
-    {
-        Box::leak(self.into_boxed_slice())
-    }
-
-    /// Returns the remaining spare capacity of the vector as a slice of
-    /// `MaybeUninit<T>`.
-    ///
-    /// The returned slice can be used to fill the vector with data (e.g. by
-    /// reading from a file) before marking the data as initialized using the
-    /// [`set_len`] method.
-    ///
-    /// [`set_len`]: Vec::set_len
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(vec_spare_capacity, maybe_uninit_extra)]
-    ///
-    /// // Allocate vector big enough for 10 elements.
-    /// let mut v = Vec::with_capacity(10);
-    ///
-    /// // Fill in the first 3 elements.
-    /// let uninit = v.spare_capacity_mut();
-    /// uninit[0].write(0);
-    /// uninit[1].write(1);
-    /// uninit[2].write(2);
-    ///
-    /// // Mark the first 3 elements of the vector as being initialized.
-    /// unsafe {
-    ///     v.set_len(3);
-    /// }
-    ///
-    /// assert_eq!(&v, &[0, 1, 2]);
-    /// ```
-    #[unstable(feature = "vec_spare_capacity", issue = "75017")]
-    #[inline]
-    pub fn spare_capacity_mut(&mut self) -> &mut [MaybeUninit<T>] {
-        unsafe {
-            slice::from_raw_parts_mut(
-                self.as_mut_ptr().add(self.len) as *mut MaybeUninit<T>,
-                self.buf.capacity() - self.len,
-            )
-        }
-    }
-}
-
-impl<T: Clone, A: Allocator> Vec<T, A> {
-    /// Resizes the `Vec` in-place so that `len` is equal to `new_len`.
-    ///
-    /// If `new_len` is greater than `len`, the `Vec` is extended by the
-    /// difference, with each additional slot filled with `value`.
-    /// If `new_len` is less than `len`, the `Vec` is simply truncated.
-    ///
-    /// This method requires `T` to implement [`Clone`],
-    /// in order to be able to clone the passed value.
-    /// If you need more flexibility (or want to rely on [`Default`] instead of
-    /// [`Clone`]), use [`Vec::resize_with`].
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// let mut vec = vec!["hello"];
-    /// vec.resize(3, "world");
-    /// assert_eq!(vec, ["hello", "world", "world"]);
-    ///
-    /// let mut vec = vec![1, 2, 3, 4];
-    /// vec.resize(2, 0);
-    /// assert_eq!(vec, [1, 2]);
-    /// ```
-    #[stable(feature = "vec_resize", since = "1.5.0")]
-    pub fn resize(&mut self, new_len: usize, value: T) {
-        let len = self.len();
-
-        if new_len > len {
-            self.extend_with(new_len - len, ExtendElement(value))
-        } else {
-            self.truncate(new_len);
-        }
-    }
-
-    /// Clones and appends all elements in a slice to the `Vec`.
-    ///
-    /// Iterates over the slice `other`, clones each element, and then appends
-    /// it to this `Vec`. The `other` vector is traversed in-order.
-    ///
-    /// Note that this function is same as [`extend`] except that it is
-    /// specialized to work with slices instead. If and when Rust gets
-    /// specialization this function will likely be deprecated (but still
-    /// available).
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// let mut vec = vec![1];
-    /// vec.extend_from_slice(&[2, 3, 4]);
-    /// assert_eq!(vec, [1, 2, 3, 4]);
-    /// ```
-    ///
-    /// [`extend`]: Vec::extend
-    #[stable(feature = "vec_extend_from_slice", since = "1.6.0")]
-    pub fn extend_from_slice(&mut self, other: &[T]) {
-        self.spec_extend(other.iter())
-    }
-}
-
-// This code generalizes `extend_with_{element,default}`.
-trait ExtendWith<T> {
-    fn next(&mut self) -> T;
-    fn last(self) -> T;
-}
-
-struct ExtendElement<T>(T);
-impl<T: Clone> ExtendWith<T> for ExtendElement<T> {
-    fn next(&mut self) -> T {
-        self.0.clone()
-    }
-    fn last(self) -> T {
-        self.0
-    }
-}
-
-struct ExtendDefault;
-impl<T: Default> ExtendWith<T> for ExtendDefault {
-    fn next(&mut self) -> T {
-        Default::default()
-    }
-    fn last(self) -> T {
-        Default::default()
-    }
-}
-
-struct ExtendFunc<F>(F);
-impl<T, F: FnMut() -> T> ExtendWith<T> for ExtendFunc<F> {
-    fn next(&mut self) -> T {
-        (self.0)()
-    }
-    fn last(mut self) -> T {
-        (self.0)()
-    }
-}
-
-impl<T, A: Allocator> Vec<T, A> {
-    /// Extend the vector by `n` values, using the given generator.
-    fn extend_with<E: ExtendWith<T>>(&mut self, n: usize, mut value: E) {
-        self.reserve(n);
-
-        unsafe {
-            let mut ptr = self.as_mut_ptr().add(self.len());
-            // Use SetLenOnDrop to work around bug where compiler
-            // may not realize the store through `ptr` through self.set_len()
-            // don't alias.
-            let mut local_len = SetLenOnDrop::new(&mut self.len);
-
-            // Write all elements except the last one
-            for _ in 1..n {
-                ptr::write(ptr, value.next());
-                ptr = ptr.offset(1);
-                // Increment the length in every step in case next() panics
-                local_len.increment_len(1);
-            }
-
-            if n > 0 {
-                // We can write the last element directly without cloning needlessly
-                ptr::write(ptr, value.last());
-                local_len.increment_len(1);
-            }
-
-            // len set by scope guard
-        }
-    }
-}
-
-// Set the length of the vec when the `SetLenOnDrop` value goes out of scope.
-//
-// The idea is: The length field in SetLenOnDrop is a local variable
-// that the optimizer will see does not alias with any stores through the Vec's data
-// pointer. This is a workaround for alias analysis issue #32155
-struct SetLenOnDrop<'a> {
-    len: &'a mut usize,
-    local_len: usize,
-}
-
-impl<'a> SetLenOnDrop<'a> {
-    #[inline]
-    fn new(len: &'a mut usize) -> Self {
-        SetLenOnDrop { local_len: *len, len }
-    }
-
-    #[inline]
-    fn increment_len(&mut self, increment: usize) {
-        self.local_len += increment;
-    }
-}
-
-impl Drop for SetLenOnDrop<'_> {
-    #[inline]
-    fn drop(&mut self) {
-        *self.len = self.local_len;
-    }
-}
-
-impl<T: PartialEq, A: Allocator> Vec<T, A> {
-    /// Removes consecutive repeated elements in the vector according to the
-    /// [`PartialEq`] trait implementation.
-    ///
-    /// If the vector is sorted, this removes all duplicates.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// let mut vec = vec![1, 2, 2, 3, 2];
-    ///
-    /// vec.dedup();
-    ///
-    /// assert_eq!(vec, [1, 2, 3, 2]);
-    /// ```
-    #[stable(feature = "rust1", since = "1.0.0")]
-    #[inline]
-    pub fn dedup(&mut self) {
-        self.dedup_by(|a, b| a == b)
-    }
-}
-
-impl<T, A: Allocator> Vec<T, A> {
-    /// Removes the first instance of `item` from the vector if the item exists.
-    ///
-    /// This method will be removed soon.
-    #[unstable(feature = "vec_remove_item", reason = "recently added", issue = "40062")]
-    #[rustc_deprecated(
-        reason = "Removing the first item equal to a needle is already easily possible \
-            with iterators and the current Vec methods. Furthermore, having a method for \
-            one particular case of removal (linear search, only the first item, no swap remove) \
-            but not for others is inconsistent. This method will be removed soon.",
-        since = "1.46.0"
-    )]
-    pub fn remove_item<V>(&mut self, item: &V) -> Option<T>
-    where
-        T: PartialEq<V>,
-    {
-        let pos = self.iter().position(|x| *x == *item)?;
-        Some(self.remove(pos))
-    }
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Internal methods and functions
-////////////////////////////////////////////////////////////////////////////////
-
-#[doc(hidden)]
-#[stable(feature = "rust1", since = "1.0.0")]
-pub fn from_elem<T: Clone>(elem: T, n: usize) -> Vec<T> {
-    <T as SpecFromElem>::from_elem(elem, n, Global)
-}
-
-#[doc(hidden)]
-#[unstable(feature = "allocator_api", issue = "32838")]
-pub fn from_elem_in<T: Clone, A: Allocator>(elem: T, n: usize, alloc: A) -> Vec<T, A> {
-    <T as SpecFromElem>::from_elem(elem, n, alloc)
-}
-
-// Specialization trait used for Vec::from_elem
-trait SpecFromElem: Sized {
-    fn from_elem<A: Allocator>(elem: Self, n: usize, alloc: A) -> Vec<Self, A>;
-}
-
-impl<T: Clone> SpecFromElem for T {
-    default fn from_elem<A: Allocator>(elem: Self, n: usize, alloc: A) -> Vec<Self, A> {
-        let mut v = Vec::with_capacity_in(n, alloc);
-        v.extend_with(n, ExtendElement(elem));
-        v
-    }
-}
-
-impl SpecFromElem for i8 {
-    #[inline]
-    fn from_elem<A: Allocator>(elem: i8, n: usize, alloc: A) -> Vec<i8, A> {
-        if elem == 0 {
-            return Vec { buf: RawVec::with_capacity_zeroed_in(n, alloc), len: n };
-        }
-        unsafe {
-            let mut v = Vec::with_capacity_in(n, alloc);
-            ptr::write_bytes(v.as_mut_ptr(), elem as u8, n);
-            v.set_len(n);
-            v
-        }
-    }
-}
-
-impl SpecFromElem for u8 {
-    #[inline]
-    fn from_elem<A: Allocator>(elem: u8, n: usize, alloc: A) -> Vec<u8, A> {
-        if elem == 0 {
-            return Vec { buf: RawVec::with_capacity_zeroed_in(n, alloc), len: n };
-        }
-        unsafe {
-            let mut v = Vec::with_capacity_in(n, alloc);
-            ptr::write_bytes(v.as_mut_ptr(), elem, n);
-            v.set_len(n);
-            v
-        }
-    }
-}
-
-impl<T: Clone + IsZero> SpecFromElem for T {
-    #[inline]
-    fn from_elem<A: Allocator>(elem: T, n: usize, alloc: A) -> Vec<T, A> {
-        if elem.is_zero() {
-            return Vec { buf: RawVec::with_capacity_zeroed_in(n, alloc), len: n };
-        }
-        let mut v = Vec::with_capacity_in(n, alloc);
-        v.extend_with(n, ExtendElement(elem));
-        v
-    }
-}
-
-#[rustc_specialization_trait]
-unsafe trait IsZero {
-    /// Whether this value is zero
-    fn is_zero(&self) -> bool;
-}
-
-macro_rules! impl_is_zero {
-    ($t:ty, $is_zero:expr) => {
-        unsafe impl IsZero for $t {
-            #[inline]
-            fn is_zero(&self) -> bool {
-                $is_zero(*self)
-            }
-        }
-    };
-}
-
-impl_is_zero!(i16, |x| x == 0);
-impl_is_zero!(i32, |x| x == 0);
-impl_is_zero!(i64, |x| x == 0);
-impl_is_zero!(i128, |x| x == 0);
-impl_is_zero!(isize, |x| x == 0);
-
-impl_is_zero!(u16, |x| x == 0);
-impl_is_zero!(u32, |x| x == 0);
-impl_is_zero!(u64, |x| x == 0);
-impl_is_zero!(u128, |x| x == 0);
-impl_is_zero!(usize, |x| x == 0);
-
-impl_is_zero!(bool, |x| x == false);
-impl_is_zero!(char, |x| x == '\0');
-
-impl_is_zero!(f32, |x: f32| x.to_bits() == 0);
-impl_is_zero!(f64, |x: f64| x.to_bits() == 0);
-
-unsafe impl<T> IsZero for *const T {
-    #[inline]
-    fn is_zero(&self) -> bool {
-        (*self).is_null()
-    }
-}
-
-unsafe impl<T> IsZero for *mut T {
-    #[inline]
-    fn is_zero(&self) -> bool {
-        (*self).is_null()
-    }
-}
-
-// `Option<&T>` and `Option<Box<T>>` are guaranteed to represent `None` as null.
-// For fat pointers, the bytes that would be the pointer metadata in the `Some`
-// variant are padding in the `None` variant, so ignoring them and
-// zero-initializing instead is ok.
-// `Option<&mut T>` never implements `Clone`, so there's no need for an impl of
-// `SpecFromElem`.
-
-unsafe impl<T: ?Sized> IsZero for Option<&T> {
-    #[inline]
-    fn is_zero(&self) -> bool {
-        self.is_none()
-    }
-}
-
-unsafe impl<T: ?Sized> IsZero for Option<Box<T>> {
-    #[inline]
-    fn is_zero(&self) -> bool {
-        self.is_none()
-    }
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Common trait implementations for Vec
-////////////////////////////////////////////////////////////////////////////////
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T, A: Allocator> ops::Deref for Vec<T, A> {
-    type Target = [T];
-
-    fn deref(&self) -> &[T] {
-        unsafe { slice::from_raw_parts(self.as_ptr(), self.len) }
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T, A: Allocator> ops::DerefMut for Vec<T, A> {
-    fn deref_mut(&mut self) -> &mut [T] {
-        unsafe { slice::from_raw_parts_mut(self.as_mut_ptr(), self.len) }
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: Clone, A: Allocator + Clone> Clone for Vec<T, A> {
-    #[cfg(not(test))]
-    fn clone(&self) -> Self {
-        let alloc = self.allocator().clone();
-        <[T]>::to_vec_in(&**self, alloc)
-    }
-
-    // HACK(japaric): with cfg(test) the inherent `[T]::to_vec` method, which is
-    // required for this method definition, is not available. Instead use the
-    // `slice::to_vec`  function which is only available with cfg(test)
-    // NB see the slice::hack module in slice.rs for more information
-    #[cfg(test)]
-    fn clone(&self) -> Self {
-        let alloc = self.allocator().clone();
-        crate::slice::to_vec(&**self, alloc)
-    }
-
-    fn clone_from(&mut self, other: &Self) {
-        // drop anything that will not be overwritten
-        self.truncate(other.len());
-
-        // self.len <= other.len due to the truncate above, so the
-        // slices here are always in-bounds.
-        let (init, tail) = other.split_at(self.len());
-
-        // reuse the contained values' allocations/resources.
-        self.clone_from_slice(init);
-        self.extend_from_slice(tail);
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: Hash, A: Allocator> Hash for Vec<T, A> {
-    #[inline]
-    fn hash<H: Hasher>(&self, state: &mut H) {
-        Hash::hash(&**self, state)
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_on_unimplemented(
-    message = "vector indices are of type `usize` or ranges of `usize`",
-    label = "vector indices are of type `usize` or ranges of `usize`"
-)]
-impl<T, I: SliceIndex<[T]>, A: Allocator> Index<I> for Vec<T, A> {
-    type Output = I::Output;
-
-    #[inline]
-    fn index(&self, index: I) -> &Self::Output {
-        Index::index(&**self, index)
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_on_unimplemented(
-    message = "vector indices are of type `usize` or ranges of `usize`",
-    label = "vector indices are of type `usize` or ranges of `usize`"
-)]
-impl<T, I: SliceIndex<[T]>, A: Allocator> IndexMut<I> for Vec<T, A> {
-    #[inline]
-    fn index_mut(&mut self, index: I) -> &mut Self::Output {
-        IndexMut::index_mut(&mut **self, index)
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T> FromIterator<T> for Vec<T> {
-    #[inline]
-    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Vec<T> {
-        <Self as SpecFromIter<T, I::IntoIter>>::from_iter(iter.into_iter())
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T, A: Allocator> IntoIterator for Vec<T, A> {
-    type Item = T;
-    type IntoIter = IntoIter<T, A>;
-
-    /// Creates a consuming iterator, that is, one that moves each value out of
-    /// the vector (from start to end). The vector cannot be used after calling
-    /// this.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// let v = vec!["a".to_string(), "b".to_string()];
-    /// for s in v.into_iter() {
-    ///     // s has type String, not &String
-    ///     println!("{}", s);
-    /// }
-    /// ```
-    #[inline]
-    fn into_iter(self) -> IntoIter<T, A> {
-        unsafe {
-            let mut me = ManuallyDrop::new(self);
-            let alloc = ptr::read(me.allocator());
-            let begin = me.as_mut_ptr();
-            let end = if mem::size_of::<T>() == 0 {
-                arith_offset(begin as *const i8, me.len() as isize) as *const T
-            } else {
-                begin.add(me.len()) as *const T
-            };
-            let cap = me.buf.capacity();
-            IntoIter {
-                buf: NonNull::new_unchecked(begin),
-                phantom: PhantomData,
-                cap,
-                alloc,
-                ptr: begin,
-                end,
-            }
-        }
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, T, A: Allocator> IntoIterator for &'a Vec<T, A> {
-    type Item = &'a T;
-    type IntoIter = slice::Iter<'a, T>;
-
-    fn into_iter(self) -> slice::Iter<'a, T> {
-        self.iter()
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, T, A: Allocator> IntoIterator for &'a mut Vec<T, A> {
-    type Item = &'a mut T;
-    type IntoIter = slice::IterMut<'a, T>;
-
-    fn into_iter(self) -> slice::IterMut<'a, T> {
-        self.iter_mut()
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T, A: Allocator> Extend<T> for Vec<T, A> {
-    #[inline]
-    fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
-        <Self as SpecExtend<T, I::IntoIter>>::spec_extend(self, iter.into_iter())
-    }
-
-    #[inline]
-    fn extend_one(&mut self, item: T) {
-        self.push(item);
-    }
-
-    #[inline]
-    fn extend_reserve(&mut self, additional: usize) {
-        self.reserve(additional);
-    }
-}
-
-/// Specialization trait used for Vec::from_iter
-///
-/// ## The delegation graph:
-///
-/// ```text
-/// +-------------+
-/// |FromIterator |
-/// +-+-----------+
-///   |
-///   v
-/// +-+-------------------------------+  +---------------------+
-/// |SpecFromIter                  +---->+SpecFromIterNested   |
-/// |where I:                      |  |  |where I:             |
-/// |  Iterator (default)----------+  |  |  Iterator (default) |
-/// |  vec::IntoIter               |  |  |  TrustedLen         |
-/// |  SourceIterMarker---fallback-+  |  |                     |
-/// |  slice::Iter                    |  |                     |
-/// |  Iterator<Item = &Clone>        |  +---------------------+
-/// +---------------------------------+
-/// ```
-trait SpecFromIter<T, I> {
-    fn from_iter(iter: I) -> Self;
-}
-
-/// Another specialization trait for Vec::from_iter
-/// necessary to manually prioritize overlapping specializations
-/// see [`SpecFromIter`] for details.
-trait SpecFromIterNested<T, I> {
-    fn from_iter(iter: I) -> Self;
-}
-
-impl<T, I> SpecFromIterNested<T, I> for Vec<T>
-where
-    I: Iterator<Item = T>,
-{
-    default fn from_iter(mut iterator: I) -> Self {
-        // Unroll the first iteration, as the vector is going to be
-        // expanded on this iteration in every case when the iterable is not
-        // empty, but the loop in extend_desugared() is not going to see the
-        // vector being full in the few subsequent loop iterations.
-        // So we get better branch prediction.
-        let mut vector = match iterator.next() {
-            None => return Vec::new(),
-            Some(element) => {
-                let (lower, _) = iterator.size_hint();
-                let mut vector = Vec::with_capacity(lower.saturating_add(1));
-                unsafe {
-                    ptr::write(vector.as_mut_ptr(), element);
-                    vector.set_len(1);
-                }
-                vector
-            }
-        };
-        // must delegate to spec_extend() since extend() itself delegates
-        // to spec_from for empty Vecs
-        <Vec<T> as SpecExtend<T, I>>::spec_extend(&mut vector, iterator);
-        vector
-    }
-}
-
-impl<T, I> SpecFromIterNested<T, I> for Vec<T>
-where
-    I: TrustedLen<Item = T>,
-{
-    fn from_iter(iterator: I) -> Self {
-        let mut vector = match iterator.size_hint() {
-            (_, Some(upper)) => Vec::with_capacity(upper),
-            _ => Vec::new(),
-        };
-        // must delegate to spec_extend() since extend() itself delegates
-        // to spec_from for empty Vecs
-        vector.spec_extend(iterator);
-        vector
-    }
-}
-
-impl<T, I> SpecFromIter<T, I> for Vec<T>
-where
-    I: Iterator<Item = T>,
-{
-    default fn from_iter(iterator: I) -> Self {
-        SpecFromIterNested::from_iter(iterator)
-    }
-}
-
-// A helper struct for in-place iteration that drops the destination slice of iteration,
-// i.e. the head. The source slice (the tail) is dropped by IntoIter.
-struct InPlaceDrop<T> {
-    inner: *mut T,
-    dst: *mut T,
-}
-
-impl<T> InPlaceDrop<T> {
-    fn len(&self) -> usize {
-        unsafe { self.dst.offset_from(self.inner) as usize }
-    }
-}
-
-impl<T> Drop for InPlaceDrop<T> {
-    #[inline]
-    fn drop(&mut self) {
-        unsafe {
-            ptr::drop_in_place(slice::from_raw_parts_mut(self.inner, self.len()));
-        }
-    }
-}
-
-impl<T> SpecFromIter<T, IntoIter<T>> for Vec<T> {
-    fn from_iter(iterator: IntoIter<T>) -> Self {
-        // A common case is passing a vector into a function which immediately
-        // re-collects into a vector. We can short circuit this if the IntoIter
-        // has not been advanced at all.
-        // When it has been advanced We can also reuse the memory and move the data to the front.
-        // But we only do so when the resulting Vec wouldn't have more unused capacity
-        // than creating it through the generic FromIterator implementation would. That limitation
-        // is not strictly necessary as Vec's allocation behavior is intentionally unspecified.
-        // But it is a conservative choice.
-        let has_advanced = iterator.buf.as_ptr() as *const _ != iterator.ptr;
-        if !has_advanced || iterator.len() >= iterator.cap / 2 {
-            unsafe {
-                let it = ManuallyDrop::new(iterator);
-                if has_advanced {
-                    ptr::copy(it.ptr, it.buf.as_ptr(), it.len());
-                }
-                return Vec::from_raw_parts(it.buf.as_ptr(), it.len(), it.cap);
-            }
-        }
-
-        let mut vec = Vec::new();
-        // must delegate to spec_extend() since extend() itself delegates
-        // to spec_from for empty Vecs
-        vec.spec_extend(iterator);
-        vec
-    }
-}
-
-fn write_in_place_with_drop<T>(
-    src_end: *const T,
-) -> impl FnMut(InPlaceDrop<T>, T) -> Result<InPlaceDrop<T>, !> {
-    move |mut sink, item| {
-        unsafe {
-            // the InPlaceIterable contract cannot be verified precisely here since
-            // try_fold has an exclusive reference to the source pointer
-            // all we can do is check if it's still in range
-            debug_assert!(sink.dst as *const _ <= src_end, "InPlaceIterable contract violation");
-            ptr::write(sink.dst, item);
-            sink.dst = sink.dst.add(1);
-        }
-        Ok(sink)
-    }
-}
-
-/// Specialization marker for collecting an iterator pipeline into a Vec while reusing the
-/// source allocation, i.e. executing the pipeline in place.
-///
-/// The SourceIter parent trait is necessary for the specializing function to access the allocation
-/// which is to be reused. But it is not sufficient for the specialization to be valid. See
-/// additional bounds on the impl.
-#[rustc_unsafe_specialization_marker]
-trait SourceIterMarker: SourceIter<Source: AsIntoIter> {}
-
-// The std-internal SourceIter/InPlaceIterable traits are only implemented by chains of
-// Adapter<Adapter<Adapter<IntoIter>>> (all owned by core/std). Additional bounds
-// on the adapter implementations (beyond `impl<I: Trait> Trait for Adapter<I>`) only depend on other
-// traits already marked as specialization traits (Copy, TrustedRandomAccess, FusedIterator).
-// I.e. the marker does not depend on lifetimes of user-supplied types. Modulo the Copy hole, which
-// several other specializations already depend on.
-impl<T> SourceIterMarker for T where T: SourceIter<Source: AsIntoIter> + InPlaceIterable {}
-
-impl<T, I> SpecFromIter<T, I> for Vec<T>
-where
-    I: Iterator<Item = T> + SourceIterMarker,
-{
-    default fn from_iter(mut iterator: I) -> Self {
-        // Additional requirements which cannot expressed via trait bounds. We rely on const eval
-        // instead:
-        // a) no ZSTs as there would be no allocation to reuse and pointer arithmetic would panic
-        // b) size match as required by Alloc contract
-        // c) alignments match as required by Alloc contract
-        if mem::size_of::<T>() == 0
-            || mem::size_of::<T>()
-                != mem::size_of::<<<I as SourceIter>::Source as AsIntoIter>::Item>()
-            || mem::align_of::<T>()
-                != mem::align_of::<<<I as SourceIter>::Source as AsIntoIter>::Item>()
-        {
-            // fallback to more generic implementations
-            return SpecFromIterNested::from_iter(iterator);
-        }
-
-        let (src_buf, src_ptr, dst_buf, dst_end, cap) = unsafe {
-            let inner = iterator.as_inner().as_into_iter();
-            (
-                inner.buf.as_ptr(),
-                inner.ptr,
-                inner.buf.as_ptr() as *mut T,
-                inner.end as *const T,
-                inner.cap,
-            )
-        };
-
-        // use try-fold since
-        // - it vectorizes better for some iterator adapters
-        // - unlike most internal iteration methods, it only takes a &mut self
-        // - it lets us thread the write pointer through its innards and get it back in the end
-        let sink = InPlaceDrop { inner: dst_buf, dst: dst_buf };
-        let sink = iterator
-            .try_fold::<_, _, Result<_, !>>(sink, write_in_place_with_drop(dst_end))
-            .unwrap();
-        // iteration succeeded, don't drop head
-        let dst = ManuallyDrop::new(sink).dst;
-
-        let src = unsafe { iterator.as_inner().as_into_iter() };
-        // check if SourceIter contract was upheld
-        // caveat: if they weren't we may not even make it to this point
-        debug_assert_eq!(src_buf, src.buf.as_ptr());
-        // check InPlaceIterable contract. This is only possible if the iterator advanced the
-        // source pointer at all. If it uses unchecked access via TrustedRandomAccess
-        // then the source pointer will stay in its initial position and we can't use it as reference
-        if src.ptr != src_ptr {
-            debug_assert!(
-                dst as *const _ <= src.ptr,
-                "InPlaceIterable contract violation, write pointer advanced beyond read pointer"
-            );
-        }
-
-        // drop any remaining values at the tail of the source
-        src.drop_remaining();
-        // but prevent drop of the allocation itself once IntoIter goes out of scope
-        src.forget_allocation();
-
-        let vec = unsafe {
-            let len = dst.offset_from(dst_buf) as usize;
-            Vec::from_raw_parts(dst_buf, len, cap)
-        };
-
-        vec
-    }
-}
-
-impl<'a, T: 'a, I> SpecFromIter<&'a T, I> for Vec<T>
-where
-    I: Iterator<Item = &'a T>,
-    T: Clone,
-{
-    default fn from_iter(iterator: I) -> Self {
-        SpecFromIter::from_iter(iterator.cloned())
-    }
-}
-
-// This utilizes `iterator.as_slice().to_vec()` since spec_extend
-// must take more steps to reason about the final capacity + length
-// and thus do more work. `to_vec()` directly allocates the correct amount
-// and fills it exactly.
-impl<'a, T: 'a + Clone> SpecFromIter<&'a T, slice::Iter<'a, T>> for Vec<T> {
-    #[cfg(not(test))]
-    fn from_iter(iterator: slice::Iter<'a, T>) -> Self {
-        iterator.as_slice().to_vec()
-    }
-
-    // HACK(japaric): with cfg(test) the inherent `[T]::to_vec` method, which is
-    // required for this method definition, is not available. Instead use the
-    // `slice::to_vec`  function which is only available with cfg(test)
-    // NB see the slice::hack module in slice.rs for more information
-    #[cfg(test)]
-    fn from_iter(iterator: slice::Iter<'a, T>) -> Self {
-        crate::slice::to_vec(iterator.as_slice(), Global)
-    }
-}
-
-// Specialization trait used for Vec::extend
-trait SpecExtend<T, I> {
-    fn spec_extend(&mut self, iter: I);
-}
-
-impl<T, I, A: Allocator> SpecExtend<T, I> for Vec<T, A>
-where
-    I: Iterator<Item = T>,
-{
-    default fn spec_extend(&mut self, iter: I) {
-        self.extend_desugared(iter)
-    }
-}
-
-impl<T, I, A: Allocator> SpecExtend<T, I> for Vec<T, A>
-where
-    I: TrustedLen<Item = T>,
-{
-    default fn spec_extend(&mut self, iterator: I) {
-        // This is the case for a TrustedLen iterator.
-        let (low, high) = iterator.size_hint();
-        if let Some(high_value) = high {
-            debug_assert_eq!(
-                low,
-                high_value,
-                "TrustedLen iterator's size hint is not exact: {:?}",
-                (low, high)
-            );
-        }
-        if let Some(additional) = high {
-            self.reserve(additional);
-            unsafe {
-                let mut ptr = self.as_mut_ptr().add(self.len());
-                let mut local_len = SetLenOnDrop::new(&mut self.len);
-                iterator.for_each(move |element| {
-                    ptr::write(ptr, element);
-                    ptr = ptr.offset(1);
-                    // NB can't overflow since we would have had to alloc the address space
-                    local_len.increment_len(1);
-                });
-            }
-        } else {
-            self.extend_desugared(iterator)
-        }
-    }
-}
-
-impl<T, A: Allocator> SpecExtend<T, IntoIter<T>> for Vec<T, A> {
-    fn spec_extend(&mut self, mut iterator: IntoIter<T>) {
-        unsafe {
-            self.append_elements(iterator.as_slice() as _);
-        }
-        iterator.ptr = iterator.end;
-    }
-}
-
-impl<'a, T: 'a, I, A: Allocator + 'a> SpecExtend<&'a T, I> for Vec<T, A>
-where
-    I: Iterator<Item = &'a T>,
-    T: Clone,
-{
-    default fn spec_extend(&mut self, iterator: I) {
-        self.spec_extend(iterator.cloned())
-    }
-}
-
-impl<'a, T: 'a, A: Allocator + 'a> SpecExtend<&'a T, slice::Iter<'a, T>> for Vec<T, A>
-where
-    T: Copy,
-{
-    fn spec_extend(&mut self, iterator: slice::Iter<'a, T>) {
-        let slice = iterator.as_slice();
-        unsafe { self.append_elements(slice) };
-    }
-}
-
-impl<T, A: Allocator> Vec<T, A> {
-    // leaf method to which various SpecFrom/SpecExtend implementations delegate when
-    // they have no further optimizations to apply
-    fn extend_desugared<I: Iterator<Item = T>>(&mut self, mut iterator: I) {
-        // This is the case for a general iterator.
-        //
-        // This function should be the moral equivalent of:
-        //
-        //      for item in iterator {
-        //          self.push(item);
-        //      }
-        while let Some(element) = iterator.next() {
-            let len = self.len();
-            if len == self.capacity() {
-                let (lower, _) = iterator.size_hint();
-                self.reserve(lower.saturating_add(1));
-            }
-            unsafe {
-                ptr::write(self.as_mut_ptr().add(len), element);
-                // NB can't overflow since we would have had to alloc the address space
-                self.set_len(len + 1);
-            }
-        }
-    }
-
-    /// Creates a splicing iterator that replaces the specified range in the vector
-    /// with the given `replace_with` iterator and yields the removed items.
-    /// `replace_with` does not need to be the same length as `range`.
-    ///
-    /// `range` is removed even if the iterator is not consumed until the end.
-    ///
-    /// It is unspecified how many elements are removed from the vector
-    /// if the `Splice` value is leaked.
-    ///
-    /// The input iterator `replace_with` is only consumed when the `Splice` value is dropped.
-    ///
-    /// This is optimal if:
-    ///
-    /// * The tail (elements in the vector after `range`) is empty,
-    /// * or `replace_with` yields fewer elements than `range`’s length
-    /// * or the lower bound of its `size_hint()` is exact.
-    ///
-    /// Otherwise, a temporary vector is allocated and the tail is moved twice.
-    ///
-    /// # Panics
-    ///
-    /// Panics if the starting point is greater than the end point or if
-    /// the end point is greater than the length of the vector.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// let mut v = vec![1, 2, 3];
-    /// let new = [7, 8];
-    /// let u: Vec<_> = v.splice(..2, new.iter().cloned()).collect();
-    /// assert_eq!(v, &[7, 8, 3]);
-    /// assert_eq!(u, &[1, 2]);
-    /// ```
-    #[inline]
-    #[stable(feature = "vec_splice", since = "1.21.0")]
-    pub fn splice<R, I>(&mut self, range: R, replace_with: I) -> Splice<'_, I::IntoIter, A>
-    where
-        R: RangeBounds<usize>,
-        I: IntoIterator<Item = T>,
-    {
-        Splice { drain: self.drain(range), replace_with: replace_with.into_iter() }
-    }
-
-    /// Creates an iterator which uses a closure to determine if an element should be removed.
-    ///
-    /// If the closure returns true, then the element is removed and yielded.
-    /// If the closure returns false, the element will remain in the vector and will not be yielded
-    /// by the iterator.
-    ///
-    /// Using this method is equivalent to the following code:
-    ///
-    /// ```
-    /// # let some_predicate = |x: &mut i32| { *x == 2 || *x == 3 || *x == 6 };
-    /// # let mut vec = vec![1, 2, 3, 4, 5, 6];
-    /// let mut i = 0;
-    /// while i != vec.len() {
-    ///     if some_predicate(&mut vec[i]) {
-    ///         let val = vec.remove(i);
-    ///         // your code here
-    ///     } else {
-    ///         i += 1;
-    ///     }
-    /// }
-    ///
-    /// # assert_eq!(vec, vec![1, 4, 5]);
-    /// ```
-    ///
-    /// But `drain_filter` is easier to use. `drain_filter` is also more efficient,
-    /// because it can backshift the elements of the array in bulk.
-    ///
-    /// Note that `drain_filter` also lets you mutate every element in the filter closure,
-    /// regardless of whether you choose to keep or remove it.
-    ///
-    /// # Examples
-    ///
-    /// Splitting an array into evens and odds, reusing the original allocation:
-    ///
-    /// ```
-    /// #![feature(drain_filter)]
-    /// let mut numbers = vec![1, 2, 3, 4, 5, 6, 8, 9, 11, 13, 14, 15];
-    ///
-    /// let evens = numbers.drain_filter(|x| *x % 2 == 0).collect::<Vec<_>>();
-    /// let odds = numbers;
-    ///
-    /// assert_eq!(evens, vec![2, 4, 6, 8, 14]);
-    /// assert_eq!(odds, vec![1, 3, 5, 9, 11, 13, 15]);
-    /// ```
-    #[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")]
-    pub fn drain_filter<F>(&mut self, filter: F) -> DrainFilter<'_, T, F, A>
-    where
-        F: FnMut(&mut T) -> bool,
-    {
-        let old_len = self.len();
-
-        // Guard against us getting leaked (leak amplification)
-        unsafe {
-            self.set_len(0);
-        }
-
-        DrainFilter { vec: self, idx: 0, del: 0, old_len, pred: filter, panic_flag: false }
-    }
-}
-
-/// Extend implementation that copies elements out of references before pushing them onto the Vec.
-///
-/// This implementation is specialized for slice iterators, where it uses [`copy_from_slice`] to
-/// append the entire slice at once.
-///
-/// [`copy_from_slice`]: ../../std/primitive.slice.html#method.copy_from_slice
-#[stable(feature = "extend_ref", since = "1.2.0")]
-impl<'a, T: Copy + 'a, A: Allocator + 'a> Extend<&'a T> for Vec<T, A> {
-    fn extend<I: IntoIterator<Item = &'a T>>(&mut self, iter: I) {
-        self.spec_extend(iter.into_iter())
-    }
-
-    #[inline]
-    fn extend_one(&mut self, &item: &'a T) {
-        self.push(item);
-    }
-
-    #[inline]
-    fn extend_reserve(&mut self, additional: usize) {
-        self.reserve(additional);
-    }
-}
-
-macro_rules! __impl_slice_eq1 {
-    ([$($vars:tt)*] $lhs:ty, $rhs:ty $(where $ty:ty: $bound:ident)?, #[$stability:meta]) => {
-        #[$stability]
-        impl<T, U, $($vars)*> PartialEq<$rhs> for $lhs
-        where
-            T: PartialEq<U>,
-            $($ty: $bound)?
-        {
-            #[inline]
-            fn eq(&self, other: &$rhs) -> bool { self[..] == other[..] }
-            #[inline]
-            fn ne(&self, other: &$rhs) -> bool { self[..] != other[..] }
-        }
-    }
-}
-
-__impl_slice_eq1! { [A: Allocator] Vec<T, A>, Vec<U, A>, #[stable(feature = "rust1", since = "1.0.0")] }
-__impl_slice_eq1! { [A: Allocator] Vec<T, A>, &[U], #[stable(feature = "rust1", since = "1.0.0")] }
-__impl_slice_eq1! { [A: Allocator] Vec<T, A>, &mut [U], #[stable(feature = "rust1", since = "1.0.0")] }
-__impl_slice_eq1! { [A: Allocator] &[T], Vec<U, A>, #[stable(feature = "partialeq_vec_for_ref_slice", since = "1.46.0")] }
-__impl_slice_eq1! { [A: Allocator] &mut [T], Vec<U, A>, #[stable(feature = "partialeq_vec_for_ref_slice", since = "1.46.0")] }
-__impl_slice_eq1! { [A: Allocator] Vec<T, A>, [U], #[stable(feature = "partialeq_vec_for_slice", since = "1.48.0")]  }
-__impl_slice_eq1! { [A: Allocator] [T], Vec<U, A>, #[stable(feature = "partialeq_vec_for_slice", since = "1.48.0")]  }
-__impl_slice_eq1! { [A: Allocator] Cow<'_, [T]>, Vec<U, A> where T: Clone, #[stable(feature = "rust1", since = "1.0.0")] }
-__impl_slice_eq1! { [] Cow<'_, [T]>, &[U] where T: Clone, #[stable(feature = "rust1", since = "1.0.0")] }
-__impl_slice_eq1! { [] Cow<'_, [T]>, &mut [U] where T: Clone, #[stable(feature = "rust1", since = "1.0.0")] }
-__impl_slice_eq1! { [A: Allocator, const N: usize] Vec<T, A>, [U; N], #[stable(feature = "rust1", since = "1.0.0")] }
-__impl_slice_eq1! { [A: Allocator, const N: usize] Vec<T, A>, &[U; N], #[stable(feature = "rust1", since = "1.0.0")] }
-
-// NOTE: some less important impls are omitted to reduce code bloat
-// FIXME(Centril): Reconsider this?
-//__impl_slice_eq1! { [const N: usize] Vec<A>, &mut [B; N], }
-//__impl_slice_eq1! { [const N: usize] [A; N], Vec<B>, }
-//__impl_slice_eq1! { [const N: usize] &[A; N], Vec<B>, }
-//__impl_slice_eq1! { [const N: usize] &mut [A; N], Vec<B>, }
-//__impl_slice_eq1! { [const N: usize] Cow<'a, [A]>, [B; N], }
-//__impl_slice_eq1! { [const N: usize] Cow<'a, [A]>, &[B; N], }
-//__impl_slice_eq1! { [const N: usize] Cow<'a, [A]>, &mut [B; N], }
-
-/// Implements comparison of vectors, [lexicographically](core::cmp::Ord#lexicographical-comparison).
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: PartialOrd, A: Allocator> PartialOrd for Vec<T, A> {
-    #[inline]
-    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
-        PartialOrd::partial_cmp(&**self, &**other)
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: Eq, A: Allocator> Eq for Vec<T, A> {}
-
-/// Implements ordering of vectors, [lexicographically](core::cmp::Ord#lexicographical-comparison).
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: Ord, A: Allocator> Ord for Vec<T, A> {
-    #[inline]
-    fn cmp(&self, other: &Self) -> Ordering {
-        Ord::cmp(&**self, &**other)
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-unsafe impl<#[may_dangle] T, A: Allocator> Drop for Vec<T, A> {
-    fn drop(&mut self) {
-        unsafe {
-            // use drop for [T]
-            // use a raw slice to refer to the elements of the vector as weakest necessary type;
-            // could avoid questions of validity in certain cases
-            ptr::drop_in_place(ptr::slice_from_raw_parts_mut(self.as_mut_ptr(), self.len))
-        }
-        // RawVec handles deallocation
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T> Default for Vec<T> {
-    /// Creates an empty `Vec<T>`.
-    fn default() -> Vec<T> {
-        Vec::new()
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: fmt::Debug, A: Allocator> fmt::Debug for Vec<T, A> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        fmt::Debug::fmt(&**self, f)
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T, A: Allocator> AsRef<Vec<T, A>> for Vec<T, A> {
-    fn as_ref(&self) -> &Vec<T, A> {
-        self
-    }
-}
-
-#[stable(feature = "vec_as_mut", since = "1.5.0")]
-impl<T, A: Allocator> AsMut<Vec<T, A>> for Vec<T, A> {
-    fn as_mut(&mut self) -> &mut Vec<T, A> {
-        self
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T, A: Allocator> AsRef<[T]> for Vec<T, A> {
-    fn as_ref(&self) -> &[T] {
-        self
-    }
-}
-
-#[stable(feature = "vec_as_mut", since = "1.5.0")]
-impl<T, A: Allocator> AsMut<[T]> for Vec<T, A> {
-    fn as_mut(&mut self) -> &mut [T] {
-        self
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: Clone> From<&[T]> for Vec<T> {
-    #[cfg(not(test))]
-    fn from(s: &[T]) -> Vec<T> {
-        s.to_vec()
-    }
-    #[cfg(test)]
-    fn from(s: &[T]) -> Vec<T> {
-        crate::slice::to_vec(s, Global)
-    }
-}
-
-#[stable(feature = "vec_from_mut", since = "1.19.0")]
-impl<T: Clone> From<&mut [T]> for Vec<T> {
-    #[cfg(not(test))]
-    fn from(s: &mut [T]) -> Vec<T> {
-        s.to_vec()
-    }
-    #[cfg(test)]
-    fn from(s: &mut [T]) -> Vec<T> {
-        crate::slice::to_vec(s, Global)
-    }
-}
-
-#[stable(feature = "vec_from_array", since = "1.44.0")]
-impl<T, const N: usize> From<[T; N]> for Vec<T> {
-    #[cfg(not(test))]
-    fn from(s: [T; N]) -> Vec<T> {
-        <[T]>::into_vec(box s)
-    }
-    #[cfg(test)]
-    fn from(s: [T; N]) -> Vec<T> {
-        crate::slice::into_vec(box s)
-    }
-}
-
-#[stable(feature = "vec_from_cow_slice", since = "1.14.0")]
-impl<'a, T> From<Cow<'a, [T]>> for Vec<T>
-where
-    [T]: ToOwned<Owned = Vec<T>>,
-{
-    fn from(s: Cow<'a, [T]>) -> Vec<T> {
-        s.into_owned()
-    }
-}
-
-// note: test pulls in libstd, which causes errors here
-#[cfg(not(test))]
-#[stable(feature = "vec_from_box", since = "1.18.0")]
-impl<T, A: Allocator> From<Box<[T], A>> for Vec<T, A> {
-    fn from(s: Box<[T], A>) -> Self {
-        let len = s.len();
-        Self { buf: RawVec::from_box(s), len }
-    }
-}
-
-// note: test pulls in libstd, which causes errors here
-#[cfg(not(test))]
-#[stable(feature = "box_from_vec", since = "1.20.0")]
-impl<T, A: Allocator> From<Vec<T, A>> for Box<[T], A> {
-    fn from(v: Vec<T, A>) -> Self {
-        v.into_boxed_slice()
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl From<&str> for Vec<u8> {
-    fn from(s: &str) -> Vec<u8> {
-        From::from(s.as_bytes())
-    }
-}
-
-#[stable(feature = "array_try_from_vec", since = "1.48.0")]
-impl<T, A: Allocator, const N: usize> TryFrom<Vec<T, A>> for [T; N] {
-    type Error = Vec<T, A>;
-
-    /// Gets the entire contents of the `Vec<T>` as an array,
-    /// if its size exactly matches that of the requested array.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::convert::TryInto;
-    /// assert_eq!(vec![1, 2, 3].try_into(), Ok([1, 2, 3]));
-    /// assert_eq!(<Vec<i32>>::new().try_into(), Ok([]));
-    /// ```
-    ///
-    /// If the length doesn't match, the input comes back in `Err`:
-    /// ```
-    /// use std::convert::TryInto;
-    /// let r: Result<[i32; 4], _> = (0..10).collect::<Vec<_>>().try_into();
-    /// assert_eq!(r, Err(vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9]));
-    /// ```
-    ///
-    /// If you're fine with just getting a prefix of the `Vec<T>`,
-    /// you can call [`.truncate(N)`](Vec::truncate) first.
-    /// ```
-    /// use std::convert::TryInto;
-    /// let mut v = String::from("hello world").into_bytes();
-    /// v.sort();
-    /// v.truncate(2);
-    /// let [a, b]: [_; 2] = v.try_into().unwrap();
-    /// assert_eq!(a, b' ');
-    /// assert_eq!(b, b'd');
-    /// ```
-    fn try_from(mut vec: Vec<T, A>) -> Result<[T; N], Vec<T, A>> {
-        if vec.len() != N {
-            return Err(vec);
-        }
-
-        // SAFETY: `.set_len(0)` is always sound.
-        unsafe { vec.set_len(0) };
-
-        // SAFETY: A `Vec`'s pointer is always aligned properly, and
-        // the alignment the array needs is the same as the items.
-        // We checked earlier that we have sufficient items.
-        // The items will not double-drop as the `set_len`
-        // tells the `Vec` not to also drop them.
-        let array = unsafe { ptr::read(vec.as_ptr() as *const [T; N]) };
-        Ok(array)
-    }
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Clone-on-write
-////////////////////////////////////////////////////////////////////////////////
-
-#[stable(feature = "cow_from_vec", since = "1.8.0")]
-impl<'a, T: Clone> From<&'a [T]> for Cow<'a, [T]> {
-    fn from(s: &'a [T]) -> Cow<'a, [T]> {
-        Cow::Borrowed(s)
-    }
-}
-
-#[stable(feature = "cow_from_vec", since = "1.8.0")]
-impl<'a, T: Clone> From<Vec<T>> for Cow<'a, [T]> {
-    fn from(v: Vec<T>) -> Cow<'a, [T]> {
-        Cow::Owned(v)
-    }
-}
-
-#[stable(feature = "cow_from_vec_ref", since = "1.28.0")]
-impl<'a, T: Clone> From<&'a Vec<T>> for Cow<'a, [T]> {
-    fn from(v: &'a Vec<T>) -> Cow<'a, [T]> {
-        Cow::Borrowed(v.as_slice())
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, T> FromIterator<T> for Cow<'a, [T]>
-where
-    T: Clone,
-{
-    fn from_iter<I: IntoIterator<Item = T>>(it: I) -> Cow<'a, [T]> {
-        Cow::Owned(FromIterator::from_iter(it))
-    }
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Iterators
-////////////////////////////////////////////////////////////////////////////////
-
-/// An iterator that moves out of a vector.
-///
-/// This `struct` is created by the `into_iter` method on [`Vec`] (provided
-/// by the [`IntoIterator`] trait).
-///
-/// # Example
-///
-/// ```
-/// let v = vec![0, 1, 2];
-/// let iter: std::vec::IntoIter<_> = v.into_iter();
-/// ```
-#[stable(feature = "rust1", since = "1.0.0")]
-pub struct IntoIter<
-    T,
-    #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global,
-> {
-    buf: NonNull<T>,
-    phantom: PhantomData<T>,
-    cap: usize,
-    alloc: A,
-    ptr: *const T,
-    end: *const T,
-}
-
-#[stable(feature = "vec_intoiter_debug", since = "1.13.0")]
-impl<T: fmt::Debug, A: Allocator> fmt::Debug for IntoIter<T, A> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.debug_tuple("IntoIter").field(&self.as_slice()).finish()
-    }
-}
-
-impl<T, A: Allocator> IntoIter<T, A> {
-    /// Returns the remaining items of this iterator as a slice.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// let vec = vec!['a', 'b', 'c'];
-    /// let mut into_iter = vec.into_iter();
-    /// assert_eq!(into_iter.as_slice(), &['a', 'b', 'c']);
-    /// let _ = into_iter.next().unwrap();
-    /// assert_eq!(into_iter.as_slice(), &['b', 'c']);
-    /// ```
-    #[stable(feature = "vec_into_iter_as_slice", since = "1.15.0")]
-    pub fn as_slice(&self) -> &[T] {
-        unsafe { slice::from_raw_parts(self.ptr, self.len()) }
-    }
-
-    /// Returns the remaining items of this iterator as a mutable slice.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// let vec = vec!['a', 'b', 'c'];
-    /// let mut into_iter = vec.into_iter();
-    /// assert_eq!(into_iter.as_slice(), &['a', 'b', 'c']);
-    /// into_iter.as_mut_slice()[2] = 'z';
-    /// assert_eq!(into_iter.next().unwrap(), 'a');
-    /// assert_eq!(into_iter.next().unwrap(), 'b');
-    /// assert_eq!(into_iter.next().unwrap(), 'z');
-    /// ```
-    #[stable(feature = "vec_into_iter_as_slice", since = "1.15.0")]
-    pub fn as_mut_slice(&mut self) -> &mut [T] {
-        unsafe { &mut *self.as_raw_mut_slice() }
-    }
-
-    /// Returns a reference to the underlying allocator.
-    #[unstable(feature = "allocator_api", issue = "32838")]
-    #[inline]
-    pub fn allocator(&self) -> &A {
-        &self.alloc
-    }
-
-    fn as_raw_mut_slice(&mut self) -> *mut [T] {
-        ptr::slice_from_raw_parts_mut(self.ptr as *mut T, self.len())
-    }
-
-    fn drop_remaining(&mut self) {
-        unsafe {
-            ptr::drop_in_place(self.as_mut_slice());
-        }
-        self.ptr = self.end;
-    }
-
-    /// Relinquishes the backing allocation, equivalent to
-    /// `ptr::write(&mut self, Vec::new().into_iter())`
-    fn forget_allocation(&mut self) {
-        self.cap = 0;
-        self.buf = unsafe { NonNull::new_unchecked(RawVec::NEW.ptr()) };
-        self.ptr = self.buf.as_ptr();
-        self.end = self.buf.as_ptr();
-    }
-}
-
-#[stable(feature = "vec_intoiter_as_ref", since = "1.46.0")]
-impl<T, A: Allocator> AsRef<[T]> for IntoIter<T, A> {
-    fn as_ref(&self) -> &[T] {
-        self.as_slice()
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-unsafe impl<T: Send, A: Allocator + Send> Send for IntoIter<T, A> {}
-#[stable(feature = "rust1", since = "1.0.0")]
-unsafe impl<T: Sync, A: Allocator> Sync for IntoIter<T, A> {}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T, A: Allocator> Iterator for IntoIter<T, A> {
-    type Item = T;
-
-    #[inline]
-    fn next(&mut self) -> Option<T> {
-        if self.ptr as *const _ == self.end {
-            None
-        } else if mem::size_of::<T>() == 0 {
-            // purposefully don't use 'ptr.offset' because for
-            // vectors with 0-size elements this would return the
-            // same pointer.
-            self.ptr = unsafe { arith_offset(self.ptr as *const i8, 1) as *mut T };
-
-            // Make up a value of this ZST.
-            Some(unsafe { mem::zeroed() })
-        } else {
-            let old = self.ptr;
-            self.ptr = unsafe { self.ptr.offset(1) };
-
-            Some(unsafe { ptr::read(old) })
-        }
-    }
-
-    #[inline]
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        let exact = if mem::size_of::<T>() == 0 {
-            (self.end as usize).wrapping_sub(self.ptr as usize)
-        } else {
-            unsafe { self.end.offset_from(self.ptr) as usize }
-        };
-        (exact, Some(exact))
-    }
-
-    #[inline]
-    fn count(self) -> usize {
-        self.len()
-    }
-
-    unsafe fn __iterator_get_unchecked(&mut self, i: usize) -> Self::Item
-    where
-        Self: TrustedRandomAccess,
-    {
-        // SAFETY: the caller must guarantee that `i` is in bounds of the
-        // `Vec<T>`, so `i` cannot overflow an `isize`, and the `self.ptr.add(i)`
-        // is guaranteed to pointer to an element of the `Vec<T>` and
-        // thus guaranteed to be valid to dereference.
-        //
-        // Also note the implementation of `Self: TrustedRandomAccess` requires
-        // that `T: Copy` so reading elements from the buffer doesn't invalidate
-        // them for `Drop`.
-        unsafe {
-            if mem::size_of::<T>() == 0 { mem::zeroed() } else { ptr::read(self.ptr.add(i)) }
-        }
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T, A: Allocator> DoubleEndedIterator for IntoIter<T, A> {
-    #[inline]
-    fn next_back(&mut self) -> Option<T> {
-        if self.end == self.ptr {
-            None
-        } else if mem::size_of::<T>() == 0 {
-            // See above for why 'ptr.offset' isn't used
-            self.end = unsafe { arith_offset(self.end as *const i8, -1) as *mut T };
-
-            // Make up a value of this ZST.
-            Some(unsafe { mem::zeroed() })
-        } else {
-            self.end = unsafe { self.end.offset(-1) };
-
-            Some(unsafe { ptr::read(self.end) })
-        }
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T, A: Allocator> ExactSizeIterator for IntoIter<T, A> {
-    fn is_empty(&self) -> bool {
-        self.ptr == self.end
-    }
-}
-
-#[stable(feature = "fused", since = "1.26.0")]
-impl<T, A: Allocator> FusedIterator for IntoIter<T, A> {}
-
-#[unstable(feature = "trusted_len", issue = "37572")]
-unsafe impl<T, A: Allocator> TrustedLen for IntoIter<T, A> {}
-
-#[doc(hidden)]
-#[unstable(issue = "none", feature = "std_internals")]
-// T: Copy as approximation for !Drop since get_unchecked does not advance self.ptr
-// and thus we can't implement drop-handling
-unsafe impl<T, A: Allocator> TrustedRandomAccess for IntoIter<T, A>
-where
-    T: Copy,
-{
-    fn may_have_side_effect() -> bool {
-        false
-    }
-}
-
-#[stable(feature = "vec_into_iter_clone", since = "1.8.0")]
-impl<T: Clone, A: Allocator + Clone> Clone for IntoIter<T, A> {
-    #[cfg(not(test))]
-    fn clone(&self) -> Self {
-        self.as_slice().to_vec_in(self.alloc.clone()).into_iter()
-    }
-    #[cfg(test)]
-    fn clone(&self) -> Self {
-        crate::slice::to_vec(self.as_slice(), self.alloc.clone()).into_iter()
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-unsafe impl<#[may_dangle] T, A: Allocator> Drop for IntoIter<T, A> {
-    fn drop(&mut self) {
-        struct DropGuard<'a, T, A: Allocator>(&'a mut IntoIter<T, A>);
-
-        impl<T, A: Allocator> Drop for DropGuard<'_, T, A> {
-            fn drop(&mut self) {
-                unsafe {
-                    // `IntoIter::alloc` is not used anymore after this
-                    let alloc = ptr::read(&self.0.alloc);
-                    // RawVec handles deallocation
-                    let _ = RawVec::from_raw_parts_in(self.0.buf.as_ptr(), self.0.cap, alloc);
-                }
-            }
-        }
-
-        let guard = DropGuard(self);
-        // destroy the remaining elements
-        unsafe {
-            ptr::drop_in_place(guard.0.as_raw_mut_slice());
-        }
-        // now `guard` will be dropped and do the rest
-    }
-}
-
-#[unstable(issue = "none", feature = "inplace_iteration")]
-unsafe impl<T, A: Allocator> InPlaceIterable for IntoIter<T, A> {}
-
-#[unstable(issue = "none", feature = "inplace_iteration")]
-unsafe impl<T, A: Allocator> SourceIter for IntoIter<T, A> {
-    type Source = Self;
-
-    #[inline]
-    unsafe fn as_inner(&mut self) -> &mut Self::Source {
-        self
-    }
-}
-
-// internal helper trait for in-place iteration specialization.
-#[rustc_specialization_trait]
-pub(crate) trait AsIntoIter {
-    type Item;
-    fn as_into_iter(&mut self) -> &mut IntoIter<Self::Item>;
-}
-
-impl<T> AsIntoIter for IntoIter<T> {
-    type Item = T;
-
-    fn as_into_iter(&mut self) -> &mut IntoIter<Self::Item> {
-        self
-    }
-}
-
-/// A draining iterator for `Vec<T>`.
-///
-/// This `struct` is created by [`Vec::drain`].
-/// See its documentation for more.
-///
-/// # Example
-///
-/// ```
-/// let mut v = vec![0, 1, 2];
-/// let iter: std::vec::Drain<_> = v.drain(..);
-/// ```
-#[stable(feature = "drain", since = "1.6.0")]
-pub struct Drain<
-    'a,
-    T: 'a,
-    #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator + 'a = Global,
-> {
-    /// Index of tail to preserve
-    tail_start: usize,
-    /// Length of tail
-    tail_len: usize,
-    /// Current remaining range to remove
-    iter: slice::Iter<'a, T>,
-    vec: NonNull<Vec<T, A>>,
-}
-
-#[stable(feature = "collection_debug", since = "1.17.0")]
-impl<T: fmt::Debug, A: Allocator> fmt::Debug for Drain<'_, T, A> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.debug_tuple("Drain").field(&self.iter.as_slice()).finish()
-    }
-}
-
-impl<'a, T, A: Allocator> Drain<'a, T, A> {
-    /// Returns the remaining items of this iterator as a slice.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// let mut vec = vec!['a', 'b', 'c'];
-    /// let mut drain = vec.drain(..);
-    /// assert_eq!(drain.as_slice(), &['a', 'b', 'c']);
-    /// let _ = drain.next().unwrap();
-    /// assert_eq!(drain.as_slice(), &['b', 'c']);
-    /// ```
-    #[stable(feature = "vec_drain_as_slice", since = "1.46.0")]
-    pub fn as_slice(&self) -> &[T] {
-        self.iter.as_slice()
-    }
-
-    /// Returns a reference to the underlying allocator.
-    #[unstable(feature = "allocator_api", issue = "32838")]
-    #[inline]
-    pub fn allocator(&self) -> &A {
-        unsafe { self.vec.as_ref().allocator() }
-    }
-}
-
-#[stable(feature = "vec_drain_as_slice", since = "1.46.0")]
-impl<'a, T, A: Allocator> AsRef<[T]> for Drain<'a, T, A> {
-    fn as_ref(&self) -> &[T] {
-        self.as_slice()
-    }
-}
-
-#[stable(feature = "drain", since = "1.6.0")]
-unsafe impl<T: Sync, A: Sync + Allocator> Sync for Drain<'_, T, A> {}
-#[stable(feature = "drain", since = "1.6.0")]
-unsafe impl<T: Send, A: Send + Allocator> Send for Drain<'_, T, A> {}
-
-#[stable(feature = "drain", since = "1.6.0")]
-impl<T, A: Allocator> Iterator for Drain<'_, T, A> {
-    type Item = T;
-
-    #[inline]
-    fn next(&mut self) -> Option<T> {
-        self.iter.next().map(|elt| unsafe { ptr::read(elt as *const _) })
-    }
-
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        self.iter.size_hint()
-    }
-}
-
-#[stable(feature = "drain", since = "1.6.0")]
-impl<T, A: Allocator> DoubleEndedIterator for Drain<'_, T, A> {
-    #[inline]
-    fn next_back(&mut self) -> Option<T> {
-        self.iter.next_back().map(|elt| unsafe { ptr::read(elt as *const _) })
-    }
-}
-
-#[stable(feature = "drain", since = "1.6.0")]
-impl<T, A: Allocator> Drop for Drain<'_, T, A> {
-    fn drop(&mut self) {
-        /// Continues dropping the remaining elements in the `Drain`, then moves back the
-        /// un-`Drain`ed elements to restore the original `Vec`.
-        struct DropGuard<'r, 'a, T, A: Allocator>(&'r mut Drain<'a, T, A>);
-
-        impl<'r, 'a, T, A: Allocator> Drop for DropGuard<'r, 'a, T, A> {
-            fn drop(&mut self) {
-                // Continue the same loop we have below. If the loop already finished, this does
-                // nothing.
-                self.0.for_each(drop);
-
-                if self.0.tail_len > 0 {
-                    unsafe {
-                        let source_vec = self.0.vec.as_mut();
-                        // memmove back untouched tail, update to new length
-                        let start = source_vec.len();
-                        let tail = self.0.tail_start;
-                        if tail != start {
-                            let src = source_vec.as_ptr().add(tail);
-                            let dst = source_vec.as_mut_ptr().add(start);
-                            ptr::copy(src, dst, self.0.tail_len);
-                        }
-                        source_vec.set_len(start + self.0.tail_len);
-                    }
-                }
-            }
-        }
-
-        // exhaust self first
-        while let Some(item) = self.next() {
-            let guard = DropGuard(self);
-            drop(item);
-            mem::forget(guard);
-        }
-
-        // Drop a `DropGuard` to move back the non-drained tail of `self`.
-        DropGuard(self);
-    }
-}
-
-#[stable(feature = "drain", since = "1.6.0")]
-impl<T, A: Allocator> ExactSizeIterator for Drain<'_, T, A> {
-    fn is_empty(&self) -> bool {
-        self.iter.is_empty()
-    }
-}
-
-#[unstable(feature = "trusted_len", issue = "37572")]
-unsafe impl<T, A: Allocator> TrustedLen for Drain<'_, T, A> {}
-
-#[stable(feature = "fused", since = "1.26.0")]
-impl<T, A: Allocator> FusedIterator for Drain<'_, T, A> {}
-
-/// A splicing iterator for `Vec`.
-///
-/// This struct is created by [`Vec::splice()`].
-/// See its documentation for more.
-///
-/// # Example
-///
-/// ```
-/// let mut v = vec![0, 1, 2];
-/// let new = [7, 8];
-/// let iter: std::vec::Splice<_> = v.splice(1.., new.iter().cloned());
-/// ```
-#[derive(Debug)]
-#[stable(feature = "vec_splice", since = "1.21.0")]
-pub struct Splice<
-    'a,
-    I: Iterator + 'a,
-    #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator + 'a = Global,
-> {
-    drain: Drain<'a, I::Item, A>,
-    replace_with: I,
-}
-
-#[stable(feature = "vec_splice", since = "1.21.0")]
-impl<I: Iterator, A: Allocator> Iterator for Splice<'_, I, A> {
-    type Item = I::Item;
-
-    fn next(&mut self) -> Option<Self::Item> {
-        self.drain.next()
-    }
-
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        self.drain.size_hint()
-    }
-}
-
-#[stable(feature = "vec_splice", since = "1.21.0")]
-impl<I: Iterator, A: Allocator> DoubleEndedIterator for Splice<'_, I, A> {
-    fn next_back(&mut self) -> Option<Self::Item> {
-        self.drain.next_back()
-    }
-}
-
-#[stable(feature = "vec_splice", since = "1.21.0")]
-impl<I: Iterator, A: Allocator> ExactSizeIterator for Splice<'_, I, A> {}
-
-#[stable(feature = "vec_splice", since = "1.21.0")]
-impl<I: Iterator, A: Allocator> Drop for Splice<'_, I, A> {
-    fn drop(&mut self) {
-        self.drain.by_ref().for_each(drop);
-
-        unsafe {
-            if self.drain.tail_len == 0 {
-                self.drain.vec.as_mut().extend(self.replace_with.by_ref());
-                return;
-            }
-
-            // First fill the range left by drain().
-            if !self.drain.fill(&mut self.replace_with) {
-                return;
-            }
-
-            // There may be more elements. Use the lower bound as an estimate.
-            // FIXME: Is the upper bound a better guess? Or something else?
-            let (lower_bound, _upper_bound) = self.replace_with.size_hint();
-            if lower_bound > 0 {
-                self.drain.move_tail(lower_bound);
-                if !self.drain.fill(&mut self.replace_with) {
-                    return;
-                }
-            }
-
-            // Collect any remaining elements.
-            // This is a zero-length vector which does not allocate if `lower_bound` was exact.
-            let mut collected = self.replace_with.by_ref().collect::<Vec<I::Item>>().into_iter();
-            // Now we have an exact count.
-            if collected.len() > 0 {
-                self.drain.move_tail(collected.len());
-                let filled = self.drain.fill(&mut collected);
-                debug_assert!(filled);
-                debug_assert_eq!(collected.len(), 0);
-            }
-        }
-        // Let `Drain::drop` move the tail back if necessary and restore `vec.len`.
-    }
-}
-
-/// Private helper methods for `Splice::drop`
-impl<T, A: Allocator> Drain<'_, T, A> {
-    /// The range from `self.vec.len` to `self.tail_start` contains elements
-    /// that have been moved out.
-    /// Fill that range as much as possible with new elements from the `replace_with` iterator.
-    /// Returns `true` if we filled the entire range. (`replace_with.next()` didn’t return `None`.)
-    unsafe fn fill<I: Iterator<Item = T>>(&mut self, replace_with: &mut I) -> bool {
-        let vec = unsafe { self.vec.as_mut() };
-        let range_start = vec.len;
-        let range_end = self.tail_start;
-        let range_slice = unsafe {
-            slice::from_raw_parts_mut(vec.as_mut_ptr().add(range_start), range_end - range_start)
-        };
-
-        for place in range_slice {
-            if let Some(new_item) = replace_with.next() {
-                unsafe { ptr::write(place, new_item) };
-                vec.len += 1;
-            } else {
-                return false;
-            }
-        }
-        true
-    }
-
-    /// Makes room for inserting more elements before the tail.
-    unsafe fn move_tail(&mut self, additional: usize) {
-        let vec = unsafe { self.vec.as_mut() };
-        let len = self.tail_start + self.tail_len;
-        vec.buf.reserve(len, additional);
-
-        let new_tail_start = self.tail_start + additional;
-        unsafe {
-            let src = vec.as_ptr().add(self.tail_start);
-            let dst = vec.as_mut_ptr().add(new_tail_start);
-            ptr::copy(src, dst, self.tail_len);
-        }
-        self.tail_start = new_tail_start;
-    }
-}
-
-/// An iterator which uses a closure to determine if an element should be removed.
-///
-/// This struct is created by [`Vec::drain_filter`].
-/// See its documentation for more.
-///
-/// # Example
-///
-/// ```
-/// #![feature(drain_filter)]
-///
-/// let mut v = vec![0, 1, 2];
-/// let iter: std::vec::DrainFilter<_, _> = v.drain_filter(|x| *x % 2 == 0);
-/// ```
-#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")]
-#[derive(Debug)]
-pub struct DrainFilter<
-    'a,
-    T,
-    F,
-    #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global,
-> where
-    F: FnMut(&mut T) -> bool,
-{
-    vec: &'a mut Vec<T, A>,
-    /// The index of the item that will be inspected by the next call to `next`.
-    idx: usize,
-    /// The number of items that have been drained (removed) thus far.
-    del: usize,
-    /// The original length of `vec` prior to draining.
-    old_len: usize,
-    /// The filter test predicate.
-    pred: F,
-    /// A flag that indicates a panic has occurred in the filter test predicate.
-    /// This is used as a hint in the drop implementation to prevent consumption
-    /// of the remainder of the `DrainFilter`. Any unprocessed items will be
-    /// backshifted in the `vec`, but no further items will be dropped or
-    /// tested by the filter predicate.
-    panic_flag: bool,
-}
-
-impl<T, F, A: Allocator> DrainFilter<'_, T, F, A>
-where
-    F: FnMut(&mut T) -> bool,
-{
-    /// Returns a reference to the underlying allocator.
-    #[unstable(feature = "allocator_api", issue = "32838")]
-    #[inline]
-    pub fn allocator(&self) -> &A {
-        self.vec.allocator()
-    }
-}
-
-#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")]
-impl<T, F, A: Allocator> Iterator for DrainFilter<'_, T, F, A>
-where
-    F: FnMut(&mut T) -> bool,
-{
-    type Item = T;
-
-    fn next(&mut self) -> Option<T> {
-        unsafe {
-            while self.idx < self.old_len {
-                let i = self.idx;
-                let v = slice::from_raw_parts_mut(self.vec.as_mut_ptr(), self.old_len);
-                self.panic_flag = true;
-                let drained = (self.pred)(&mut v[i]);
-                self.panic_flag = false;
-                // Update the index *after* the predicate is called. If the index
-                // is updated prior and the predicate panics, the element at this
-                // index would be leaked.
-                self.idx += 1;
-                if drained {
-                    self.del += 1;
-                    return Some(ptr::read(&v[i]));
-                } else if self.del > 0 {
-                    let del = self.del;
-                    let src: *const T = &v[i];
-                    let dst: *mut T = &mut v[i - del];
-                    ptr::copy_nonoverlapping(src, dst, 1);
-                }
-            }
-            None
-        }
-    }
-
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        (0, Some(self.old_len - self.idx))
-    }
-}
-
-#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")]
-impl<T, F, A: Allocator> Drop for DrainFilter<'_, T, F, A>
-where
-    F: FnMut(&mut T) -> bool,
-{
-    fn drop(&mut self) {
-        struct BackshiftOnDrop<'a, 'b, T, F, A: Allocator>
-        where
-            F: FnMut(&mut T) -> bool,
-        {
-            drain: &'b mut DrainFilter<'a, T, F, A>,
-        }
-
-        impl<'a, 'b, T, F, A: Allocator> Drop for BackshiftOnDrop<'a, 'b, T, F, A>
-        where
-            F: FnMut(&mut T) -> bool,
-        {
-            fn drop(&mut self) {
-                unsafe {
-                    if self.drain.idx < self.drain.old_len && self.drain.del > 0 {
-                        // This is a pretty messed up state, and there isn't really an
-                        // obviously right thing to do. We don't want to keep trying
-                        // to execute `pred`, so we just backshift all the unprocessed
-                        // elements and tell the vec that they still exist. The backshift
-                        // is required to prevent a double-drop of the last successfully
-                        // drained item prior to a panic in the predicate.
-                        let ptr = self.drain.vec.as_mut_ptr();
-                        let src = ptr.add(self.drain.idx);
-                        let dst = src.sub(self.drain.del);
-                        let tail_len = self.drain.old_len - self.drain.idx;
-                        src.copy_to(dst, tail_len);
-                    }
-                    self.drain.vec.set_len(self.drain.old_len - self.drain.del);
-                }
-            }
-        }
-
-        let backshift = BackshiftOnDrop { drain: self };
-
-        // Attempt to consume any remaining elements if the filter predicate
-        // has not yet panicked. We'll backshift any remaining elements
-        // whether we've already panicked or if the consumption here panics.
-        if !backshift.drain.panic_flag {
-            backshift.drain.for_each(drop);
-        }
-    }
-}
diff --git a/library/alloc/src/vec/cow.rs b/library/alloc/src/vec/cow.rs
new file mode 100644 (file)
index 0000000..73d15d3
--- /dev/null
@@ -0,0 +1,35 @@
+use crate::borrow::Cow;
+use core::iter::FromIterator;
+
+use super::Vec;
+
+#[stable(feature = "cow_from_vec", since = "1.8.0")]
+impl<'a, T: Clone> From<&'a [T]> for Cow<'a, [T]> {
+    fn from(s: &'a [T]) -> Cow<'a, [T]> {
+        Cow::Borrowed(s)
+    }
+}
+
+#[stable(feature = "cow_from_vec", since = "1.8.0")]
+impl<'a, T: Clone> From<Vec<T>> for Cow<'a, [T]> {
+    fn from(v: Vec<T>) -> Cow<'a, [T]> {
+        Cow::Owned(v)
+    }
+}
+
+#[stable(feature = "cow_from_vec_ref", since = "1.28.0")]
+impl<'a, T: Clone> From<&'a Vec<T>> for Cow<'a, [T]> {
+    fn from(v: &'a Vec<T>) -> Cow<'a, [T]> {
+        Cow::Borrowed(v.as_slice())
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a, T> FromIterator<T> for Cow<'a, [T]>
+where
+    T: Clone,
+{
+    fn from_iter<I: IntoIterator<Item = T>>(it: I) -> Cow<'a, [T]> {
+        Cow::Owned(FromIterator::from_iter(it))
+    }
+}
diff --git a/library/alloc/src/vec/drain.rs b/library/alloc/src/vec/drain.rs
new file mode 100644 (file)
index 0000000..fb32d14
--- /dev/null
@@ -0,0 +1,155 @@
+use crate::alloc::{Allocator, Global};
+use core::fmt;
+use core::iter::{FusedIterator, TrustedLen};
+use core::mem::{self};
+use core::ptr::{self, NonNull};
+use core::slice::{self};
+
+use super::Vec;
+
+/// A draining iterator for `Vec<T>`.
+///
+/// This `struct` is created by [`Vec::drain`].
+/// See its documentation for more.
+///
+/// # Example
+///
+/// ```
+/// let mut v = vec![0, 1, 2];
+/// let iter: std::vec::Drain<_> = v.drain(..);
+/// ```
+#[stable(feature = "drain", since = "1.6.0")]
+pub struct Drain<
+    'a,
+    T: 'a,
+    #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator + 'a = Global,
+> {
+    /// Index of tail to preserve
+    pub(super) tail_start: usize,
+    /// Length of tail
+    pub(super) tail_len: usize,
+    /// Current remaining range to remove
+    pub(super) iter: slice::Iter<'a, T>,
+    pub(super) vec: NonNull<Vec<T, A>>,
+}
+
+#[stable(feature = "collection_debug", since = "1.17.0")]
+impl<T: fmt::Debug, A: Allocator> fmt::Debug for Drain<'_, T, A> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_tuple("Drain").field(&self.iter.as_slice()).finish()
+    }
+}
+
+impl<'a, T, A: Allocator> Drain<'a, T, A> {
+    /// Returns the remaining items of this iterator as a slice.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// let mut vec = vec!['a', 'b', 'c'];
+    /// let mut drain = vec.drain(..);
+    /// assert_eq!(drain.as_slice(), &['a', 'b', 'c']);
+    /// let _ = drain.next().unwrap();
+    /// assert_eq!(drain.as_slice(), &['b', 'c']);
+    /// ```
+    #[stable(feature = "vec_drain_as_slice", since = "1.46.0")]
+    pub fn as_slice(&self) -> &[T] {
+        self.iter.as_slice()
+    }
+
+    /// Returns a reference to the underlying allocator.
+    #[unstable(feature = "allocator_api", issue = "32838")]
+    #[inline]
+    pub fn allocator(&self) -> &A {
+        unsafe { self.vec.as_ref().allocator() }
+    }
+}
+
+#[stable(feature = "vec_drain_as_slice", since = "1.46.0")]
+impl<'a, T, A: Allocator> AsRef<[T]> for Drain<'a, T, A> {
+    fn as_ref(&self) -> &[T] {
+        self.as_slice()
+    }
+}
+
+#[stable(feature = "drain", since = "1.6.0")]
+unsafe impl<T: Sync, A: Sync + Allocator> Sync for Drain<'_, T, A> {}
+#[stable(feature = "drain", since = "1.6.0")]
+unsafe impl<T: Send, A: Send + Allocator> Send for Drain<'_, T, A> {}
+
+#[stable(feature = "drain", since = "1.6.0")]
+impl<T, A: Allocator> Iterator for Drain<'_, T, A> {
+    type Item = T;
+
+    #[inline]
+    fn next(&mut self) -> Option<T> {
+        self.iter.next().map(|elt| unsafe { ptr::read(elt as *const _) })
+    }
+
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        self.iter.size_hint()
+    }
+}
+
+#[stable(feature = "drain", since = "1.6.0")]
+impl<T, A: Allocator> DoubleEndedIterator for Drain<'_, T, A> {
+    #[inline]
+    fn next_back(&mut self) -> Option<T> {
+        self.iter.next_back().map(|elt| unsafe { ptr::read(elt as *const _) })
+    }
+}
+
+#[stable(feature = "drain", since = "1.6.0")]
+impl<T, A: Allocator> Drop for Drain<'_, T, A> {
+    fn drop(&mut self) {
+        /// Continues dropping the remaining elements in the `Drain`, then moves back the
+        /// un-`Drain`ed elements to restore the original `Vec`.
+        struct DropGuard<'r, 'a, T, A: Allocator>(&'r mut Drain<'a, T, A>);
+
+        impl<'r, 'a, T, A: Allocator> Drop for DropGuard<'r, 'a, T, A> {
+            fn drop(&mut self) {
+                // Continue the same loop we have below. If the loop already finished, this does
+                // nothing.
+                self.0.for_each(drop);
+
+                if self.0.tail_len > 0 {
+                    unsafe {
+                        let source_vec = self.0.vec.as_mut();
+                        // memmove back untouched tail, update to new length
+                        let start = source_vec.len();
+                        let tail = self.0.tail_start;
+                        if tail != start {
+                            let src = source_vec.as_ptr().add(tail);
+                            let dst = source_vec.as_mut_ptr().add(start);
+                            ptr::copy(src, dst, self.0.tail_len);
+                        }
+                        source_vec.set_len(start + self.0.tail_len);
+                    }
+                }
+            }
+        }
+
+        // exhaust self first
+        while let Some(item) = self.next() {
+            let guard = DropGuard(self);
+            drop(item);
+            mem::forget(guard);
+        }
+
+        // Drop a `DropGuard` to move back the non-drained tail of `self`.
+        DropGuard(self);
+    }
+}
+
+#[stable(feature = "drain", since = "1.6.0")]
+impl<T, A: Allocator> ExactSizeIterator for Drain<'_, T, A> {
+    fn is_empty(&self) -> bool {
+        self.iter.is_empty()
+    }
+}
+
+#[unstable(feature = "trusted_len", issue = "37572")]
+unsafe impl<T, A: Allocator> TrustedLen for Drain<'_, T, A> {}
+
+#[stable(feature = "fused", since = "1.26.0")]
+impl<T, A: Allocator> FusedIterator for Drain<'_, T, A> {}
diff --git a/library/alloc/src/vec/drain_filter.rs b/library/alloc/src/vec/drain_filter.rs
new file mode 100644 (file)
index 0000000..3c37c92
--- /dev/null
@@ -0,0 +1,143 @@
+use crate::alloc::{Allocator, Global};
+use core::ptr::{self};
+use core::slice::{self};
+
+use super::Vec;
+
+/// An iterator which uses a closure to determine if an element should be removed.
+///
+/// This struct is created by [`Vec::drain_filter`].
+/// See its documentation for more.
+///
+/// # Example
+///
+/// ```
+/// #![feature(drain_filter)]
+///
+/// let mut v = vec![0, 1, 2];
+/// let iter: std::vec::DrainFilter<_, _> = v.drain_filter(|x| *x % 2 == 0);
+/// ```
+#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")]
+#[derive(Debug)]
+pub struct DrainFilter<
+    'a,
+    T,
+    F,
+    #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global,
+> where
+    F: FnMut(&mut T) -> bool,
+{
+    pub(super) vec: &'a mut Vec<T, A>,
+    /// The index of the item that will be inspected by the next call to `next`.
+    pub(super) idx: usize,
+    /// The number of items that have been drained (removed) thus far.
+    pub(super) del: usize,
+    /// The original length of `vec` prior to draining.
+    pub(super) old_len: usize,
+    /// The filter test predicate.
+    pub(super) pred: F,
+    /// A flag that indicates a panic has occurred in the filter test predicate.
+    /// This is used as a hint in the drop implementation to prevent consumption
+    /// of the remainder of the `DrainFilter`. Any unprocessed items will be
+    /// backshifted in the `vec`, but no further items will be dropped or
+    /// tested by the filter predicate.
+    pub(super) panic_flag: bool,
+}
+
+impl<T, F, A: Allocator> DrainFilter<'_, T, F, A>
+where
+    F: FnMut(&mut T) -> bool,
+{
+    /// Returns a reference to the underlying allocator.
+    #[unstable(feature = "allocator_api", issue = "32838")]
+    #[inline]
+    pub fn allocator(&self) -> &A {
+        self.vec.allocator()
+    }
+}
+
+#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")]
+impl<T, F, A: Allocator> Iterator for DrainFilter<'_, T, F, A>
+where
+    F: FnMut(&mut T) -> bool,
+{
+    type Item = T;
+
+    fn next(&mut self) -> Option<T> {
+        unsafe {
+            while self.idx < self.old_len {
+                let i = self.idx;
+                let v = slice::from_raw_parts_mut(self.vec.as_mut_ptr(), self.old_len);
+                self.panic_flag = true;
+                let drained = (self.pred)(&mut v[i]);
+                self.panic_flag = false;
+                // Update the index *after* the predicate is called. If the index
+                // is updated prior and the predicate panics, the element at this
+                // index would be leaked.
+                self.idx += 1;
+                if drained {
+                    self.del += 1;
+                    return Some(ptr::read(&v[i]));
+                } else if self.del > 0 {
+                    let del = self.del;
+                    let src: *const T = &v[i];
+                    let dst: *mut T = &mut v[i - del];
+                    ptr::copy_nonoverlapping(src, dst, 1);
+                }
+            }
+            None
+        }
+    }
+
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        (0, Some(self.old_len - self.idx))
+    }
+}
+
+#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")]
+impl<T, F, A: Allocator> Drop for DrainFilter<'_, T, F, A>
+where
+    F: FnMut(&mut T) -> bool,
+{
+    fn drop(&mut self) {
+        struct BackshiftOnDrop<'a, 'b, T, F, A: Allocator>
+        where
+            F: FnMut(&mut T) -> bool,
+        {
+            drain: &'b mut DrainFilter<'a, T, F, A>,
+        }
+
+        impl<'a, 'b, T, F, A: Allocator> Drop for BackshiftOnDrop<'a, 'b, T, F, A>
+        where
+            F: FnMut(&mut T) -> bool,
+        {
+            fn drop(&mut self) {
+                unsafe {
+                    if self.drain.idx < self.drain.old_len && self.drain.del > 0 {
+                        // This is a pretty messed up state, and there isn't really an
+                        // obviously right thing to do. We don't want to keep trying
+                        // to execute `pred`, so we just backshift all the unprocessed
+                        // elements and tell the vec that they still exist. The backshift
+                        // is required to prevent a double-drop of the last successfully
+                        // drained item prior to a panic in the predicate.
+                        let ptr = self.drain.vec.as_mut_ptr();
+                        let src = ptr.add(self.drain.idx);
+                        let dst = src.sub(self.drain.del);
+                        let tail_len = self.drain.old_len - self.drain.idx;
+                        src.copy_to(dst, tail_len);
+                    }
+                    self.drain.vec.set_len(self.drain.old_len - self.drain.del);
+                }
+            }
+        }
+
+        let backshift = BackshiftOnDrop { drain: self };
+
+        // Attempt to consume any remaining elements if the filter predicate
+        // has not yet panicked. We'll backshift any remaining elements
+        // whether we've already panicked or if the consumption here panics.
+        if !backshift.drain.panic_flag {
+            backshift.drain.for_each(drop);
+        }
+    }
+}
diff --git a/library/alloc/src/vec/in_place_drop.rs b/library/alloc/src/vec/in_place_drop.rs
new file mode 100644 (file)
index 0000000..354d25c
--- /dev/null
@@ -0,0 +1,24 @@
+use core::ptr::{self};
+use core::slice::{self};
+
+// A helper struct for in-place iteration that drops the destination slice of iteration,
+// i.e. the head. The source slice (the tail) is dropped by IntoIter.
+pub(super) struct InPlaceDrop<T> {
+    pub(super) inner: *mut T,
+    pub(super) dst: *mut T,
+}
+
+impl<T> InPlaceDrop<T> {
+    fn len(&self) -> usize {
+        unsafe { self.dst.offset_from(self.inner) as usize }
+    }
+}
+
+impl<T> Drop for InPlaceDrop<T> {
+    #[inline]
+    fn drop(&mut self) {
+        unsafe {
+            ptr::drop_in_place(slice::from_raw_parts_mut(self.inner, self.len()));
+        }
+    }
+}
diff --git a/library/alloc/src/vec/into_iter.rs b/library/alloc/src/vec/into_iter.rs
new file mode 100644 (file)
index 0000000..f131d06
--- /dev/null
@@ -0,0 +1,283 @@
+use crate::alloc::{Allocator, Global};
+use crate::raw_vec::RawVec;
+use core::fmt;
+use core::intrinsics::arith_offset;
+use core::iter::{FusedIterator, InPlaceIterable, SourceIter, TrustedLen, TrustedRandomAccess};
+use core::marker::PhantomData;
+use core::mem::{self};
+use core::ptr::{self, NonNull};
+use core::slice::{self};
+
+/// An iterator that moves out of a vector.
+///
+/// This `struct` is created by the `into_iter` method on [`Vec`](super::Vec)
+/// (provided by the [`IntoIterator`] trait).
+///
+/// # Example
+///
+/// ```
+/// let v = vec![0, 1, 2];
+/// let iter: std::vec::IntoIter<_> = v.into_iter();
+/// ```
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct IntoIter<
+    T,
+    #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global,
+> {
+    pub(super) buf: NonNull<T>,
+    pub(super) phantom: PhantomData<T>,
+    pub(super) cap: usize,
+    pub(super) alloc: A,
+    pub(super) ptr: *const T,
+    pub(super) end: *const T,
+}
+
+#[stable(feature = "vec_intoiter_debug", since = "1.13.0")]
+impl<T: fmt::Debug, A: Allocator> fmt::Debug for IntoIter<T, A> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_tuple("IntoIter").field(&self.as_slice()).finish()
+    }
+}
+
+impl<T, A: Allocator> IntoIter<T, A> {
+    /// Returns the remaining items of this iterator as a slice.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// let vec = vec!['a', 'b', 'c'];
+    /// let mut into_iter = vec.into_iter();
+    /// assert_eq!(into_iter.as_slice(), &['a', 'b', 'c']);
+    /// let _ = into_iter.next().unwrap();
+    /// assert_eq!(into_iter.as_slice(), &['b', 'c']);
+    /// ```
+    #[stable(feature = "vec_into_iter_as_slice", since = "1.15.0")]
+    pub fn as_slice(&self) -> &[T] {
+        unsafe { slice::from_raw_parts(self.ptr, self.len()) }
+    }
+
+    /// Returns the remaining items of this iterator as a mutable slice.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// let vec = vec!['a', 'b', 'c'];
+    /// let mut into_iter = vec.into_iter();
+    /// assert_eq!(into_iter.as_slice(), &['a', 'b', 'c']);
+    /// into_iter.as_mut_slice()[2] = 'z';
+    /// assert_eq!(into_iter.next().unwrap(), 'a');
+    /// assert_eq!(into_iter.next().unwrap(), 'b');
+    /// assert_eq!(into_iter.next().unwrap(), 'z');
+    /// ```
+    #[stable(feature = "vec_into_iter_as_slice", since = "1.15.0")]
+    pub fn as_mut_slice(&mut self) -> &mut [T] {
+        unsafe { &mut *self.as_raw_mut_slice() }
+    }
+
+    /// Returns a reference to the underlying allocator.
+    #[unstable(feature = "allocator_api", issue = "32838")]
+    #[inline]
+    pub fn allocator(&self) -> &A {
+        &self.alloc
+    }
+
+    fn as_raw_mut_slice(&mut self) -> *mut [T] {
+        ptr::slice_from_raw_parts_mut(self.ptr as *mut T, self.len())
+    }
+
+    pub(super) fn drop_remaining(&mut self) {
+        unsafe {
+            ptr::drop_in_place(self.as_mut_slice());
+        }
+        self.ptr = self.end;
+    }
+
+    /// Relinquishes the backing allocation, equivalent to
+    /// `ptr::write(&mut self, Vec::new().into_iter())`
+    pub(super) fn forget_allocation(&mut self) {
+        self.cap = 0;
+        self.buf = unsafe { NonNull::new_unchecked(RawVec::NEW.ptr()) };
+        self.ptr = self.buf.as_ptr();
+        self.end = self.buf.as_ptr();
+    }
+}
+
+#[stable(feature = "vec_intoiter_as_ref", since = "1.46.0")]
+impl<T, A: Allocator> AsRef<[T]> for IntoIter<T, A> {
+    fn as_ref(&self) -> &[T] {
+        self.as_slice()
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+unsafe impl<T: Send, A: Allocator + Send> Send for IntoIter<T, A> {}
+#[stable(feature = "rust1", since = "1.0.0")]
+unsafe impl<T: Sync, A: Allocator> Sync for IntoIter<T, A> {}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T, A: Allocator> Iterator for IntoIter<T, A> {
+    type Item = T;
+
+    #[inline]
+    fn next(&mut self) -> Option<T> {
+        if self.ptr as *const _ == self.end {
+            None
+        } else if mem::size_of::<T>() == 0 {
+            // purposefully don't use 'ptr.offset' because for
+            // vectors with 0-size elements this would return the
+            // same pointer.
+            self.ptr = unsafe { arith_offset(self.ptr as *const i8, 1) as *mut T };
+
+            // Make up a value of this ZST.
+            Some(unsafe { mem::zeroed() })
+        } else {
+            let old = self.ptr;
+            self.ptr = unsafe { self.ptr.offset(1) };
+
+            Some(unsafe { ptr::read(old) })
+        }
+    }
+
+    #[inline]
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        let exact = if mem::size_of::<T>() == 0 {
+            (self.end as usize).wrapping_sub(self.ptr as usize)
+        } else {
+            unsafe { self.end.offset_from(self.ptr) as usize }
+        };
+        (exact, Some(exact))
+    }
+
+    #[inline]
+    fn count(self) -> usize {
+        self.len()
+    }
+
+    unsafe fn __iterator_get_unchecked(&mut self, i: usize) -> Self::Item
+    where
+        Self: TrustedRandomAccess,
+    {
+        // SAFETY: the caller must guarantee that `i` is in bounds of the
+        // `Vec<T>`, so `i` cannot overflow an `isize`, and the `self.ptr.add(i)`
+        // is guaranteed to pointer to an element of the `Vec<T>` and
+        // thus guaranteed to be valid to dereference.
+        //
+        // Also note the implementation of `Self: TrustedRandomAccess` requires
+        // that `T: Copy` so reading elements from the buffer doesn't invalidate
+        // them for `Drop`.
+        unsafe {
+            if mem::size_of::<T>() == 0 { mem::zeroed() } else { ptr::read(self.ptr.add(i)) }
+        }
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T, A: Allocator> DoubleEndedIterator for IntoIter<T, A> {
+    #[inline]
+    fn next_back(&mut self) -> Option<T> {
+        if self.end == self.ptr {
+            None
+        } else if mem::size_of::<T>() == 0 {
+            // See above for why 'ptr.offset' isn't used
+            self.end = unsafe { arith_offset(self.end as *const i8, -1) as *mut T };
+
+            // Make up a value of this ZST.
+            Some(unsafe { mem::zeroed() })
+        } else {
+            self.end = unsafe { self.end.offset(-1) };
+
+            Some(unsafe { ptr::read(self.end) })
+        }
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T, A: Allocator> ExactSizeIterator for IntoIter<T, A> {
+    fn is_empty(&self) -> bool {
+        self.ptr == self.end
+    }
+}
+
+#[stable(feature = "fused", since = "1.26.0")]
+impl<T, A: Allocator> FusedIterator for IntoIter<T, A> {}
+
+#[unstable(feature = "trusted_len", issue = "37572")]
+unsafe impl<T, A: Allocator> TrustedLen for IntoIter<T, A> {}
+
+#[doc(hidden)]
+#[unstable(issue = "none", feature = "std_internals")]
+// T: Copy as approximation for !Drop since get_unchecked does not advance self.ptr
+// and thus we can't implement drop-handling
+unsafe impl<T, A: Allocator> TrustedRandomAccess for IntoIter<T, A>
+where
+    T: Copy,
+{
+    fn may_have_side_effect() -> bool {
+        false
+    }
+}
+
+#[stable(feature = "vec_into_iter_clone", since = "1.8.0")]
+impl<T: Clone, A: Allocator + Clone> Clone for IntoIter<T, A> {
+    #[cfg(not(test))]
+    fn clone(&self) -> Self {
+        self.as_slice().to_vec_in(self.alloc.clone()).into_iter()
+    }
+    #[cfg(test)]
+    fn clone(&self) -> Self {
+        crate::slice::to_vec(self.as_slice(), self.alloc.clone()).into_iter()
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+unsafe impl<#[may_dangle] T, A: Allocator> Drop for IntoIter<T, A> {
+    fn drop(&mut self) {
+        struct DropGuard<'a, T, A: Allocator>(&'a mut IntoIter<T, A>);
+
+        impl<T, A: Allocator> Drop for DropGuard<'_, T, A> {
+            fn drop(&mut self) {
+                unsafe {
+                    // `IntoIter::alloc` is not used anymore after this
+                    let alloc = ptr::read(&self.0.alloc);
+                    // RawVec handles deallocation
+                    let _ = RawVec::from_raw_parts_in(self.0.buf.as_ptr(), self.0.cap, alloc);
+                }
+            }
+        }
+
+        let guard = DropGuard(self);
+        // destroy the remaining elements
+        unsafe {
+            ptr::drop_in_place(guard.0.as_raw_mut_slice());
+        }
+        // now `guard` will be dropped and do the rest
+    }
+}
+
+#[unstable(issue = "none", feature = "inplace_iteration")]
+unsafe impl<T, A: Allocator> InPlaceIterable for IntoIter<T, A> {}
+
+#[unstable(issue = "none", feature = "inplace_iteration")]
+unsafe impl<T, A: Allocator> SourceIter for IntoIter<T, A> {
+    type Source = Self;
+
+    #[inline]
+    unsafe fn as_inner(&mut self) -> &mut Self::Source {
+        self
+    }
+}
+
+// internal helper trait for in-place iteration specialization.
+#[rustc_specialization_trait]
+pub(crate) trait AsIntoIter {
+    type Item;
+    fn as_into_iter(&mut self) -> &mut IntoIter<Self::Item>;
+}
+
+impl<T> AsIntoIter for IntoIter<T> {
+    type Item = T;
+
+    fn as_into_iter(&mut self) -> &mut IntoIter<Self::Item> {
+        self
+    }
+}
diff --git a/library/alloc/src/vec/is_zero.rs b/library/alloc/src/vec/is_zero.rs
new file mode 100644 (file)
index 0000000..b573997
--- /dev/null
@@ -0,0 +1,71 @@
+use crate::boxed::Box;
+
+#[rustc_specialization_trait]
+pub(super) unsafe trait IsZero {
+    /// Whether this value is zero
+    fn is_zero(&self) -> bool;
+}
+
+macro_rules! impl_is_zero {
+    ($t:ty, $is_zero:expr) => {
+        unsafe impl IsZero for $t {
+            #[inline]
+            fn is_zero(&self) -> bool {
+                $is_zero(*self)
+            }
+        }
+    };
+}
+
+impl_is_zero!(i16, |x| x == 0);
+impl_is_zero!(i32, |x| x == 0);
+impl_is_zero!(i64, |x| x == 0);
+impl_is_zero!(i128, |x| x == 0);
+impl_is_zero!(isize, |x| x == 0);
+
+impl_is_zero!(u16, |x| x == 0);
+impl_is_zero!(u32, |x| x == 0);
+impl_is_zero!(u64, |x| x == 0);
+impl_is_zero!(u128, |x| x == 0);
+impl_is_zero!(usize, |x| x == 0);
+
+impl_is_zero!(bool, |x| x == false);
+impl_is_zero!(char, |x| x == '\0');
+
+impl_is_zero!(f32, |x: f32| x.to_bits() == 0);
+impl_is_zero!(f64, |x: f64| x.to_bits() == 0);
+
+unsafe impl<T> IsZero for *const T {
+    #[inline]
+    fn is_zero(&self) -> bool {
+        (*self).is_null()
+    }
+}
+
+unsafe impl<T> IsZero for *mut T {
+    #[inline]
+    fn is_zero(&self) -> bool {
+        (*self).is_null()
+    }
+}
+
+// `Option<&T>` and `Option<Box<T>>` are guaranteed to represent `None` as null.
+// For fat pointers, the bytes that would be the pointer metadata in the `Some`
+// variant are padding in the `None` variant, so ignoring them and
+// zero-initializing instead is ok.
+// `Option<&mut T>` never implements `Clone`, so there's no need for an impl of
+// `SpecFromElem`.
+
+unsafe impl<T: ?Sized> IsZero for Option<&T> {
+    #[inline]
+    fn is_zero(&self) -> bool {
+        self.is_none()
+    }
+}
+
+unsafe impl<T: ?Sized> IsZero for Option<Box<T>> {
+    #[inline]
+    fn is_zero(&self) -> bool {
+        self.is_none()
+    }
+}
diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs
new file mode 100644 (file)
index 0000000..2a83eb3
--- /dev/null
@@ -0,0 +1,2513 @@
+//! A contiguous growable array type with heap-allocated contents, written
+//! `Vec<T>`.
+//!
+//! Vectors have `O(1)` indexing, amortized `O(1)` push (to the end) and
+//! `O(1)` pop (from the end).
+//!
+//! Vectors ensure they never allocate more than `isize::MAX` bytes.
+//!
+//! # Examples
+//!
+//! You can explicitly create a [`Vec`] with [`Vec::new`]:
+//!
+//! ```
+//! let v: Vec<i32> = Vec::new();
+//! ```
+//!
+//! ...or by using the [`vec!`] macro:
+//!
+//! ```
+//! let v: Vec<i32> = vec![];
+//!
+//! let v = vec![1, 2, 3, 4, 5];
+//!
+//! let v = vec![0; 10]; // ten zeroes
+//! ```
+//!
+//! You can [`push`] values onto the end of a vector (which will grow the vector
+//! as needed):
+//!
+//! ```
+//! let mut v = vec![1, 2];
+//!
+//! v.push(3);
+//! ```
+//!
+//! Popping values works in much the same way:
+//!
+//! ```
+//! let mut v = vec![1, 2];
+//!
+//! let two = v.pop();
+//! ```
+//!
+//! Vectors also support indexing (through the [`Index`] and [`IndexMut`] traits):
+//!
+//! ```
+//! let mut v = vec![1, 2, 3];
+//! let three = v[2];
+//! v[1] = v[1] + 5;
+//! ```
+//!
+//! [`push`]: Vec::push
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+use core::cmp::{self, Ordering};
+use core::convert::TryFrom;
+use core::fmt;
+use core::hash::{Hash, Hasher};
+use core::intrinsics::{arith_offset, assume};
+use core::iter::FromIterator;
+use core::marker::PhantomData;
+use core::mem::{self, ManuallyDrop, MaybeUninit};
+use core::ops::{self, Index, IndexMut, Range, RangeBounds};
+use core::ptr::{self, NonNull};
+use core::slice::{self, SliceIndex};
+
+use crate::alloc::{Allocator, Global};
+use crate::borrow::{Cow, ToOwned};
+use crate::boxed::Box;
+use crate::collections::TryReserveError;
+use crate::raw_vec::RawVec;
+
+#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")]
+pub use self::drain_filter::DrainFilter;
+
+mod drain_filter;
+
+#[stable(feature = "vec_splice", since = "1.21.0")]
+pub use self::splice::Splice;
+
+mod splice;
+
+#[stable(feature = "drain", since = "1.6.0")]
+pub use self::drain::Drain;
+
+mod drain;
+
+mod cow;
+
+pub(crate) use self::into_iter::AsIntoIter;
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use self::into_iter::IntoIter;
+
+mod into_iter;
+
+use self::is_zero::IsZero;
+
+mod is_zero;
+
+mod source_iter_marker;
+
+mod partial_eq;
+
+use self::spec_from_elem::SpecFromElem;
+
+mod spec_from_elem;
+
+use self::set_len_on_drop::SetLenOnDrop;
+
+mod set_len_on_drop;
+
+use self::in_place_drop::InPlaceDrop;
+
+mod in_place_drop;
+
+use self::spec_from_iter_nested::SpecFromIterNested;
+
+mod spec_from_iter_nested;
+
+use self::spec_from_iter::SpecFromIter;
+
+mod spec_from_iter;
+
+use self::spec_extend::SpecExtend;
+
+mod spec_extend;
+
+/// A contiguous growable array type, written `Vec<T>` but pronounced 'vector'.
+///
+/// # Examples
+///
+/// ```
+/// let mut vec = Vec::new();
+/// vec.push(1);
+/// vec.push(2);
+///
+/// assert_eq!(vec.len(), 2);
+/// assert_eq!(vec[0], 1);
+///
+/// assert_eq!(vec.pop(), Some(2));
+/// assert_eq!(vec.len(), 1);
+///
+/// vec[0] = 7;
+/// assert_eq!(vec[0], 7);
+///
+/// vec.extend([1, 2, 3].iter().copied());
+///
+/// for x in &vec {
+///     println!("{}", x);
+/// }
+/// assert_eq!(vec, [7, 1, 2, 3]);
+/// ```
+///
+/// The [`vec!`] macro is provided to make initialization more convenient:
+///
+/// ```
+/// let mut vec = vec![1, 2, 3];
+/// vec.push(4);
+/// assert_eq!(vec, [1, 2, 3, 4]);
+/// ```
+///
+/// It can also initialize each element of a `Vec<T>` with a given value.
+/// This may be more efficient than performing allocation and initialization
+/// in separate steps, especially when initializing a vector of zeros:
+///
+/// ```
+/// let vec = vec![0; 5];
+/// assert_eq!(vec, [0, 0, 0, 0, 0]);
+///
+/// // The following is equivalent, but potentially slower:
+/// let mut vec = Vec::with_capacity(5);
+/// vec.resize(5, 0);
+/// assert_eq!(vec, [0, 0, 0, 0, 0]);
+/// ```
+///
+/// For more information, see
+/// [Capacity and Reallocation](#capacity-and-reallocation).
+///
+/// Use a `Vec<T>` as an efficient stack:
+///
+/// ```
+/// let mut stack = Vec::new();
+///
+/// stack.push(1);
+/// stack.push(2);
+/// stack.push(3);
+///
+/// while let Some(top) = stack.pop() {
+///     // Prints 3, 2, 1
+///     println!("{}", top);
+/// }
+/// ```
+///
+/// # Indexing
+///
+/// The `Vec` type allows to access values by index, because it implements the
+/// [`Index`] trait. An example will be more explicit:
+///
+/// ```
+/// let v = vec![0, 2, 4, 6];
+/// println!("{}", v[1]); // it will display '2'
+/// ```
+///
+/// However be careful: if you try to access an index which isn't in the `Vec`,
+/// your software will panic! You cannot do this:
+///
+/// ```should_panic
+/// let v = vec![0, 2, 4, 6];
+/// println!("{}", v[6]); // it will panic!
+/// ```
+///
+/// Use [`get`] and [`get_mut`] if you want to check whether the index is in
+/// the `Vec`.
+///
+/// # Slicing
+///
+/// A `Vec` can be mutable. Slices, on the other hand, are read-only objects.
+/// To get a [slice], use [`&`]. Example:
+///
+/// ```
+/// fn read_slice(slice: &[usize]) {
+///     // ...
+/// }
+///
+/// let v = vec![0, 1];
+/// read_slice(&v);
+///
+/// // ... and that's all!
+/// // you can also do it like this:
+/// let u: &[usize] = &v;
+/// // or like this:
+/// let u: &[_] = &v;
+/// ```
+///
+/// In Rust, it's more common to pass slices as arguments rather than vectors
+/// when you just want to provide read access. The same goes for [`String`] and
+/// [`&str`].
+///
+/// # Capacity and reallocation
+///
+/// The capacity of a vector is the amount of space allocated for any future
+/// elements that will be added onto the vector. This is not to be confused with
+/// the *length* of a vector, which specifies the number of actual elements
+/// within the vector. If a vector's length exceeds its capacity, its capacity
+/// will automatically be increased, but its elements will have to be
+/// reallocated.
+///
+/// For example, a vector with capacity 10 and length 0 would be an empty vector
+/// with space for 10 more elements. Pushing 10 or fewer elements onto the
+/// vector will not change its capacity or cause reallocation to occur. However,
+/// if the vector's length is increased to 11, it will have to reallocate, which
+/// can be slow. For this reason, it is recommended to use [`Vec::with_capacity`]
+/// whenever possible to specify how big the vector is expected to get.
+///
+/// # Guarantees
+///
+/// Due to its incredibly fundamental nature, `Vec` makes a lot of guarantees
+/// about its design. This ensures that it's as low-overhead as possible in
+/// the general case, and can be correctly manipulated in primitive ways
+/// by unsafe code. Note that these guarantees refer to an unqualified `Vec<T>`.
+/// If additional type parameters are added (e.g., to support custom allocators),
+/// overriding their defaults may change the behavior.
+///
+/// Most fundamentally, `Vec` is and always will be a (pointer, capacity, length)
+/// triplet. No more, no less. The order of these fields is completely
+/// unspecified, and you should use the appropriate methods to modify these.
+/// The pointer will never be null, so this type is null-pointer-optimized.
+///
+/// However, the pointer may not actually point to allocated memory. In particular,
+/// if you construct a `Vec` with capacity 0 via [`Vec::new`], [`vec![]`][`vec!`],
+/// [`Vec::with_capacity(0)`][`Vec::with_capacity`], or by calling [`shrink_to_fit`]
+/// on an empty Vec, it will not allocate memory. Similarly, if you store zero-sized
+/// types inside a `Vec`, it will not allocate space for them. *Note that in this case
+/// the `Vec` may not report a [`capacity`] of 0*. `Vec` will allocate if and only
+/// if [`mem::size_of::<T>`]`() * capacity() > 0`. In general, `Vec`'s allocation
+/// details are very subtle &mdash; if you intend to allocate memory using a `Vec`
+/// and use it for something else (either to pass to unsafe code, or to build your
+/// own memory-backed collection), be sure to deallocate this memory by using
+/// `from_raw_parts` to recover the `Vec` and then dropping it.
+///
+/// If a `Vec` *has* allocated memory, then the memory it points to is on the heap
+/// (as defined by the allocator Rust is configured to use by default), and its
+/// pointer points to [`len`] initialized, contiguous elements in order (what
+/// you would see if you coerced it to a slice), followed by [`capacity`]` -
+/// `[`len`] logically uninitialized, contiguous elements.
+///
+/// `Vec` will never perform a "small optimization" where elements are actually
+/// stored on the stack for two reasons:
+///
+/// * It would make it more difficult for unsafe code to correctly manipulate
+///   a `Vec`. The contents of a `Vec` wouldn't have a stable address if it were
+///   only moved, and it would be more difficult to determine if a `Vec` had
+///   actually allocated memory.
+///
+/// * It would penalize the general case, incurring an additional branch
+///   on every access.
+///
+/// `Vec` will never automatically shrink itself, even if completely empty. This
+/// ensures no unnecessary allocations or deallocations occur. Emptying a `Vec`
+/// and then filling it back up to the same [`len`] should incur no calls to
+/// the allocator. If you wish to free up unused memory, use
+/// [`shrink_to_fit`].
+///
+/// [`push`] and [`insert`] will never (re)allocate if the reported capacity is
+/// sufficient. [`push`] and [`insert`] *will* (re)allocate if
+/// [`len`]` == `[`capacity`]. That is, the reported capacity is completely
+/// accurate, and can be relied on. It can even be used to manually free the memory
+/// allocated by a `Vec` if desired. Bulk insertion methods *may* reallocate, even
+/// when not necessary.
+///
+/// `Vec` does not guarantee any particular growth strategy when reallocating
+/// when full, nor when [`reserve`] is called. The current strategy is basic
+/// and it may prove desirable to use a non-constant growth factor. Whatever
+/// strategy is used will of course guarantee *O*(1) amortized [`push`].
+///
+/// `vec![x; n]`, `vec![a, b, c, d]`, and
+/// [`Vec::with_capacity(n)`][`Vec::with_capacity`], will all produce a `Vec`
+/// with exactly the requested capacity. If [`len`]` == `[`capacity`],
+/// (as is the case for the [`vec!`] macro), then a `Vec<T>` can be converted to
+/// and from a [`Box<[T]>`][owned slice] without reallocating or moving the elements.
+///
+/// `Vec` will not specifically overwrite any data that is removed from it,
+/// but also won't specifically preserve it. Its uninitialized memory is
+/// scratch space that it may use however it wants. It will generally just do
+/// whatever is most efficient or otherwise easy to implement. Do not rely on
+/// removed data to be erased for security purposes. Even if you drop a `Vec`, its
+/// buffer may simply be reused by another `Vec`. Even if you zero a `Vec`'s memory
+/// first, that may not actually happen because the optimizer does not consider
+/// this a side-effect that must be preserved. There is one case which we will
+/// not break, however: using `unsafe` code to write to the excess capacity,
+/// and then increasing the length to match, is always valid.
+///
+/// `Vec` does not currently guarantee the order in which elements are dropped.
+/// The order has changed in the past and may change again.
+///
+/// [`get`]: ../../std/vec/struct.Vec.html#method.get
+/// [`get_mut`]: ../../std/vec/struct.Vec.html#method.get_mut
+/// [`String`]: crate::string::String
+/// [`&str`]: type@str
+/// [`shrink_to_fit`]: Vec::shrink_to_fit
+/// [`capacity`]: Vec::capacity
+/// [`mem::size_of::<T>`]: core::mem::size_of
+/// [`len`]: Vec::len
+/// [`push`]: Vec::push
+/// [`insert`]: Vec::insert
+/// [`reserve`]: Vec::reserve
+/// [owned slice]: Box
+/// [slice]: ../../std/primitive.slice.html
+/// [`&`]: ../../std/primitive.reference.html
+#[stable(feature = "rust1", since = "1.0.0")]
+#[cfg_attr(not(test), rustc_diagnostic_item = "vec_type")]
+pub struct Vec<T, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global> {
+    buf: RawVec<T, A>,
+    len: usize,
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Inherent methods
+////////////////////////////////////////////////////////////////////////////////
+
+impl<T> Vec<T> {
+    /// Constructs a new, empty `Vec<T>`.
+    ///
+    /// The vector will not allocate until elements are pushed onto it.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # #![allow(unused_mut)]
+    /// let mut vec: Vec<i32> = Vec::new();
+    /// ```
+    #[inline]
+    #[rustc_const_stable(feature = "const_vec_new", since = "1.39.0")]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub const fn new() -> Self {
+        Vec { buf: RawVec::NEW, len: 0 }
+    }
+
+    /// Constructs a new, empty `Vec<T>` with the specified capacity.
+    ///
+    /// The vector will be able to hold exactly `capacity` elements without
+    /// reallocating. If `capacity` is 0, the vector will not allocate.
+    ///
+    /// It is important to note that although the returned vector has the
+    /// *capacity* specified, the vector will have a zero *length*. For an
+    /// explanation of the difference between length and capacity, see
+    /// *[Capacity and reallocation]*.
+    ///
+    /// [Capacity and reallocation]: #capacity-and-reallocation
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// let mut vec = Vec::with_capacity(10);
+    ///
+    /// // The vector contains no items, even though it has capacity for more
+    /// assert_eq!(vec.len(), 0);
+    /// assert_eq!(vec.capacity(), 10);
+    ///
+    /// // These are all done without reallocating...
+    /// for i in 0..10 {
+    ///     vec.push(i);
+    /// }
+    /// assert_eq!(vec.len(), 10);
+    /// assert_eq!(vec.capacity(), 10);
+    ///
+    /// // ...but this may make the vector reallocate
+    /// vec.push(11);
+    /// assert_eq!(vec.len(), 11);
+    /// assert!(vec.capacity() >= 11);
+    /// ```
+    #[inline]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn with_capacity(capacity: usize) -> Self {
+        Self::with_capacity_in(capacity, Global)
+    }
+
+    /// Creates a `Vec<T>` directly from the raw components of another vector.
+    ///
+    /// # Safety
+    ///
+    /// This is highly unsafe, due to the number of invariants that aren't
+    /// checked:
+    ///
+    /// * `ptr` needs to have been previously allocated via [`String`]/`Vec<T>`
+    ///   (at least, it's highly likely to be incorrect if it wasn't).
+    /// * `T` needs to have the same size and alignment as what `ptr` was allocated with.
+    ///   (`T` having a less strict alignment is not sufficient, the alignment really
+    ///   needs to be equal to satisfy the [`dealloc`] requirement that memory must be
+    ///   allocated and deallocated with the same layout.)
+    /// * `length` needs to be less than or equal to `capacity`.
+    /// * `capacity` needs to be the capacity that the pointer was allocated with.
+    ///
+    /// Violating these may cause problems like corrupting the allocator's
+    /// internal data structures. For example it is **not** safe
+    /// to build a `Vec<u8>` from a pointer to a C `char` array with length `size_t`.
+    /// It's also not safe to build one from a `Vec<u16>` and its length, because
+    /// the allocator cares about the alignment, and these two types have different
+    /// alignments. The buffer was allocated with alignment 2 (for `u16`), but after
+    /// turning it into a `Vec<u8>` it'll be deallocated with alignment 1.
+    ///
+    /// The ownership of `ptr` is effectively transferred to the
+    /// `Vec<T>` which may then deallocate, reallocate or change the
+    /// contents of memory pointed to by the pointer at will. Ensure
+    /// that nothing else uses the pointer after calling this
+    /// function.
+    ///
+    /// [`String`]: crate::string::String
+    /// [`dealloc`]: crate::alloc::GlobalAlloc::dealloc
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::ptr;
+    /// use std::mem;
+    ///
+    /// let v = vec![1, 2, 3];
+    ///
+    // FIXME Update this when vec_into_raw_parts is stabilized
+    /// // Prevent running `v`'s destructor so we are in complete control
+    /// // of the allocation.
+    /// let mut v = mem::ManuallyDrop::new(v);
+    ///
+    /// // Pull out the various important pieces of information about `v`
+    /// let p = v.as_mut_ptr();
+    /// let len = v.len();
+    /// let cap = v.capacity();
+    ///
+    /// unsafe {
+    ///     // Overwrite memory with 4, 5, 6
+    ///     for i in 0..len as isize {
+    ///         ptr::write(p.offset(i), 4 + i);
+    ///     }
+    ///
+    ///     // Put everything back together into a Vec
+    ///     let rebuilt = Vec::from_raw_parts(p, len, cap);
+    ///     assert_eq!(rebuilt, [4, 5, 6]);
+    /// }
+    /// ```
+    #[inline]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub unsafe fn from_raw_parts(ptr: *mut T, length: usize, capacity: usize) -> Self {
+        unsafe { Self::from_raw_parts_in(ptr, length, capacity, Global) }
+    }
+}
+
+impl<T, A: Allocator> Vec<T, A> {
+    /// Constructs a new, empty `Vec<T, A>`.
+    ///
+    /// The vector will not allocate until elements are pushed onto it.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(allocator_api)]
+    ///
+    /// use std::alloc::System;
+    ///
+    /// # #[allow(unused_mut)]
+    /// let mut vec: Vec<i32, _> = Vec::new_in(System);
+    /// ```
+    #[inline]
+    #[unstable(feature = "allocator_api", issue = "32838")]
+    pub const fn new_in(alloc: A) -> Self {
+        Vec { buf: RawVec::new_in(alloc), len: 0 }
+    }
+
+    /// Constructs a new, empty `Vec<T, A>` with the specified capacity with the provided
+    /// allocator.
+    ///
+    /// The vector will be able to hold exactly `capacity` elements without
+    /// reallocating. If `capacity` is 0, the vector will not allocate.
+    ///
+    /// It is important to note that although the returned vector has the
+    /// *capacity* specified, the vector will have a zero *length*. For an
+    /// explanation of the difference between length and capacity, see
+    /// *[Capacity and reallocation]*.
+    ///
+    /// [Capacity and reallocation]: #capacity-and-reallocation
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(allocator_api)]
+    ///
+    /// use std::alloc::System;
+    ///
+    /// let mut vec = Vec::with_capacity_in(10, System);
+    ///
+    /// // The vector contains no items, even though it has capacity for more
+    /// assert_eq!(vec.len(), 0);
+    /// assert_eq!(vec.capacity(), 10);
+    ///
+    /// // These are all done without reallocating...
+    /// for i in 0..10 {
+    ///     vec.push(i);
+    /// }
+    /// assert_eq!(vec.len(), 10);
+    /// assert_eq!(vec.capacity(), 10);
+    ///
+    /// // ...but this may make the vector reallocate
+    /// vec.push(11);
+    /// assert_eq!(vec.len(), 11);
+    /// assert!(vec.capacity() >= 11);
+    /// ```
+    #[inline]
+    #[unstable(feature = "allocator_api", issue = "32838")]
+    pub fn with_capacity_in(capacity: usize, alloc: A) -> Self {
+        Vec { buf: RawVec::with_capacity_in(capacity, alloc), len: 0 }
+    }
+
+    /// Creates a `Vec<T, A>` directly from the raw components of another vector.
+    ///
+    /// # Safety
+    ///
+    /// This is highly unsafe, due to the number of invariants that aren't
+    /// checked:
+    ///
+    /// * `ptr` needs to have been previously allocated via [`String`]/`Vec<T>`
+    ///   (at least, it's highly likely to be incorrect if it wasn't).
+    /// * `T` needs to have the same size and alignment as what `ptr` was allocated with.
+    ///   (`T` having a less strict alignment is not sufficient, the alignment really
+    ///   needs to be equal to satisfy the [`dealloc`] requirement that memory must be
+    ///   allocated and deallocated with the same layout.)
+    /// * `length` needs to be less than or equal to `capacity`.
+    /// * `capacity` needs to be the capacity that the pointer was allocated with.
+    ///
+    /// Violating these may cause problems like corrupting the allocator's
+    /// internal data structures. For example it is **not** safe
+    /// to build a `Vec<u8>` from a pointer to a C `char` array with length `size_t`.
+    /// It's also not safe to build one from a `Vec<u16>` and its length, because
+    /// the allocator cares about the alignment, and these two types have different
+    /// alignments. The buffer was allocated with alignment 2 (for `u16`), but after
+    /// turning it into a `Vec<u8>` it'll be deallocated with alignment 1.
+    ///
+    /// The ownership of `ptr` is effectively transferred to the
+    /// `Vec<T>` which may then deallocate, reallocate or change the
+    /// contents of memory pointed to by the pointer at will. Ensure
+    /// that nothing else uses the pointer after calling this
+    /// function.
+    ///
+    /// [`String`]: crate::string::String
+    /// [`dealloc`]: crate::alloc::GlobalAlloc::dealloc
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(allocator_api)]
+    ///
+    /// use std::alloc::System;
+    ///
+    /// use std::ptr;
+    /// use std::mem;
+    ///
+    /// let mut v = Vec::with_capacity_in(3, System);
+    /// v.push(1);
+    /// v.push(2);
+    /// v.push(3);
+    ///
+    // FIXME Update this when vec_into_raw_parts is stabilized
+    /// // Prevent running `v`'s destructor so we are in complete control
+    /// // of the allocation.
+    /// let mut v = mem::ManuallyDrop::new(v);
+    ///
+    /// // Pull out the various important pieces of information about `v`
+    /// let p = v.as_mut_ptr();
+    /// let len = v.len();
+    /// let cap = v.capacity();
+    /// let alloc = v.allocator();
+    ///
+    /// unsafe {
+    ///     // Overwrite memory with 4, 5, 6
+    ///     for i in 0..len as isize {
+    ///         ptr::write(p.offset(i), 4 + i);
+    ///     }
+    ///
+    ///     // Put everything back together into a Vec
+    ///     let rebuilt = Vec::from_raw_parts_in(p, len, cap, alloc.clone());
+    ///     assert_eq!(rebuilt, [4, 5, 6]);
+    /// }
+    /// ```
+    #[inline]
+    #[unstable(feature = "allocator_api", issue = "32838")]
+    pub unsafe fn from_raw_parts_in(ptr: *mut T, length: usize, capacity: usize, alloc: A) -> Self {
+        unsafe { Vec { buf: RawVec::from_raw_parts_in(ptr, capacity, alloc), len: length } }
+    }
+
+    /// Decomposes a `Vec<T>` into its raw components.
+    ///
+    /// Returns the raw pointer to the underlying data, the length of
+    /// the vector (in elements), and the allocated capacity of the
+    /// data (in elements). These are the same arguments in the same
+    /// order as the arguments to [`from_raw_parts`].
+    ///
+    /// After calling this function, the caller is responsible for the
+    /// memory previously managed by the `Vec`. The only way to do
+    /// this is to convert the raw pointer, length, and capacity back
+    /// into a `Vec` with the [`from_raw_parts`] function, allowing
+    /// the destructor to perform the cleanup.
+    ///
+    /// [`from_raw_parts`]: Vec::from_raw_parts
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(vec_into_raw_parts)]
+    /// let v: Vec<i32> = vec![-1, 0, 1];
+    ///
+    /// let (ptr, len, cap) = v.into_raw_parts();
+    ///
+    /// let rebuilt = unsafe {
+    ///     // We can now make changes to the components, such as
+    ///     // transmuting the raw pointer to a compatible type.
+    ///     let ptr = ptr as *mut u32;
+    ///
+    ///     Vec::from_raw_parts(ptr, len, cap)
+    /// };
+    /// assert_eq!(rebuilt, [4294967295, 0, 1]);
+    /// ```
+    #[unstable(feature = "vec_into_raw_parts", reason = "new API", issue = "65816")]
+    pub fn into_raw_parts(self) -> (*mut T, usize, usize) {
+        let mut me = ManuallyDrop::new(self);
+        (me.as_mut_ptr(), me.len(), me.capacity())
+    }
+
+    /// Decomposes a `Vec<T>` into its raw components.
+    ///
+    /// Returns the raw pointer to the underlying data, the length of the vector (in elements),
+    /// the allocated capacity of the data (in elements), and the allocator. These are the same
+    /// arguments in the same order as the arguments to [`from_raw_parts_in`].
+    ///
+    /// After calling this function, the caller is responsible for the
+    /// memory previously managed by the `Vec`. The only way to do
+    /// this is to convert the raw pointer, length, and capacity back
+    /// into a `Vec` with the [`from_raw_parts_in`] function, allowing
+    /// the destructor to perform the cleanup.
+    ///
+    /// [`from_raw_parts_in`]: Vec::from_raw_parts_in
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(allocator_api, vec_into_raw_parts)]
+    ///
+    /// use std::alloc::System;
+    ///
+    /// let mut v: Vec<i32, System> = Vec::new_in(System);
+    /// v.push(-1);
+    /// v.push(0);
+    /// v.push(1);
+    ///
+    /// let (ptr, len, cap, alloc) = v.into_raw_parts_with_alloc();
+    ///
+    /// let rebuilt = unsafe {
+    ///     // We can now make changes to the components, such as
+    ///     // transmuting the raw pointer to a compatible type.
+    ///     let ptr = ptr as *mut u32;
+    ///
+    ///     Vec::from_raw_parts_in(ptr, len, cap, alloc)
+    /// };
+    /// assert_eq!(rebuilt, [4294967295, 0, 1]);
+    /// ```
+    #[unstable(feature = "allocator_api", issue = "32838")]
+    // #[unstable(feature = "vec_into_raw_parts", reason = "new API", issue = "65816")]
+    pub fn into_raw_parts_with_alloc(self) -> (*mut T, usize, usize, A) {
+        let mut me = ManuallyDrop::new(self);
+        let len = me.len();
+        let capacity = me.capacity();
+        let ptr = me.as_mut_ptr();
+        let alloc = unsafe { ptr::read(me.allocator()) };
+        (ptr, len, capacity, alloc)
+    }
+
+    /// Returns the number of elements the vector can hold without
+    /// reallocating.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// let vec: Vec<i32> = Vec::with_capacity(10);
+    /// assert_eq!(vec.capacity(), 10);
+    /// ```
+    #[inline]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn capacity(&self) -> usize {
+        self.buf.capacity()
+    }
+
+    /// Reserves capacity for at least `additional` more elements to be inserted
+    /// in the given `Vec<T>`. The collection may reserve more space to avoid
+    /// frequent reallocations. After calling `reserve`, capacity will be
+    /// greater than or equal to `self.len() + additional`. Does nothing if
+    /// capacity is already sufficient.
+    ///
+    /// # Panics
+    ///
+    /// Panics if the new capacity exceeds `isize::MAX` bytes.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// let mut vec = vec![1];
+    /// vec.reserve(10);
+    /// assert!(vec.capacity() >= 11);
+    /// ```
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn reserve(&mut self, additional: usize) {
+        self.buf.reserve(self.len, additional);
+    }
+
+    /// Reserves the minimum capacity for exactly `additional` more elements to
+    /// be inserted in the given `Vec<T>`. After calling `reserve_exact`,
+    /// capacity will be greater than or equal to `self.len() + additional`.
+    /// Does nothing if the capacity is already sufficient.
+    ///
+    /// Note that the allocator may give the collection more space than it
+    /// requests. Therefore, capacity can not be relied upon to be precisely
+    /// minimal. Prefer `reserve` if future insertions are expected.
+    ///
+    /// # Panics
+    ///
+    /// Panics if the new capacity overflows `usize`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// let mut vec = vec![1];
+    /// vec.reserve_exact(10);
+    /// assert!(vec.capacity() >= 11);
+    /// ```
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn reserve_exact(&mut self, additional: usize) {
+        self.buf.reserve_exact(self.len, additional);
+    }
+
+    /// Tries to reserve capacity for at least `additional` more elements to be inserted
+    /// in the given `Vec<T>`. The collection may reserve more space to avoid
+    /// frequent reallocations. After calling `try_reserve`, capacity will be
+    /// greater than or equal to `self.len() + additional`. Does nothing if
+    /// capacity is already sufficient.
+    ///
+    /// # Errors
+    ///
+    /// If the capacity overflows, or the allocator reports a failure, then an error
+    /// is returned.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(try_reserve)]
+    /// use std::collections::TryReserveError;
+    ///
+    /// fn process_data(data: &[u32]) -> Result<Vec<u32>, TryReserveError> {
+    ///     let mut output = Vec::new();
+    ///
+    ///     // Pre-reserve the memory, exiting if we can't
+    ///     output.try_reserve(data.len())?;
+    ///
+    ///     // Now we know this can't OOM in the middle of our complex work
+    ///     output.extend(data.iter().map(|&val| {
+    ///         val * 2 + 5 // very complicated
+    ///     }));
+    ///
+    ///     Ok(output)
+    /// }
+    /// # process_data(&[1, 2, 3]).expect("why is the test harness OOMing on 12 bytes?");
+    /// ```
+    #[unstable(feature = "try_reserve", reason = "new API", issue = "48043")]
+    pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> {
+        self.buf.try_reserve(self.len, additional)
+    }
+
+    /// Tries to reserve the minimum capacity for exactly `additional`
+    /// elements to be inserted in the given `Vec<T>`. After calling
+    /// `try_reserve_exact`, capacity will be greater than or equal to
+    /// `self.len() + additional` if it returns `Ok(())`.
+    /// Does nothing if the capacity is already sufficient.
+    ///
+    /// Note that the allocator may give the collection more space than it
+    /// requests. Therefore, capacity can not be relied upon to be precisely
+    /// minimal. Prefer `reserve` if future insertions are expected.
+    ///
+    /// # Errors
+    ///
+    /// If the capacity overflows, or the allocator reports a failure, then an error
+    /// is returned.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(try_reserve)]
+    /// use std::collections::TryReserveError;
+    ///
+    /// fn process_data(data: &[u32]) -> Result<Vec<u32>, TryReserveError> {
+    ///     let mut output = Vec::new();
+    ///
+    ///     // Pre-reserve the memory, exiting if we can't
+    ///     output.try_reserve_exact(data.len())?;
+    ///
+    ///     // Now we know this can't OOM in the middle of our complex work
+    ///     output.extend(data.iter().map(|&val| {
+    ///         val * 2 + 5 // very complicated
+    ///     }));
+    ///
+    ///     Ok(output)
+    /// }
+    /// # process_data(&[1, 2, 3]).expect("why is the test harness OOMing on 12 bytes?");
+    /// ```
+    #[unstable(feature = "try_reserve", reason = "new API", issue = "48043")]
+    pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), TryReserveError> {
+        self.buf.try_reserve_exact(self.len, additional)
+    }
+
+    /// Shrinks the capacity of the vector as much as possible.
+    ///
+    /// It will drop down as close as possible to the length but the allocator
+    /// may still inform the vector that there is space for a few more elements.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// let mut vec = Vec::with_capacity(10);
+    /// vec.extend([1, 2, 3].iter().cloned());
+    /// assert_eq!(vec.capacity(), 10);
+    /// vec.shrink_to_fit();
+    /// assert!(vec.capacity() >= 3);
+    /// ```
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn shrink_to_fit(&mut self) {
+        // The capacity is never less than the length, and there's nothing to do when
+        // they are equal, so we can avoid the panic case in `RawVec::shrink_to_fit`
+        // by only calling it with a greater capacity.
+        if self.capacity() > self.len {
+            self.buf.shrink_to_fit(self.len);
+        }
+    }
+
+    /// Shrinks the capacity of the vector with a lower bound.
+    ///
+    /// The capacity will remain at least as large as both the length
+    /// and the supplied value.
+    ///
+    /// # Panics
+    ///
+    /// Panics if the current capacity is smaller than the supplied
+    /// minimum capacity.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(shrink_to)]
+    /// let mut vec = Vec::with_capacity(10);
+    /// vec.extend([1, 2, 3].iter().cloned());
+    /// assert_eq!(vec.capacity(), 10);
+    /// vec.shrink_to(4);
+    /// assert!(vec.capacity() >= 4);
+    /// vec.shrink_to(0);
+    /// assert!(vec.capacity() >= 3);
+    /// ```
+    #[unstable(feature = "shrink_to", reason = "new API", issue = "56431")]
+    pub fn shrink_to(&mut self, min_capacity: usize) {
+        self.buf.shrink_to_fit(cmp::max(self.len, min_capacity));
+    }
+
+    /// Converts the vector into [`Box<[T]>`][owned slice].
+    ///
+    /// Note that this will drop any excess capacity.
+    ///
+    /// [owned slice]: Box
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// let v = vec![1, 2, 3];
+    ///
+    /// let slice = v.into_boxed_slice();
+    /// ```
+    ///
+    /// Any excess capacity is removed:
+    ///
+    /// ```
+    /// let mut vec = Vec::with_capacity(10);
+    /// vec.extend([1, 2, 3].iter().cloned());
+    ///
+    /// assert_eq!(vec.capacity(), 10);
+    /// let slice = vec.into_boxed_slice();
+    /// assert_eq!(slice.into_vec().capacity(), 3);
+    /// ```
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn into_boxed_slice(mut self) -> Box<[T], A> {
+        unsafe {
+            self.shrink_to_fit();
+            let me = ManuallyDrop::new(self);
+            let buf = ptr::read(&me.buf);
+            let len = me.len();
+            buf.into_box(len).assume_init()
+        }
+    }
+
+    /// Shortens the vector, keeping the first `len` elements and dropping
+    /// the rest.
+    ///
+    /// If `len` is greater than the vector's current length, this has no
+    /// effect.
+    ///
+    /// The [`drain`] method can emulate `truncate`, but causes the excess
+    /// elements to be returned instead of dropped.
+    ///
+    /// Note that this method has no effect on the allocated capacity
+    /// of the vector.
+    ///
+    /// # Examples
+    ///
+    /// Truncating a five element vector to two elements:
+    ///
+    /// ```
+    /// let mut vec = vec![1, 2, 3, 4, 5];
+    /// vec.truncate(2);
+    /// assert_eq!(vec, [1, 2]);
+    /// ```
+    ///
+    /// No truncation occurs when `len` is greater than the vector's current
+    /// length:
+    ///
+    /// ```
+    /// let mut vec = vec![1, 2, 3];
+    /// vec.truncate(8);
+    /// assert_eq!(vec, [1, 2, 3]);
+    /// ```
+    ///
+    /// Truncating when `len == 0` is equivalent to calling the [`clear`]
+    /// method.
+    ///
+    /// ```
+    /// let mut vec = vec![1, 2, 3];
+    /// vec.truncate(0);
+    /// assert_eq!(vec, []);
+    /// ```
+    ///
+    /// [`clear`]: Vec::clear
+    /// [`drain`]: Vec::drain
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn truncate(&mut self, len: usize) {
+        // This is safe because:
+        //
+        // * the slice passed to `drop_in_place` is valid; the `len > self.len`
+        //   case avoids creating an invalid slice, and
+        // * the `len` of the vector is shrunk before calling `drop_in_place`,
+        //   such that no value will be dropped twice in case `drop_in_place`
+        //   were to panic once (if it panics twice, the program aborts).
+        unsafe {
+            if len > self.len {
+                return;
+            }
+            let remaining_len = self.len - len;
+            let s = ptr::slice_from_raw_parts_mut(self.as_mut_ptr().add(len), remaining_len);
+            self.len = len;
+            ptr::drop_in_place(s);
+        }
+    }
+
+    /// Extracts a slice containing the entire vector.
+    ///
+    /// Equivalent to `&s[..]`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::io::{self, Write};
+    /// let buffer = vec![1, 2, 3, 5, 8];
+    /// io::sink().write(buffer.as_slice()).unwrap();
+    /// ```
+    #[inline]
+    #[stable(feature = "vec_as_slice", since = "1.7.0")]
+    pub fn as_slice(&self) -> &[T] {
+        self
+    }
+
+    /// Extracts a mutable slice of the entire vector.
+    ///
+    /// Equivalent to `&mut s[..]`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::io::{self, Read};
+    /// let mut buffer = vec![0; 3];
+    /// io::repeat(0b101).read_exact(buffer.as_mut_slice()).unwrap();
+    /// ```
+    #[inline]
+    #[stable(feature = "vec_as_slice", since = "1.7.0")]
+    pub fn as_mut_slice(&mut self) -> &mut [T] {
+        self
+    }
+
+    /// Returns a raw pointer to the vector's buffer.
+    ///
+    /// The caller must ensure that the vector outlives the pointer this
+    /// function returns, or else it will end up pointing to garbage.
+    /// Modifying the vector may cause its buffer to be reallocated,
+    /// which would also make any pointers to it invalid.
+    ///
+    /// The caller must also ensure that the memory the pointer (non-transitively) points to
+    /// is never written to (except inside an `UnsafeCell`) using this pointer or any pointer
+    /// derived from it. If you need to mutate the contents of the slice, use [`as_mut_ptr`].
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// let x = vec![1, 2, 4];
+    /// let x_ptr = x.as_ptr();
+    ///
+    /// unsafe {
+    ///     for i in 0..x.len() {
+    ///         assert_eq!(*x_ptr.add(i), 1 << i);
+    ///     }
+    /// }
+    /// ```
+    ///
+    /// [`as_mut_ptr`]: Vec::as_mut_ptr
+    #[stable(feature = "vec_as_ptr", since = "1.37.0")]
+    #[inline]
+    pub fn as_ptr(&self) -> *const T {
+        // We shadow the slice method of the same name to avoid going through
+        // `deref`, which creates an intermediate reference.
+        let ptr = self.buf.ptr();
+        unsafe {
+            assume(!ptr.is_null());
+        }
+        ptr
+    }
+
+    /// Returns an unsafe mutable pointer to the vector's buffer.
+    ///
+    /// The caller must ensure that the vector outlives the pointer this
+    /// function returns, or else it will end up pointing to garbage.
+    /// Modifying the vector may cause its buffer to be reallocated,
+    /// which would also make any pointers to it invalid.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// // Allocate vector big enough for 4 elements.
+    /// let size = 4;
+    /// let mut x: Vec<i32> = Vec::with_capacity(size);
+    /// let x_ptr = x.as_mut_ptr();
+    ///
+    /// // Initialize elements via raw pointer writes, then set length.
+    /// unsafe {
+    ///     for i in 0..size {
+    ///         *x_ptr.add(i) = i as i32;
+    ///     }
+    ///     x.set_len(size);
+    /// }
+    /// assert_eq!(&*x, &[0, 1, 2, 3]);
+    /// ```
+    #[stable(feature = "vec_as_ptr", since = "1.37.0")]
+    #[inline]
+    pub fn as_mut_ptr(&mut self) -> *mut T {
+        // We shadow the slice method of the same name to avoid going through
+        // `deref_mut`, which creates an intermediate reference.
+        let ptr = self.buf.ptr();
+        unsafe {
+            assume(!ptr.is_null());
+        }
+        ptr
+    }
+
+    /// Returns a reference to the underlying allocator.
+    #[unstable(feature = "allocator_api", issue = "32838")]
+    #[inline]
+    pub fn allocator(&self) -> &A {
+        self.buf.allocator()
+    }
+
+    /// Forces the length of the vector to `new_len`.
+    ///
+    /// This is a low-level operation that maintains none of the normal
+    /// invariants of the type. Normally changing the length of a vector
+    /// is done using one of the safe operations instead, such as
+    /// [`truncate`], [`resize`], [`extend`], or [`clear`].
+    ///
+    /// [`truncate`]: Vec::truncate
+    /// [`resize`]: Vec::resize
+    /// [`extend`]: Extend::extend
+    /// [`clear`]: Vec::clear
+    ///
+    /// # Safety
+    ///
+    /// - `new_len` must be less than or equal to [`capacity()`].
+    /// - The elements at `old_len..new_len` must be initialized.
+    ///
+    /// [`capacity()`]: Vec::capacity
+    ///
+    /// # Examples
+    ///
+    /// This method can be useful for situations in which the vector
+    /// is serving as a buffer for other code, particularly over FFI:
+    ///
+    /// ```no_run
+    /// # #![allow(dead_code)]
+    /// # // This is just a minimal skeleton for the doc example;
+    /// # // don't use this as a starting point for a real library.
+    /// # pub struct StreamWrapper { strm: *mut std::ffi::c_void }
+    /// # const Z_OK: i32 = 0;
+    /// # extern "C" {
+    /// #     fn deflateGetDictionary(
+    /// #         strm: *mut std::ffi::c_void,
+    /// #         dictionary: *mut u8,
+    /// #         dictLength: *mut usize,
+    /// #     ) -> i32;
+    /// # }
+    /// # impl StreamWrapper {
+    /// pub fn get_dictionary(&self) -> Option<Vec<u8>> {
+    ///     // Per the FFI method's docs, "32768 bytes is always enough".
+    ///     let mut dict = Vec::with_capacity(32_768);
+    ///     let mut dict_length = 0;
+    ///     // SAFETY: When `deflateGetDictionary` returns `Z_OK`, it holds that:
+    ///     // 1. `dict_length` elements were initialized.
+    ///     // 2. `dict_length` <= the capacity (32_768)
+    ///     // which makes `set_len` safe to call.
+    ///     unsafe {
+    ///         // Make the FFI call...
+    ///         let r = deflateGetDictionary(self.strm, dict.as_mut_ptr(), &mut dict_length);
+    ///         if r == Z_OK {
+    ///             // ...and update the length to what was initialized.
+    ///             dict.set_len(dict_length);
+    ///             Some(dict)
+    ///         } else {
+    ///             None
+    ///         }
+    ///     }
+    /// }
+    /// # }
+    /// ```
+    ///
+    /// While the following example is sound, there is a memory leak since
+    /// the inner vectors were not freed prior to the `set_len` call:
+    ///
+    /// ```
+    /// let mut vec = vec![vec![1, 0, 0],
+    ///                    vec![0, 1, 0],
+    ///                    vec![0, 0, 1]];
+    /// // SAFETY:
+    /// // 1. `old_len..0` is empty so no elements need to be initialized.
+    /// // 2. `0 <= capacity` always holds whatever `capacity` is.
+    /// unsafe {
+    ///     vec.set_len(0);
+    /// }
+    /// ```
+    ///
+    /// Normally, here, one would use [`clear`] instead to correctly drop
+    /// the contents and thus not leak memory.
+    #[inline]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub unsafe fn set_len(&mut self, new_len: usize) {
+        debug_assert!(new_len <= self.capacity());
+
+        self.len = new_len;
+    }
+
+    /// Removes an element from the vector and returns it.
+    ///
+    /// The removed element is replaced by the last element of the vector.
+    ///
+    /// This does not preserve ordering, but is O(1).
+    ///
+    /// # Panics
+    ///
+    /// Panics if `index` is out of bounds.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// let mut v = vec!["foo", "bar", "baz", "qux"];
+    ///
+    /// assert_eq!(v.swap_remove(1), "bar");
+    /// assert_eq!(v, ["foo", "qux", "baz"]);
+    ///
+    /// assert_eq!(v.swap_remove(0), "foo");
+    /// assert_eq!(v, ["baz", "qux"]);
+    /// ```
+    #[inline]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn swap_remove(&mut self, index: usize) -> T {
+        #[cold]
+        #[inline(never)]
+        fn assert_failed(index: usize, len: usize) -> ! {
+            panic!("swap_remove index (is {}) should be < len (is {})", index, len);
+        }
+
+        let len = self.len();
+        if index >= len {
+            assert_failed(index, len);
+        }
+        unsafe {
+            // We replace self[index] with the last element. Note that if the
+            // bounds check above succeeds there must be a last element (which
+            // can be self[index] itself).
+            let last = ptr::read(self.as_ptr().add(len - 1));
+            let hole = self.as_mut_ptr().add(index);
+            self.set_len(len - 1);
+            ptr::replace(hole, last)
+        }
+    }
+
+    /// Inserts an element at position `index` within the vector, shifting all
+    /// elements after it to the right.
+    ///
+    /// # Panics
+    ///
+    /// Panics if `index > len`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// let mut vec = vec![1, 2, 3];
+    /// vec.insert(1, 4);
+    /// assert_eq!(vec, [1, 4, 2, 3]);
+    /// vec.insert(4, 5);
+    /// assert_eq!(vec, [1, 4, 2, 3, 5]);
+    /// ```
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn insert(&mut self, index: usize, element: T) {
+        #[cold]
+        #[inline(never)]
+        fn assert_failed(index: usize, len: usize) -> ! {
+            panic!("insertion index (is {}) should be <= len (is {})", index, len);
+        }
+
+        let len = self.len();
+        if index > len {
+            assert_failed(index, len);
+        }
+
+        // space for the new element
+        if len == self.buf.capacity() {
+            self.reserve(1);
+        }
+
+        unsafe {
+            // infallible
+            // The spot to put the new value
+            {
+                let p = self.as_mut_ptr().add(index);
+                // Shift everything over to make space. (Duplicating the
+                // `index`th element into two consecutive places.)
+                ptr::copy(p, p.offset(1), len - index);
+                // Write it in, overwriting the first copy of the `index`th
+                // element.
+                ptr::write(p, element);
+            }
+            self.set_len(len + 1);
+        }
+    }
+
+    /// Removes and returns the element at position `index` within the vector,
+    /// shifting all elements after it to the left.
+    ///
+    /// # Panics
+    ///
+    /// Panics if `index` is out of bounds.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// let mut v = vec![1, 2, 3];
+    /// assert_eq!(v.remove(1), 2);
+    /// assert_eq!(v, [1, 3]);
+    /// ```
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn remove(&mut self, index: usize) -> T {
+        #[cold]
+        #[inline(never)]
+        fn assert_failed(index: usize, len: usize) -> ! {
+            panic!("removal index (is {}) should be < len (is {})", index, len);
+        }
+
+        let len = self.len();
+        if index >= len {
+            assert_failed(index, len);
+        }
+        unsafe {
+            // infallible
+            let ret;
+            {
+                // the place we are taking from.
+                let ptr = self.as_mut_ptr().add(index);
+                // copy it out, unsafely having a copy of the value on
+                // the stack and in the vector at the same time.
+                ret = ptr::read(ptr);
+
+                // Shift everything down to fill in that spot.
+                ptr::copy(ptr.offset(1), ptr, len - index - 1);
+            }
+            self.set_len(len - 1);
+            ret
+        }
+    }
+
+    /// Retains only the elements specified by the predicate.
+    ///
+    /// In other words, remove all elements `e` such that `f(&e)` returns `false`.
+    /// This method operates in place, visiting each element exactly once in the
+    /// original order, and preserves the order of the retained elements.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// let mut vec = vec![1, 2, 3, 4];
+    /// vec.retain(|&x| x % 2 == 0);
+    /// assert_eq!(vec, [2, 4]);
+    /// ```
+    ///
+    /// The exact order may be useful for tracking external state, like an index.
+    ///
+    /// ```
+    /// let mut vec = vec![1, 2, 3, 4, 5];
+    /// let keep = [false, true, true, false, true];
+    /// let mut i = 0;
+    /// vec.retain(|_| (keep[i], i += 1).0);
+    /// assert_eq!(vec, [2, 3, 5]);
+    /// ```
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn retain<F>(&mut self, mut f: F)
+    where
+        F: FnMut(&T) -> bool,
+    {
+        let len = self.len();
+        let mut del = 0;
+        {
+            let v = &mut **self;
+
+            for i in 0..len {
+                if !f(&v[i]) {
+                    del += 1;
+                } else if del > 0 {
+                    v.swap(i - del, i);
+                }
+            }
+        }
+        if del > 0 {
+            self.truncate(len - del);
+        }
+    }
+
+    /// Removes all but the first of consecutive elements in the vector that resolve to the same
+    /// key.
+    ///
+    /// If the vector is sorted, this removes all duplicates.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// let mut vec = vec![10, 20, 21, 30, 20];
+    ///
+    /// vec.dedup_by_key(|i| *i / 10);
+    ///
+    /// assert_eq!(vec, [10, 20, 30, 20]);
+    /// ```
+    #[stable(feature = "dedup_by", since = "1.16.0")]
+    #[inline]
+    pub fn dedup_by_key<F, K>(&mut self, mut key: F)
+    where
+        F: FnMut(&mut T) -> K,
+        K: PartialEq,
+    {
+        self.dedup_by(|a, b| key(a) == key(b))
+    }
+
+    /// Removes all but the first of consecutive elements in the vector satisfying a given equality
+    /// relation.
+    ///
+    /// The `same_bucket` function is passed references to two elements from the vector and
+    /// must determine if the elements compare equal. The elements are passed in opposite order
+    /// from their order in the slice, so if `same_bucket(a, b)` returns `true`, `a` is removed.
+    ///
+    /// If the vector is sorted, this removes all duplicates.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// let mut vec = vec!["foo", "bar", "Bar", "baz", "bar"];
+    ///
+    /// vec.dedup_by(|a, b| a.eq_ignore_ascii_case(b));
+    ///
+    /// assert_eq!(vec, ["foo", "bar", "baz", "bar"]);
+    /// ```
+    #[stable(feature = "dedup_by", since = "1.16.0")]
+    pub fn dedup_by<F>(&mut self, same_bucket: F)
+    where
+        F: FnMut(&mut T, &mut T) -> bool,
+    {
+        let len = {
+            let (dedup, _) = self.as_mut_slice().partition_dedup_by(same_bucket);
+            dedup.len()
+        };
+        self.truncate(len);
+    }
+
+    /// Appends an element to the back of a collection.
+    ///
+    /// # Panics
+    ///
+    /// Panics if the new capacity exceeds `isize::MAX` bytes.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// let mut vec = vec![1, 2];
+    /// vec.push(3);
+    /// assert_eq!(vec, [1, 2, 3]);
+    /// ```
+    #[inline]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn push(&mut self, value: T) {
+        // This will panic or abort if we would allocate > isize::MAX bytes
+        // or if the length increment would overflow for zero-sized types.
+        if self.len == self.buf.capacity() {
+            self.reserve(1);
+        }
+        unsafe {
+            let end = self.as_mut_ptr().add(self.len);
+            ptr::write(end, value);
+            self.len += 1;
+        }
+    }
+
+    /// Removes the last element from a vector and returns it, or [`None`] if it
+    /// is empty.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// let mut vec = vec![1, 2, 3];
+    /// assert_eq!(vec.pop(), Some(3));
+    /// assert_eq!(vec, [1, 2]);
+    /// ```
+    #[inline]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn pop(&mut self) -> Option<T> {
+        if self.len == 0 {
+            None
+        } else {
+            unsafe {
+                self.len -= 1;
+                Some(ptr::read(self.as_ptr().add(self.len())))
+            }
+        }
+    }
+
+    /// Moves all the elements of `other` into `Self`, leaving `other` empty.
+    ///
+    /// # Panics
+    ///
+    /// Panics if the number of elements in the vector overflows a `usize`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// let mut vec = vec![1, 2, 3];
+    /// let mut vec2 = vec![4, 5, 6];
+    /// vec.append(&mut vec2);
+    /// assert_eq!(vec, [1, 2, 3, 4, 5, 6]);
+    /// assert_eq!(vec2, []);
+    /// ```
+    #[inline]
+    #[stable(feature = "append", since = "1.4.0")]
+    pub fn append(&mut self, other: &mut Self) {
+        unsafe {
+            self.append_elements(other.as_slice() as _);
+            other.set_len(0);
+        }
+    }
+
+    /// Appends elements to `Self` from other buffer.
+    #[inline]
+    unsafe fn append_elements(&mut self, other: *const [T]) {
+        let count = unsafe { (*other).len() };
+        self.reserve(count);
+        let len = self.len();
+        unsafe { ptr::copy_nonoverlapping(other as *const T, self.as_mut_ptr().add(len), count) };
+        self.len += count;
+    }
+
+    /// Creates a draining iterator that removes the specified range in the vector
+    /// and yields the removed items.
+    ///
+    /// When the iterator **is** dropped, all elements in the range are removed
+    /// from the vector, even if the iterator was not fully consumed. If the
+    /// iterator **is not** dropped (with [`mem::forget`] for example), it is
+    /// unspecified how many elements are removed.
+    ///
+    /// # Panics
+    ///
+    /// Panics if the starting point is greater than the end point or if
+    /// the end point is greater than the length of the vector.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// let mut v = vec![1, 2, 3];
+    /// let u: Vec<_> = v.drain(1..).collect();
+    /// assert_eq!(v, &[1]);
+    /// assert_eq!(u, &[2, 3]);
+    ///
+    /// // A full range clears the vector
+    /// v.drain(..);
+    /// assert_eq!(v, &[]);
+    /// ```
+    #[stable(feature = "drain", since = "1.6.0")]
+    pub fn drain<R>(&mut self, range: R) -> Drain<'_, T, A>
+    where
+        R: RangeBounds<usize>,
+    {
+        // Memory safety
+        //
+        // When the Drain is first created, it shortens the length of
+        // the source vector to make sure no uninitialized or moved-from elements
+        // are accessible at all if the Drain's destructor never gets to run.
+        //
+        // Drain will ptr::read out the values to remove.
+        // When finished, remaining tail of the vec is copied back to cover
+        // the hole, and the vector length is restored to the new length.
+        //
+        let len = self.len();
+        let Range { start, end } = range.assert_len(len);
+
+        unsafe {
+            // set self.vec length's to start, to be safe in case Drain is leaked
+            self.set_len(start);
+            // Use the borrow in the IterMut to indicate borrowing behavior of the
+            // whole Drain iterator (like &mut T).
+            let range_slice = slice::from_raw_parts_mut(self.as_mut_ptr().add(start), end - start);
+            Drain {
+                tail_start: end,
+                tail_len: len - end,
+                iter: range_slice.iter(),
+                vec: NonNull::from(self),
+            }
+        }
+    }
+
+    /// Clears the vector, removing all values.
+    ///
+    /// Note that this method has no effect on the allocated capacity
+    /// of the vector.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// let mut v = vec![1, 2, 3];
+    ///
+    /// v.clear();
+    ///
+    /// assert!(v.is_empty());
+    /// ```
+    #[inline]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn clear(&mut self) {
+        self.truncate(0)
+    }
+
+    /// Returns the number of elements in the vector, also referred to
+    /// as its 'length'.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// let a = vec![1, 2, 3];
+    /// assert_eq!(a.len(), 3);
+    /// ```
+    #[doc(alias = "length")]
+    #[inline]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn len(&self) -> usize {
+        self.len
+    }
+
+    /// Returns `true` if the vector contains no elements.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// let mut v = Vec::new();
+    /// assert!(v.is_empty());
+    ///
+    /// v.push(1);
+    /// assert!(!v.is_empty());
+    /// ```
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn is_empty(&self) -> bool {
+        self.len() == 0
+    }
+
+    /// Splits the collection into two at the given index.
+    ///
+    /// Returns a newly allocated vector containing the elements in the range
+    /// `[at, len)`. After the call, the original vector will be left containing
+    /// the elements `[0, at)` with its previous capacity unchanged.
+    ///
+    /// # Panics
+    ///
+    /// Panics if `at > len`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// let mut vec = vec![1, 2, 3];
+    /// let vec2 = vec.split_off(1);
+    /// assert_eq!(vec, [1]);
+    /// assert_eq!(vec2, [2, 3]);
+    /// ```
+    #[inline]
+    #[must_use = "use `.truncate()` if you don't need the other half"]
+    #[stable(feature = "split_off", since = "1.4.0")]
+    pub fn split_off(&mut self, at: usize) -> Self
+    where
+        A: Clone,
+    {
+        #[cold]
+        #[inline(never)]
+        fn assert_failed(at: usize, len: usize) -> ! {
+            panic!("`at` split index (is {}) should be <= len (is {})", at, len);
+        }
+
+        if at > self.len() {
+            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_in(self.capacity(), self.allocator().clone()),
+            );
+        }
+
+        let other_len = self.len - at;
+        let mut other = Vec::with_capacity_in(other_len, self.allocator().clone());
+
+        // Unsafely `set_len` and copy items to `other`.
+        unsafe {
+            self.set_len(at);
+            other.set_len(other_len);
+
+            ptr::copy_nonoverlapping(self.as_ptr().add(at), other.as_mut_ptr(), other.len());
+        }
+        other
+    }
+
+    /// Resizes the `Vec` in-place so that `len` is equal to `new_len`.
+    ///
+    /// If `new_len` is greater than `len`, the `Vec` is extended by the
+    /// difference, with each additional slot filled with the result of
+    /// calling the closure `f`. The return values from `f` will end up
+    /// in the `Vec` in the order they have been generated.
+    ///
+    /// If `new_len` is less than `len`, the `Vec` is simply truncated.
+    ///
+    /// This method uses a closure to create new values on every push. If
+    /// you'd rather [`Clone`] a given value, use [`Vec::resize`]. If you
+    /// want to use the [`Default`] trait to generate values, you can
+    /// pass [`Default::default`] as the second argument.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// let mut vec = vec![1, 2, 3];
+    /// vec.resize_with(5, Default::default);
+    /// assert_eq!(vec, [1, 2, 3, 0, 0]);
+    ///
+    /// let mut vec = vec![];
+    /// let mut p = 1;
+    /// vec.resize_with(4, || { p *= 2; p });
+    /// assert_eq!(vec, [2, 4, 8, 16]);
+    /// ```
+    #[stable(feature = "vec_resize_with", since = "1.33.0")]
+    pub fn resize_with<F>(&mut self, new_len: usize, f: F)
+    where
+        F: FnMut() -> T,
+    {
+        let len = self.len();
+        if new_len > len {
+            self.extend_with(new_len - len, ExtendFunc(f));
+        } else {
+            self.truncate(new_len);
+        }
+    }
+
+    /// Consumes and leaks the `Vec`, returning a mutable reference to the contents,
+    /// `&'a mut [T]`. Note that the type `T` must outlive the chosen lifetime
+    /// `'a`. If the type has only static references, or none at all, then this
+    /// may be chosen to be `'static`.
+    ///
+    /// This function is similar to the [`leak`][Box::leak] function on [`Box`]
+    /// except that there is no way to recover the leaked memory.
+    ///
+    /// This function is mainly useful for data that lives for the remainder of
+    /// the program's life. Dropping the returned reference will cause a memory
+    /// leak.
+    ///
+    /// # Examples
+    ///
+    /// Simple usage:
+    ///
+    /// ```
+    /// let x = vec![1, 2, 3];
+    /// let static_ref: &'static mut [usize] = x.leak();
+    /// static_ref[0] += 1;
+    /// assert_eq!(static_ref, &[2, 2, 3]);
+    /// ```
+    #[stable(feature = "vec_leak", since = "1.47.0")]
+    #[inline]
+    pub fn leak<'a>(self) -> &'a mut [T]
+    where
+        A: 'a,
+    {
+        Box::leak(self.into_boxed_slice())
+    }
+
+    /// Returns the remaining spare capacity of the vector as a slice of
+    /// `MaybeUninit<T>`.
+    ///
+    /// The returned slice can be used to fill the vector with data (e.g. by
+    /// reading from a file) before marking the data as initialized using the
+    /// [`set_len`] method.
+    ///
+    /// [`set_len`]: Vec::set_len
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(vec_spare_capacity, maybe_uninit_extra)]
+    ///
+    /// // Allocate vector big enough for 10 elements.
+    /// let mut v = Vec::with_capacity(10);
+    ///
+    /// // Fill in the first 3 elements.
+    /// let uninit = v.spare_capacity_mut();
+    /// uninit[0].write(0);
+    /// uninit[1].write(1);
+    /// uninit[2].write(2);
+    ///
+    /// // Mark the first 3 elements of the vector as being initialized.
+    /// unsafe {
+    ///     v.set_len(3);
+    /// }
+    ///
+    /// assert_eq!(&v, &[0, 1, 2]);
+    /// ```
+    #[unstable(feature = "vec_spare_capacity", issue = "75017")]
+    #[inline]
+    pub fn spare_capacity_mut(&mut self) -> &mut [MaybeUninit<T>] {
+        unsafe {
+            slice::from_raw_parts_mut(
+                self.as_mut_ptr().add(self.len) as *mut MaybeUninit<T>,
+                self.buf.capacity() - self.len,
+            )
+        }
+    }
+}
+
+impl<T: Clone, A: Allocator> Vec<T, A> {
+    /// Resizes the `Vec` in-place so that `len` is equal to `new_len`.
+    ///
+    /// If `new_len` is greater than `len`, the `Vec` is extended by the
+    /// difference, with each additional slot filled with `value`.
+    /// If `new_len` is less than `len`, the `Vec` is simply truncated.
+    ///
+    /// This method requires `T` to implement [`Clone`],
+    /// in order to be able to clone the passed value.
+    /// If you need more flexibility (or want to rely on [`Default`] instead of
+    /// [`Clone`]), use [`Vec::resize_with`].
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// let mut vec = vec!["hello"];
+    /// vec.resize(3, "world");
+    /// assert_eq!(vec, ["hello", "world", "world"]);
+    ///
+    /// let mut vec = vec![1, 2, 3, 4];
+    /// vec.resize(2, 0);
+    /// assert_eq!(vec, [1, 2]);
+    /// ```
+    #[stable(feature = "vec_resize", since = "1.5.0")]
+    pub fn resize(&mut self, new_len: usize, value: T) {
+        let len = self.len();
+
+        if new_len > len {
+            self.extend_with(new_len - len, ExtendElement(value))
+        } else {
+            self.truncate(new_len);
+        }
+    }
+
+    /// Clones and appends all elements in a slice to the `Vec`.
+    ///
+    /// Iterates over the slice `other`, clones each element, and then appends
+    /// it to this `Vec`. The `other` vector is traversed in-order.
+    ///
+    /// Note that this function is same as [`extend`] except that it is
+    /// specialized to work with slices instead. If and when Rust gets
+    /// specialization this function will likely be deprecated (but still
+    /// available).
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// let mut vec = vec![1];
+    /// vec.extend_from_slice(&[2, 3, 4]);
+    /// assert_eq!(vec, [1, 2, 3, 4]);
+    /// ```
+    ///
+    /// [`extend`]: Vec::extend
+    #[stable(feature = "vec_extend_from_slice", since = "1.6.0")]
+    pub fn extend_from_slice(&mut self, other: &[T]) {
+        self.spec_extend(other.iter())
+    }
+}
+
+// This code generalizes `extend_with_{element,default}`.
+trait ExtendWith<T> {
+    fn next(&mut self) -> T;
+    fn last(self) -> T;
+}
+
+struct ExtendElement<T>(T);
+impl<T: Clone> ExtendWith<T> for ExtendElement<T> {
+    fn next(&mut self) -> T {
+        self.0.clone()
+    }
+    fn last(self) -> T {
+        self.0
+    }
+}
+
+struct ExtendDefault;
+impl<T: Default> ExtendWith<T> for ExtendDefault {
+    fn next(&mut self) -> T {
+        Default::default()
+    }
+    fn last(self) -> T {
+        Default::default()
+    }
+}
+
+struct ExtendFunc<F>(F);
+impl<T, F: FnMut() -> T> ExtendWith<T> for ExtendFunc<F> {
+    fn next(&mut self) -> T {
+        (self.0)()
+    }
+    fn last(mut self) -> T {
+        (self.0)()
+    }
+}
+
+impl<T, A: Allocator> Vec<T, A> {
+    /// Extend the vector by `n` values, using the given generator.
+    fn extend_with<E: ExtendWith<T>>(&mut self, n: usize, mut value: E) {
+        self.reserve(n);
+
+        unsafe {
+            let mut ptr = self.as_mut_ptr().add(self.len());
+            // Use SetLenOnDrop to work around bug where compiler
+            // may not realize the store through `ptr` through self.set_len()
+            // don't alias.
+            let mut local_len = SetLenOnDrop::new(&mut self.len);
+
+            // Write all elements except the last one
+            for _ in 1..n {
+                ptr::write(ptr, value.next());
+                ptr = ptr.offset(1);
+                // Increment the length in every step in case next() panics
+                local_len.increment_len(1);
+            }
+
+            if n > 0 {
+                // We can write the last element directly without cloning needlessly
+                ptr::write(ptr, value.last());
+                local_len.increment_len(1);
+            }
+
+            // len set by scope guard
+        }
+    }
+}
+
+impl<T: PartialEq, A: Allocator> Vec<T, A> {
+    /// Removes consecutive repeated elements in the vector according to the
+    /// [`PartialEq`] trait implementation.
+    ///
+    /// If the vector is sorted, this removes all duplicates.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// let mut vec = vec![1, 2, 2, 3, 2];
+    ///
+    /// vec.dedup();
+    ///
+    /// assert_eq!(vec, [1, 2, 3, 2]);
+    /// ```
+    #[stable(feature = "rust1", since = "1.0.0")]
+    #[inline]
+    pub fn dedup(&mut self) {
+        self.dedup_by(|a, b| a == b)
+    }
+}
+
+impl<T, A: Allocator> Vec<T, A> {
+    /// Removes the first instance of `item` from the vector if the item exists.
+    ///
+    /// This method will be removed soon.
+    #[unstable(feature = "vec_remove_item", reason = "recently added", issue = "40062")]
+    #[rustc_deprecated(
+        reason = "Removing the first item equal to a needle is already easily possible \
+            with iterators and the current Vec methods. Furthermore, having a method for \
+            one particular case of removal (linear search, only the first item, no swap remove) \
+            but not for others is inconsistent. This method will be removed soon.",
+        since = "1.46.0"
+    )]
+    pub fn remove_item<V>(&mut self, item: &V) -> Option<T>
+    where
+        T: PartialEq<V>,
+    {
+        let pos = self.iter().position(|x| *x == *item)?;
+        Some(self.remove(pos))
+    }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Internal methods and functions
+////////////////////////////////////////////////////////////////////////////////
+
+#[doc(hidden)]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub fn from_elem<T: Clone>(elem: T, n: usize) -> Vec<T> {
+    <T as SpecFromElem>::from_elem(elem, n, Global)
+}
+
+#[doc(hidden)]
+#[unstable(feature = "allocator_api", issue = "32838")]
+pub fn from_elem_in<T: Clone, A: Allocator>(elem: T, n: usize, alloc: A) -> Vec<T, A> {
+    <T as SpecFromElem>::from_elem(elem, n, alloc)
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Common trait implementations for Vec
+////////////////////////////////////////////////////////////////////////////////
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T, A: Allocator> ops::Deref for Vec<T, A> {
+    type Target = [T];
+
+    fn deref(&self) -> &[T] {
+        unsafe { slice::from_raw_parts(self.as_ptr(), self.len) }
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T, A: Allocator> ops::DerefMut for Vec<T, A> {
+    fn deref_mut(&mut self) -> &mut [T] {
+        unsafe { slice::from_raw_parts_mut(self.as_mut_ptr(), self.len) }
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: Clone, A: Allocator + Clone> Clone for Vec<T, A> {
+    #[cfg(not(test))]
+    fn clone(&self) -> Self {
+        let alloc = self.allocator().clone();
+        <[T]>::to_vec_in(&**self, alloc)
+    }
+
+    // HACK(japaric): with cfg(test) the inherent `[T]::to_vec` method, which is
+    // required for this method definition, is not available. Instead use the
+    // `slice::to_vec`  function which is only available with cfg(test)
+    // NB see the slice::hack module in slice.rs for more information
+    #[cfg(test)]
+    fn clone(&self) -> Self {
+        let alloc = self.allocator().clone();
+        crate::slice::to_vec(&**self, alloc)
+    }
+
+    fn clone_from(&mut self, other: &Self) {
+        // drop anything that will not be overwritten
+        self.truncate(other.len());
+
+        // self.len <= other.len due to the truncate above, so the
+        // slices here are always in-bounds.
+        let (init, tail) = other.split_at(self.len());
+
+        // reuse the contained values' allocations/resources.
+        self.clone_from_slice(init);
+        self.extend_from_slice(tail);
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: Hash, A: Allocator> Hash for Vec<T, A> {
+    #[inline]
+    fn hash<H: Hasher>(&self, state: &mut H) {
+        Hash::hash(&**self, state)
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_on_unimplemented(
+    message = "vector indices are of type `usize` or ranges of `usize`",
+    label = "vector indices are of type `usize` or ranges of `usize`"
+)]
+impl<T, I: SliceIndex<[T]>, A: Allocator> Index<I> for Vec<T, A> {
+    type Output = I::Output;
+
+    #[inline]
+    fn index(&self, index: I) -> &Self::Output {
+        Index::index(&**self, index)
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_on_unimplemented(
+    message = "vector indices are of type `usize` or ranges of `usize`",
+    label = "vector indices are of type `usize` or ranges of `usize`"
+)]
+impl<T, I: SliceIndex<[T]>, A: Allocator> IndexMut<I> for Vec<T, A> {
+    #[inline]
+    fn index_mut(&mut self, index: I) -> &mut Self::Output {
+        IndexMut::index_mut(&mut **self, index)
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T> FromIterator<T> for Vec<T> {
+    #[inline]
+    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Vec<T> {
+        <Self as SpecFromIter<T, I::IntoIter>>::from_iter(iter.into_iter())
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T, A: Allocator> IntoIterator for Vec<T, A> {
+    type Item = T;
+    type IntoIter = IntoIter<T, A>;
+
+    /// Creates a consuming iterator, that is, one that moves each value out of
+    /// the vector (from start to end). The vector cannot be used after calling
+    /// this.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// let v = vec!["a".to_string(), "b".to_string()];
+    /// for s in v.into_iter() {
+    ///     // s has type String, not &String
+    ///     println!("{}", s);
+    /// }
+    /// ```
+    #[inline]
+    fn into_iter(self) -> IntoIter<T, A> {
+        unsafe {
+            let mut me = ManuallyDrop::new(self);
+            let alloc = ptr::read(me.allocator());
+            let begin = me.as_mut_ptr();
+            let end = if mem::size_of::<T>() == 0 {
+                arith_offset(begin as *const i8, me.len() as isize) as *const T
+            } else {
+                begin.add(me.len()) as *const T
+            };
+            let cap = me.buf.capacity();
+            IntoIter {
+                buf: NonNull::new_unchecked(begin),
+                phantom: PhantomData,
+                cap,
+                alloc,
+                ptr: begin,
+                end,
+            }
+        }
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a, T, A: Allocator> IntoIterator for &'a Vec<T, A> {
+    type Item = &'a T;
+    type IntoIter = slice::Iter<'a, T>;
+
+    fn into_iter(self) -> slice::Iter<'a, T> {
+        self.iter()
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a, T, A: Allocator> IntoIterator for &'a mut Vec<T, A> {
+    type Item = &'a mut T;
+    type IntoIter = slice::IterMut<'a, T>;
+
+    fn into_iter(self) -> slice::IterMut<'a, T> {
+        self.iter_mut()
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T, A: Allocator> Extend<T> for Vec<T, A> {
+    #[inline]
+    fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
+        <Self as SpecExtend<T, I::IntoIter>>::spec_extend(self, iter.into_iter())
+    }
+
+    #[inline]
+    fn extend_one(&mut self, item: T) {
+        self.push(item);
+    }
+
+    #[inline]
+    fn extend_reserve(&mut self, additional: usize) {
+        self.reserve(additional);
+    }
+}
+
+impl<T, A: Allocator> Vec<T, A> {
+    // leaf method to which various SpecFrom/SpecExtend implementations delegate when
+    // they have no further optimizations to apply
+    fn extend_desugared<I: Iterator<Item = T>>(&mut self, mut iterator: I) {
+        // This is the case for a general iterator.
+        //
+        // This function should be the moral equivalent of:
+        //
+        //      for item in iterator {
+        //          self.push(item);
+        //      }
+        while let Some(element) = iterator.next() {
+            let len = self.len();
+            if len == self.capacity() {
+                let (lower, _) = iterator.size_hint();
+                self.reserve(lower.saturating_add(1));
+            }
+            unsafe {
+                ptr::write(self.as_mut_ptr().add(len), element);
+                // NB can't overflow since we would have had to alloc the address space
+                self.set_len(len + 1);
+            }
+        }
+    }
+
+    /// Creates a splicing iterator that replaces the specified range in the vector
+    /// with the given `replace_with` iterator and yields the removed items.
+    /// `replace_with` does not need to be the same length as `range`.
+    ///
+    /// `range` is removed even if the iterator is not consumed until the end.
+    ///
+    /// It is unspecified how many elements are removed from the vector
+    /// if the `Splice` value is leaked.
+    ///
+    /// The input iterator `replace_with` is only consumed when the `Splice` value is dropped.
+    ///
+    /// This is optimal if:
+    ///
+    /// * The tail (elements in the vector after `range`) is empty,
+    /// * or `replace_with` yields fewer elements than `range`’s length
+    /// * or the lower bound of its `size_hint()` is exact.
+    ///
+    /// Otherwise, a temporary vector is allocated and the tail is moved twice.
+    ///
+    /// # Panics
+    ///
+    /// Panics if the starting point is greater than the end point or if
+    /// the end point is greater than the length of the vector.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// let mut v = vec![1, 2, 3];
+    /// let new = [7, 8];
+    /// let u: Vec<_> = v.splice(..2, new.iter().cloned()).collect();
+    /// assert_eq!(v, &[7, 8, 3]);
+    /// assert_eq!(u, &[1, 2]);
+    /// ```
+    #[inline]
+    #[stable(feature = "vec_splice", since = "1.21.0")]
+    pub fn splice<R, I>(&mut self, range: R, replace_with: I) -> Splice<'_, I::IntoIter, A>
+    where
+        R: RangeBounds<usize>,
+        I: IntoIterator<Item = T>,
+    {
+        Splice { drain: self.drain(range), replace_with: replace_with.into_iter() }
+    }
+
+    /// Creates an iterator which uses a closure to determine if an element should be removed.
+    ///
+    /// If the closure returns true, then the element is removed and yielded.
+    /// If the closure returns false, the element will remain in the vector and will not be yielded
+    /// by the iterator.
+    ///
+    /// Using this method is equivalent to the following code:
+    ///
+    /// ```
+    /// # let some_predicate = |x: &mut i32| { *x == 2 || *x == 3 || *x == 6 };
+    /// # let mut vec = vec![1, 2, 3, 4, 5, 6];
+    /// let mut i = 0;
+    /// while i != vec.len() {
+    ///     if some_predicate(&mut vec[i]) {
+    ///         let val = vec.remove(i);
+    ///         // your code here
+    ///     } else {
+    ///         i += 1;
+    ///     }
+    /// }
+    ///
+    /// # assert_eq!(vec, vec![1, 4, 5]);
+    /// ```
+    ///
+    /// But `drain_filter` is easier to use. `drain_filter` is also more efficient,
+    /// because it can backshift the elements of the array in bulk.
+    ///
+    /// Note that `drain_filter` also lets you mutate every element in the filter closure,
+    /// regardless of whether you choose to keep or remove it.
+    ///
+    /// # Examples
+    ///
+    /// Splitting an array into evens and odds, reusing the original allocation:
+    ///
+    /// ```
+    /// #![feature(drain_filter)]
+    /// let mut numbers = vec![1, 2, 3, 4, 5, 6, 8, 9, 11, 13, 14, 15];
+    ///
+    /// let evens = numbers.drain_filter(|x| *x % 2 == 0).collect::<Vec<_>>();
+    /// let odds = numbers;
+    ///
+    /// assert_eq!(evens, vec![2, 4, 6, 8, 14]);
+    /// assert_eq!(odds, vec![1, 3, 5, 9, 11, 13, 15]);
+    /// ```
+    #[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")]
+    pub fn drain_filter<F>(&mut self, filter: F) -> DrainFilter<'_, T, F, A>
+    where
+        F: FnMut(&mut T) -> bool,
+    {
+        let old_len = self.len();
+
+        // Guard against us getting leaked (leak amplification)
+        unsafe {
+            self.set_len(0);
+        }
+
+        DrainFilter { vec: self, idx: 0, del: 0, old_len, pred: filter, panic_flag: false }
+    }
+}
+
+/// Extend implementation that copies elements out of references before pushing them onto the Vec.
+///
+/// This implementation is specialized for slice iterators, where it uses [`copy_from_slice`] to
+/// append the entire slice at once.
+///
+/// [`copy_from_slice`]: ../../std/primitive.slice.html#method.copy_from_slice
+#[stable(feature = "extend_ref", since = "1.2.0")]
+impl<'a, T: Copy + 'a, A: Allocator + 'a> Extend<&'a T> for Vec<T, A> {
+    fn extend<I: IntoIterator<Item = &'a T>>(&mut self, iter: I) {
+        self.spec_extend(iter.into_iter())
+    }
+
+    #[inline]
+    fn extend_one(&mut self, &item: &'a T) {
+        self.push(item);
+    }
+
+    #[inline]
+    fn extend_reserve(&mut self, additional: usize) {
+        self.reserve(additional);
+    }
+}
+
+/// Implements comparison of vectors, [lexicographically](core::cmp::Ord#lexicographical-comparison).
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: PartialOrd, A: Allocator> PartialOrd for Vec<T, A> {
+    #[inline]
+    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+        PartialOrd::partial_cmp(&**self, &**other)
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: Eq, A: Allocator> Eq for Vec<T, A> {}
+
+/// Implements ordering of vectors, [lexicographically](core::cmp::Ord#lexicographical-comparison).
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: Ord, A: Allocator> Ord for Vec<T, A> {
+    #[inline]
+    fn cmp(&self, other: &Self) -> Ordering {
+        Ord::cmp(&**self, &**other)
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+unsafe impl<#[may_dangle] T, A: Allocator> Drop for Vec<T, A> {
+    fn drop(&mut self) {
+        unsafe {
+            // use drop for [T]
+            // use a raw slice to refer to the elements of the vector as weakest necessary type;
+            // could avoid questions of validity in certain cases
+            ptr::drop_in_place(ptr::slice_from_raw_parts_mut(self.as_mut_ptr(), self.len))
+        }
+        // RawVec handles deallocation
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T> Default for Vec<T> {
+    /// Creates an empty `Vec<T>`.
+    fn default() -> Vec<T> {
+        Vec::new()
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: fmt::Debug, A: Allocator> fmt::Debug for Vec<T, A> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt::Debug::fmt(&**self, f)
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T, A: Allocator> AsRef<Vec<T, A>> for Vec<T, A> {
+    fn as_ref(&self) -> &Vec<T, A> {
+        self
+    }
+}
+
+#[stable(feature = "vec_as_mut", since = "1.5.0")]
+impl<T, A: Allocator> AsMut<Vec<T, A>> for Vec<T, A> {
+    fn as_mut(&mut self) -> &mut Vec<T, A> {
+        self
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T, A: Allocator> AsRef<[T]> for Vec<T, A> {
+    fn as_ref(&self) -> &[T] {
+        self
+    }
+}
+
+#[stable(feature = "vec_as_mut", since = "1.5.0")]
+impl<T, A: Allocator> AsMut<[T]> for Vec<T, A> {
+    fn as_mut(&mut self) -> &mut [T] {
+        self
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: Clone> From<&[T]> for Vec<T> {
+    #[cfg(not(test))]
+    fn from(s: &[T]) -> Vec<T> {
+        s.to_vec()
+    }
+    #[cfg(test)]
+    fn from(s: &[T]) -> Vec<T> {
+        crate::slice::to_vec(s, Global)
+    }
+}
+
+#[stable(feature = "vec_from_mut", since = "1.19.0")]
+impl<T: Clone> From<&mut [T]> for Vec<T> {
+    #[cfg(not(test))]
+    fn from(s: &mut [T]) -> Vec<T> {
+        s.to_vec()
+    }
+    #[cfg(test)]
+    fn from(s: &mut [T]) -> Vec<T> {
+        crate::slice::to_vec(s, Global)
+    }
+}
+
+#[stable(feature = "vec_from_array", since = "1.44.0")]
+impl<T, const N: usize> From<[T; N]> for Vec<T> {
+    #[cfg(not(test))]
+    fn from(s: [T; N]) -> Vec<T> {
+        <[T]>::into_vec(box s)
+    }
+    #[cfg(test)]
+    fn from(s: [T; N]) -> Vec<T> {
+        crate::slice::into_vec(box s)
+    }
+}
+
+#[stable(feature = "vec_from_cow_slice", since = "1.14.0")]
+impl<'a, T> From<Cow<'a, [T]>> for Vec<T>
+where
+    [T]: ToOwned<Owned = Vec<T>>,
+{
+    fn from(s: Cow<'a, [T]>) -> Vec<T> {
+        s.into_owned()
+    }
+}
+
+// note: test pulls in libstd, which causes errors here
+#[cfg(not(test))]
+#[stable(feature = "vec_from_box", since = "1.18.0")]
+impl<T, A: Allocator> From<Box<[T], A>> for Vec<T, A> {
+    fn from(s: Box<[T], A>) -> Self {
+        let len = s.len();
+        Self { buf: RawVec::from_box(s), len }
+    }
+}
+
+// note: test pulls in libstd, which causes errors here
+#[cfg(not(test))]
+#[stable(feature = "box_from_vec", since = "1.20.0")]
+impl<T, A: Allocator> From<Vec<T, A>> for Box<[T], A> {
+    fn from(v: Vec<T, A>) -> Self {
+        v.into_boxed_slice()
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl From<&str> for Vec<u8> {
+    fn from(s: &str) -> Vec<u8> {
+        From::from(s.as_bytes())
+    }
+}
+
+#[stable(feature = "array_try_from_vec", since = "1.48.0")]
+impl<T, A: Allocator, const N: usize> TryFrom<Vec<T, A>> for [T; N] {
+    type Error = Vec<T, A>;
+
+    /// Gets the entire contents of the `Vec<T>` as an array,
+    /// if its size exactly matches that of the requested array.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::convert::TryInto;
+    /// assert_eq!(vec![1, 2, 3].try_into(), Ok([1, 2, 3]));
+    /// assert_eq!(<Vec<i32>>::new().try_into(), Ok([]));
+    /// ```
+    ///
+    /// If the length doesn't match, the input comes back in `Err`:
+    /// ```
+    /// use std::convert::TryInto;
+    /// let r: Result<[i32; 4], _> = (0..10).collect::<Vec<_>>().try_into();
+    /// assert_eq!(r, Err(vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9]));
+    /// ```
+    ///
+    /// If you're fine with just getting a prefix of the `Vec<T>`,
+    /// you can call [`.truncate(N)`](Vec::truncate) first.
+    /// ```
+    /// use std::convert::TryInto;
+    /// let mut v = String::from("hello world").into_bytes();
+    /// v.sort();
+    /// v.truncate(2);
+    /// let [a, b]: [_; 2] = v.try_into().unwrap();
+    /// assert_eq!(a, b' ');
+    /// assert_eq!(b, b'd');
+    /// ```
+    fn try_from(mut vec: Vec<T, A>) -> Result<[T; N], Vec<T, A>> {
+        if vec.len() != N {
+            return Err(vec);
+        }
+
+        // SAFETY: `.set_len(0)` is always sound.
+        unsafe { vec.set_len(0) };
+
+        // SAFETY: A `Vec`'s pointer is always aligned properly, and
+        // the alignment the array needs is the same as the items.
+        // We checked earlier that we have sufficient items.
+        // The items will not double-drop as the `set_len`
+        // tells the `Vec` not to also drop them.
+        let array = unsafe { ptr::read(vec.as_ptr() as *const [T; N]) };
+        Ok(array)
+    }
+}
diff --git a/library/alloc/src/vec/partial_eq.rs b/library/alloc/src/vec/partial_eq.rs
new file mode 100644 (file)
index 0000000..ff90b6c
--- /dev/null
@@ -0,0 +1,43 @@
+use crate::alloc::Allocator;
+use crate::borrow::Cow;
+
+use super::Vec;
+
+macro_rules! __impl_slice_eq1 {
+    ([$($vars:tt)*] $lhs:ty, $rhs:ty $(where $ty:ty: $bound:ident)?, #[$stability:meta]) => {
+        #[$stability]
+        impl<T, U, $($vars)*> PartialEq<$rhs> for $lhs
+        where
+            T: PartialEq<U>,
+            $($ty: $bound)?
+        {
+            #[inline]
+            fn eq(&self, other: &$rhs) -> bool { self[..] == other[..] }
+            #[inline]
+            fn ne(&self, other: &$rhs) -> bool { self[..] != other[..] }
+        }
+    }
+}
+
+__impl_slice_eq1! { [A: Allocator] Vec<T, A>, Vec<U, A>, #[stable(feature = "rust1", since = "1.0.0")] }
+__impl_slice_eq1! { [A: Allocator] Vec<T, A>, &[U], #[stable(feature = "rust1", since = "1.0.0")] }
+__impl_slice_eq1! { [A: Allocator] Vec<T, A>, &mut [U], #[stable(feature = "rust1", since = "1.0.0")] }
+__impl_slice_eq1! { [A: Allocator] &[T], Vec<U, A>, #[stable(feature = "partialeq_vec_for_ref_slice", since = "1.46.0")] }
+__impl_slice_eq1! { [A: Allocator] &mut [T], Vec<U, A>, #[stable(feature = "partialeq_vec_for_ref_slice", since = "1.46.0")] }
+__impl_slice_eq1! { [A: Allocator] Vec<T, A>, [U], #[stable(feature = "partialeq_vec_for_slice", since = "1.48.0")]  }
+__impl_slice_eq1! { [A: Allocator] [T], Vec<U, A>, #[stable(feature = "partialeq_vec_for_slice", since = "1.48.0")]  }
+__impl_slice_eq1! { [A: Allocator] Cow<'_, [T]>, Vec<U, A> where T: Clone, #[stable(feature = "rust1", since = "1.0.0")] }
+__impl_slice_eq1! { [] Cow<'_, [T]>, &[U] where T: Clone, #[stable(feature = "rust1", since = "1.0.0")] }
+__impl_slice_eq1! { [] Cow<'_, [T]>, &mut [U] where T: Clone, #[stable(feature = "rust1", since = "1.0.0")] }
+__impl_slice_eq1! { [A: Allocator, const N: usize] Vec<T, A>, [U; N], #[stable(feature = "rust1", since = "1.0.0")] }
+__impl_slice_eq1! { [A: Allocator, const N: usize] Vec<T, A>, &[U; N], #[stable(feature = "rust1", since = "1.0.0")] }
+
+// NOTE: some less important impls are omitted to reduce code bloat
+// FIXME(Centril): Reconsider this?
+//__impl_slice_eq1! { [const N: usize] Vec<A>, &mut [B; N], }
+//__impl_slice_eq1! { [const N: usize] [A; N], Vec<B>, }
+//__impl_slice_eq1! { [const N: usize] &[A; N], Vec<B>, }
+//__impl_slice_eq1! { [const N: usize] &mut [A; N], Vec<B>, }
+//__impl_slice_eq1! { [const N: usize] Cow<'a, [A]>, [B; N], }
+//__impl_slice_eq1! { [const N: usize] Cow<'a, [A]>, &[B; N], }
+//__impl_slice_eq1! { [const N: usize] Cow<'a, [A]>, &mut [B; N], }
diff --git a/library/alloc/src/vec/set_len_on_drop.rs b/library/alloc/src/vec/set_len_on_drop.rs
new file mode 100644 (file)
index 0000000..8b66bc8
--- /dev/null
@@ -0,0 +1,28 @@
+// Set the length of the vec when the `SetLenOnDrop` value goes out of scope.
+//
+// The idea is: The length field in SetLenOnDrop is a local variable
+// that the optimizer will see does not alias with any stores through the Vec's data
+// pointer. This is a workaround for alias analysis issue #32155
+pub(super) struct SetLenOnDrop<'a> {
+    len: &'a mut usize,
+    local_len: usize,
+}
+
+impl<'a> SetLenOnDrop<'a> {
+    #[inline]
+    pub(super) fn new(len: &'a mut usize) -> Self {
+        SetLenOnDrop { local_len: *len, len }
+    }
+
+    #[inline]
+    pub(super) fn increment_len(&mut self, increment: usize) {
+        self.local_len += increment;
+    }
+}
+
+impl Drop for SetLenOnDrop<'_> {
+    #[inline]
+    fn drop(&mut self) {
+        *self.len = self.local_len;
+    }
+}
diff --git a/library/alloc/src/vec/source_iter_marker.rs b/library/alloc/src/vec/source_iter_marker.rs
new file mode 100644 (file)
index 0000000..8c0e955
--- /dev/null
@@ -0,0 +1,108 @@
+use core::iter::{InPlaceIterable, SourceIter};
+use core::mem::{self, ManuallyDrop};
+use core::ptr::{self};
+
+use super::{AsIntoIter, InPlaceDrop, SpecFromIter, SpecFromIterNested, Vec};
+
+/// Specialization marker for collecting an iterator pipeline into a Vec while reusing the
+/// source allocation, i.e. executing the pipeline in place.
+///
+/// The SourceIter parent trait is necessary for the specializing function to access the allocation
+/// which is to be reused. But it is not sufficient for the specialization to be valid. See
+/// additional bounds on the impl.
+#[rustc_unsafe_specialization_marker]
+pub(super) trait SourceIterMarker: SourceIter<Source: AsIntoIter> {}
+
+// The std-internal SourceIter/InPlaceIterable traits are only implemented by chains of
+// Adapter<Adapter<Adapter<IntoIter>>> (all owned by core/std). Additional bounds
+// on the adapter implementations (beyond `impl<I: Trait> Trait for Adapter<I>`) only depend on other
+// traits already marked as specialization traits (Copy, TrustedRandomAccess, FusedIterator).
+// I.e. the marker does not depend on lifetimes of user-supplied types. Modulo the Copy hole, which
+// several other specializations already depend on.
+impl<T> SourceIterMarker for T where T: SourceIter<Source: AsIntoIter> + InPlaceIterable {}
+
+impl<T, I> SpecFromIter<T, I> for Vec<T>
+where
+    I: Iterator<Item = T> + SourceIterMarker,
+{
+    default fn from_iter(mut iterator: I) -> Self {
+        // Additional requirements which cannot expressed via trait bounds. We rely on const eval
+        // instead:
+        // a) no ZSTs as there would be no allocation to reuse and pointer arithmetic would panic
+        // b) size match as required by Alloc contract
+        // c) alignments match as required by Alloc contract
+        if mem::size_of::<T>() == 0
+            || mem::size_of::<T>()
+                != mem::size_of::<<<I as SourceIter>::Source as AsIntoIter>::Item>()
+            || mem::align_of::<T>()
+                != mem::align_of::<<<I as SourceIter>::Source as AsIntoIter>::Item>()
+        {
+            // fallback to more generic implementations
+            return SpecFromIterNested::from_iter(iterator);
+        }
+
+        let (src_buf, src_ptr, dst_buf, dst_end, cap) = unsafe {
+            let inner = iterator.as_inner().as_into_iter();
+            (
+                inner.buf.as_ptr(),
+                inner.ptr,
+                inner.buf.as_ptr() as *mut T,
+                inner.end as *const T,
+                inner.cap,
+            )
+        };
+
+        // use try-fold since
+        // - it vectorizes better for some iterator adapters
+        // - unlike most internal iteration methods, it only takes a &mut self
+        // - it lets us thread the write pointer through its innards and get it back in the end
+        let sink = InPlaceDrop { inner: dst_buf, dst: dst_buf };
+        let sink = iterator
+            .try_fold::<_, _, Result<_, !>>(sink, write_in_place_with_drop(dst_end))
+            .unwrap();
+        // iteration succeeded, don't drop head
+        let dst = ManuallyDrop::new(sink).dst;
+
+        let src = unsafe { iterator.as_inner().as_into_iter() };
+        // check if SourceIter contract was upheld
+        // caveat: if they weren't we may not even make it to this point
+        debug_assert_eq!(src_buf, src.buf.as_ptr());
+        // check InPlaceIterable contract. This is only possible if the iterator advanced the
+        // source pointer at all. If it uses unchecked access via TrustedRandomAccess
+        // then the source pointer will stay in its initial position and we can't use it as reference
+        if src.ptr != src_ptr {
+            debug_assert!(
+                dst as *const _ <= src.ptr,
+                "InPlaceIterable contract violation, write pointer advanced beyond read pointer"
+            );
+        }
+
+        // drop any remaining values at the tail of the source
+        src.drop_remaining();
+        // but prevent drop of the allocation itself once IntoIter goes out of scope
+        src.forget_allocation();
+
+        let vec = unsafe {
+            let len = dst.offset_from(dst_buf) as usize;
+            Vec::from_raw_parts(dst_buf, len, cap)
+        };
+
+        vec
+    }
+}
+
+fn write_in_place_with_drop<T>(
+    src_end: *const T,
+) -> impl FnMut(InPlaceDrop<T>, T) -> Result<InPlaceDrop<T>, !> {
+    move |mut sink, item| {
+        unsafe {
+            // the InPlaceIterable contract cannot be verified precisely here since
+            // try_fold has an exclusive reference to the source pointer
+            // all we can do is check if it's still in range
+            debug_assert!(sink.dst as *const _ <= src_end, "InPlaceIterable contract violation");
+            ptr::write(sink.dst, item);
+            sink.dst = sink.dst.add(1);
+        }
+        Ok(sink)
+    }
+}
diff --git a/library/alloc/src/vec/spec_extend.rs b/library/alloc/src/vec/spec_extend.rs
new file mode 100644 (file)
index 0000000..b6186a7
--- /dev/null
@@ -0,0 +1,82 @@
+use crate::alloc::Allocator;
+use core::iter::TrustedLen;
+use core::ptr::{self};
+use core::slice::{self};
+
+use super::{IntoIter, SetLenOnDrop, Vec};
+
+// Specialization trait used for Vec::extend
+pub(super) trait SpecExtend<T, I> {
+    fn spec_extend(&mut self, iter: I);
+}
+
+impl<T, I, A: Allocator> SpecExtend<T, I> for Vec<T, A>
+where
+    I: Iterator<Item = T>,
+{
+    default fn spec_extend(&mut self, iter: I) {
+        self.extend_desugared(iter)
+    }
+}
+
+impl<T, I, A: Allocator> SpecExtend<T, I> for Vec<T, A>
+where
+    I: TrustedLen<Item = T>,
+{
+    default fn spec_extend(&mut self, iterator: I) {
+        // This is the case for a TrustedLen iterator.
+        let (low, high) = iterator.size_hint();
+        if let Some(high_value) = high {
+            debug_assert_eq!(
+                low,
+                high_value,
+                "TrustedLen iterator's size hint is not exact: {:?}",
+                (low, high)
+            );
+        }
+        if let Some(additional) = high {
+            self.reserve(additional);
+            unsafe {
+                let mut ptr = self.as_mut_ptr().add(self.len());
+                let mut local_len = SetLenOnDrop::new(&mut self.len);
+                iterator.for_each(move |element| {
+                    ptr::write(ptr, element);
+                    ptr = ptr.offset(1);
+                    // NB can't overflow since we would have had to alloc the address space
+                    local_len.increment_len(1);
+                });
+            }
+        } else {
+            self.extend_desugared(iterator)
+        }
+    }
+}
+
+impl<T, A: Allocator> SpecExtend<T, IntoIter<T>> for Vec<T, A> {
+    fn spec_extend(&mut self, mut iterator: IntoIter<T>) {
+        unsafe {
+            self.append_elements(iterator.as_slice() as _);
+        }
+        iterator.ptr = iterator.end;
+    }
+}
+
+impl<'a, T: 'a, I, A: Allocator + 'a> SpecExtend<&'a T, I> for Vec<T, A>
+where
+    I: Iterator<Item = &'a T>,
+    T: Clone,
+{
+    default fn spec_extend(&mut self, iterator: I) {
+        self.spec_extend(iterator.cloned())
+    }
+}
+
+impl<'a, T: 'a, A: Allocator + 'a> SpecExtend<&'a T, slice::Iter<'a, T>> for Vec<T, A>
+where
+    T: Copy,
+{
+    fn spec_extend(&mut self, iterator: slice::Iter<'a, T>) {
+        let slice = iterator.as_slice();
+        unsafe { self.append_elements(slice) };
+    }
+}
diff --git a/library/alloc/src/vec/spec_from_elem.rs b/library/alloc/src/vec/spec_from_elem.rs
new file mode 100644 (file)
index 0000000..de61017
--- /dev/null
@@ -0,0 +1,60 @@
+use crate::alloc::Allocator;
+use crate::raw_vec::RawVec;
+use core::ptr::{self};
+
+use super::{ExtendElement, IsZero, Vec};
+
+// Specialization trait used for Vec::from_elem
+pub(super) trait SpecFromElem: Sized {
+    fn from_elem<A: Allocator>(elem: Self, n: usize, alloc: A) -> Vec<Self, A>;
+}
+
+impl<T: Clone> SpecFromElem for T {
+    default fn from_elem<A: Allocator>(elem: Self, n: usize, alloc: A) -> Vec<Self, A> {
+        let mut v = Vec::with_capacity_in(n, alloc);
+        v.extend_with(n, ExtendElement(elem));
+        v
+    }
+}
+
+impl SpecFromElem for i8 {
+    #[inline]
+    fn from_elem<A: Allocator>(elem: i8, n: usize, alloc: A) -> Vec<i8, A> {
+        if elem == 0 {
+            return Vec { buf: RawVec::with_capacity_zeroed_in(n, alloc), len: n };
+        }
+        unsafe {
+            let mut v = Vec::with_capacity_in(n, alloc);
+            ptr::write_bytes(v.as_mut_ptr(), elem as u8, n);
+            v.set_len(n);
+            v
+        }
+    }
+}
+
+impl SpecFromElem for u8 {
+    #[inline]
+    fn from_elem<A: Allocator>(elem: u8, n: usize, alloc: A) -> Vec<u8, A> {
+        if elem == 0 {
+            return Vec { buf: RawVec::with_capacity_zeroed_in(n, alloc), len: n };
+        }
+        unsafe {
+            let mut v = Vec::with_capacity_in(n, alloc);
+            ptr::write_bytes(v.as_mut_ptr(), elem, n);
+            v.set_len(n);
+            v
+        }
+    }
+}
+
+impl<T: Clone + IsZero> SpecFromElem for T {
+    #[inline]
+    fn from_elem<A: Allocator>(elem: T, n: usize, alloc: A) -> Vec<T, A> {
+        if elem.is_zero() {
+            return Vec { buf: RawVec::with_capacity_zeroed_in(n, alloc), len: n };
+        }
+        let mut v = Vec::with_capacity_in(n, alloc);
+        v.extend_with(n, ExtendElement(elem));
+        v
+    }
+}
diff --git a/library/alloc/src/vec/spec_from_iter.rs b/library/alloc/src/vec/spec_from_iter.rs
new file mode 100644 (file)
index 0000000..bbfcc68
--- /dev/null
@@ -0,0 +1,97 @@
+use core::mem::ManuallyDrop;
+use core::ptr::{self};
+use core::slice::{self};
+
+use super::{IntoIter, SpecExtend, SpecFromIterNested, Vec};
+
+/// Specialization trait used for Vec::from_iter
+///
+/// ## The delegation graph:
+///
+/// ```text
+/// +-------------+
+/// |FromIterator |
+/// +-+-----------+
+///   |
+///   v
+/// +-+-------------------------------+  +---------------------+
+/// |SpecFromIter                  +---->+SpecFromIterNested   |
+/// |where I:                      |  |  |where I:             |
+/// |  Iterator (default)----------+  |  |  Iterator (default) |
+/// |  vec::IntoIter               |  |  |  TrustedLen         |
+/// |  SourceIterMarker---fallback-+  |  |                     |
+/// |  slice::Iter                    |  |                     |
+/// |  Iterator<Item = &Clone>        |  +---------------------+
+/// +---------------------------------+
+/// ```
+pub(super) trait SpecFromIter<T, I> {
+    fn from_iter(iter: I) -> Self;
+}
+
+impl<T, I> SpecFromIter<T, I> for Vec<T>
+where
+    I: Iterator<Item = T>,
+{
+    default fn from_iter(iterator: I) -> Self {
+        SpecFromIterNested::from_iter(iterator)
+    }
+}
+
+impl<T> SpecFromIter<T, IntoIter<T>> for Vec<T> {
+    fn from_iter(iterator: IntoIter<T>) -> Self {
+        // A common case is passing a vector into a function which immediately
+        // re-collects into a vector. We can short circuit this if the IntoIter
+        // has not been advanced at all.
+        // When it has been advanced We can also reuse the memory and move the data to the front.
+        // But we only do so when the resulting Vec wouldn't have more unused capacity
+        // than creating it through the generic FromIterator implementation would. That limitation
+        // is not strictly necessary as Vec's allocation behavior is intentionally unspecified.
+        // But it is a conservative choice.
+        let has_advanced = iterator.buf.as_ptr() as *const _ != iterator.ptr;
+        if !has_advanced || iterator.len() >= iterator.cap / 2 {
+            unsafe {
+                let it = ManuallyDrop::new(iterator);
+                if has_advanced {
+                    ptr::copy(it.ptr, it.buf.as_ptr(), it.len());
+                }
+                return Vec::from_raw_parts(it.buf.as_ptr(), it.len(), it.cap);
+            }
+        }
+
+        let mut vec = Vec::new();
+        // must delegate to spec_extend() since extend() itself delegates
+        // to spec_from for empty Vecs
+        vec.spec_extend(iterator);
+        vec
+    }
+}
+
+impl<'a, T: 'a, I> SpecFromIter<&'a T, I> for Vec<T>
+where
+    I: Iterator<Item = &'a T>,
+    T: Clone,
+{
+    default fn from_iter(iterator: I) -> Self {
+        SpecFromIter::from_iter(iterator.cloned())
+    }
+}
+
+// This utilizes `iterator.as_slice().to_vec()` since spec_extend
+// must take more steps to reason about the final capacity + length
+// and thus do more work. `to_vec()` directly allocates the correct amount
+// and fills it exactly.
+impl<'a, T: 'a + Clone> SpecFromIter<&'a T, slice::Iter<'a, T>> for Vec<T> {
+    #[cfg(not(test))]
+    fn from_iter(iterator: slice::Iter<'a, T>) -> Self {
+        iterator.as_slice().to_vec()
+    }
+
+    // HACK(japaric): with cfg(test) the inherent `[T]::to_vec` method, which is
+    // required for this method definition, is not available. Instead use the
+    // `slice::to_vec`  function which is only available with cfg(test)
+    // NB see the slice::hack module in slice.rs for more information
+    #[cfg(test)]
+    fn from_iter(iterator: slice::Iter<'a, T>) -> Self {
+        crate::slice::to_vec(iterator.as_slice(), crate::alloc::Global)
+    }
+}
diff --git a/library/alloc/src/vec/spec_from_iter_nested.rs b/library/alloc/src/vec/spec_from_iter_nested.rs
new file mode 100644 (file)
index 0000000..6abd4ff
--- /dev/null
@@ -0,0 +1,56 @@
+use core::iter::TrustedLen;
+use core::ptr::{self};
+
+use super::{SpecExtend, Vec};
+
+/// Another specialization trait for Vec::from_iter
+/// necessary to manually prioritize overlapping specializations
+/// see [`SpecFromIter`] for details.
+pub(super) trait SpecFromIterNested<T, I> {
+    fn from_iter(iter: I) -> Self;
+}
+
+impl<T, I> SpecFromIterNested<T, I> for Vec<T>
+where
+    I: Iterator<Item = T>,
+{
+    default fn from_iter(mut iterator: I) -> Self {
+        // Unroll the first iteration, as the vector is going to be
+        // expanded on this iteration in every case when the iterable is not
+        // empty, but the loop in extend_desugared() is not going to see the
+        // vector being full in the few subsequent loop iterations.
+        // So we get better branch prediction.
+        let mut vector = match iterator.next() {
+            None => return Vec::new(),
+            Some(element) => {
+                let (lower, _) = iterator.size_hint();
+                let mut vector = Vec::with_capacity(lower.saturating_add(1));
+                unsafe {
+                    ptr::write(vector.as_mut_ptr(), element);
+                    vector.set_len(1);
+                }
+                vector
+            }
+        };
+        // must delegate to spec_extend() since extend() itself delegates
+        // to spec_from for empty Vecs
+        <Vec<T> as SpecExtend<T, I>>::spec_extend(&mut vector, iterator);
+        vector
+    }
+}
+
+impl<T, I> SpecFromIterNested<T, I> for Vec<T>
+where
+    I: TrustedLen<Item = T>,
+{
+    fn from_iter(iterator: I) -> Self {
+        let mut vector = match iterator.size_hint() {
+            (_, Some(upper)) => Vec::with_capacity(upper),
+            _ => Vec::new(),
+        };
+        // must delegate to spec_extend() since extend() itself delegates
+        // to spec_from for empty Vecs
+        vector.spec_extend(iterator);
+        vector
+    }
+}
diff --git a/library/alloc/src/vec/splice.rs b/library/alloc/src/vec/splice.rs
new file mode 100644 (file)
index 0000000..0a27b5b
--- /dev/null
@@ -0,0 +1,133 @@
+use crate::alloc::{Allocator, Global};
+use core::ptr::{self};
+use core::slice::{self};
+
+use super::{Drain, Vec};
+
+/// A splicing iterator for `Vec`.
+///
+/// This struct is created by [`Vec::splice()`].
+/// See its documentation for more.
+///
+/// # Example
+///
+/// ```
+/// let mut v = vec![0, 1, 2];
+/// let new = [7, 8];
+/// let iter: std::vec::Splice<_> = v.splice(1.., new.iter().cloned());
+/// ```
+#[derive(Debug)]
+#[stable(feature = "vec_splice", since = "1.21.0")]
+pub struct Splice<
+    'a,
+    I: Iterator + 'a,
+    #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator + 'a = Global,
+> {
+    pub(super) drain: Drain<'a, I::Item, A>,
+    pub(super) replace_with: I,
+}
+
+#[stable(feature = "vec_splice", since = "1.21.0")]
+impl<I: Iterator, A: Allocator> Iterator for Splice<'_, I, A> {
+    type Item = I::Item;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        self.drain.next()
+    }
+
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        self.drain.size_hint()
+    }
+}
+
+#[stable(feature = "vec_splice", since = "1.21.0")]
+impl<I: Iterator, A: Allocator> DoubleEndedIterator for Splice<'_, I, A> {
+    fn next_back(&mut self) -> Option<Self::Item> {
+        self.drain.next_back()
+    }
+}
+
+#[stable(feature = "vec_splice", since = "1.21.0")]
+impl<I: Iterator, A: Allocator> ExactSizeIterator for Splice<'_, I, A> {}
+
+#[stable(feature = "vec_splice", since = "1.21.0")]
+impl<I: Iterator, A: Allocator> Drop for Splice<'_, I, A> {
+    fn drop(&mut self) {
+        self.drain.by_ref().for_each(drop);
+
+        unsafe {
+            if self.drain.tail_len == 0 {
+                self.drain.vec.as_mut().extend(self.replace_with.by_ref());
+                return;
+            }
+
+            // First fill the range left by drain().
+            if !self.drain.fill(&mut self.replace_with) {
+                return;
+            }
+
+            // There may be more elements. Use the lower bound as an estimate.
+            // FIXME: Is the upper bound a better guess? Or something else?
+            let (lower_bound, _upper_bound) = self.replace_with.size_hint();
+            if lower_bound > 0 {
+                self.drain.move_tail(lower_bound);
+                if !self.drain.fill(&mut self.replace_with) {
+                    return;
+                }
+            }
+
+            // Collect any remaining elements.
+            // This is a zero-length vector which does not allocate if `lower_bound` was exact.
+            let mut collected = self.replace_with.by_ref().collect::<Vec<I::Item>>().into_iter();
+            // Now we have an exact count.
+            if collected.len() > 0 {
+                self.drain.move_tail(collected.len());
+                let filled = self.drain.fill(&mut collected);
+                debug_assert!(filled);
+                debug_assert_eq!(collected.len(), 0);
+            }
+        }
+        // Let `Drain::drop` move the tail back if necessary and restore `vec.len`.
+    }
+}
+
+/// Private helper methods for `Splice::drop`
+impl<T, A: Allocator> Drain<'_, T, A> {
+    /// The range from `self.vec.len` to `self.tail_start` contains elements
+    /// that have been moved out.
+    /// Fill that range as much as possible with new elements from the `replace_with` iterator.
+    /// Returns `true` if we filled the entire range. (`replace_with.next()` didn’t return `None`.)
+    unsafe fn fill<I: Iterator<Item = T>>(&mut self, replace_with: &mut I) -> bool {
+        let vec = unsafe { self.vec.as_mut() };
+        let range_start = vec.len;
+        let range_end = self.tail_start;
+        let range_slice = unsafe {
+            slice::from_raw_parts_mut(vec.as_mut_ptr().add(range_start), range_end - range_start)
+        };
+
+        for place in range_slice {
+            if let Some(new_item) = replace_with.next() {
+                unsafe { ptr::write(place, new_item) };
+                vec.len += 1;
+            } else {
+                return false;
+            }
+        }
+        true
+    }
+
+    /// Makes room for inserting more elements before the tail.
+    unsafe fn move_tail(&mut self, additional: usize) {
+        let vec = unsafe { self.vec.as_mut() };
+        let len = self.tail_start + self.tail_len;
+        vec.buf.reserve(len, additional);
+
+        let new_tail_start = self.tail_start + additional;
+        unsafe {
+            let src = vec.as_ptr().add(self.tail_start);
+            let dst = vec.as_mut_ptr().add(new_tail_start);
+            ptr::copy(src, dst, self.tail_len);
+        }
+        self.tail_start = new_tail_start;
+    }
+}
index b7cc03f8eb999403f45f2a70939bbf92f960c569..b56437bd188fe70575d1ddc4395742f59c0aef68 100644 (file)
@@ -16,7 +16,6 @@
 #![feature(slice_ptr_get)]
 #![feature(split_inclusive)]
 #![feature(binary_heap_retain)]
-#![feature(deque_range)]
 #![feature(inplace_iteration)]
 #![feature(iter_map_while)]
 #![feature(int_bits_const)]
index c198797e650f6f05e263fc850f0fd2820c44533c..6ec0f0b5ffc5b6200d0b0d23f9c3160da582eeb0 100644 (file)
 /// * `Layout` queries and calculations in general must be correct. Callers of
 ///   this trait are allowed to rely on the contracts defined on each method,
 ///   and implementors must ensure such contracts remain true.
+///
+/// * You may not rely on allocations actually happening, even if there are explicit
+///   heap allocations in the source. The optimizer may detect unused allocations that it can either
+///   eliminate entirely or move to the stack and thus never invoke the allocator. The
+///   optimizer may further assume that allocation is infallible, so code that used to fail due
+///   to allocator failures may now suddenly work because the optimizer worked around the
+///   need for an allocation. More concretely, the following code example is unsound, irrespective
+///   of whether your custom allocator allows counting how many allocations have happened.
+///
+///   ```rust,ignore (unsound and has placeholders)
+///   drop(Box::new(42));
+///   let number_of_heap_allocs = /* call private allocator API */;
+///   unsafe { std::intrinsics::assume(number_of_heap_allocs > 0); }
+///   ```
+///
+///   Note that the optimizations mentioned above are not the only
+///   optimization that can be applied. You may generally not rely on heap allocations
+///   happening if they can be removed without changing program behavior.
+///   Whether allocations happen or not is not part of the program behavior, even if it
+///   could be detected via an allocator that tracks allocations by printing or otherwise
+///   having side effects.
 #[stable(feature = "global_alloc", since = "1.28.0")]
 pub unsafe trait GlobalAlloc {
     /// Allocate memory as described by the given `layout`.
index a7cb1023229bb68d7c22dd82b5114675f270354b..71548bec7aaeeed40612784ef5413548ac8e36ab 100644 (file)
@@ -463,6 +463,37 @@ fn drop(&mut self) {
         unsafe { crate::mem::transmute_copy::<_, [U; N]>(&dst) }
     }
 
+    /// 'Zips up' two arrays into a single array of pairs.
+    ///
+    /// `zip()` returns a new array where every element is a tuple where the
+    /// first element comes from the first array, and the second element comes
+    /// from the second array. In other words, it zips two arrays together,
+    /// into a single one.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(array_zip)]
+    /// let x = [1, 2, 3];
+    /// let y = [4, 5, 6];
+    /// let z = x.zip(y);
+    /// assert_eq!(z, [(1, 4), (2, 5), (3, 6)]);
+    /// ```
+    #[unstable(feature = "array_zip", issue = "80094")]
+    pub fn zip<U>(self, rhs: [U; N]) -> [(T, U); N] {
+        use crate::mem::MaybeUninit;
+
+        let mut dst = MaybeUninit::uninit_array::<N>();
+        for (i, (lhs, rhs)) in IntoIter::new(self).zip(IntoIter::new(rhs)).enumerate() {
+            dst[i].write((lhs, rhs));
+        }
+        // FIXME: Convert to crate::mem::transmute once it works with generics.
+        // unsafe { crate::mem::transmute::<[MaybeUninit<U>; N], [U; N]>(dst) }
+        // SAFETY: At this point we've properly initialized the whole array
+        // and we just need to cast it to the correct type.
+        unsafe { crate::mem::transmute_copy::<_, [(T, U); N]>(&dst) }
+    }
+
     /// Returns a slice containing the entire array. Equivalent to `&s[..]`.
     #[unstable(feature = "array_methods", issue = "76118")]
     pub fn as_slice(&self) -> &[T] {
index 394db5b5917f007a82253f9df9cfcc50b1d473cd..de05a8c82e8f6a6d373f151d0c037391df1221ac 100644 (file)
@@ -47,6 +47,7 @@
 ///
 /// assert_eq!(None, c);
 /// ```
+#[doc(alias = "chr")]
 #[inline]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub fn from_u32(i: u32) -> Option<char> {
index 52921822693854f19ea8434be128d0cbb9ac165b..938dc214486a67a6b04c4aa8938c0b47fffab89a 100644 (file)
 
     /// Allocate at compile time. Should not be called at runtime.
     #[rustc_const_unstable(feature = "const_heap", issue = "79597")]
-    #[cfg(not(bootstrap))]
     pub fn const_allocate(size: usize, align: usize) -> *mut u8;
 }
 
@@ -1846,20 +1845,22 @@ pub(crate) fn is_nonoverlapping<T>(src: *const T, dst: *const T, count: usize) -
 /// [`Vec::append`]: ../../std/vec/struct.Vec.html#method.append
 #[doc(alias = "memcpy")]
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "none")]
 #[inline]
-pub unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize) {
+pub const unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize) {
     extern "rust-intrinsic" {
         fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize);
     }
 
-    if cfg!(debug_assertions)
+    // FIXME: Perform these checks only at run time
+    /*if cfg!(debug_assertions)
         && !(is_aligned_and_not_null(src)
             && is_aligned_and_not_null(dst)
             && is_nonoverlapping(src, dst, count))
     {
         // Not panicking to keep codegen impact smaller.
         abort();
-    }
+    }*/
 
     // SAFETY: the safety contract for `copy_nonoverlapping` must be
     // upheld by the caller.
@@ -1928,16 +1929,19 @@ pub unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize) {
 /// ```
 #[doc(alias = "memmove")]
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "none")]
 #[inline]
-pub unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) {
+pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) {
     extern "rust-intrinsic" {
+        #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "none")]
         fn copy<T>(src: *const T, dst: *mut T, count: usize);
     }
 
-    if cfg!(debug_assertions) && !(is_aligned_and_not_null(src) && is_aligned_and_not_null(dst)) {
+    // FIXME: Perform these checks only at run time
+    /*if cfg!(debug_assertions) && !(is_aligned_and_not_null(src) && is_aligned_and_not_null(dst)) {
         // Not panicking to keep codegen impact smaller.
         abort();
-    }
+    }*/
 
     // SAFETY: the safety contract for `copy` must be upheld by the caller.
     unsafe { copy(src, dst, count) }
diff --git a/library/core/src/iter/adapters/intersperse.rs b/library/core/src/iter/adapters/intersperse.rs
new file mode 100644 (file)
index 0000000..3623267
--- /dev/null
@@ -0,0 +1,76 @@
+use super::Peekable;
+
+/// An iterator adapter that places a separator between all elements.
+#[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")]
+#[derive(Debug, Clone)]
+pub struct Intersperse<I: Iterator>
+where
+    I::Item: Clone,
+{
+    separator: I::Item,
+    iter: Peekable<I>,
+    needs_sep: bool,
+}
+
+impl<I: Iterator> Intersperse<I>
+where
+    I::Item: Clone,
+{
+    pub(in crate::iter) fn new(iter: I, separator: I::Item) -> Self {
+        Self { iter: iter.peekable(), separator, needs_sep: false }
+    }
+}
+
+#[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")]
+impl<I> Iterator for Intersperse<I>
+where
+    I: Iterator,
+    I::Item: Clone,
+{
+    type Item = I::Item;
+
+    #[inline]
+    fn next(&mut self) -> Option<I::Item> {
+        if self.needs_sep && self.iter.peek().is_some() {
+            self.needs_sep = false;
+            Some(self.separator.clone())
+        } else {
+            self.needs_sep = true;
+            self.iter.next()
+        }
+    }
+
+    fn fold<B, F>(mut self, init: B, mut f: F) -> B
+    where
+        Self: Sized,
+        F: FnMut(B, Self::Item) -> B,
+    {
+        let mut accum = init;
+
+        // Use `peek()` first to avoid calling `next()` on an empty iterator.
+        if !self.needs_sep || self.iter.peek().is_some() {
+            if let Some(x) = self.iter.next() {
+                accum = f(accum, x);
+            }
+        }
+
+        let element = &self.separator;
+
+        self.iter.fold(accum, |mut accum, x| {
+            accum = f(accum, element.clone());
+            accum = f(accum, x);
+            accum
+        })
+    }
+
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        let (lo, hi) = self.iter.size_hint();
+        let next_is_elem = !self.needs_sep;
+        let lo = lo.saturating_sub(next_is_elem as usize).saturating_add(lo);
+        let hi = match hi {
+            Some(hi) => hi.saturating_sub(next_is_elem as usize).checked_add(hi),
+            None => None,
+        };
+        (lo, hi)
+    }
+}
index b8d3430f91099a82adf33b25d2c0410f2d5c3382..7dfbf32cea7b89773d4fdc926abfe85fbb0f709a 100644 (file)
@@ -11,6 +11,7 @@
 mod flatten;
 mod fuse;
 mod inspect;
+mod intersperse;
 mod map;
 mod map_while;
 mod peekable;
@@ -41,6 +42,9 @@
 #[stable(feature = "iter_copied", since = "1.36.0")]
 pub use self::copied::Copied;
 
+#[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")]
+pub use self::intersperse::Intersperse;
+
 #[unstable(feature = "iter_map_while", reason = "recently added", issue = "68537")]
 pub use self::map_while::MapWhile;
 
index 3e74637b49f1cafef7cfe569ca1e5a4fd9ce10c8..569de719d03d69b4d86ced6d44fc3cebb93507fb 100644 (file)
 pub use self::adapters::Copied;
 #[stable(feature = "iterator_flatten", since = "1.29.0")]
 pub use self::adapters::Flatten;
+#[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")]
+pub use self::adapters::Intersperse;
 #[unstable(feature = "iter_map_while", reason = "recently added", issue = "68537")]
 pub use self::adapters::MapWhile;
 #[unstable(feature = "inplace_iteration", issue = "none")]
index eadbdf45c7c6ff43740c23f0dae7765a6737208e..996d62e2b4a42fd0c34a77edd6ed7a7887a1f653 100644 (file)
@@ -91,6 +91,7 @@ pub trait ExactSizeIterator: Iterator {
     ///
     /// assert_eq!(5, five.len());
     /// ```
+    #[doc(alias = "length")]
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
     fn len(&self) -> usize {
index 7ba16f89284e1f70902eb5944ac9b0e3d773f802..633175702d870a9e623d4532d432f60bf6e10d08 100644 (file)
@@ -8,7 +8,7 @@
 use super::super::TrustedRandomAccess;
 use super::super::{Chain, Cloned, Copied, Cycle, Enumerate, Filter, FilterMap, Fuse};
 use super::super::{FlatMap, Flatten};
-use super::super::{FromIterator, Product, Sum, Zip};
+use super::super::{FromIterator, Intersperse, Product, Sum, Zip};
 use super::super::{
     Inspect, Map, MapWhile, Peekable, Rev, Scan, Skip, SkipWhile, StepBy, Take, TakeWhile,
 };
@@ -569,6 +569,28 @@ fn zip<U>(self, other: U) -> Zip<Self, U::IntoIter>
         Zip::new(self, other.into_iter())
     }
 
+    /// Places a copy of `separator` between all elements.
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// #![feature(iter_intersperse)]
+    ///
+    /// let hello = ["Hello", "World"].iter().copied().intersperse(" ").collect::<String>();
+    /// assert_eq!(hello, "Hello World");
+    /// ```
+    #[inline]
+    #[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")]
+    fn intersperse(self, separator: Self::Item) -> Intersperse<Self>
+    where
+        Self: Sized,
+        Self::Item: Clone,
+    {
+        Intersperse::new(self, separator)
+    }
+
     /// Takes a closure and creates an iterator which calls that closure on each
     /// element.
     ///
index 5b19bf6b80f388d5b04c475f9dd9a6c46d2760fd..099b98b824d82a0d02f117dc9f72e1495d772010 100644 (file)
 #![feature(arbitrary_self_types)]
 #![feature(asm)]
 #![feature(cfg_target_has_atomic)]
-#![cfg_attr(not(bootstrap), feature(const_heap))]
+#![feature(const_heap)]
 #![feature(const_alloc_layout)]
 #![feature(const_assert_type)]
 #![feature(const_discriminant)]
 #![feature(const_cell_into_inner)]
+#![feature(const_intrinsic_copy)]
 #![feature(const_checked_int_methods)]
 #![feature(const_euclidean_int_methods)]
 #![feature(const_float_classify)]
@@ -93,6 +94,7 @@
 #![feature(const_precise_live_drops)]
 #![feature(const_ptr_offset)]
 #![feature(const_ptr_offset_from)]
+#![feature(const_ptr_read)]
 #![feature(const_raw_ptr_comparison)]
 #![feature(const_raw_ptr_deref)]
 #![feature(const_slice_from_raw_parts)]
 #![feature(doc_spotlight)]
 #![feature(duration_consts_2)]
 #![feature(duration_saturating_ops)]
+#![feature(extended_key_value_attributes)]
 #![feature(extern_types)]
 #![feature(fundamental)]
 #![feature(intrinsics)]
 #![feature(nll)]
 #![feature(exhaustive_patterns)]
 #![feature(no_core)]
-#![cfg_attr(bootstrap, feature(optin_builtin_traits))]
-#![cfg_attr(not(bootstrap), feature(auto_traits))]
+#![feature(auto_traits)]
 #![feature(or_patterns)]
 #![feature(prelude_import)]
 #![feature(repr_simd, platform_intrinsics)]
index 0699c9eab1871922b819558ef3ac74286da95eeb..1634aff7b4dc9b37971e12c2d07261e14dc66908 100644 (file)
@@ -2,7 +2,7 @@
 #[macro_export]
 #[allow_internal_unstable(core_panic, const_caller_location)]
 #[stable(feature = "core", since = "1.6.0")]
-#[cfg_attr(not(bootstrap), rustc_diagnostic_item = "core_panic_macro")]
+#[rustc_diagnostic_item = "core_panic_macro"]
 macro_rules! panic {
     () => (
         $crate::panic!("explicit panic")
@@ -163,7 +163,7 @@ macro_rules! assert_ne {
 /// ```
 #[macro_export]
 #[stable(feature = "rust1", since = "1.0.0")]
-#[cfg_attr(not(bootstrap), rustc_diagnostic_item = "debug_assert_macro")]
+#[rustc_diagnostic_item = "debug_assert_macro"]
 macro_rules! debug_assert {
     ($($arg:tt)*) => (if $crate::cfg!(debug_assertions) { $crate::assert!($($arg)*); })
 }
@@ -1217,7 +1217,7 @@ macro_rules! include {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_builtin_macro]
     #[macro_export]
-    #[cfg_attr(not(bootstrap), rustc_diagnostic_item = "assert_macro")]
+    #[rustc_diagnostic_item = "assert_macro"]
     #[allow_internal_unstable(core_panic)]
     macro_rules! assert {
         ($cond:expr $(,)?) => {{ /* compiler built-in */ }};
index 57e0bb1499bdef0b1333ce9a100da3d608d60d8a..b2a4d897eededb224022d19864bf9e3459f425ac 100644 (file)
@@ -575,8 +575,9 @@ pub const fn as_mut_ptr(&mut self) -> *mut T {
     /// // they both get dropped!
     /// ```
     #[unstable(feature = "maybe_uninit_extra", issue = "63567")]
+    #[rustc_const_unstable(feature = "maybe_uninit_extra", issue = "63567")]
     #[inline(always)]
-    pub unsafe fn assume_init_read(&self) -> T {
+    pub const unsafe fn assume_init_read(&self) -> T {
         // SAFETY: the caller must guarantee that `self` is initialized.
         // Reading from `self.as_ptr()` is safe since `self` should be initialized.
         unsafe {
index e84014c68a6760a9be112b9c5cbb5917e3b077fd..22e44a3c4090459a44d9c49230a4ae5706ade726 100644 (file)
@@ -151,9 +151,14 @@ pub const fn forget<T>(t: T) {
 #[inline]
 #[unstable(feature = "forget_unsized", issue = "none")]
 pub fn forget_unsized<T: ?Sized>(t: T) {
+    #[cfg(bootstrap)]
     // SAFETY: the forget intrinsic could be safe, but there's no point in making it safe since
     // we'll be implementing this function soon via `ManuallyDrop`
-    unsafe { intrinsics::forget(t) }
+    unsafe {
+        intrinsics::forget(t)
+    }
+    #[cfg(not(bootstrap))]
+    intrinsics::forget(t)
 }
 
 /// Returns the size of a type in bytes.
@@ -374,7 +379,8 @@ pub const fn size_of_val<T: ?Sized>(val: &T) -> usize {
 /// ```
 #[inline]
 #[unstable(feature = "layout_for_ptr", issue = "69835")]
-pub unsafe fn size_of_val_raw<T: ?Sized>(val: *const T) -> usize {
+#[rustc_const_unstable(feature = "const_size_of_val_raw", issue = "46571")]
+pub const unsafe fn size_of_val_raw<T: ?Sized>(val: *const T) -> usize {
     intrinsics::size_of_val(val)
 }
 
@@ -505,7 +511,8 @@ pub const fn align_of_val<T: ?Sized>(val: &T) -> usize {
 /// ```
 #[inline]
 #[unstable(feature = "layout_for_ptr", issue = "69835")]
-pub unsafe fn align_of_val_raw<T: ?Sized>(val: *const T) -> usize {
+#[rustc_const_unstable(feature = "const_align_of_val_raw", issue = "46571")]
+pub const unsafe fn align_of_val_raw<T: ?Sized>(val: *const T) -> usize {
     intrinsics::min_align_of_val(val)
 }
 
index 2cde5d9995b62ec9908e8212ce880f595e08e302..162ed7d1b8dfecd1b5a54b947f6b6172bcb2bb12 100644 (file)
 macro_rules! int_impl {
-    ($SelfT:ty, $ActualT:ident, $UnsignedT:ty, $BITS:expr, $Min:expr, $Max:expr, $Feature:expr,
-     $EndFeature:expr, $rot:expr, $rot_op:expr, $rot_result:expr, $swap_op:expr, $swapped:expr,
+    ($SelfT:ty, $ActualT:ident, $UnsignedT:ty, $BITS:expr, $Min:expr, $Max:expr,
+     $rot:expr, $rot_op:expr, $rot_result:expr, $swap_op:expr, $swapped:expr,
      $reversed:expr, $le_bytes:expr, $be_bytes:expr,
      $to_xe_bytes_doc:expr, $from_xe_bytes_doc:expr) => {
-        doc_comment! {
-            concat!("The smallest value that can be represented by this integer type.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(", stringify!($SelfT), "::MIN, ", stringify!($Min), ");",
-$EndFeature, "
-```"),
-            #[stable(feature = "assoc_int_consts", since = "1.43.0")]
-            pub const MIN: Self = !0 ^ ((!0 as $UnsignedT) >> 1) as Self;
-        }
-
-        doc_comment! {
-            concat!("The largest value that can be represented by this integer type.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(", stringify!($SelfT), "::MAX, ", stringify!($Max), ");",
-$EndFeature, "
-```"),
-            #[stable(feature = "assoc_int_consts", since = "1.43.0")]
-            pub const MAX: Self = !Self::MIN;
-        }
-
-        doc_comment! {
-            concat!("The size of this integer type in bits.
-
-# Examples
-
-```
-", $Feature, "#![feature(int_bits_const)]
-assert_eq!(", stringify!($SelfT), "::BITS, ", stringify!($BITS), ");",
-$EndFeature, "
-```"),
-            #[unstable(feature = "int_bits_const", issue = "76904")]
-            pub const BITS: u32 = $BITS;
-        }
-
-        doc_comment! {
-            concat!("Converts a string slice in a given base to an integer.
-
-The string is expected to be an optional `+` or `-` sign followed by digits.
-Leading and trailing whitespace represent an error. Digits are a subset of these characters,
-depending on `radix`:
-
- * `0-9`
- * `a-z`
- * `A-Z`
-
-# Panics
-
-This function panics if `radix` is not in the range from 2 to 36.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(", stringify!($SelfT), "::from_str_radix(\"A\", 16), Ok(10));",
-$EndFeature, "
-```"),
-            #[stable(feature = "rust1", since = "1.0.0")]
-            pub fn from_str_radix(src: &str, radix: u32) -> Result<Self, ParseIntError> {
-                from_str_radix(src, radix)
-            }
-        }
-
-        doc_comment! {
-            concat!("Returns the number of ones in the binary representation of `self`.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "let n = 0b100_0000", stringify!($SelfT), ";
-
-assert_eq!(n.count_ones(), 1);",
-$EndFeature, "
-```
-"),
-            #[stable(feature = "rust1", since = "1.0.0")]
-            #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
-            #[doc(alias = "popcount")]
-            #[doc(alias = "popcnt")]
-            #[inline]
-            pub const fn count_ones(self) -> u32 { (self as $UnsignedT).count_ones() }
-        }
-
-        doc_comment! {
-            concat!("Returns the number of zeros in the binary representation of `self`.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(", stringify!($SelfT), "::MAX.count_zeros(), 1);", $EndFeature, "
-```"),
-            #[stable(feature = "rust1", since = "1.0.0")]
-            #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
-            #[inline]
-            pub const fn count_zeros(self) -> u32 {
-                (!self).count_ones()
-            }
-        }
-
-        doc_comment! {
-            concat!("Returns the number of leading zeros in the binary representation of `self`.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "let n = -1", stringify!($SelfT), ";
-
-assert_eq!(n.leading_zeros(), 0);",
-$EndFeature, "
-```"),
-            #[stable(feature = "rust1", since = "1.0.0")]
-            #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
-            #[inline]
-            pub const fn leading_zeros(self) -> u32 {
-                (self as $UnsignedT).leading_zeros()
-            }
-        }
-
-        doc_comment! {
-            concat!("Returns the number of trailing zeros in the binary representation of `self`.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "let n = -4", stringify!($SelfT), ";
-
-assert_eq!(n.trailing_zeros(), 2);",
-$EndFeature, "
-```"),
-            #[stable(feature = "rust1", since = "1.0.0")]
-            #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
-            #[inline]
-            pub const fn trailing_zeros(self) -> u32 {
-                (self as $UnsignedT).trailing_zeros()
-            }
-        }
-
-        doc_comment! {
-            concat!("Returns the number of leading ones in the binary representation of `self`.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "let n = -1", stringify!($SelfT), ";
-
-assert_eq!(n.leading_ones(), ", stringify!($BITS), ");",
-$EndFeature, "
-```"),
-            #[stable(feature = "leading_trailing_ones", since = "1.46.0")]
-            #[rustc_const_stable(feature = "leading_trailing_ones", since = "1.46.0")]
-            #[inline]
-            pub const fn leading_ones(self) -> u32 {
-                (self as $UnsignedT).leading_ones()
-            }
-        }
-
-        doc_comment! {
-            concat!("Returns the number of trailing ones in the binary representation of `self`.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "let n = 3", stringify!($SelfT), ";
-
-assert_eq!(n.trailing_ones(), 2);",
-$EndFeature, "
-```"),
-            #[stable(feature = "leading_trailing_ones", since = "1.46.0")]
-            #[rustc_const_stable(feature = "leading_trailing_ones", since = "1.46.0")]
-            #[inline]
-            pub const fn trailing_ones(self) -> u32 {
-                (self as $UnsignedT).trailing_ones()
-            }
-        }
-
-        doc_comment! {
-            concat!("Shifts the bits to the left by a specified amount, `n`,
-wrapping the truncated bits to the end of the resulting integer.
-
-Please note this isn't the same operation as the `<<` shifting operator!
-
-# Examples
-
-Basic usage:
-
-```
-let n = ", $rot_op, stringify!($SelfT), ";
-let m = ", $rot_result, ";
-
-assert_eq!(n.rotate_left(", $rot, "), m);
-```"),
-            #[stable(feature = "rust1", since = "1.0.0")]
-            #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
-            #[must_use = "this returns the result of the operation, \
-                          without modifying the original"]
-            #[inline]
-            pub const fn rotate_left(self, n: u32) -> Self {
-                (self as $UnsignedT).rotate_left(n) as Self
-            }
-        }
-
-        doc_comment! {
-            concat!("Shifts the bits to the right by a specified amount, `n`,
-wrapping the truncated bits to the beginning of the resulting
-integer.
-
-Please note this isn't the same operation as the `>>` shifting operator!
-
-# Examples
-
-Basic usage:
-
-```
-let n = ", $rot_result, stringify!($SelfT), ";
-let m = ", $rot_op, ";
-
-assert_eq!(n.rotate_right(", $rot, "), m);
-```"),
-            #[stable(feature = "rust1", since = "1.0.0")]
-            #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
-            #[must_use = "this returns the result of the operation, \
-                          without modifying the original"]
-            #[inline]
-            pub const fn rotate_right(self, n: u32) -> Self {
-                (self as $UnsignedT).rotate_right(n) as Self
-            }
-        }
-
-        doc_comment! {
-            concat!("Reverses the byte order of the integer.
-
-# Examples
-
-Basic usage:
-
-```
-let n = ", $swap_op, stringify!($SelfT), ";
-
-let m = n.swap_bytes();
-
-assert_eq!(m, ", $swapped, ");
-```"),
-            #[stable(feature = "rust1", since = "1.0.0")]
-            #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
-            #[inline]
-            pub const fn swap_bytes(self) -> Self {
-                (self as $UnsignedT).swap_bytes() as Self
-            }
-        }
-
-        doc_comment! {
-            concat!("Reverses the order of bits in the integer. The least significant bit becomes the most significant bit,
-                second least-significant bit becomes second most-significant bit, etc.
-
-# Examples
-
-Basic usage:
-
-```
-let n = ", $swap_op, stringify!($SelfT), ";
-let m = n.reverse_bits();
-
-assert_eq!(m, ", $reversed, ");
-assert_eq!(0, 0", stringify!($SelfT), ".reverse_bits());
-```"),
-            #[stable(feature = "reverse_bits", since = "1.37.0")]
-            #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
-            #[inline]
-            #[must_use]
-            pub const fn reverse_bits(self) -> Self {
-                (self as $UnsignedT).reverse_bits() as Self
-            }
-        }
-
-        doc_comment! {
-            concat!("Converts an integer from big endian to the target's endianness.
-
-On big endian this is a no-op. On little endian the bytes are swapped.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "let n = 0x1A", stringify!($SelfT), ";
-
-if cfg!(target_endian = \"big\") {
-    assert_eq!(", stringify!($SelfT), "::from_be(n), n)
-} else {
-    assert_eq!(", stringify!($SelfT), "::from_be(n), n.swap_bytes())
-}",
-$EndFeature, "
-```"),
-            #[stable(feature = "rust1", since = "1.0.0")]
-            #[rustc_const_stable(feature = "const_int_conversions", since = "1.32.0")]
-            #[inline]
-            pub const fn from_be(x: Self) -> Self {
-                #[cfg(target_endian = "big")]
-                {
-                    x
-                }
-                #[cfg(not(target_endian = "big"))]
-                {
-                    x.swap_bytes()
-                }
-            }
-        }
-
-        doc_comment! {
-            concat!("Converts an integer from little endian to the target's endianness.
-
-On little endian this is a no-op. On big endian the bytes are swapped.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "let n = 0x1A", stringify!($SelfT), ";
-
-if cfg!(target_endian = \"little\") {
-    assert_eq!(", stringify!($SelfT), "::from_le(n), n)
-} else {
-    assert_eq!(", stringify!($SelfT), "::from_le(n), n.swap_bytes())
-}",
-$EndFeature, "
-```"),
-            #[stable(feature = "rust1", since = "1.0.0")]
-            #[rustc_const_stable(feature = "const_int_conversions", since = "1.32.0")]
-            #[inline]
-            pub const fn from_le(x: Self) -> Self {
-                #[cfg(target_endian = "little")]
-                {
-                    x
-                }
-                #[cfg(not(target_endian = "little"))]
-                {
-                    x.swap_bytes()
-                }
-            }
-        }
-
-        doc_comment! {
-            concat!("Converts `self` to big endian from the target's endianness.
-
-On big endian this is a no-op. On little endian the bytes are swapped.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "let n = 0x1A", stringify!($SelfT), ";
-
-if cfg!(target_endian = \"big\") {
-    assert_eq!(n.to_be(), n)
-} else {
-    assert_eq!(n.to_be(), n.swap_bytes())
-}",
-$EndFeature, "
-```"),
-            #[stable(feature = "rust1", since = "1.0.0")]
-            #[rustc_const_stable(feature = "const_int_conversions", since = "1.32.0")]
-            #[inline]
-            pub const fn to_be(self) -> Self { // or not to be?
-                #[cfg(target_endian = "big")]
-                {
-                    self
-                }
-                #[cfg(not(target_endian = "big"))]
-                {
-                    self.swap_bytes()
-                }
-            }
-        }
-
-        doc_comment! {
-            concat!("Converts `self` to little endian from the target's endianness.
-
-On little endian this is a no-op. On big endian the bytes are swapped.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "let n = 0x1A", stringify!($SelfT), ";
-
-if cfg!(target_endian = \"little\") {
-    assert_eq!(n.to_le(), n)
-} else {
-    assert_eq!(n.to_le(), n.swap_bytes())
-}",
-$EndFeature, "
-```"),
-            #[stable(feature = "rust1", since = "1.0.0")]
-            #[rustc_const_stable(feature = "const_int_conversions", since = "1.32.0")]
-            #[inline]
-            pub const fn to_le(self) -> Self {
-                #[cfg(target_endian = "little")]
-                {
-                    self
-                }
-                #[cfg(not(target_endian = "little"))]
-                {
-                    self.swap_bytes()
-                }
-            }
-        }
-
-        doc_comment! {
-            concat!("Checked integer addition. Computes `self + rhs`, returning `None`
-if overflow occurred.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!((", stringify!($SelfT),
-"::MAX - 2).checked_add(1), Some(", stringify!($SelfT), "::MAX - 1));
-assert_eq!((", stringify!($SelfT), "::MAX - 2).checked_add(3), None);",
-$EndFeature, "
-```"),
-            #[stable(feature = "rust1", since = "1.0.0")]
-            #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")]
-            #[must_use = "this returns the result of the operation, \
-                          without modifying the original"]
-            #[inline]
-            pub const fn checked_add(self, rhs: Self) -> Option<Self> {
-                let (a, b) = self.overflowing_add(rhs);
-                if unlikely!(b) {None} else {Some(a)}
-            }
-        }
-
-        doc_comment! {
-            concat!("Unchecked integer addition. Computes `self + rhs`, assuming overflow
-cannot occur. This results in undefined behavior when `self + rhs > ", stringify!($SelfT),
-"::MAX` or `self + rhs < ", stringify!($SelfT), "::MIN`."),
-            #[unstable(
-                feature = "unchecked_math",
-                reason = "niche optimization path",
-                issue = "none",
-            )]
-            #[must_use = "this returns the result of the operation, \
-                          without modifying the original"]
-            #[inline]
-            pub unsafe fn unchecked_add(self, rhs: Self) -> Self {
-                // SAFETY: the caller must uphold the safety contract for
-                // `unchecked_add`.
-                unsafe { intrinsics::unchecked_add(self, rhs) }
-            }
-        }
-
-        doc_comment! {
-            concat!("Checked integer subtraction. Computes `self - rhs`, returning `None` if
-overflow occurred.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!((", stringify!($SelfT),
-"::MIN + 2).checked_sub(1), Some(", stringify!($SelfT), "::MIN + 1));
-assert_eq!((", stringify!($SelfT), "::MIN + 2).checked_sub(3), None);",
-$EndFeature, "
-```"),
-            #[stable(feature = "rust1", since = "1.0.0")]
-            #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")]
-            #[must_use = "this returns the result of the operation, \
-                          without modifying the original"]
-            #[inline]
-            pub const fn checked_sub(self, rhs: Self) -> Option<Self> {
-                let (a, b) = self.overflowing_sub(rhs);
-                if unlikely!(b) {None} else {Some(a)}
-            }
-        }
-
-        doc_comment! {
-            concat!("Unchecked integer subtraction. Computes `self - rhs`, assuming overflow
-cannot occur. This results in undefined behavior when `self - rhs > ", stringify!($SelfT),
-"::MAX` or `self - rhs < ", stringify!($SelfT), "::MIN`."),
-            #[unstable(
-                feature = "unchecked_math",
-                reason = "niche optimization path",
-                issue = "none",
-            )]
-            #[must_use = "this returns the result of the operation, \
-                          without modifying the original"]
-            #[inline]
-            pub unsafe fn unchecked_sub(self, rhs: Self) -> Self {
-                // SAFETY: the caller must uphold the safety contract for
-                // `unchecked_sub`.
-                unsafe { intrinsics::unchecked_sub(self, rhs) }
-            }
-        }
-
-        doc_comment! {
-            concat!("Checked integer multiplication. Computes `self * rhs`, returning `None` if
-overflow occurred.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(", stringify!($SelfT),
-"::MAX.checked_mul(1), Some(", stringify!($SelfT), "::MAX));
-assert_eq!(", stringify!($SelfT), "::MAX.checked_mul(2), None);",
-$EndFeature, "
-```"),
-            #[stable(feature = "rust1", since = "1.0.0")]
-            #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")]
-            #[must_use = "this returns the result of the operation, \
-                          without modifying the original"]
-            #[inline]
-            pub const fn checked_mul(self, rhs: Self) -> Option<Self> {
-                let (a, b) = self.overflowing_mul(rhs);
-                if unlikely!(b) {None} else {Some(a)}
-            }
-        }
-
-        doc_comment! {
-            concat!("Unchecked integer multiplication. Computes `self * rhs`, assuming overflow
-cannot occur. This results in undefined behavior when `self * rhs > ", stringify!($SelfT),
-"::MAX` or `self * rhs < ", stringify!($SelfT), "::MIN`."),
-            #[unstable(
-                feature = "unchecked_math",
-                reason = "niche optimization path",
-                issue = "none",
-            )]
-            #[must_use = "this returns the result of the operation, \
-                          without modifying the original"]
-            #[inline]
-            pub unsafe fn unchecked_mul(self, rhs: Self) -> Self {
-                // SAFETY: the caller must uphold the safety contract for
-                // `unchecked_mul`.
-                unsafe { intrinsics::unchecked_mul(self, rhs) }
-            }
-        }
-
-        doc_comment! {
-            concat!("Checked integer division. Computes `self / rhs`, returning `None` if `rhs == 0`
-or the division results in overflow.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!((", stringify!($SelfT),
-"::MIN + 1).checked_div(-1), Some(", stringify!($Max), "));
-assert_eq!(", stringify!($SelfT), "::MIN.checked_div(-1), None);
-assert_eq!((1", stringify!($SelfT), ").checked_div(0), None);",
-$EndFeature, "
-```"),
-            #[stable(feature = "rust1", since = "1.0.0")]
-            #[rustc_const_unstable(feature = "const_checked_int_methods", issue = "53718")]
-            #[must_use = "this returns the result of the operation, \
-                          without modifying the original"]
-            #[inline]
-            pub const fn checked_div(self, rhs: Self) -> Option<Self> {
-                if unlikely!(rhs == 0 || (self == Self::MIN && rhs == -1)) {
-                    None
-                } else {
-                    // SAFETY: div by zero and by INT_MIN have been checked above
-                    Some(unsafe { intrinsics::unchecked_div(self, rhs) })
-                }
-            }
-        }
-
-        doc_comment! {
-            concat!("Checked Euclidean division. Computes `self.div_euclid(rhs)`,
-returning `None` if `rhs == 0` or the division results in overflow.
-
-# Examples
-
-Basic usage:
-
-```
-assert_eq!((", stringify!($SelfT),
-"::MIN + 1).checked_div_euclid(-1), Some(", stringify!($Max), "));
-assert_eq!(", stringify!($SelfT), "::MIN.checked_div_euclid(-1), None);
-assert_eq!((1", stringify!($SelfT), ").checked_div_euclid(0), None);
-```"),
-            #[stable(feature = "euclidean_division", since = "1.38.0")]
-            #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
-            #[must_use = "this returns the result of the operation, \
-                          without modifying the original"]
-            #[inline]
-            pub const fn checked_div_euclid(self, rhs: Self) -> Option<Self> {
-                if unlikely!(rhs == 0 || (self == Self::MIN && rhs == -1)) {
-                    None
-                } else {
-                    Some(self.div_euclid(rhs))
-                }
-            }
-        }
-
-        doc_comment! {
-            concat!("Checked integer remainder. Computes `self % rhs`, returning `None` if
-`rhs == 0` or the division results in overflow.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "
-assert_eq!(5", stringify!($SelfT), ".checked_rem(2), Some(1));
-assert_eq!(5", stringify!($SelfT), ".checked_rem(0), None);
-assert_eq!(", stringify!($SelfT), "::MIN.checked_rem(-1), None);",
-$EndFeature, "
-```"),
-            #[stable(feature = "wrapping", since = "1.7.0")]
-            #[rustc_const_unstable(feature = "const_checked_int_methods", issue = "53718")]
-            #[must_use = "this returns the result of the operation, \
-                          without modifying the original"]
-            #[inline]
-            pub const fn checked_rem(self, rhs: Self) -> Option<Self> {
-                if unlikely!(rhs == 0 || (self == Self::MIN && rhs == -1)) {
-                    None
-                } else {
-                    // SAFETY: div by zero and by INT_MIN have been checked above
-                    Some(unsafe { intrinsics::unchecked_rem(self, rhs) })
-                }
-            }
-        }
-
-        doc_comment! {
-            concat!("Checked Euclidean remainder. Computes `self.rem_euclid(rhs)`, returning `None`
-if `rhs == 0` or the division results in overflow.
-
-# Examples
-
-Basic usage:
-
-```
-assert_eq!(5", stringify!($SelfT), ".checked_rem_euclid(2), Some(1));
-assert_eq!(5", stringify!($SelfT), ".checked_rem_euclid(0), None);
-assert_eq!(", stringify!($SelfT), "::MIN.checked_rem_euclid(-1), None);
-```"),
-            #[stable(feature = "euclidean_division", since = "1.38.0")]
-            #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
-            #[must_use = "this returns the result of the operation, \
-                          without modifying the original"]
-            #[inline]
-            pub const fn checked_rem_euclid(self, rhs: Self) -> Option<Self> {
-                if unlikely!(rhs == 0 || (self == Self::MIN && rhs == -1)) {
-                    None
-                } else {
-                    Some(self.rem_euclid(rhs))
-                }
-            }
-        }
-
-        doc_comment! {
-            concat!("Checked negation. Computes `-self`, returning `None` if `self == MIN`.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "
-assert_eq!(5", stringify!($SelfT), ".checked_neg(), Some(-5));
-assert_eq!(", stringify!($SelfT), "::MIN.checked_neg(), None);",
-$EndFeature, "
-```"),
-            #[stable(feature = "wrapping", since = "1.7.0")]
-            #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")]
-            #[inline]
-            pub const fn checked_neg(self) -> Option<Self> {
-                let (a, b) = self.overflowing_neg();
-                if unlikely!(b) {None} else {Some(a)}
-            }
-        }
-
-        doc_comment! {
-            concat!("Checked shift left. Computes `self << rhs`, returning `None` if `rhs` is larger
-than or equal to the number of bits in `self`.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(0x1", stringify!($SelfT), ".checked_shl(4), Some(0x10));
-assert_eq!(0x1", stringify!($SelfT), ".checked_shl(129), None);",
-$EndFeature, "
-```"),
-            #[stable(feature = "wrapping", since = "1.7.0")]
-            #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")]
-            #[must_use = "this returns the result of the operation, \
-                          without modifying the original"]
-            #[inline]
-            pub const fn checked_shl(self, rhs: u32) -> Option<Self> {
-                let (a, b) = self.overflowing_shl(rhs);
-                if unlikely!(b) {None} else {Some(a)}
-            }
-        }
-
-        doc_comment! {
-            concat!("Checked shift right. Computes `self >> rhs`, returning `None` if `rhs` is
-larger than or equal to the number of bits in `self`.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(0x10", stringify!($SelfT), ".checked_shr(4), Some(0x1));
-assert_eq!(0x10", stringify!($SelfT), ".checked_shr(128), None);",
-$EndFeature, "
-```"),
-            #[stable(feature = "wrapping", since = "1.7.0")]
-            #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")]
-            #[must_use = "this returns the result of the operation, \
-                          without modifying the original"]
-            #[inline]
-            pub const fn checked_shr(self, rhs: u32) -> Option<Self> {
-                let (a, b) = self.overflowing_shr(rhs);
-                if unlikely!(b) {None} else {Some(a)}
-            }
-        }
-
-        doc_comment! {
-            concat!("Checked absolute value. Computes `self.abs()`, returning `None` if
-`self == MIN`.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "
-assert_eq!((-5", stringify!($SelfT), ").checked_abs(), Some(5));
-assert_eq!(", stringify!($SelfT), "::MIN.checked_abs(), None);",
-$EndFeature, "
-```"),
-            #[stable(feature = "no_panic_abs", since = "1.13.0")]
-            #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")]
-            #[inline]
-            pub const fn checked_abs(self) -> Option<Self> {
-                if self.is_negative() {
-                    self.checked_neg()
-                } else {
-                    Some(self)
-                }
-            }
-        }
-
-        doc_comment! {
-            concat!("Checked exponentiation. Computes `self.pow(exp)`, returning `None` if
-overflow occurred.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(8", stringify!($SelfT), ".checked_pow(2), Some(64));
-assert_eq!(", stringify!($SelfT), "::MAX.checked_pow(2), None);",
-$EndFeature, "
-```"),
-
-            #[stable(feature = "no_panic_pow", since = "1.34.0")]
-            #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")]
-            #[must_use = "this returns the result of the operation, \
-                          without modifying the original"]
-            #[inline]
-            pub const fn checked_pow(self, mut exp: u32) -> Option<Self> {
-                if exp == 0 {
-                    return Some(1);
-                }
-                let mut base = self;
-                let mut acc: Self = 1;
-
-                while exp > 1 {
-                    if (exp & 1) == 1 {
-                        acc = try_opt!(acc.checked_mul(base));
-                    }
-                    exp /= 2;
-                    base = try_opt!(base.checked_mul(base));
-                }
-                // since exp!=0, finally the exp must be 1.
-                // Deal with the final bit of the exponent separately, since
-                // squaring the base afterwards is not necessary and may cause a
-                // needless overflow.
-                Some(try_opt!(acc.checked_mul(base)))
-            }
-        }
-
-        doc_comment! {
-            concat!("Saturating integer addition. Computes `self + rhs`, saturating at the numeric
-bounds instead of overflowing.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(100", stringify!($SelfT), ".saturating_add(1), 101);
-assert_eq!(", stringify!($SelfT), "::MAX.saturating_add(100), ", stringify!($SelfT),
-"::MAX);
-assert_eq!(", stringify!($SelfT), "::MIN.saturating_add(-1), ", stringify!($SelfT),
-"::MIN);",
-$EndFeature, "
-```"),
-
-            #[stable(feature = "rust1", since = "1.0.0")]
-            #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")]
-            #[must_use = "this returns the result of the operation, \
-                          without modifying the original"]
-            #[inline]
-            pub const fn saturating_add(self, rhs: Self) -> Self {
-                intrinsics::saturating_add(self, rhs)
-            }
-        }
-
-        doc_comment! {
-            concat!("Saturating integer subtraction. Computes `self - rhs`, saturating at the
-numeric bounds instead of overflowing.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(100", stringify!($SelfT), ".saturating_sub(127), -27);
-assert_eq!(", stringify!($SelfT), "::MIN.saturating_sub(100), ", stringify!($SelfT),
-"::MIN);
-assert_eq!(", stringify!($SelfT), "::MAX.saturating_sub(-1), ", stringify!($SelfT),
-"::MAX);",
-$EndFeature, "
-```"),
-            #[stable(feature = "rust1", since = "1.0.0")]
-            #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")]
-            #[must_use = "this returns the result of the operation, \
-                          without modifying the original"]
-            #[inline]
-            pub const fn saturating_sub(self, rhs: Self) -> Self {
-                intrinsics::saturating_sub(self, rhs)
-            }
-        }
-
-        doc_comment! {
-            concat!("Saturating integer negation. Computes `-self`, returning `MAX` if `self == MIN`
-instead of overflowing.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(100", stringify!($SelfT), ".saturating_neg(), -100);
-assert_eq!((-100", stringify!($SelfT), ").saturating_neg(), 100);
-assert_eq!(", stringify!($SelfT), "::MIN.saturating_neg(), ", stringify!($SelfT),
-"::MAX);
-assert_eq!(", stringify!($SelfT), "::MAX.saturating_neg(), ", stringify!($SelfT),
-"::MIN + 1);",
-$EndFeature, "
-```"),
-
-            #[stable(feature = "saturating_neg", since = "1.45.0")]
-            #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")]
-            #[inline]
-            pub const fn saturating_neg(self) -> Self {
-                intrinsics::saturating_sub(0, self)
-            }
-        }
-
-        doc_comment! {
-            concat!("Saturating absolute value. Computes `self.abs()`, returning `MAX` if `self ==
-MIN` instead of overflowing.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(100", stringify!($SelfT), ".saturating_abs(), 100);
-assert_eq!((-100", stringify!($SelfT), ").saturating_abs(), 100);
-assert_eq!(", stringify!($SelfT), "::MIN.saturating_abs(), ", stringify!($SelfT),
-"::MAX);
-assert_eq!((", stringify!($SelfT), "::MIN + 1).saturating_abs(), ", stringify!($SelfT),
-"::MAX);",
-$EndFeature, "
-```"),
-
-            #[stable(feature = "saturating_neg", since = "1.45.0")]
-            #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")]
-            #[inline]
-            pub const fn saturating_abs(self) -> Self {
-                if self.is_negative() {
-                    self.saturating_neg()
-                } else {
-                    self
-                }
-            }
-        }
-
-        doc_comment! {
-            concat!("Saturating integer multiplication. Computes `self * rhs`, saturating at the
-numeric bounds instead of overflowing.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "
-assert_eq!(10", stringify!($SelfT), ".saturating_mul(12), 120);
-assert_eq!(", stringify!($SelfT), "::MAX.saturating_mul(10), ", stringify!($SelfT), "::MAX);
-assert_eq!(", stringify!($SelfT), "::MIN.saturating_mul(10), ", stringify!($SelfT), "::MIN);",
-$EndFeature, "
-```"),
-            #[stable(feature = "wrapping", since = "1.7.0")]
-            #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")]
-            #[must_use = "this returns the result of the operation, \
-                          without modifying the original"]
-            #[inline]
-            pub const fn saturating_mul(self, rhs: Self) -> Self {
-                match self.checked_mul(rhs) {
-                    Some(x) => x,
-                    None => if (self < 0) == (rhs < 0) {
-                        Self::MAX
-                    } else {
-                        Self::MIN
-                    }
-                }
-            }
-        }
-
-        doc_comment! {
-            concat!("Saturating integer exponentiation. Computes `self.pow(exp)`,
-saturating at the numeric bounds instead of overflowing.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "
-assert_eq!((-4", stringify!($SelfT), ").saturating_pow(3), -64);
-assert_eq!(", stringify!($SelfT), "::MIN.saturating_pow(2), ", stringify!($SelfT), "::MAX);
-assert_eq!(", stringify!($SelfT), "::MIN.saturating_pow(3), ", stringify!($SelfT), "::MIN);",
-$EndFeature, "
-```"),
-            #[stable(feature = "no_panic_pow", since = "1.34.0")]
-            #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")]
-            #[must_use = "this returns the result of the operation, \
-                          without modifying the original"]
-            #[inline]
-            pub const fn saturating_pow(self, exp: u32) -> Self {
-                match self.checked_pow(exp) {
-                    Some(x) => x,
-                    None if self < 0 && exp % 2 == 1 => Self::MIN,
-                    None => Self::MAX,
-                }
-            }
-        }
-
-        doc_comment! {
-            concat!("Wrapping (modular) addition. Computes `self + rhs`, wrapping around at the
-boundary of the type.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_add(27), 127);
-assert_eq!(", stringify!($SelfT), "::MAX.wrapping_add(2), ", stringify!($SelfT),
-"::MIN + 1);",
-$EndFeature, "
-```"),
-            #[stable(feature = "rust1", since = "1.0.0")]
-            #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
-            #[must_use = "this returns the result of the operation, \
-                          without modifying the original"]
-            #[inline]
-            pub const fn wrapping_add(self, rhs: Self) -> Self {
-                intrinsics::wrapping_add(self, rhs)
-            }
-        }
-
-        doc_comment! {
-            concat!("Wrapping (modular) subtraction. Computes `self - rhs`, wrapping around at the
-boundary of the type.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(0", stringify!($SelfT), ".wrapping_sub(127), -127);
-assert_eq!((-2", stringify!($SelfT), ").wrapping_sub(", stringify!($SelfT), "::MAX), ",
-stringify!($SelfT), "::MAX);",
-$EndFeature, "
-```"),
-            #[stable(feature = "rust1", since = "1.0.0")]
-            #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
-            #[must_use = "this returns the result of the operation, \
-                          without modifying the original"]
-            #[inline]
-            pub const fn wrapping_sub(self, rhs: Self) -> Self {
-                intrinsics::wrapping_sub(self, rhs)
-            }
-        }
-
-        doc_comment! {
-            concat!("Wrapping (modular) multiplication. Computes `self * rhs`, wrapping around at
-the boundary of the type.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(10", stringify!($SelfT), ".wrapping_mul(12), 120);
-assert_eq!(11i8.wrapping_mul(12), -124);",
-$EndFeature, "
-```"),
-            #[stable(feature = "rust1", since = "1.0.0")]
-            #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
-            #[must_use = "this returns the result of the operation, \
-                          without modifying the original"]
-            #[inline]
-            pub const fn wrapping_mul(self, rhs: Self) -> Self {
-                intrinsics::wrapping_mul(self, rhs)
-            }
-        }
-
-        doc_comment! {
-            concat!("Wrapping (modular) division. Computes `self / rhs`, wrapping around at the
-boundary of the type.
-
-The only case where such wrapping can occur is when one divides `MIN / -1` on a signed type (where
-`MIN` is the negative minimal value for the type); this is equivalent to `-MIN`, a positive value
-that is too large to represent in the type. In such a case, this function returns `MIN` itself.
-
-# Panics
-
-This function will panic if `rhs` is 0.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_div(10), 10);
-assert_eq!((-128i8).wrapping_div(-1), -128);",
-$EndFeature, "
-```"),
-            #[stable(feature = "num_wrapping", since = "1.2.0")]
-            #[rustc_const_unstable(feature = "const_wrapping_int_methods", issue = "53718")]
-            #[must_use = "this returns the result of the operation, \
-                          without modifying the original"]
-            #[inline]
-            pub const fn wrapping_div(self, rhs: Self) -> Self {
-                self.overflowing_div(rhs).0
-            }
-        }
-
-        doc_comment! {
-            concat!("Wrapping Euclidean division. Computes `self.div_euclid(rhs)`,
-wrapping around at the boundary of the type.
-
-Wrapping will only occur in `MIN / -1` on a signed type (where `MIN` is the negative minimal value
-for the type). This is equivalent to `-MIN`, a positive value that is too large to represent in the
-type. In this case, this method returns `MIN` itself.
-
-# Panics
-
-This function will panic if `rhs` is 0.
-
-# Examples
-
-Basic usage:
-
-```
-assert_eq!(100", stringify!($SelfT), ".wrapping_div_euclid(10), 10);
-assert_eq!((-128i8).wrapping_div_euclid(-1), -128);
-```"),
-            #[stable(feature = "euclidean_division", since = "1.38.0")]
-            #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
-            #[must_use = "this returns the result of the operation, \
-                          without modifying the original"]
-            #[inline]
-            pub const fn wrapping_div_euclid(self, rhs: Self) -> Self {
-                self.overflowing_div_euclid(rhs).0
-            }
-        }
-
-        doc_comment! {
-            concat!("Wrapping (modular) remainder. Computes `self % rhs`, wrapping around at the
-boundary of the type.
-
-Such wrap-around never actually occurs mathematically; implementation artifacts make `x % y`
-invalid for `MIN / -1` on a signed type (where `MIN` is the negative minimal value). In such a case,
-this function returns `0`.
-
-# Panics
-
-This function will panic if `rhs` is 0.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_rem(10), 0);
-assert_eq!((-128i8).wrapping_rem(-1), 0);",
-$EndFeature, "
-```"),
-            #[stable(feature = "num_wrapping", since = "1.2.0")]
-            #[rustc_const_unstable(feature = "const_wrapping_int_methods", issue = "53718")]
-            #[must_use = "this returns the result of the operation, \
-                          without modifying the original"]
-            #[inline]
-            pub const fn wrapping_rem(self, rhs: Self) -> Self {
-                self.overflowing_rem(rhs).0
-            }
-        }
-
-        doc_comment! {
-            concat!("Wrapping Euclidean remainder. Computes `self.rem_euclid(rhs)`, wrapping around
-at the boundary of the type.
-
-Wrapping will only occur in `MIN % -1` on a signed type (where `MIN` is the negative minimal value
-for the type). In this case, this method returns 0.
-
-# Panics
-
-This function will panic if `rhs` is 0.
-
-# Examples
-
-Basic usage:
-
-```
-assert_eq!(100", stringify!($SelfT), ".wrapping_rem_euclid(10), 0);
-assert_eq!((-128i8).wrapping_rem_euclid(-1), 0);
-```"),
-            #[stable(feature = "euclidean_division", since = "1.38.0")]
-            #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
-            #[must_use = "this returns the result of the operation, \
-                          without modifying the original"]
-            #[inline]
-            pub const fn wrapping_rem_euclid(self, rhs: Self) -> Self {
-                self.overflowing_rem_euclid(rhs).0
-            }
-        }
-
-        doc_comment! {
-            concat!("Wrapping (modular) negation. Computes `-self`, wrapping around at the boundary
-of the type.
-
-The only case where such wrapping can occur is when one negates `MIN` on a signed type (where `MIN`
-is the negative minimal value for the type); this is a positive value that is too large to represent
-in the type. In such a case, this function returns `MIN` itself.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_neg(), -100);
-assert_eq!(", stringify!($SelfT), "::MIN.wrapping_neg(), ", stringify!($SelfT),
-"::MIN);",
-$EndFeature, "
-```"),
-            #[stable(feature = "num_wrapping", since = "1.2.0")]
-            #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
-            #[inline]
-            pub const fn wrapping_neg(self) -> Self {
-                self.overflowing_neg().0
-            }
-        }
-
-        doc_comment! {
-            concat!("Panic-free bitwise shift-left; yields `self << mask(rhs)`, where `mask` removes
-any high-order bits of `rhs` that would cause the shift to exceed the bitwidth of the type.
-
-Note that this is *not* the same as a rotate-left; the RHS of a wrapping shift-left is restricted to
-the range of the type, rather than the bits shifted out of the LHS being returned to the other end.
-The primitive integer types all implement a [`rotate_left`](#method.rotate_left) function,
-which may be what you want instead.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!((-1", stringify!($SelfT), ").wrapping_shl(7), -128);
-assert_eq!((-1", stringify!($SelfT), ").wrapping_shl(128), -1);",
-$EndFeature, "
-```"),
-            #[stable(feature = "num_wrapping", since = "1.2.0")]
-            #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
-            #[must_use = "this returns the result of the operation, \
-                          without modifying the original"]
-            #[inline]
-            pub const fn wrapping_shl(self, rhs: u32) -> Self {
-                // SAFETY: the masking by the bitsize of the type ensures that we do not shift
-                // out of bounds
-                unsafe {
-                    intrinsics::unchecked_shl(self, (rhs & ($BITS - 1)) as $SelfT)
-                }
-            }
-        }
-
-        doc_comment! {
-            concat!("Panic-free bitwise shift-right; yields `self >> mask(rhs)`, where `mask`
-removes any high-order bits of `rhs` that would cause the shift to exceed the bitwidth of the type.
-
-Note that this is *not* the same as a rotate-right; the RHS of a wrapping shift-right is restricted
-to the range of the type, rather than the bits shifted out of the LHS being returned to the other
-end. The primitive integer types all implement a [`rotate_right`](#method.rotate_right) function,
-which may be what you want instead.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!((-128", stringify!($SelfT), ").wrapping_shr(7), -1);
-assert_eq!((-128i16).wrapping_shr(64), -128);",
-$EndFeature, "
-```"),
-            #[stable(feature = "num_wrapping", since = "1.2.0")]
-            #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
-            #[must_use = "this returns the result of the operation, \
-                          without modifying the original"]
-            #[inline]
-            pub const fn wrapping_shr(self, rhs: u32) -> Self {
-                // SAFETY: the masking by the bitsize of the type ensures that we do not shift
-                // out of bounds
-                unsafe {
-                    intrinsics::unchecked_shr(self, (rhs & ($BITS - 1)) as $SelfT)
-                }
-            }
-        }
-
-        doc_comment! {
-            concat!("Wrapping (modular) absolute value. Computes `self.abs()`, wrapping around at
-the boundary of the type.
-
-The only case where such wrapping can occur is when one takes the absolute value of the negative
-minimal value for the type; this is a positive value that is too large to represent in the type. In
-such a case, this function returns `MIN` itself.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_abs(), 100);
-assert_eq!((-100", stringify!($SelfT), ").wrapping_abs(), 100);
-assert_eq!(", stringify!($SelfT), "::MIN.wrapping_abs(), ", stringify!($SelfT),
-"::MIN);
-assert_eq!((-128i8).wrapping_abs() as u8, 128);",
-$EndFeature, "
-```"),
-            #[stable(feature = "no_panic_abs", since = "1.13.0")]
-            #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
-            #[allow(unused_attributes)]
-            #[inline]
-            pub const fn wrapping_abs(self) -> Self {
-                 if self.is_negative() {
-                     self.wrapping_neg()
-                 } else {
-                     self
-                 }
-            }
-        }
-
-        doc_comment! {
-            concat!("Computes the absolute value of `self` without any wrapping
-or panicking.
-
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "#![feature(unsigned_abs)]
-assert_eq!(100", stringify!($SelfT), ".unsigned_abs(), 100", stringify!($UnsignedT), ");
-assert_eq!((-100", stringify!($SelfT), ").unsigned_abs(), 100", stringify!($UnsignedT), ");
-assert_eq!((-128i8).unsigned_abs(), 128u8);",
-$EndFeature, "
-```"),
-            #[unstable(feature = "unsigned_abs", issue = "74913")]
-            #[inline]
-            pub const fn unsigned_abs(self) -> $UnsignedT {
-                 self.wrapping_abs() as $UnsignedT
-            }
-        }
-
-        doc_comment! {
-            concat!("Wrapping (modular) exponentiation. Computes `self.pow(exp)`,
-wrapping around at the boundary of the type.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(3", stringify!($SelfT), ".wrapping_pow(4), 81);
-assert_eq!(3i8.wrapping_pow(5), -13);
-assert_eq!(3i8.wrapping_pow(6), -39);",
-$EndFeature, "
-```"),
-            #[stable(feature = "no_panic_pow", since = "1.34.0")]
-            #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")]
-            #[must_use = "this returns the result of the operation, \
-                          without modifying the original"]
-            #[inline]
-            pub const fn wrapping_pow(self, mut exp: u32) -> Self {
-                if exp == 0 {
-                    return 1;
-                }
-                let mut base = self;
-                let mut acc: Self = 1;
-
-                while exp > 1 {
-                    if (exp & 1) == 1 {
-                        acc = acc.wrapping_mul(base);
-                    }
-                    exp /= 2;
-                    base = base.wrapping_mul(base);
-                }
-
-                // since exp!=0, finally the exp must be 1.
-                // Deal with the final bit of the exponent separately, since
-                // squaring the base afterwards is not necessary and may cause a
-                // needless overflow.
-                acc.wrapping_mul(base)
-            }
-        }
-
-        doc_comment! {
-            concat!("Calculates `self` + `rhs`
-
-Returns a tuple of the addition along with a boolean indicating whether an arithmetic overflow would
-occur. If an overflow would have occurred then the wrapped value is returned.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "
-assert_eq!(5", stringify!($SelfT), ".overflowing_add(2), (7, false));
-assert_eq!(", stringify!($SelfT), "::MAX.overflowing_add(1), (", stringify!($SelfT),
-"::MIN, true));", $EndFeature, "
-```"),
-            #[stable(feature = "wrapping", since = "1.7.0")]
-            #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
-            #[must_use = "this returns the result of the operation, \
-                          without modifying the original"]
-            #[inline]
-            pub const fn overflowing_add(self, rhs: Self) -> (Self, bool) {
-                let (a, b) = intrinsics::add_with_overflow(self as $ActualT, rhs as $ActualT);
-                (a as Self, b)
-            }
-        }
-
-        doc_comment! {
-            concat!("Calculates `self` - `rhs`
-
-Returns a tuple of the subtraction along with a boolean indicating whether an arithmetic overflow
-would occur. If an overflow would have occurred then the wrapped value is returned.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "
-assert_eq!(5", stringify!($SelfT), ".overflowing_sub(2), (3, false));
-assert_eq!(", stringify!($SelfT), "::MIN.overflowing_sub(1), (", stringify!($SelfT),
-"::MAX, true));", $EndFeature, "
-```"),
-            #[stable(feature = "wrapping", since = "1.7.0")]
-            #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
-            #[must_use = "this returns the result of the operation, \
-                          without modifying the original"]
-            #[inline]
-            pub const fn overflowing_sub(self, rhs: Self) -> (Self, bool) {
-                let (a, b) = intrinsics::sub_with_overflow(self as $ActualT, rhs as $ActualT);
-                (a as Self, b)
-            }
-        }
-
-        doc_comment! {
-            concat!("Calculates the multiplication of `self` and `rhs`.
-
-Returns a tuple of the multiplication along with a boolean indicating whether an arithmetic overflow
-would occur. If an overflow would have occurred then the wrapped value is returned.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(5", stringify!($SelfT), ".overflowing_mul(2), (10, false));
-assert_eq!(1_000_000_000i32.overflowing_mul(10), (1410065408, true));",
-$EndFeature, "
-```"),
-            #[stable(feature = "wrapping", since = "1.7.0")]
-            #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
-            #[must_use = "this returns the result of the operation, \
-                          without modifying the original"]
-            #[inline]
-            pub const fn overflowing_mul(self, rhs: Self) -> (Self, bool) {
-                let (a, b) = intrinsics::mul_with_overflow(self as $ActualT, rhs as $ActualT);
-                (a as Self, b)
-            }
-        }
-
-        doc_comment! {
-            concat!("Calculates the divisor when `self` is divided by `rhs`.
-
-Returns a tuple of the divisor along with a boolean indicating whether an arithmetic overflow would
-occur. If an overflow would occur then self is returned.
-
-# Panics
-
-This function will panic if `rhs` is 0.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "
-assert_eq!(5", stringify!($SelfT), ".overflowing_div(2), (2, false));
-assert_eq!(", stringify!($SelfT), "::MIN.overflowing_div(-1), (", stringify!($SelfT),
-"::MIN, true));",
-$EndFeature, "
-```"),
-            #[inline]
-            #[stable(feature = "wrapping", since = "1.7.0")]
-            #[rustc_const_unstable(feature = "const_overflowing_int_methods", issue = "53718")]
-            #[must_use = "this returns the result of the operation, \
-                          without modifying the original"]
-            pub const fn overflowing_div(self, rhs: Self) -> (Self, bool) {
-                if unlikely!(self == Self::MIN && rhs == -1) {
-                    (self, true)
-                } else {
-                    (self / rhs, false)
-                }
-            }
-        }
-
-        doc_comment! {
-            concat!("Calculates the quotient of Euclidean division `self.div_euclid(rhs)`.
-
-Returns a tuple of the divisor along with a boolean indicating whether an arithmetic overflow would
-occur. If an overflow would occur then `self` is returned.
-
-# Panics
-
-This function will panic if `rhs` is 0.
-
-# Examples
-
-Basic usage:
-
-```
-assert_eq!(5", stringify!($SelfT), ".overflowing_div_euclid(2), (2, false));
-assert_eq!(", stringify!($SelfT), "::MIN.overflowing_div_euclid(-1), (", stringify!($SelfT),
-"::MIN, true));
-```"),
-            #[inline]
-            #[stable(feature = "euclidean_division", since = "1.38.0")]
-            #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
-            #[must_use = "this returns the result of the operation, \
-                          without modifying the original"]
-            pub const fn overflowing_div_euclid(self, rhs: Self) -> (Self, bool) {
-                if unlikely!(self == Self::MIN && rhs == -1) {
-                    (self, true)
-                } else {
-                    (self.div_euclid(rhs), false)
-                }
-            }
-        }
-
-        doc_comment! {
-            concat!("Calculates the remainder when `self` is divided by `rhs`.
-
-Returns a tuple of the remainder after dividing along with a boolean indicating whether an
-arithmetic overflow would occur. If an overflow would occur then 0 is returned.
-
-# Panics
-
-This function will panic if `rhs` is 0.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "
-assert_eq!(5", stringify!($SelfT), ".overflowing_rem(2), (1, false));
-assert_eq!(", stringify!($SelfT), "::MIN.overflowing_rem(-1), (0, true));",
-$EndFeature, "
-```"),
-            #[inline]
-            #[stable(feature = "wrapping", since = "1.7.0")]
-            #[rustc_const_unstable(feature = "const_overflowing_int_methods", issue = "53718")]
-            #[must_use = "this returns the result of the operation, \
-                          without modifying the original"]
-            pub const fn overflowing_rem(self, rhs: Self) -> (Self, bool) {
-                if unlikely!(self == Self::MIN && rhs == -1) {
-                    (0, true)
-                } else {
-                    (self % rhs, false)
-                }
-            }
-        }
-
-
-        doc_comment! {
-            concat!("Overflowing Euclidean remainder. Calculates `self.rem_euclid(rhs)`.
-
-Returns a tuple of the remainder after dividing along with a boolean indicating whether an
-arithmetic overflow would occur. If an overflow would occur then 0 is returned.
-
-# Panics
-
-This function will panic if `rhs` is 0.
-
-# Examples
-
-Basic usage:
-
-```
-assert_eq!(5", stringify!($SelfT), ".overflowing_rem_euclid(2), (1, false));
-assert_eq!(", stringify!($SelfT), "::MIN.overflowing_rem_euclid(-1), (0, true));
-```"),
-            #[stable(feature = "euclidean_division", since = "1.38.0")]
-            #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
-            #[must_use = "this returns the result of the operation, \
-                          without modifying the original"]
-            #[inline]
-            pub const fn overflowing_rem_euclid(self, rhs: Self) -> (Self, bool) {
-                if unlikely!(self == Self::MIN && rhs == -1) {
-                    (0, true)
-                } else {
-                    (self.rem_euclid(rhs), false)
+        /// The smallest value that can be represented by this integer type.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN, ", stringify!($Min), ");")]
+        /// ```
+        #[stable(feature = "assoc_int_consts", since = "1.43.0")]
+        pub const MIN: Self = !0 ^ ((!0 as $UnsignedT) >> 1) as Self;
+
+        /// The largest value that can be represented by this integer type.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX, ", stringify!($Max), ");")]
+        /// ```
+        #[stable(feature = "assoc_int_consts", since = "1.43.0")]
+        pub const MAX: Self = !Self::MIN;
+
+        /// The size of this integer type in bits.
+        ///
+        /// # Examples
+        ///
+        /// ```
+        /// #![feature(int_bits_const)]
+        #[doc = concat!("assert_eq!(", stringify!($SelfT), "::BITS, ", stringify!($BITS), ");")]
+        /// ```
+        #[unstable(feature = "int_bits_const", issue = "76904")]
+        pub const BITS: u32 = $BITS;
+
+        /// Converts a string slice in a given base to an integer.
+        ///
+        /// The string is expected to be an optional `+` or `-` sign followed by digits.
+        /// Leading and trailing whitespace represent an error. Digits are a subset of these characters,
+        /// depending on `radix`:
+        ///
+        ///  * `0-9`
+        ///  * `a-z`
+        ///  * `A-Z`
+        ///
+        /// # Panics
+        ///
+        /// This function panics if `radix` is not in the range from 2 to 36.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("assert_eq!(", stringify!($SelfT), "::from_str_radix(\"A\", 16), Ok(10));")]
+        /// ```
+        #[stable(feature = "rust1", since = "1.0.0")]
+        pub fn from_str_radix(src: &str, radix: u32) -> Result<Self, ParseIntError> {
+            from_str_radix(src, radix)
+        }
+
+        /// Returns the number of ones in the binary representation of `self`.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("let n = 0b100_0000", stringify!($SelfT), ";")]
+        ///
+        /// assert_eq!(n.count_ones(), 1);
+        /// ```
+        ///
+        #[stable(feature = "rust1", since = "1.0.0")]
+        #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
+        #[doc(alias = "popcount")]
+        #[doc(alias = "popcnt")]
+        #[inline]
+        pub const fn count_ones(self) -> u32 { (self as $UnsignedT).count_ones() }
+
+        /// Returns the number of zeros in the binary representation of `self`.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.count_zeros(), 1);")]
+        /// ```
+        #[stable(feature = "rust1", since = "1.0.0")]
+        #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
+        #[inline]
+        pub const fn count_zeros(self) -> u32 {
+            (!self).count_ones()
+        }
+
+        /// Returns the number of leading zeros in the binary representation of `self`.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("let n = -1", stringify!($SelfT), ";")]
+        ///
+        /// assert_eq!(n.leading_zeros(), 0);
+        /// ```
+        #[stable(feature = "rust1", since = "1.0.0")]
+        #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
+        #[inline]
+        pub const fn leading_zeros(self) -> u32 {
+            (self as $UnsignedT).leading_zeros()
+        }
+
+        /// Returns the number of trailing zeros in the binary representation of `self`.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("let n = -4", stringify!($SelfT), ";")]
+        ///
+        /// assert_eq!(n.trailing_zeros(), 2);
+        /// ```
+        #[stable(feature = "rust1", since = "1.0.0")]
+        #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
+        #[inline]
+        pub const fn trailing_zeros(self) -> u32 {
+            (self as $UnsignedT).trailing_zeros()
+        }
+
+        /// Returns the number of leading ones in the binary representation of `self`.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("let n = -1", stringify!($SelfT), ";")]
+        ///
+        #[doc = concat!("assert_eq!(n.leading_ones(), ", stringify!($BITS), ");")]
+        /// ```
+        #[stable(feature = "leading_trailing_ones", since = "1.46.0")]
+        #[rustc_const_stable(feature = "leading_trailing_ones", since = "1.46.0")]
+        #[inline]
+        pub const fn leading_ones(self) -> u32 {
+            (self as $UnsignedT).leading_ones()
+        }
+
+        /// Returns the number of trailing ones in the binary representation of `self`.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("let n = 3", stringify!($SelfT), ";")]
+        ///
+        /// assert_eq!(n.trailing_ones(), 2);
+        /// ```
+        #[stable(feature = "leading_trailing_ones", since = "1.46.0")]
+        #[rustc_const_stable(feature = "leading_trailing_ones", since = "1.46.0")]
+        #[inline]
+        pub const fn trailing_ones(self) -> u32 {
+            (self as $UnsignedT).trailing_ones()
+        }
+
+        /// Shifts the bits to the left by a specified amount, `n`,
+        /// wrapping the truncated bits to the end of the resulting integer.
+        ///
+        /// Please note this isn't the same operation as the `<<` shifting operator!
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("let n = ", $rot_op, stringify!($SelfT), ";")]
+        #[doc = concat!("let m = ", $rot_result, ";")]
+        ///
+        #[doc = concat!("assert_eq!(n.rotate_left(", $rot, "), m);")]
+        /// ```
+        #[stable(feature = "rust1", since = "1.0.0")]
+        #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const fn rotate_left(self, n: u32) -> Self {
+            (self as $UnsignedT).rotate_left(n) as Self
+        }
+
+        /// Shifts the bits to the right by a specified amount, `n`,
+        /// wrapping the truncated bits to the beginning of the resulting
+        /// integer.
+        ///
+        /// Please note this isn't the same operation as the `>>` shifting operator!
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("let n = ", $rot_result, stringify!($SelfT), ";")]
+        #[doc = concat!("let m = ", $rot_op, ";")]
+        ///
+        #[doc = concat!("assert_eq!(n.rotate_right(", $rot, "), m);")]
+        /// ```
+        #[stable(feature = "rust1", since = "1.0.0")]
+        #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const fn rotate_right(self, n: u32) -> Self {
+            (self as $UnsignedT).rotate_right(n) as Self
+        }
+
+        /// Reverses the byte order of the integer.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("let n = ", $swap_op, stringify!($SelfT), ";")]
+        ///
+        /// let m = n.swap_bytes();
+        ///
+        #[doc = concat!("assert_eq!(m, ", $swapped, ");")]
+        /// ```
+        #[stable(feature = "rust1", since = "1.0.0")]
+        #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
+        #[inline]
+        pub const fn swap_bytes(self) -> Self {
+            (self as $UnsignedT).swap_bytes() as Self
+        }
+
+        /// Reverses the order of bits in the integer. The least significant bit becomes the most significant bit,
+        ///                 second least-significant bit becomes second most-significant bit, etc.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("let n = ", $swap_op, stringify!($SelfT), ";")]
+        /// let m = n.reverse_bits();
+        ///
+        #[doc = concat!("assert_eq!(m, ", $reversed, ");")]
+        #[doc = concat!("assert_eq!(0, 0", stringify!($SelfT), ".reverse_bits());")]
+        /// ```
+        #[stable(feature = "reverse_bits", since = "1.37.0")]
+        #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
+        #[inline]
+        #[must_use]
+        pub const fn reverse_bits(self) -> Self {
+            (self as $UnsignedT).reverse_bits() as Self
+        }
+
+        /// Converts an integer from big endian to the target's endianness.
+        ///
+        /// On big endian this is a no-op. On little endian the bytes are swapped.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("let n = 0x1A", stringify!($SelfT), ";")]
+        ///
+        /// if cfg!(target_endian = "big") {
+        #[doc = concat!("    assert_eq!(", stringify!($SelfT), "::from_be(n), n)")]
+        /// } else {
+        #[doc = concat!("    assert_eq!(", stringify!($SelfT), "::from_be(n), n.swap_bytes())")]
+        /// }
+        /// ```
+        #[stable(feature = "rust1", since = "1.0.0")]
+        #[rustc_const_stable(feature = "const_int_conversions", since = "1.32.0")]
+        #[inline]
+        pub const fn from_be(x: Self) -> Self {
+            #[cfg(target_endian = "big")]
+            {
+                x
+            }
+            #[cfg(not(target_endian = "big"))]
+            {
+                x.swap_bytes()
+            }
+        }
+
+        /// Converts an integer from little endian to the target's endianness.
+        ///
+        /// On little endian this is a no-op. On big endian the bytes are swapped.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("let n = 0x1A", stringify!($SelfT), ";")]
+        ///
+        /// if cfg!(target_endian = "little") {
+        #[doc = concat!("    assert_eq!(", stringify!($SelfT), "::from_le(n), n)")]
+        /// } else {
+        #[doc = concat!("    assert_eq!(", stringify!($SelfT), "::from_le(n), n.swap_bytes())")]
+        /// }
+        /// ```
+        #[stable(feature = "rust1", since = "1.0.0")]
+        #[rustc_const_stable(feature = "const_int_conversions", since = "1.32.0")]
+        #[inline]
+        pub const fn from_le(x: Self) -> Self {
+            #[cfg(target_endian = "little")]
+            {
+                x
+            }
+            #[cfg(not(target_endian = "little"))]
+            {
+                x.swap_bytes()
+            }
+        }
+
+        /// Converts `self` to big endian from the target's endianness.
+        ///
+        /// On big endian this is a no-op. On little endian the bytes are swapped.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("let n = 0x1A", stringify!($SelfT), ";")]
+        ///
+        /// if cfg!(target_endian = "big") {
+        ///     assert_eq!(n.to_be(), n)
+        /// } else {
+        ///     assert_eq!(n.to_be(), n.swap_bytes())
+        /// }
+        /// ```
+        #[stable(feature = "rust1", since = "1.0.0")]
+        #[rustc_const_stable(feature = "const_int_conversions", since = "1.32.0")]
+        #[inline]
+        pub const fn to_be(self) -> Self { // or not to be?
+            #[cfg(target_endian = "big")]
+            {
+                self
+            }
+            #[cfg(not(target_endian = "big"))]
+            {
+                self.swap_bytes()
+            }
+        }
+
+        /// Converts `self` to little endian from the target's endianness.
+        ///
+        /// On little endian this is a no-op. On big endian the bytes are swapped.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("let n = 0x1A", stringify!($SelfT), ";")]
+        ///
+        /// if cfg!(target_endian = "little") {
+        ///     assert_eq!(n.to_le(), n)
+        /// } else {
+        ///     assert_eq!(n.to_le(), n.swap_bytes())
+        /// }
+        /// ```
+        #[stable(feature = "rust1", since = "1.0.0")]
+        #[rustc_const_stable(feature = "const_int_conversions", since = "1.32.0")]
+        #[inline]
+        pub const fn to_le(self) -> Self {
+            #[cfg(target_endian = "little")]
+            {
+                self
+            }
+            #[cfg(not(target_endian = "little"))]
+            {
+                self.swap_bytes()
+            }
+        }
+
+        /// Checked integer addition. Computes `self + rhs`, returning `None`
+        /// if overflow occurred.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).checked_add(1), Some(", stringify!($SelfT), "::MAX - 1));")]
+        #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).checked_add(3), None);")]
+        /// ```
+        #[stable(feature = "rust1", since = "1.0.0")]
+        #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const fn checked_add(self, rhs: Self) -> Option<Self> {
+            let (a, b) = self.overflowing_add(rhs);
+            if unlikely!(b) {None} else {Some(a)}
+        }
+
+        /// Unchecked integer addition. Computes `self + rhs`, assuming overflow
+        /// cannot occur. This results in undefined behavior when
+        #[doc = concat!("`self + rhs > ", stringify!($SelfT), "::MAX` or `self + rhs < ", stringify!($SelfT), "::MIN`.")]
+        #[unstable(
+            feature = "unchecked_math",
+            reason = "niche optimization path",
+            issue = "none",
+        )]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub unsafe fn unchecked_add(self, rhs: Self) -> Self {
+            // SAFETY: the caller must uphold the safety contract for
+            // `unchecked_add`.
+            unsafe { intrinsics::unchecked_add(self, rhs) }
+        }
+
+        /// Checked integer subtraction. Computes `self - rhs`, returning `None` if
+        /// overflow occurred.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MIN + 2).checked_sub(1), Some(", stringify!($SelfT), "::MIN + 1));")]
+        #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MIN + 2).checked_sub(3), None);")]
+        /// ```
+        #[stable(feature = "rust1", since = "1.0.0")]
+        #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const fn checked_sub(self, rhs: Self) -> Option<Self> {
+            let (a, b) = self.overflowing_sub(rhs);
+            if unlikely!(b) {None} else {Some(a)}
+        }
+
+        /// Unchecked integer subtraction. Computes `self - rhs`, assuming overflow
+        /// cannot occur. This results in undefined behavior when
+        #[doc = concat!("`self - rhs > ", stringify!($SelfT), "::MAX` or `self - rhs < ", stringify!($SelfT), "::MIN`.")]
+        #[unstable(
+            feature = "unchecked_math",
+            reason = "niche optimization path",
+            issue = "none",
+        )]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub unsafe fn unchecked_sub(self, rhs: Self) -> Self {
+            // SAFETY: the caller must uphold the safety contract for
+            // `unchecked_sub`.
+            unsafe { intrinsics::unchecked_sub(self, rhs) }
+        }
+
+        /// Checked integer multiplication. Computes `self * rhs`, returning `None` if
+        /// overflow occurred.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.checked_mul(1), Some(", stringify!($SelfT), "::MAX));")]
+        #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.checked_mul(2), None);")]
+        /// ```
+        #[stable(feature = "rust1", since = "1.0.0")]
+        #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const fn checked_mul(self, rhs: Self) -> Option<Self> {
+            let (a, b) = self.overflowing_mul(rhs);
+            if unlikely!(b) {None} else {Some(a)}
+        }
+
+        /// Unchecked integer multiplication. Computes `self * rhs`, assuming overflow
+        /// cannot occur. This results in undefined behavior when
+        #[doc = concat!("`self * rhs > ", stringify!($SelfT), "::MAX` or `self * rhs < ", stringify!($SelfT), "::MIN`.")]
+        #[unstable(
+            feature = "unchecked_math",
+            reason = "niche optimization path",
+            issue = "none",
+        )]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub unsafe fn unchecked_mul(self, rhs: Self) -> Self {
+            // SAFETY: the caller must uphold the safety contract for
+            // `unchecked_mul`.
+            unsafe { intrinsics::unchecked_mul(self, rhs) }
+        }
+
+        /// Checked integer division. Computes `self / rhs`, returning `None` if `rhs == 0`
+        /// or the division results in overflow.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MIN + 1).checked_div(-1), Some(", stringify!($Max), "));")]
+        #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.checked_div(-1), None);")]
+        #[doc = concat!("assert_eq!((1", stringify!($SelfT), ").checked_div(0), None);")]
+        /// ```
+        #[stable(feature = "rust1", since = "1.0.0")]
+        #[rustc_const_unstable(feature = "const_checked_int_methods", issue = "53718")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const fn checked_div(self, rhs: Self) -> Option<Self> {
+            if unlikely!(rhs == 0 || (self == Self::MIN && rhs == -1)) {
+                None
+            } else {
+                // SAFETY: div by zero and by INT_MIN have been checked above
+                Some(unsafe { intrinsics::unchecked_div(self, rhs) })
+            }
+        }
+
+        /// Checked Euclidean division. Computes `self.div_euclid(rhs)`,
+        /// returning `None` if `rhs == 0` or the division results in overflow.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MIN + 1).checked_div_euclid(-1), Some(", stringify!($Max), "));")]
+        #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.checked_div_euclid(-1), None);")]
+        #[doc = concat!("assert_eq!((1", stringify!($SelfT), ").checked_div_euclid(0), None);")]
+        /// ```
+        #[stable(feature = "euclidean_division", since = "1.38.0")]
+        #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const fn checked_div_euclid(self, rhs: Self) -> Option<Self> {
+            if unlikely!(rhs == 0 || (self == Self::MIN && rhs == -1)) {
+                None
+            } else {
+                Some(self.div_euclid(rhs))
+            }
+        }
+
+        /// Checked integer remainder. Computes `self % rhs`, returning `None` if
+        /// `rhs == 0` or the division results in overflow.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        ///
+        #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".checked_rem(2), Some(1));")]
+        #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".checked_rem(0), None);")]
+        #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.checked_rem(-1), None);")]
+        /// ```
+        #[stable(feature = "wrapping", since = "1.7.0")]
+        #[rustc_const_unstable(feature = "const_checked_int_methods", issue = "53718")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const fn checked_rem(self, rhs: Self) -> Option<Self> {
+            if unlikely!(rhs == 0 || (self == Self::MIN && rhs == -1)) {
+                None
+            } else {
+                // SAFETY: div by zero and by INT_MIN have been checked above
+                Some(unsafe { intrinsics::unchecked_rem(self, rhs) })
+            }
+        }
+
+        /// Checked Euclidean remainder. Computes `self.rem_euclid(rhs)`, returning `None`
+        /// if `rhs == 0` or the division results in overflow.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".checked_rem_euclid(2), Some(1));")]
+        #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".checked_rem_euclid(0), None);")]
+        #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.checked_rem_euclid(-1), None);")]
+        /// ```
+        #[stable(feature = "euclidean_division", since = "1.38.0")]
+        #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const fn checked_rem_euclid(self, rhs: Self) -> Option<Self> {
+            if unlikely!(rhs == 0 || (self == Self::MIN && rhs == -1)) {
+                None
+            } else {
+                Some(self.rem_euclid(rhs))
+            }
+        }
+
+        /// Checked negation. Computes `-self`, returning `None` if `self == MIN`.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        ///
+        #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".checked_neg(), Some(-5));")]
+        #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.checked_neg(), None);")]
+        /// ```
+        #[stable(feature = "wrapping", since = "1.7.0")]
+        #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")]
+        #[inline]
+        pub const fn checked_neg(self) -> Option<Self> {
+            let (a, b) = self.overflowing_neg();
+            if unlikely!(b) {None} else {Some(a)}
+        }
+
+        /// Checked shift left. Computes `self << rhs`, returning `None` if `rhs` is larger
+        /// than or equal to the number of bits in `self`.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".checked_shl(4), Some(0x10));")]
+        #[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".checked_shl(129), None);")]
+        /// ```
+        #[stable(feature = "wrapping", since = "1.7.0")]
+        #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const fn checked_shl(self, rhs: u32) -> Option<Self> {
+            let (a, b) = self.overflowing_shl(rhs);
+            if unlikely!(b) {None} else {Some(a)}
+        }
+
+        /// Checked shift right. Computes `self >> rhs`, returning `None` if `rhs` is
+        /// larger than or equal to the number of bits in `self`.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".checked_shr(4), Some(0x1));")]
+        #[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".checked_shr(128), None);")]
+        /// ```
+        #[stable(feature = "wrapping", since = "1.7.0")]
+        #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const fn checked_shr(self, rhs: u32) -> Option<Self> {
+            let (a, b) = self.overflowing_shr(rhs);
+            if unlikely!(b) {None} else {Some(a)}
+        }
+
+        /// Checked absolute value. Computes `self.abs()`, returning `None` if
+        /// `self == MIN`.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        ///
+        #[doc = concat!("assert_eq!((-5", stringify!($SelfT), ").checked_abs(), Some(5));")]
+        #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.checked_abs(), None);")]
+        /// ```
+        #[stable(feature = "no_panic_abs", since = "1.13.0")]
+        #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")]
+        #[inline]
+        pub const fn checked_abs(self) -> Option<Self> {
+            if self.is_negative() {
+                self.checked_neg()
+            } else {
+                Some(self)
+            }
+        }
+
+        /// Checked exponentiation. Computes `self.pow(exp)`, returning `None` if
+        /// overflow occurred.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("assert_eq!(8", stringify!($SelfT), ".checked_pow(2), Some(64));")]
+        #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.checked_pow(2), None);")]
+        /// ```
+
+        #[stable(feature = "no_panic_pow", since = "1.34.0")]
+        #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const fn checked_pow(self, mut exp: u32) -> Option<Self> {
+            if exp == 0 {
+                return Some(1);
+            }
+            let mut base = self;
+            let mut acc: Self = 1;
+
+            while exp > 1 {
+                if (exp & 1) == 1 {
+                    acc = try_opt!(acc.checked_mul(base));
                 }
-            }
-        }
-
-
-        doc_comment! {
-            concat!("Negates self, overflowing if this is equal to the minimum value.
-
-Returns a tuple of the negated version of self along with a boolean indicating whether an overflow
-happened. If `self` is the minimum value (e.g., `i32::MIN` for values of type `i32`), then the
-minimum value will be returned again and `true` will be returned for an overflow happening.
-
-# Examples
-
-Basic usage:
-
-```
-assert_eq!(2", stringify!($SelfT), ".overflowing_neg(), (-2, false));
-assert_eq!(", stringify!($SelfT), "::MIN.overflowing_neg(), (", stringify!($SelfT),
-"::MIN, true));", $EndFeature, "
-```"),
-            #[inline]
-            #[stable(feature = "wrapping", since = "1.7.0")]
-            #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
-            #[allow(unused_attributes)]
-            pub const fn overflowing_neg(self) -> (Self, bool) {
-                if unlikely!(self == Self::MIN) {
-                    (Self::MIN, true)
+                exp /= 2;
+                base = try_opt!(base.checked_mul(base));
+            }
+            // since exp!=0, finally the exp must be 1.
+            // Deal with the final bit of the exponent separately, since
+            // squaring the base afterwards is not necessary and may cause a
+            // needless overflow.
+            Some(try_opt!(acc.checked_mul(base)))
+        }
+
+        /// Saturating integer addition. Computes `self + rhs`, saturating at the numeric
+        /// bounds instead of overflowing.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".saturating_add(1), 101);")]
+        #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.saturating_add(100), ", stringify!($SelfT), "::MAX);")]
+        #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.saturating_add(-1), ", stringify!($SelfT), "::MIN);")]
+        /// ```
+
+        #[stable(feature = "rust1", since = "1.0.0")]
+        #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const fn saturating_add(self, rhs: Self) -> Self {
+            intrinsics::saturating_add(self, rhs)
+        }
+
+        /// Saturating integer subtraction. Computes `self - rhs`, saturating at the
+        /// numeric bounds instead of overflowing.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".saturating_sub(127), -27);")]
+        #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.saturating_sub(100), ", stringify!($SelfT), "::MIN);")]
+        #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.saturating_sub(-1), ", stringify!($SelfT), "::MAX);")]
+        /// ```
+        #[stable(feature = "rust1", since = "1.0.0")]
+        #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const fn saturating_sub(self, rhs: Self) -> Self {
+            intrinsics::saturating_sub(self, rhs)
+        }
+
+        /// Saturating integer negation. Computes `-self`, returning `MAX` if `self == MIN`
+        /// instead of overflowing.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".saturating_neg(), -100);")]
+        #[doc = concat!("assert_eq!((-100", stringify!($SelfT), ").saturating_neg(), 100);")]
+        #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.saturating_neg(), ", stringify!($SelfT), "::MAX);")]
+        #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.saturating_neg(), ", stringify!($SelfT), "::MIN + 1);")]
+        /// ```
+
+        #[stable(feature = "saturating_neg", since = "1.45.0")]
+        #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")]
+        #[inline]
+        pub const fn saturating_neg(self) -> Self {
+            intrinsics::saturating_sub(0, self)
+        }
+
+        /// Saturating absolute value. Computes `self.abs()`, returning `MAX` if `self ==
+        /// MIN` instead of overflowing.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".saturating_abs(), 100);")]
+        #[doc = concat!("assert_eq!((-100", stringify!($SelfT), ").saturating_abs(), 100);")]
+        #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.saturating_abs(), ", stringify!($SelfT), "::MAX);")]
+        #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MIN + 1).saturating_abs(), ", stringify!($SelfT), "::MAX);")]
+        /// ```
+
+        #[stable(feature = "saturating_neg", since = "1.45.0")]
+        #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")]
+        #[inline]
+        pub const fn saturating_abs(self) -> Self {
+            if self.is_negative() {
+                self.saturating_neg()
+            } else {
+                self
+            }
+        }
+
+        /// Saturating integer multiplication. Computes `self * rhs`, saturating at the
+        /// numeric bounds instead of overflowing.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        ///
+        #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".saturating_mul(12), 120);")]
+        #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.saturating_mul(10), ", stringify!($SelfT), "::MAX);")]
+        #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.saturating_mul(10), ", stringify!($SelfT), "::MIN);")]
+        /// ```
+        #[stable(feature = "wrapping", since = "1.7.0")]
+        #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const fn saturating_mul(self, rhs: Self) -> Self {
+            match self.checked_mul(rhs) {
+                Some(x) => x,
+                None => if (self < 0) == (rhs < 0) {
+                    Self::MAX
                 } else {
-                    (-self, false)
+                    Self::MIN
                 }
             }
         }
 
-        doc_comment! {
-            concat!("Shifts self left by `rhs` bits.
-
-Returns a tuple of the shifted version of self along with a boolean indicating whether the shift
-value was larger than or equal to the number of bits. If the shift value is too large, then value is
-masked (N-1) where N is the number of bits, and this value is then used to perform the shift.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(0x1", stringify!($SelfT),".overflowing_shl(4), (0x10, false));
-assert_eq!(0x1i32.overflowing_shl(36), (0x10, true));",
-$EndFeature, "
-```"),
-            #[stable(feature = "wrapping", since = "1.7.0")]
-            #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
-            #[must_use = "this returns the result of the operation, \
-                          without modifying the original"]
-            #[inline]
-            pub const fn overflowing_shl(self, rhs: u32) -> (Self, bool) {
-                (self.wrapping_shl(rhs), (rhs > ($BITS - 1)))
-            }
-        }
-
-        doc_comment! {
-            concat!("Shifts self right by `rhs` bits.
-
-Returns a tuple of the shifted version of self along with a boolean indicating whether the shift
-value was larger than or equal to the number of bits. If the shift value is too large, then value is
-masked (N-1) where N is the number of bits, and this value is then used to perform the shift.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(0x10", stringify!($SelfT), ".overflowing_shr(4), (0x1, false));
-assert_eq!(0x10i32.overflowing_shr(36), (0x1, true));",
-$EndFeature, "
-```"),
-            #[stable(feature = "wrapping", since = "1.7.0")]
-            #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
-            #[must_use = "this returns the result of the operation, \
-                          without modifying the original"]
-            #[inline]
-            pub const fn overflowing_shr(self, rhs: u32) -> (Self, bool) {
-                (self.wrapping_shr(rhs), (rhs > ($BITS - 1)))
-            }
-        }
-
-        doc_comment! {
-            concat!("Computes the absolute value of `self`.
-
-Returns a tuple of the absolute version of self along with a boolean indicating whether an overflow
-happened. If self is the minimum value (e.g., ", stringify!($SelfT), "::MIN for values of type
- ", stringify!($SelfT), "), then the minimum value will be returned again and true will be returned
-for an overflow happening.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(10", stringify!($SelfT), ".overflowing_abs(), (10, false));
-assert_eq!((-10", stringify!($SelfT), ").overflowing_abs(), (10, false));
-assert_eq!((", stringify!($SelfT), "::MIN).overflowing_abs(), (", stringify!($SelfT),
-"::MIN, true));",
-$EndFeature, "
-```"),
-            #[stable(feature = "no_panic_abs", since = "1.13.0")]
-            #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
-            #[inline]
-            pub const fn overflowing_abs(self) -> (Self, bool) {
-                (self.wrapping_abs(), self == Self::MIN)
-            }
-        }
-
-        doc_comment! {
-            concat!("Raises self to the power of `exp`, using exponentiation by squaring.
-
-Returns a tuple of the exponentiation along with a bool indicating
-whether an overflow happened.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(3", stringify!($SelfT), ".overflowing_pow(4), (81, false));
-assert_eq!(3i8.overflowing_pow(5), (-13, true));",
-$EndFeature, "
-```"),
-            #[stable(feature = "no_panic_pow", since = "1.34.0")]
-            #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")]
-            #[must_use = "this returns the result of the operation, \
-                          without modifying the original"]
-            #[inline]
-            pub const fn overflowing_pow(self, mut exp: u32) -> (Self, bool) {
-                if exp == 0 {
-                    return (1,false);
+        /// Saturating integer exponentiation. Computes `self.pow(exp)`,
+        /// saturating at the numeric bounds instead of overflowing.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        ///
+        #[doc = concat!("assert_eq!((-4", stringify!($SelfT), ").saturating_pow(3), -64);")]
+        #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.saturating_pow(2), ", stringify!($SelfT), "::MAX);")]
+        #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.saturating_pow(3), ", stringify!($SelfT), "::MIN);")]
+        /// ```
+        #[stable(feature = "no_panic_pow", since = "1.34.0")]
+        #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const fn saturating_pow(self, exp: u32) -> Self {
+            match self.checked_pow(exp) {
+                Some(x) => x,
+                None if self < 0 && exp % 2 == 1 => Self::MIN,
+                None => Self::MAX,
+            }
+        }
+
+        /// Wrapping (modular) addition. Computes `self + rhs`, wrapping around at the
+        /// boundary of the type.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".wrapping_add(27), 127);")]
+        #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.wrapping_add(2), ", stringify!($SelfT), "::MIN + 1);")]
+        /// ```
+        #[stable(feature = "rust1", since = "1.0.0")]
+        #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const fn wrapping_add(self, rhs: Self) -> Self {
+            intrinsics::wrapping_add(self, rhs)
+        }
+
+        /// Wrapping (modular) subtraction. Computes `self - rhs`, wrapping around at the
+        /// boundary of the type.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".wrapping_sub(127), -127);")]
+        #[doc = concat!("assert_eq!((-2", stringify!($SelfT), ").wrapping_sub(", stringify!($SelfT), "::MAX), ", stringify!($SelfT), "::MAX);")]
+        /// ```
+        #[stable(feature = "rust1", since = "1.0.0")]
+        #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const fn wrapping_sub(self, rhs: Self) -> Self {
+            intrinsics::wrapping_sub(self, rhs)
+        }
+
+        /// Wrapping (modular) multiplication. Computes `self * rhs`, wrapping around at
+        /// the boundary of the type.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".wrapping_mul(12), 120);")]
+        /// assert_eq!(11i8.wrapping_mul(12), -124);
+        /// ```
+        #[stable(feature = "rust1", since = "1.0.0")]
+        #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const fn wrapping_mul(self, rhs: Self) -> Self {
+            intrinsics::wrapping_mul(self, rhs)
+        }
+
+        /// Wrapping (modular) division. Computes `self / rhs`, wrapping around at the
+        /// boundary of the type.
+        ///
+        /// The only case where such wrapping can occur is when one divides `MIN / -1` on a signed type (where
+        /// `MIN` is the negative minimal value for the type); this is equivalent to `-MIN`, a positive value
+        /// that is too large to represent in the type. In such a case, this function returns `MIN` itself.
+        ///
+        /// # Panics
+        ///
+        /// This function will panic if `rhs` is 0.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".wrapping_div(10), 10);")]
+        /// assert_eq!((-128i8).wrapping_div(-1), -128);
+        /// ```
+        #[stable(feature = "num_wrapping", since = "1.2.0")]
+        #[rustc_const_unstable(feature = "const_wrapping_int_methods", issue = "53718")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const fn wrapping_div(self, rhs: Self) -> Self {
+            self.overflowing_div(rhs).0
+        }
+
+        /// Wrapping Euclidean division. Computes `self.div_euclid(rhs)`,
+        /// wrapping around at the boundary of the type.
+        ///
+        /// Wrapping will only occur in `MIN / -1` on a signed type (where `MIN` is the negative minimal value
+        /// for the type). This is equivalent to `-MIN`, a positive value that is too large to represent in the
+        /// type. In this case, this method returns `MIN` itself.
+        ///
+        /// # Panics
+        ///
+        /// This function will panic if `rhs` is 0.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".wrapping_div_euclid(10), 10);")]
+        /// assert_eq!((-128i8).wrapping_div_euclid(-1), -128);
+        /// ```
+        #[stable(feature = "euclidean_division", since = "1.38.0")]
+        #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const fn wrapping_div_euclid(self, rhs: Self) -> Self {
+            self.overflowing_div_euclid(rhs).0
+        }
+
+        /// Wrapping (modular) remainder. Computes `self % rhs`, wrapping around at the
+        /// boundary of the type.
+        ///
+        /// Such wrap-around never actually occurs mathematically; implementation artifacts make `x % y`
+        /// invalid for `MIN / -1` on a signed type (where `MIN` is the negative minimal value). In such a case,
+        /// this function returns `0`.
+        ///
+        /// # Panics
+        ///
+        /// This function will panic if `rhs` is 0.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".wrapping_rem(10), 0);")]
+        /// assert_eq!((-128i8).wrapping_rem(-1), 0);
+        /// ```
+        #[stable(feature = "num_wrapping", since = "1.2.0")]
+        #[rustc_const_unstable(feature = "const_wrapping_int_methods", issue = "53718")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const fn wrapping_rem(self, rhs: Self) -> Self {
+            self.overflowing_rem(rhs).0
+        }
+
+        /// Wrapping Euclidean remainder. Computes `self.rem_euclid(rhs)`, wrapping around
+        /// at the boundary of the type.
+        ///
+        /// Wrapping will only occur in `MIN % -1` on a signed type (where `MIN` is the negative minimal value
+        /// for the type). In this case, this method returns 0.
+        ///
+        /// # Panics
+        ///
+        /// This function will panic if `rhs` is 0.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".wrapping_rem_euclid(10), 0);")]
+        /// assert_eq!((-128i8).wrapping_rem_euclid(-1), 0);
+        /// ```
+        #[stable(feature = "euclidean_division", since = "1.38.0")]
+        #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const fn wrapping_rem_euclid(self, rhs: Self) -> Self {
+            self.overflowing_rem_euclid(rhs).0
+        }
+
+        /// Wrapping (modular) negation. Computes `-self`, wrapping around at the boundary
+        /// of the type.
+        ///
+        /// The only case where such wrapping can occur is when one negates `MIN` on a signed type (where `MIN`
+        /// is the negative minimal value for the type); this is a positive value that is too large to represent
+        /// in the type. In such a case, this function returns `MIN` itself.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".wrapping_neg(), -100);")]
+        #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.wrapping_neg(), ", stringify!($SelfT), "::MIN);")]
+        /// ```
+        #[stable(feature = "num_wrapping", since = "1.2.0")]
+        #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
+        #[inline]
+        pub const fn wrapping_neg(self) -> Self {
+            self.overflowing_neg().0
+        }
+
+        /// Panic-free bitwise shift-left; yields `self << mask(rhs)`, where `mask` removes
+        /// any high-order bits of `rhs` that would cause the shift to exceed the bitwidth of the type.
+        ///
+        /// Note that this is *not* the same as a rotate-left; the RHS of a wrapping shift-left is restricted to
+        /// the range of the type, rather than the bits shifted out of the LHS being returned to the other end.
+        /// The primitive integer types all implement a [`rotate_left`](#method.rotate_left) function,
+        /// which may be what you want instead.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("assert_eq!((-1", stringify!($SelfT), ").wrapping_shl(7), -128);")]
+        #[doc = concat!("assert_eq!((-1", stringify!($SelfT), ").wrapping_shl(128), -1);")]
+        /// ```
+        #[stable(feature = "num_wrapping", since = "1.2.0")]
+        #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const fn wrapping_shl(self, rhs: u32) -> Self {
+            // SAFETY: the masking by the bitsize of the type ensures that we do not shift
+            // out of bounds
+            unsafe {
+                intrinsics::unchecked_shl(self, (rhs & ($BITS - 1)) as $SelfT)
+            }
+        }
+
+        /// Panic-free bitwise shift-right; yields `self >> mask(rhs)`, where `mask`
+        /// removes any high-order bits of `rhs` that would cause the shift to exceed the bitwidth of the type.
+        ///
+        /// Note that this is *not* the same as a rotate-right; the RHS of a wrapping shift-right is restricted
+        /// to the range of the type, rather than the bits shifted out of the LHS being returned to the other
+        /// end. The primitive integer types all implement a [`rotate_right`](#method.rotate_right) function,
+        /// which may be what you want instead.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("assert_eq!((-128", stringify!($SelfT), ").wrapping_shr(7), -1);")]
+        /// assert_eq!((-128i16).wrapping_shr(64), -128);
+        /// ```
+        #[stable(feature = "num_wrapping", since = "1.2.0")]
+        #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const fn wrapping_shr(self, rhs: u32) -> Self {
+            // SAFETY: the masking by the bitsize of the type ensures that we do not shift
+            // out of bounds
+            unsafe {
+                intrinsics::unchecked_shr(self, (rhs & ($BITS - 1)) as $SelfT)
+            }
+        }
+
+        /// Wrapping (modular) absolute value. Computes `self.abs()`, wrapping around at
+        /// the boundary of the type.
+        ///
+        /// The only case where such wrapping can occur is when one takes the absolute value of the negative
+        /// minimal value for the type; this is a positive value that is too large to represent in the type. In
+        /// such a case, this function returns `MIN` itself.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".wrapping_abs(), 100);")]
+        #[doc = concat!("assert_eq!((-100", stringify!($SelfT), ").wrapping_abs(), 100);")]
+        #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.wrapping_abs(), ", stringify!($SelfT), "::MIN);")]
+        /// assert_eq!((-128i8).wrapping_abs() as u8, 128);
+        /// ```
+        #[stable(feature = "no_panic_abs", since = "1.13.0")]
+        #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
+        #[allow(unused_attributes)]
+        #[inline]
+        pub const fn wrapping_abs(self) -> Self {
+             if self.is_negative() {
+                 self.wrapping_neg()
+             } else {
+                 self
+             }
+        }
+
+        /// Computes the absolute value of `self` without any wrapping
+        /// or panicking.
+        ///
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        /// #![feature(unsigned_abs)]
+        #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".unsigned_abs(), 100", stringify!($UnsignedT), ");")]
+        #[doc = concat!("assert_eq!((-100", stringify!($SelfT), ").unsigned_abs(), 100", stringify!($UnsignedT), ");")]
+        /// assert_eq!((-128i8).unsigned_abs(), 128u8);
+        /// ```
+        #[unstable(feature = "unsigned_abs", issue = "74913")]
+        #[inline]
+        pub const fn unsigned_abs(self) -> $UnsignedT {
+             self.wrapping_abs() as $UnsignedT
+        }
+
+        /// Wrapping (modular) exponentiation. Computes `self.pow(exp)`,
+        /// wrapping around at the boundary of the type.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("assert_eq!(3", stringify!($SelfT), ".wrapping_pow(4), 81);")]
+        /// assert_eq!(3i8.wrapping_pow(5), -13);
+        /// assert_eq!(3i8.wrapping_pow(6), -39);
+        /// ```
+        #[stable(feature = "no_panic_pow", since = "1.34.0")]
+        #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const fn wrapping_pow(self, mut exp: u32) -> Self {
+            if exp == 0 {
+                return 1;
+            }
+            let mut base = self;
+            let mut acc: Self = 1;
+
+            while exp > 1 {
+                if (exp & 1) == 1 {
+                    acc = acc.wrapping_mul(base);
                 }
-                let mut base = self;
-                let mut acc: Self = 1;
-                let mut overflown = false;
-                // Scratch space for storing results of overflowing_mul.
-                let mut r;
-
-                while exp > 1 {
-                    if (exp & 1) == 1 {
-                        r = acc.overflowing_mul(base);
-                        acc = r.0;
-                        overflown |= r.1;
-                    }
-                    exp /= 2;
-                    r = base.overflowing_mul(base);
-                    base = r.0;
+                exp /= 2;
+                base = base.wrapping_mul(base);
+            }
+
+            // since exp!=0, finally the exp must be 1.
+            // Deal with the final bit of the exponent separately, since
+            // squaring the base afterwards is not necessary and may cause a
+            // needless overflow.
+            acc.wrapping_mul(base)
+        }
+
+        /// Calculates `self` + `rhs`
+        ///
+        /// Returns a tuple of the addition along with a boolean indicating whether an arithmetic overflow would
+        /// occur. If an overflow would have occurred then the wrapped value is returned.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        ///
+        #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".overflowing_add(2), (7, false));")]
+        #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.overflowing_add(1), (", stringify!($SelfT), "::MIN, true));")]
+        /// ```
+        #[stable(feature = "wrapping", since = "1.7.0")]
+        #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const fn overflowing_add(self, rhs: Self) -> (Self, bool) {
+            let (a, b) = intrinsics::add_with_overflow(self as $ActualT, rhs as $ActualT);
+            (a as Self, b)
+        }
+
+        /// Calculates `self` - `rhs`
+        ///
+        /// Returns a tuple of the subtraction along with a boolean indicating whether an arithmetic overflow
+        /// would occur. If an overflow would have occurred then the wrapped value is returned.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        ///
+        #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".overflowing_sub(2), (3, false));")]
+        #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.overflowing_sub(1), (", stringify!($SelfT), "::MAX, true));")]
+        /// ```
+        #[stable(feature = "wrapping", since = "1.7.0")]
+        #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const fn overflowing_sub(self, rhs: Self) -> (Self, bool) {
+            let (a, b) = intrinsics::sub_with_overflow(self as $ActualT, rhs as $ActualT);
+            (a as Self, b)
+        }
+
+        /// Calculates the multiplication of `self` and `rhs`.
+        ///
+        /// Returns a tuple of the multiplication along with a boolean indicating whether an arithmetic overflow
+        /// would occur. If an overflow would have occurred then the wrapped value is returned.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".overflowing_mul(2), (10, false));")]
+        /// assert_eq!(1_000_000_000i32.overflowing_mul(10), (1410065408, true));
+        /// ```
+        #[stable(feature = "wrapping", since = "1.7.0")]
+        #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const fn overflowing_mul(self, rhs: Self) -> (Self, bool) {
+            let (a, b) = intrinsics::mul_with_overflow(self as $ActualT, rhs as $ActualT);
+            (a as Self, b)
+        }
+
+        /// Calculates the divisor when `self` is divided by `rhs`.
+        ///
+        /// Returns a tuple of the divisor along with a boolean indicating whether an arithmetic overflow would
+        /// occur. If an overflow would occur then self is returned.
+        ///
+        /// # Panics
+        ///
+        /// This function will panic if `rhs` is 0.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        ///
+        #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".overflowing_div(2), (2, false));")]
+        #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.overflowing_div(-1), (", stringify!($SelfT), "::MIN, true));")]
+        /// ```
+        #[inline]
+        #[stable(feature = "wrapping", since = "1.7.0")]
+        #[rustc_const_unstable(feature = "const_overflowing_int_methods", issue = "53718")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        pub const fn overflowing_div(self, rhs: Self) -> (Self, bool) {
+            if unlikely!(self == Self::MIN && rhs == -1) {
+                (self, true)
+            } else {
+                (self / rhs, false)
+            }
+        }
+
+        /// Calculates the quotient of Euclidean division `self.div_euclid(rhs)`.
+        ///
+        /// Returns a tuple of the divisor along with a boolean indicating whether an arithmetic overflow would
+        /// occur. If an overflow would occur then `self` is returned.
+        ///
+        /// # Panics
+        ///
+        /// This function will panic if `rhs` is 0.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".overflowing_div_euclid(2), (2, false));")]
+        #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.overflowing_div_euclid(-1), (", stringify!($SelfT), "::MIN, true));")]
+        /// ```
+        #[inline]
+        #[stable(feature = "euclidean_division", since = "1.38.0")]
+        #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        pub const fn overflowing_div_euclid(self, rhs: Self) -> (Self, bool) {
+            if unlikely!(self == Self::MIN && rhs == -1) {
+                (self, true)
+            } else {
+                (self.div_euclid(rhs), false)
+            }
+        }
+
+        /// Calculates the remainder when `self` is divided by `rhs`.
+        ///
+        /// Returns a tuple of the remainder after dividing along with a boolean indicating whether an
+        /// arithmetic overflow would occur. If an overflow would occur then 0 is returned.
+        ///
+        /// # Panics
+        ///
+        /// This function will panic if `rhs` is 0.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        ///
+        #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".overflowing_rem(2), (1, false));")]
+        #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.overflowing_rem(-1), (0, true));")]
+        /// ```
+        #[inline]
+        #[stable(feature = "wrapping", since = "1.7.0")]
+        #[rustc_const_unstable(feature = "const_overflowing_int_methods", issue = "53718")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        pub const fn overflowing_rem(self, rhs: Self) -> (Self, bool) {
+            if unlikely!(self == Self::MIN && rhs == -1) {
+                (0, true)
+            } else {
+                (self % rhs, false)
+            }
+        }
+
+
+        /// Overflowing Euclidean remainder. Calculates `self.rem_euclid(rhs)`.
+        ///
+        /// Returns a tuple of the remainder after dividing along with a boolean indicating whether an
+        /// arithmetic overflow would occur. If an overflow would occur then 0 is returned.
+        ///
+        /// # Panics
+        ///
+        /// This function will panic if `rhs` is 0.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".overflowing_rem_euclid(2), (1, false));")]
+        #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.overflowing_rem_euclid(-1), (0, true));")]
+        /// ```
+        #[stable(feature = "euclidean_division", since = "1.38.0")]
+        #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const fn overflowing_rem_euclid(self, rhs: Self) -> (Self, bool) {
+            if unlikely!(self == Self::MIN && rhs == -1) {
+                (0, true)
+            } else {
+                (self.rem_euclid(rhs), false)
+            }
+        }
+
+
+        /// Negates self, overflowing if this is equal to the minimum value.
+        ///
+        /// Returns a tuple of the negated version of self along with a boolean indicating whether an overflow
+        /// happened. If `self` is the minimum value (e.g., `i32::MIN` for values of type `i32`), then the
+        /// minimum value will be returned again and `true` will be returned for an overflow happening.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".overflowing_neg(), (-2, false));")]
+        #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.overflowing_neg(), (", stringify!($SelfT), "::MIN, true));")]
+        /// ```
+        #[inline]
+        #[stable(feature = "wrapping", since = "1.7.0")]
+        #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
+        #[allow(unused_attributes)]
+        pub const fn overflowing_neg(self) -> (Self, bool) {
+            if unlikely!(self == Self::MIN) {
+                (Self::MIN, true)
+            } else {
+                (-self, false)
+            }
+        }
+
+        /// Shifts self left by `rhs` bits.
+        ///
+        /// Returns a tuple of the shifted version of self along with a boolean indicating whether the shift
+        /// value was larger than or equal to the number of bits. If the shift value is too large, then value is
+        /// masked (N-1) where N is the number of bits, and this value is then used to perform the shift.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("assert_eq!(0x1", stringify!($SelfT),".overflowing_shl(4), (0x10, false));")]
+        /// assert_eq!(0x1i32.overflowing_shl(36), (0x10, true));
+        /// ```
+        #[stable(feature = "wrapping", since = "1.7.0")]
+        #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const fn overflowing_shl(self, rhs: u32) -> (Self, bool) {
+            (self.wrapping_shl(rhs), (rhs > ($BITS - 1)))
+        }
+
+        /// Shifts self right by `rhs` bits.
+        ///
+        /// Returns a tuple of the shifted version of self along with a boolean indicating whether the shift
+        /// value was larger than or equal to the number of bits. If the shift value is too large, then value is
+        /// masked (N-1) where N is the number of bits, and this value is then used to perform the shift.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".overflowing_shr(4), (0x1, false));")]
+        /// assert_eq!(0x10i32.overflowing_shr(36), (0x1, true));
+        /// ```
+        #[stable(feature = "wrapping", since = "1.7.0")]
+        #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const fn overflowing_shr(self, rhs: u32) -> (Self, bool) {
+            (self.wrapping_shr(rhs), (rhs > ($BITS - 1)))
+        }
+
+        /// Computes the absolute value of `self`.
+        ///
+        /// Returns a tuple of the absolute version of self along with a boolean indicating whether an overflow
+        /// happened. If self is the minimum value
+        #[doc = concat!("(e.g., ", stringify!($SelfT), "::MIN for values of type ", stringify!($SelfT), "),")]
+        /// then the minimum value will be returned again and true will be returned
+        /// for an overflow happening.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".overflowing_abs(), (10, false));")]
+        #[doc = concat!("assert_eq!((-10", stringify!($SelfT), ").overflowing_abs(), (10, false));")]
+        #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MIN).overflowing_abs(), (", stringify!($SelfT), "::MIN, true));")]
+        /// ```
+        #[stable(feature = "no_panic_abs", since = "1.13.0")]
+        #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
+        #[inline]
+        pub const fn overflowing_abs(self) -> (Self, bool) {
+            (self.wrapping_abs(), self == Self::MIN)
+        }
+
+        /// Raises self to the power of `exp`, using exponentiation by squaring.
+        ///
+        /// Returns a tuple of the exponentiation along with a bool indicating
+        /// whether an overflow happened.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("assert_eq!(3", stringify!($SelfT), ".overflowing_pow(4), (81, false));")]
+        /// assert_eq!(3i8.overflowing_pow(5), (-13, true));
+        /// ```
+        #[stable(feature = "no_panic_pow", since = "1.34.0")]
+        #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const fn overflowing_pow(self, mut exp: u32) -> (Self, bool) {
+            if exp == 0 {
+                return (1,false);
+            }
+            let mut base = self;
+            let mut acc: Self = 1;
+            let mut overflown = false;
+            // Scratch space for storing results of overflowing_mul.
+            let mut r;
+
+            while exp > 1 {
+                if (exp & 1) == 1 {
+                    r = acc.overflowing_mul(base);
+                    acc = r.0;
                     overflown |= r.1;
                 }
-
-                // since exp!=0, finally the exp must be 1.
-                // Deal with the final bit of the exponent separately, since
-                // squaring the base afterwards is not necessary and may cause a
-                // needless overflow.
-                r = acc.overflowing_mul(base);
-                r.1 |= overflown;
-                r
-            }
-        }
-
-        doc_comment! {
-            concat!("Raises self to the power of `exp`, using exponentiation by squaring.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "let x: ", stringify!($SelfT), " = 2; // or any other integer type
-
-assert_eq!(x.pow(5), 32);",
-$EndFeature, "
-```"),
-            #[stable(feature = "rust1", since = "1.0.0")]
-            #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")]
-            #[must_use = "this returns the result of the operation, \
-                          without modifying the original"]
-            #[inline]
-            #[rustc_inherit_overflow_checks]
-            pub const fn pow(self, mut exp: u32) -> Self {
-                if exp == 0 {
-                    return 1;
-                }
-                let mut base = self;
-                let mut acc = 1;
-
-                while exp > 1 {
-                    if (exp & 1) == 1 {
-                        acc = acc * base;
-                    }
-                    exp /= 2;
-                    base = base * base;
-                }
-
-                // since exp!=0, finally the exp must be 1.
-                // Deal with the final bit of the exponent separately, since
-                // squaring the base afterwards is not necessary and may cause a
-                // needless overflow.
-                acc * base
-            }
-        }
-
-        doc_comment! {
-            concat!("Calculates the quotient of Euclidean division of `self` by `rhs`.
-
-This computes the integer `n` such that `self = n * rhs + self.rem_euclid(rhs)`,
-with `0 <= self.rem_euclid(rhs) < rhs`.
-
-In other words, the result is `self / rhs` rounded to the integer `n`
-such that `self >= n * rhs`.
-If `self > 0`, this is equal to round towards zero (the default in Rust);
-if `self < 0`, this is equal to round towards +/- infinity.
-
-# Panics
-
-This function will panic if `rhs` is 0 or the division results in overflow.
-
-# Examples
-
-Basic usage:
-
-```
-let a: ", stringify!($SelfT), " = 7; // or any other integer type
-let b = 4;
-
-assert_eq!(a.div_euclid(b), 1); // 7 >= 4 * 1
-assert_eq!(a.div_euclid(-b), -1); // 7 >= -4 * -1
-assert_eq!((-a).div_euclid(b), -2); // -7 >= 4 * -2
-assert_eq!((-a).div_euclid(-b), 2); // -7 >= -4 * 2
-```"),
-            #[stable(feature = "euclidean_division", since = "1.38.0")]
-            #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
-            #[must_use = "this returns the result of the operation, \
-                          without modifying the original"]
-            #[inline]
-            #[rustc_inherit_overflow_checks]
-            pub const fn div_euclid(self, rhs: Self) -> Self {
-                let q = self / rhs;
-                if self % rhs < 0 {
-                    return if rhs > 0 { q - 1 } else { q + 1 }
-                }
-                q
-            }
-        }
-
-
-        doc_comment! {
-            concat!("Calculates the least nonnegative remainder of `self (mod rhs)`.
-
-This is done as if by the Euclidean division algorithm -- given
-`r = self.rem_euclid(rhs)`, `self = rhs * self.div_euclid(rhs) + r`, and
-`0 <= r < abs(rhs)`.
-
-# Panics
-
-This function will panic if `rhs` is 0 or the division results in overflow.
-
-# Examples
-
-Basic usage:
-
-```
-let a: ", stringify!($SelfT), " = 7; // or any other integer type
-let b = 4;
-
-assert_eq!(a.rem_euclid(b), 3);
-assert_eq!((-a).rem_euclid(b), 1);
-assert_eq!(a.rem_euclid(-b), 3);
-assert_eq!((-a).rem_euclid(-b), 1);
-```"),
-            #[stable(feature = "euclidean_division", since = "1.38.0")]
-            #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
-            #[must_use = "this returns the result of the operation, \
-                          without modifying the original"]
-            #[inline]
-            #[rustc_inherit_overflow_checks]
-            pub const fn rem_euclid(self, rhs: Self) -> Self {
-                let r = self % rhs;
-                if r < 0 {
-                    if rhs < 0 {
-                        r - rhs
-                    } else {
-                        r + rhs
-                    }
-                } else {
-                    r
+                exp /= 2;
+                r = base.overflowing_mul(base);
+                base = r.0;
+                overflown |= r.1;
+            }
+
+            // since exp!=0, finally the exp must be 1.
+            // Deal with the final bit of the exponent separately, since
+            // squaring the base afterwards is not necessary and may cause a
+            // needless overflow.
+            r = acc.overflowing_mul(base);
+            r.1 |= overflown;
+            r
+        }
+
+        /// Raises self to the power of `exp`, using exponentiation by squaring.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("let x: ", stringify!($SelfT), " = 2; // or any other integer type")]
+        ///
+        /// assert_eq!(x.pow(5), 32);
+        /// ```
+        #[stable(feature = "rust1", since = "1.0.0")]
+        #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        #[rustc_inherit_overflow_checks]
+        pub const fn pow(self, mut exp: u32) -> Self {
+            if exp == 0 {
+                return 1;
+            }
+            let mut base = self;
+            let mut acc = 1;
+
+            while exp > 1 {
+                if (exp & 1) == 1 {
+                    acc = acc * base;
                 }
-            }
-        }
-
-        doc_comment! {
-            concat!("Computes the absolute value of `self`.
-
-# Overflow behavior
-
-The absolute value of `", stringify!($SelfT), "::MIN` cannot be represented as an
-`", stringify!($SelfT), "`, and attempting to calculate it will cause an overflow. This means that
-code in debug mode will trigger a panic on this case and optimized code will return `",
-stringify!($SelfT), "::MIN` without a panic.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(10", stringify!($SelfT), ".abs(), 10);
-assert_eq!((-10", stringify!($SelfT), ").abs(), 10);",
-$EndFeature, "
-```"),
-            #[stable(feature = "rust1", since = "1.0.0")]
-            #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
-            #[allow(unused_attributes)]
-            #[inline]
-            #[rustc_inherit_overflow_checks]
-            pub const fn abs(self) -> Self {
-                // Note that the #[inline] above means that the overflow
-                // semantics of the subtraction depend on the crate we're being
-                // inlined into.
-                if self.is_negative() {
-                    -self
+                exp /= 2;
+                base = base * base;
+            }
+
+            // since exp!=0, finally the exp must be 1.
+            // Deal with the final bit of the exponent separately, since
+            // squaring the base afterwards is not necessary and may cause a
+            // needless overflow.
+            acc * base
+        }
+
+        /// Calculates the quotient of Euclidean division of `self` by `rhs`.
+        ///
+        /// This computes the integer `n` such that `self = n * rhs + self.rem_euclid(rhs)`,
+        /// with `0 <= self.rem_euclid(rhs) < rhs`.
+        ///
+        /// In other words, the result is `self / rhs` rounded to the integer `n`
+        /// such that `self >= n * rhs`.
+        /// If `self > 0`, this is equal to round towards zero (the default in Rust);
+        /// if `self < 0`, this is equal to round towards +/- infinity.
+        ///
+        /// # Panics
+        ///
+        /// This function will panic if `rhs` is 0 or the division results in overflow.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("let a: ", stringify!($SelfT), " = 7; // or any other integer type")]
+        /// let b = 4;
+        ///
+        /// assert_eq!(a.div_euclid(b), 1); // 7 >= 4 * 1
+        /// assert_eq!(a.div_euclid(-b), -1); // 7 >= -4 * -1
+        /// assert_eq!((-a).div_euclid(b), -2); // -7 >= 4 * -2
+        /// assert_eq!((-a).div_euclid(-b), 2); // -7 >= -4 * 2
+        /// ```
+        #[stable(feature = "euclidean_division", since = "1.38.0")]
+        #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        #[rustc_inherit_overflow_checks]
+        pub const fn div_euclid(self, rhs: Self) -> Self {
+            let q = self / rhs;
+            if self % rhs < 0 {
+                return if rhs > 0 { q - 1 } else { q + 1 }
+            }
+            q
+        }
+
+
+        /// Calculates the least nonnegative remainder of `self (mod rhs)`.
+        ///
+        /// This is done as if by the Euclidean division algorithm -- given
+        /// `r = self.rem_euclid(rhs)`, `self = rhs * self.div_euclid(rhs) + r`, and
+        /// `0 <= r < abs(rhs)`.
+        ///
+        /// # Panics
+        ///
+        /// This function will panic if `rhs` is 0 or the division results in overflow.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("let a: ", stringify!($SelfT), " = 7; // or any other integer type")]
+        /// let b = 4;
+        ///
+        /// assert_eq!(a.rem_euclid(b), 3);
+        /// assert_eq!((-a).rem_euclid(b), 1);
+        /// assert_eq!(a.rem_euclid(-b), 3);
+        /// assert_eq!((-a).rem_euclid(-b), 1);
+        /// ```
+        #[stable(feature = "euclidean_division", since = "1.38.0")]
+        #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        #[rustc_inherit_overflow_checks]
+        pub const fn rem_euclid(self, rhs: Self) -> Self {
+            let r = self % rhs;
+            if r < 0 {
+                if rhs < 0 {
+                    r - rhs
                 } else {
-                    self
-                }
-            }
-        }
-
-        doc_comment! {
-            concat!("Returns a number representing sign of `self`.
-
- - `0` if the number is zero
- - `1` if the number is positive
- - `-1` if the number is negative
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(10", stringify!($SelfT), ".signum(), 1);
-assert_eq!(0", stringify!($SelfT), ".signum(), 0);
-assert_eq!((-10", stringify!($SelfT), ").signum(), -1);",
-$EndFeature, "
-```"),
-            #[stable(feature = "rust1", since = "1.0.0")]
-            #[rustc_const_stable(feature = "const_int_sign", since = "1.47.0")]
-            #[inline]
-            pub const fn signum(self) -> Self {
-                match self {
-                    n if n > 0 =>  1,
-                    0          =>  0,
-                    _          => -1,
+                    r + rhs
                 }
+            } else {
+                r
             }
         }
 
-        doc_comment! {
-            concat!("Returns `true` if `self` is positive and `false` if the number is zero or
-negative.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert!(10", stringify!($SelfT), ".is_positive());
-assert!(!(-10", stringify!($SelfT), ").is_positive());",
-$EndFeature, "
-```"),
-            #[stable(feature = "rust1", since = "1.0.0")]
-            #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
-            #[inline]
-            pub const fn is_positive(self) -> bool { self > 0 }
-        }
-
-        doc_comment! {
-            concat!("Returns `true` if `self` is negative and `false` if the number is zero or
-positive.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert!((-10", stringify!($SelfT), ").is_negative());
-assert!(!10", stringify!($SelfT), ".is_negative());",
-$EndFeature, "
-```"),
-            #[stable(feature = "rust1", since = "1.0.0")]
-            #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
-            #[inline]
-            pub const fn is_negative(self) -> bool { self < 0 }
-        }
-
-        doc_comment! {
-            concat!("Return the memory representation of this integer as a byte array in
-big-endian (network) byte order.
-",
-$to_xe_bytes_doc,
-"
-# Examples
-
-```
-let bytes = ", $swap_op, stringify!($SelfT), ".to_be_bytes();
-assert_eq!(bytes, ", $be_bytes, ");
-```"),
-            #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
-            #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")]
-            #[inline]
-            pub const fn to_be_bytes(self) -> [u8; mem::size_of::<Self>()] {
-                self.to_be().to_ne_bytes()
-            }
-        }
-
-doc_comment! {
-            concat!("Return the memory representation of this integer as a byte array in
-little-endian byte order.
-",
-$to_xe_bytes_doc,
-"
-# Examples
-
-```
-let bytes = ", $swap_op, stringify!($SelfT), ".to_le_bytes();
-assert_eq!(bytes, ", $le_bytes, ");
-```"),
-            #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
-            #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")]
-            #[inline]
-            pub const fn to_le_bytes(self) -> [u8; mem::size_of::<Self>()] {
-                self.to_le().to_ne_bytes()
-            }
-        }
-
-        doc_comment! {
-            concat!("
-Return the memory representation of this integer as a byte array in
-native byte order.
-
-As the target platform's native endianness is used, portable code
-should use [`to_be_bytes`] or [`to_le_bytes`], as appropriate,
-instead.
-",
-$to_xe_bytes_doc,
-"
-[`to_be_bytes`]: #method.to_be_bytes
-[`to_le_bytes`]: #method.to_le_bytes
-
-# Examples
-
-```
-let bytes = ", $swap_op, stringify!($SelfT), ".to_ne_bytes();
-assert_eq!(
-    bytes,
-    if cfg!(target_endian = \"big\") {
-        ", $be_bytes, "
-    } else {
-        ", $le_bytes, "
-    }
-);
-```"),
-            #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
-            #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")]
-            // SAFETY: const sound because integers are plain old datatypes so we can always
-            // transmute them to arrays of bytes
-            #[rustc_allow_const_fn_unstable(const_fn_transmute)]
-            #[inline]
-            pub const fn to_ne_bytes(self) -> [u8; mem::size_of::<Self>()] {
-                // SAFETY: integers are plain old datatypes so we can always transmute them to
-                // arrays of bytes
-                unsafe { mem::transmute(self) }
-            }
-        }
-
-        doc_comment! {
-            concat!("
-Return the memory representation of this integer as a byte array in
-native byte order.
-
-[`to_ne_bytes`] should be preferred over this whenever possible.
-
-[`to_ne_bytes`]: #method.to_ne_bytes
-",
-
-"
-# Examples
-
-```
-#![feature(num_as_ne_bytes)]
-let num = ", $swap_op, stringify!($SelfT), ";
-let bytes = num.as_ne_bytes();
-assert_eq!(
-    bytes,
-    if cfg!(target_endian = \"big\") {
-        &", $be_bytes, "
-    } else {
-        &", $le_bytes, "
-    }
-);
-```"),
-            #[unstable(feature = "num_as_ne_bytes", issue = "76976")]
-            #[inline]
-            pub fn as_ne_bytes(&self) -> &[u8; mem::size_of::<Self>()] {
-                // SAFETY: integers are plain old datatypes so we can always transmute them to
-                // arrays of bytes
-                unsafe { &*(self as *const Self as *const _) }
-            }
-        }
-
-doc_comment! {
-            concat!("Create an integer value from its representation as a byte array in
-big endian.
-",
-$from_xe_bytes_doc,
-"
-# Examples
-
-```
-let value = ", stringify!($SelfT), "::from_be_bytes(", $be_bytes, ");
-assert_eq!(value, ", $swap_op, ");
-```
-
-When starting from a slice rather than an array, fallible conversion APIs can be used:
-
-```
-use std::convert::TryInto;
-
-fn read_be_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " {
-    let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">());
-    *input = rest;
-    ", stringify!($SelfT), "::from_be_bytes(int_bytes.try_into().unwrap())
-}
-```"),
-            #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
-            #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")]
-            #[inline]
-            pub const fn from_be_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
-                Self::from_be(Self::from_ne_bytes(bytes))
-            }
-        }
-
-doc_comment! {
-            concat!("
-Create an integer value from its representation as a byte array in
-little endian.
-",
-$from_xe_bytes_doc,
-"
-# Examples
-
-```
-let value = ", stringify!($SelfT), "::from_le_bytes(", $le_bytes, ");
-assert_eq!(value, ", $swap_op, ");
-```
-
-When starting from a slice rather than an array, fallible conversion APIs can be used:
-
-```
-use std::convert::TryInto;
-
-fn read_le_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " {
-    let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">());
-    *input = rest;
-    ", stringify!($SelfT), "::from_le_bytes(int_bytes.try_into().unwrap())
-}
-```"),
-            #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
-            #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")]
-            #[inline]
-            pub const fn from_le_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
-                Self::from_le(Self::from_ne_bytes(bytes))
-            }
-        }
-
-        doc_comment! {
-            concat!("Create an integer value from its memory representation as a byte
-array in native endianness.
-
-As the target platform's native endianness is used, portable code
-likely wants to use [`from_be_bytes`] or [`from_le_bytes`], as
-appropriate instead.
-
-[`from_be_bytes`]: #method.from_be_bytes
-[`from_le_bytes`]: #method.from_le_bytes
-",
-$from_xe_bytes_doc,
-"
-# Examples
-
-```
-let value = ", stringify!($SelfT), "::from_ne_bytes(if cfg!(target_endian = \"big\") {
-    ", $be_bytes, "
-} else {
-    ", $le_bytes, "
-});
-assert_eq!(value, ", $swap_op, ");
-```
-
-When starting from a slice rather than an array, fallible conversion APIs can be used:
-
-```
-use std::convert::TryInto;
-
-fn read_ne_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " {
-    let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">());
-    *input = rest;
-    ", stringify!($SelfT), "::from_ne_bytes(int_bytes.try_into().unwrap())
-}
-```"),
-            #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
-            #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")]
-            // SAFETY: const sound because integers are plain old datatypes so we can always
-            // transmute to them
-            #[rustc_allow_const_fn_unstable(const_fn_transmute)]
-            #[inline]
-            pub const fn from_ne_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
-                // SAFETY: integers are plain old datatypes so we can always transmute to them
-                unsafe { mem::transmute(bytes) }
-            }
-        }
-
-        doc_comment! {
-            concat!("**This method is soft-deprecated.**
-
-Although using it won’t cause a compilation warning,
-new code should use [`", stringify!($SelfT), "::MIN", "`](#associatedconstant.MIN) instead.
-
-Returns the smallest value that can be represented by this integer type."),
-            #[stable(feature = "rust1", since = "1.0.0")]
-            #[inline(always)]
-            #[rustc_promotable]
-            #[rustc_const_stable(feature = "const_min_value", since = "1.32.0")]
-            pub const fn min_value() -> Self {
-                Self::MIN
-            }
-        }
-
-        doc_comment! {
-            concat!("**This method is soft-deprecated.**
-
-Although using it won’t cause a compilation warning,
-new code should use [`", stringify!($SelfT), "::MAX", "`](#associatedconstant.MAX) instead.
-
-Returns the largest value that can be represented by this integer type."),
-            #[stable(feature = "rust1", since = "1.0.0")]
-            #[inline(always)]
-            #[rustc_promotable]
-            #[rustc_const_stable(feature = "const_max_value", since = "1.32.0")]
-            pub const fn max_value() -> Self {
-                Self::MAX
-            }
+        /// Computes the absolute value of `self`.
+        ///
+        /// # Overflow behavior
+        ///
+        /// The absolute value of
+        #[doc = concat!("`", stringify!($SelfT), "::MIN`")]
+        /// cannot be represented as an
+        #[doc = concat!("`", stringify!($SelfT), "`,")]
+        /// and attempting to calculate it will cause an overflow. This means
+        /// that code in debug mode will trigger a panic on this case and
+        /// optimized code will return
+        #[doc = concat!("`", stringify!($SelfT), "::MIN`")]
+        /// without a panic.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".abs(), 10);")]
+        #[doc = concat!("assert_eq!((-10", stringify!($SelfT), ").abs(), 10);")]
+        /// ```
+        #[stable(feature = "rust1", since = "1.0.0")]
+        #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
+        #[allow(unused_attributes)]
+        #[inline]
+        #[rustc_inherit_overflow_checks]
+        pub const fn abs(self) -> Self {
+            // Note that the #[inline] above means that the overflow
+            // semantics of the subtraction depend on the crate we're being
+            // inlined into.
+            if self.is_negative() {
+                -self
+            } else {
+                self
+            }
+        }
+
+        /// Returns a number representing sign of `self`.
+        ///
+        ///  - `0` if the number is zero
+        ///  - `1` if the number is positive
+        ///  - `-1` if the number is negative
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".signum(), 1);")]
+        #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".signum(), 0);")]
+        #[doc = concat!("assert_eq!((-10", stringify!($SelfT), ").signum(), -1);")]
+        /// ```
+        #[stable(feature = "rust1", since = "1.0.0")]
+        #[rustc_const_stable(feature = "const_int_sign", since = "1.47.0")]
+        #[inline]
+        pub const fn signum(self) -> Self {
+            match self {
+                n if n > 0 =>  1,
+                0          =>  0,
+                _          => -1,
+            }
+        }
+
+        /// Returns `true` if `self` is positive and `false` if the number is zero or
+        /// negative.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("assert!(10", stringify!($SelfT), ".is_positive());")]
+        #[doc = concat!("assert!(!(-10", stringify!($SelfT), ").is_positive());")]
+        /// ```
+        #[stable(feature = "rust1", since = "1.0.0")]
+        #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
+        #[inline]
+        pub const fn is_positive(self) -> bool { self > 0 }
+
+        /// Returns `true` if `self` is negative and `false` if the number is zero or
+        /// positive.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("assert!((-10", stringify!($SelfT), ").is_negative());")]
+        #[doc = concat!("assert!(!10", stringify!($SelfT), ".is_negative());")]
+        /// ```
+        #[stable(feature = "rust1", since = "1.0.0")]
+        #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
+        #[inline]
+        pub const fn is_negative(self) -> bool { self < 0 }
+
+        /// Return the memory representation of this integer as a byte array in
+        /// big-endian (network) byte order.
+        ///
+        #[doc = $to_xe_bytes_doc]
+        ///
+        /// # Examples
+        ///
+        /// ```
+        #[doc = concat!("let bytes = ", $swap_op, stringify!($SelfT), ".to_be_bytes();")]
+        #[doc = concat!("assert_eq!(bytes, ", $be_bytes, ");")]
+        /// ```
+        #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
+        #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")]
+        #[inline]
+        pub const fn to_be_bytes(self) -> [u8; mem::size_of::<Self>()] {
+            self.to_be().to_ne_bytes()
+        }
+
+        /// Return the memory representation of this integer as a byte array in
+        /// little-endian byte order.
+        ///
+        #[doc = $to_xe_bytes_doc]
+        ///
+        /// # Examples
+        ///
+        /// ```
+        #[doc = concat!("let bytes = ", $swap_op, stringify!($SelfT), ".to_le_bytes();")]
+        #[doc = concat!("assert_eq!(bytes, ", $le_bytes, ");")]
+        /// ```
+        #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
+        #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")]
+        #[inline]
+        pub const fn to_le_bytes(self) -> [u8; mem::size_of::<Self>()] {
+            self.to_le().to_ne_bytes()
+        }
+
+        /// Return the memory representation of this integer as a byte array in
+        /// native byte order.
+        ///
+        /// As the target platform's native endianness is used, portable code
+        /// should use [`to_be_bytes`] or [`to_le_bytes`], as appropriate,
+        /// instead.
+        ///
+        #[doc = $to_xe_bytes_doc]
+        ///
+        /// [`to_be_bytes`]: #method.to_be_bytes
+        /// [`to_le_bytes`]: #method.to_le_bytes
+        ///
+        /// # Examples
+        ///
+        /// ```
+        #[doc = concat!("let bytes = ", $swap_op, stringify!($SelfT), ".to_ne_bytes();")]
+        /// assert_eq!(
+        ///     bytes,
+        ///     if cfg!(target_endian = "big") {
+        #[doc = concat!("        ", $be_bytes)]
+        ///     } else {
+        #[doc = concat!("        ", $le_bytes)]
+        ///     }
+        /// );
+        /// ```
+        #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
+        #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")]
+        // SAFETY: const sound because integers are plain old datatypes so we can always
+        // transmute them to arrays of bytes
+        #[rustc_allow_const_fn_unstable(const_fn_transmute)]
+        #[inline]
+        pub const fn to_ne_bytes(self) -> [u8; mem::size_of::<Self>()] {
+            // SAFETY: integers are plain old datatypes so we can always transmute them to
+            // arrays of bytes
+            unsafe { mem::transmute(self) }
+        }
+
+        /// Return the memory representation of this integer as a byte array in
+        /// native byte order.
+        ///
+        /// [`to_ne_bytes`] should be preferred over this whenever possible.
+        ///
+        /// [`to_ne_bytes`]: #method.to_ne_bytes
+        ///
+        /// # Examples
+        ///
+        /// ```
+        /// #![feature(num_as_ne_bytes)]
+        #[doc = concat!("let num = ", $swap_op, stringify!($SelfT), ";")]
+        /// let bytes = num.as_ne_bytes();
+        /// assert_eq!(
+        ///     bytes,
+        ///     if cfg!(target_endian = "big") {
+        #[doc = concat!("        &", $be_bytes)]
+        ///     } else {
+        #[doc = concat!("        &", $le_bytes)]
+        ///     }
+        /// );
+        /// ```
+        #[unstable(feature = "num_as_ne_bytes", issue = "76976")]
+        #[inline]
+        pub fn as_ne_bytes(&self) -> &[u8; mem::size_of::<Self>()] {
+            // SAFETY: integers are plain old datatypes so we can always transmute them to
+            // arrays of bytes
+            unsafe { &*(self as *const Self as *const _) }
+        }
+
+        /// Create an integer value from its representation as a byte array in
+        /// big endian.
+        ///
+        #[doc = $to_xe_bytes_doc]
+        ///
+        /// # Examples
+        ///
+        /// ```
+        #[doc = concat!("let value = ", stringify!($SelfT), "::from_be_bytes(", $be_bytes, ");")]
+        #[doc = concat!("assert_eq!(value, ", $swap_op, ");")]
+        /// ```
+        ///
+        /// When starting from a slice rather than an array, fallible conversion APIs can be used:
+        ///
+        /// ```
+        /// use std::convert::TryInto;
+        ///
+        #[doc = concat!("fn read_be_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " {")]
+        #[doc = concat!("    let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">());")]
+        ///     *input = rest;
+        #[doc = concat!("    ", stringify!($SelfT), "::from_be_bytes(int_bytes.try_into().unwrap())")]
+        /// }
+        /// ```
+        #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
+        #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")]
+        #[inline]
+        pub const fn from_be_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
+            Self::from_be(Self::from_ne_bytes(bytes))
+        }
+
+        /// Create an integer value from its representation as a byte array in
+        /// little endian.
+        ///
+        #[doc = $to_xe_bytes_doc]
+        ///
+        /// # Examples
+        ///
+        /// ```
+        #[doc = concat!("let value = ", stringify!($SelfT), "::from_le_bytes(", $le_bytes, ");")]
+        #[doc = concat!("assert_eq!(value, ", $swap_op, ");")]
+        /// ```
+        ///
+        /// When starting from a slice rather than an array, fallible conversion APIs can be used:
+        ///
+        /// ```
+        /// use std::convert::TryInto;
+        ///
+        #[doc = concat!("fn read_le_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " {")]
+        #[doc = concat!("    let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">());")]
+        ///     *input = rest;
+        #[doc = concat!("    ", stringify!($SelfT), "::from_le_bytes(int_bytes.try_into().unwrap())")]
+        /// }
+        /// ```
+        #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
+        #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")]
+        #[inline]
+        pub const fn from_le_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
+            Self::from_le(Self::from_ne_bytes(bytes))
+        }
+
+        /// Create an integer value from its memory representation as a byte
+        /// array in native endianness.
+        ///
+        /// As the target platform's native endianness is used, portable code
+        /// likely wants to use [`from_be_bytes`] or [`from_le_bytes`], as
+        /// appropriate instead.
+        ///
+        /// [`from_be_bytes`]: #method.from_be_bytes
+        /// [`from_le_bytes`]: #method.from_le_bytes
+        ///
+        #[doc = $to_xe_bytes_doc]
+        ///
+        /// # Examples
+        ///
+        /// ```
+        #[doc = concat!("let value = ", stringify!($SelfT), "::from_ne_bytes(if cfg!(target_endian = \"big\") {")]
+        #[doc = concat!("    ", $be_bytes)]
+        /// } else {
+        #[doc = concat!("    ", $le_bytes)]
+        /// });
+        #[doc = concat!("assert_eq!(value, ", $swap_op, ");")]
+        /// ```
+        ///
+        /// When starting from a slice rather than an array, fallible conversion APIs can be used:
+        ///
+        /// ```
+        /// use std::convert::TryInto;
+        ///
+        #[doc = concat!("fn read_ne_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " {")]
+        #[doc = concat!("    let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">());")]
+        ///     *input = rest;
+        #[doc = concat!("    ", stringify!($SelfT), "::from_ne_bytes(int_bytes.try_into().unwrap())")]
+        /// }
+        /// ```
+        #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
+        #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")]
+        // SAFETY: const sound because integers are plain old datatypes so we can always
+        // transmute to them
+        #[rustc_allow_const_fn_unstable(const_fn_transmute)]
+        #[inline]
+        pub const fn from_ne_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
+            // SAFETY: integers are plain old datatypes so we can always transmute to them
+            unsafe { mem::transmute(bytes) }
+        }
+
+        /// **This method is soft-deprecated.**
+        ///
+        /// Although using it won’t cause a compilation warning, new code should use
+        #[doc = concat!("[`", stringify!($SelfT), "::MIN", "`](#associatedconstant.MIN)")]
+        /// instead.
+        ///
+        /// Returns the smallest value that can be represented by this integer type.
+        #[stable(feature = "rust1", since = "1.0.0")]
+        #[inline(always)]
+        #[rustc_promotable]
+        #[rustc_const_stable(feature = "const_min_value", since = "1.32.0")]
+        pub const fn min_value() -> Self {
+            Self::MIN
+        }
+
+        /// **This method is soft-deprecated.**
+        ///
+        /// Although using it won’t cause a compilation warning, new code should use
+        #[doc = concat!("[`", stringify!($SelfT), "::MAX", "`](#associatedconstant.MAX)")]
+        /// instead.
+        ///
+        /// Returns the largest value that can be represented by this integer type.
+        #[stable(feature = "rust1", since = "1.0.0")]
+        #[inline(always)]
+        #[rustc_promotable]
+        #[rustc_const_stable(feature = "const_max_value", since = "1.32.0")]
+        pub const fn max_value() -> Self {
+            Self::MAX
         }
     }
 }
index 9f5ae57b74adee4f8edfad538a71ba9d6239544c..6bdfa18fa434ccf8ccf53a9f1499b22bf40c986c 100644 (file)
@@ -23,13 +23,6 @@ macro_rules! unlikely {
     };
 }
 
-macro_rules! doc_comment {
-    ($x:expr, $($tt:tt)*) => {
-        #[doc = $x]
-        $($tt)*
-    };
-}
-
 // All these modules are technically private and only exposed for coretests:
 pub mod bignum;
 pub mod dec2flt;
@@ -95,26 +88,26 @@ macro_rules! usize_isize_from_xe_bytes_doc {
 
 #[lang = "i8"]
 impl i8 {
-    int_impl! { i8, i8, u8, 8, -128, 127, "", "", 2, "-0x7e", "0xa", "0x12", "0x12", "0x48",
+    int_impl! { i8, i8, u8, 8, -128, 127, 2, "-0x7e", "0xa", "0x12", "0x12", "0x48",
     "[0x12]", "[0x12]", "", "" }
 }
 
 #[lang = "i16"]
 impl i16 {
-    int_impl! { i16, i16, u16, 16, -32768, 32767, "", "", 4, "-0x5ffd", "0x3a", "0x1234", "0x3412",
+    int_impl! { i16, i16, u16, 16, -32768, 32767, 4, "-0x5ffd", "0x3a", "0x1234", "0x3412",
     "0x2c48", "[0x34, 0x12]", "[0x12, 0x34]", "", "" }
 }
 
 #[lang = "i32"]
 impl i32 {
-    int_impl! { i32, i32, u32, 32, -2147483648, 2147483647, "", "", 8, "0x10000b3", "0xb301",
+    int_impl! { i32, i32, u32, 32, -2147483648, 2147483647, 8, "0x10000b3", "0xb301",
     "0x12345678", "0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]",
     "[0x12, 0x34, 0x56, 0x78]", "", "" }
 }
 
 #[lang = "i64"]
 impl i64 {
-    int_impl! { i64, i64, u64, 64, -9223372036854775808, 9223372036854775807, "", "", 12,
+    int_impl! { i64, i64, u64, 64, -9223372036854775808, 9223372036854775807, 12,
     "0xaa00000000006e1", "0x6e10aa", "0x1234567890123456", "0x5634129078563412",
     "0x6a2c48091e6a2c48", "[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]",
     "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]", "", "" }
@@ -123,7 +116,7 @@ impl i64 {
 #[lang = "i128"]
 impl i128 {
     int_impl! { i128, i128, u128, 128, -170141183460469231731687303715884105728,
-    170141183460469231731687303715884105727, "", "", 16,
+    170141183460469231731687303715884105727, 16,
     "0x13f40000000000000000000000004f76", "0x4f7613f4", "0x12345678901234567890123456789012",
     "0x12907856341290785634129078563412", "0x48091e6a2c48091e6a2c48091e6a2c48",
     "[0x12, 0x90, 0x78, 0x56, 0x34, 0x12, 0x90, 0x78, \
@@ -135,7 +128,7 @@ impl i128 {
 #[cfg(target_pointer_width = "16")]
 #[lang = "isize"]
 impl isize {
-    int_impl! { isize, i16, usize, 16, -32768, 32767, "", "", 4, "-0x5ffd", "0x3a", "0x1234",
+    int_impl! { isize, i16, usize, 16, -32768, 32767, 4, "-0x5ffd", "0x3a", "0x1234",
     "0x3412", "0x2c48", "[0x34, 0x12]", "[0x12, 0x34]",
     usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() }
 }
@@ -143,7 +136,7 @@ impl isize {
 #[cfg(target_pointer_width = "32")]
 #[lang = "isize"]
 impl isize {
-    int_impl! { isize, i32, usize, 32, -2147483648, 2147483647, "", "", 8, "0x10000b3", "0xb301",
+    int_impl! { isize, i32, usize, 32, -2147483648, 2147483647, 8, "0x10000b3", "0xb301",
     "0x12345678", "0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]",
     "[0x12, 0x34, 0x56, 0x78]",
     usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() }
@@ -152,7 +145,7 @@ impl isize {
 #[cfg(target_pointer_width = "64")]
 #[lang = "isize"]
 impl isize {
-    int_impl! { isize, i64, usize, 64, -9223372036854775808, 9223372036854775807, "", "",
+    int_impl! { isize, i64, usize, 64, -9223372036854775808, 9223372036854775807,
     12, "0xaa00000000006e1", "0x6e10aa",  "0x1234567890123456", "0x5634129078563412",
      "0x6a2c48091e6a2c48", "[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]",
      "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]",
@@ -161,7 +154,7 @@ impl isize {
 
 #[lang = "u8"]
 impl u8 {
-    uint_impl! { u8, u8, 8, 255, "", "", 2, "0x82", "0xa", "0x12", "0x12", "0x48", "[0x12]",
+    uint_impl! { u8, u8, 8, 255, 2, "0x82", "0xa", "0x12", "0x12", "0x48", "[0x12]",
     "[0x12]", "", "" }
 
     /// Checks if the value is within the ASCII range.
@@ -660,19 +653,19 @@ pub const fn is_ascii_control(&self) -> bool {
 
 #[lang = "u16"]
 impl u16 {
-    uint_impl! { u16, u16, 16, 65535, "", "", 4, "0xa003", "0x3a", "0x1234", "0x3412", "0x2c48",
+    uint_impl! { u16, u16, 16, 65535, 4, "0xa003", "0x3a", "0x1234", "0x3412", "0x2c48",
     "[0x34, 0x12]", "[0x12, 0x34]", "", "" }
 }
 
 #[lang = "u32"]
 impl u32 {
-    uint_impl! { u32, u32, 32, 4294967295, "", "", 8, "0x10000b3", "0xb301", "0x12345678",
+    uint_impl! { u32, u32, 32, 4294967295, 8, "0x10000b3", "0xb301", "0x12345678",
     "0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]", "[0x12, 0x34, 0x56, 0x78]", "", "" }
 }
 
 #[lang = "u64"]
 impl u64 {
-    uint_impl! { u64, u64, 64, 18446744073709551615, "", "", 12, "0xaa00000000006e1", "0x6e10aa",
+    uint_impl! { u64, u64, 64, 18446744073709551615, 12, "0xaa00000000006e1", "0x6e10aa",
     "0x1234567890123456", "0x5634129078563412", "0x6a2c48091e6a2c48",
     "[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]",
     "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]",
@@ -681,7 +674,7 @@ impl u64 {
 
 #[lang = "u128"]
 impl u128 {
-    uint_impl! { u128, u128, 128, 340282366920938463463374607431768211455, "", "", 16,
+    uint_impl! { u128, u128, 128, 340282366920938463463374607431768211455, 16,
     "0x13f40000000000000000000000004f76", "0x4f7613f4", "0x12345678901234567890123456789012",
     "0x12907856341290785634129078563412", "0x48091e6a2c48091e6a2c48091e6a2c48",
     "[0x12, 0x90, 0x78, 0x56, 0x34, 0x12, 0x90, 0x78, \
@@ -694,14 +687,14 @@ impl u128 {
 #[cfg(target_pointer_width = "16")]
 #[lang = "usize"]
 impl usize {
-    uint_impl! { usize, u16, 16, 65535, "", "", 4, "0xa003", "0x3a", "0x1234", "0x3412", "0x2c48",
+    uint_impl! { usize, u16, 16, 65535, 4, "0xa003", "0x3a", "0x1234", "0x3412", "0x2c48",
     "[0x34, 0x12]", "[0x12, 0x34]",
     usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() }
 }
 #[cfg(target_pointer_width = "32")]
 #[lang = "usize"]
 impl usize {
-    uint_impl! { usize, u32, 32, 4294967295, "", "", 8, "0x10000b3", "0xb301", "0x12345678",
+    uint_impl! { usize, u32, 32, 4294967295, 8, "0x10000b3", "0xb301", "0x12345678",
     "0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]", "[0x12, 0x34, 0x56, 0x78]",
     usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() }
 }
@@ -709,7 +702,7 @@ impl usize {
 #[cfg(target_pointer_width = "64")]
 #[lang = "usize"]
 impl usize {
-    uint_impl! { usize, u64, 64, 18446744073709551615, "", "", 12, "0xaa00000000006e1", "0x6e10aa",
+    uint_impl! { usize, u64, 64, 18446744073709551615, 12, "0xaa00000000006e1", "0x6e10aa",
     "0x1234567890123456", "0x5634129078563412", "0x6a2c48091e6a2c48",
     "[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]",
      "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]",
index 716b4a90e5ec279885a1647014449ccf9974d891..ba8918b192fa301da03fca8efbc944cfdb2b5b1c 100644 (file)
@@ -1,20 +1,13 @@
 //! Definitions of integer that is known not to equal zero.
 
 use crate::fmt;
-use crate::ops::{BitOr, BitOrAssign};
+use crate::ops::{BitOr, BitOrAssign, Div, Rem};
 use crate::str::FromStr;
 
 use super::from_str_radix;
 use super::{IntErrorKind, ParseIntError};
 use crate::intrinsics;
 
-macro_rules! doc_comment {
-    ($x:expr, $($tt:tt)*) => {
-        #[doc = $x]
-        $($tt)*
-    };
-}
-
 macro_rules! impl_nonzero_fmt {
     ( #[$stability: meta] ( $( $Trait: ident ),+ ) for $Ty: ident ) => {
         $(
@@ -32,24 +25,21 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 macro_rules! nonzero_integers {
     ( $( #[$stability: meta] $Ty: ident($Int: ty); )+ ) => {
         $(
-            doc_comment! {
-                concat!("An integer that is known not to equal zero.
-
-This enables some memory layout optimization.
-For example, `Option<", stringify!($Ty), ">` is the same size as `", stringify!($Int), "`:
-
-```rust
-use std::mem::size_of;
-assert_eq!(size_of::<Option<core::num::", stringify!($Ty), ">>(), size_of::<", stringify!($Int),
-">());
-```"),
-                #[$stability]
-                #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
-                #[repr(transparent)]
-                #[rustc_layout_scalar_valid_range_start(1)]
-                #[rustc_nonnull_optimization_guaranteed]
-                pub struct $Ty($Int);
-            }
+            /// An integer that is known not to equal zero.
+            ///
+            /// This enables some memory layout optimization.
+            #[doc = concat!("For example, `Option<", stringify!($Ty), ">` is the same size as `", stringify!($Int), "`:")]
+            ///
+            /// ```rust
+            /// use std::mem::size_of;
+            #[doc = concat!("assert_eq!(size_of::<Option<core::num::", stringify!($Ty), ">>(), size_of::<", stringify!($Int), ">());")]
+            /// ```
+            #[$stability]
+            #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
+            #[repr(transparent)]
+            #[rustc_layout_scalar_valid_range_start(1)]
+            #[rustc_nonnull_optimization_guaranteed]
+            pub struct $Ty($Int);
 
             impl $Ty {
                 /// Creates a non-zero without checking the value.
@@ -90,13 +80,10 @@ pub const fn get(self) -> $Int {
 
             #[stable(feature = "from_nonzero", since = "1.31.0")]
             impl From<$Ty> for $Int {
-                doc_comment! {
-                    concat!(
-"Converts a `", stringify!($Ty), "` into an `", stringify!($Int), "`"),
-                    #[inline]
-                    fn from(nonzero: $Ty) -> Self {
-                        nonzero.0
-                    }
+                #[doc = concat!("Converts a `", stringify!($Ty), "` into an `", stringify!($Int), "`")]
+                #[inline]
+                fn from(nonzero: $Ty) -> Self {
+                    nonzero.0
                 }
             }
 
@@ -195,53 +182,49 @@ macro_rules! nonzero_leading_trailing_zeros {
     ( $( $Ty: ident($Uint: ty) , $LeadingTestExpr:expr ;)+ ) => {
         $(
             impl $Ty {
-                doc_comment! {
-                    concat!("Returns the number of leading zeros in the binary representation of `self`.
-
-On many architectures, this function can perform better than `leading_zeros()` on the underlying integer type, as special handling of zero can be avoided.
-
-# Examples
-
-Basic usage:
-
-```
-#![feature(nonzero_leading_trailing_zeros)]
-let n = std::num::", stringify!($Ty), "::new(", stringify!($LeadingTestExpr), ").unwrap();
-
-assert_eq!(n.leading_zeros(), 0);
-```"),
-                    #[unstable(feature = "nonzero_leading_trailing_zeros", issue = "79143")]
-                    #[rustc_const_unstable(feature = "nonzero_leading_trailing_zeros", issue = "79143")]
-                    #[inline]
-                    pub const fn leading_zeros(self) -> u32 {
-                        // SAFETY: since `self` can not be zero it is safe to call ctlz_nonzero
-                        unsafe { intrinsics::ctlz_nonzero(self.0 as $Uint) as u32 }
-                    }
+                /// Returns the number of leading zeros in the binary representation of `self`.
+                ///
+                /// On many architectures, this function can perform better than `leading_zeros()` on the underlying integer type, as special handling of zero can be avoided.
+                ///
+                /// # Examples
+                ///
+                /// Basic usage:
+                ///
+                /// ```
+                /// #![feature(nonzero_leading_trailing_zeros)]
+                #[doc = concat!("let n = std::num::", stringify!($Ty), "::new(", stringify!($LeadingTestExpr), ").unwrap();")]
+                ///
+                /// assert_eq!(n.leading_zeros(), 0);
+                /// ```
+                #[unstable(feature = "nonzero_leading_trailing_zeros", issue = "79143")]
+                #[rustc_const_unstable(feature = "nonzero_leading_trailing_zeros", issue = "79143")]
+                #[inline]
+                pub const fn leading_zeros(self) -> u32 {
+                    // SAFETY: since `self` can not be zero it is safe to call ctlz_nonzero
+                    unsafe { intrinsics::ctlz_nonzero(self.0 as $Uint) as u32 }
                 }
 
-                doc_comment! {
-                    concat!("Returns the number of trailing zeros in the binary representation
-of `self`.
-
-On many architectures, this function can perform better than `trailing_zeros()` on the underlying integer type, as special handling of zero can be avoided.
-
-# Examples
-
-Basic usage:
-
-```
-#![feature(nonzero_leading_trailing_zeros)]
-let n = std::num::", stringify!($Ty), "::new(0b0101000).unwrap();
-
-assert_eq!(n.trailing_zeros(), 3);
-```"),
-                    #[unstable(feature = "nonzero_leading_trailing_zeros", issue = "79143")]
-                    #[rustc_const_unstable(feature = "nonzero_leading_trailing_zeros", issue = "79143")]
-                    #[inline]
-                    pub const fn trailing_zeros(self) -> u32 {
-                        // SAFETY: since `self` can not be zero it is safe to call cttz_nonzero
-                        unsafe { intrinsics::cttz_nonzero(self.0 as $Uint) as u32 }
-                    }
+                /// Returns the number of trailing zeros in the binary representation
+                /// of `self`.
+                ///
+                /// On many architectures, this function can perform better than `trailing_zeros()` on the underlying integer type, as special handling of zero can be avoided.
+                ///
+                /// # Examples
+                ///
+                /// Basic usage:
+                ///
+                /// ```
+                /// #![feature(nonzero_leading_trailing_zeros)]
+                #[doc = concat!("let n = std::num::", stringify!($Ty), "::new(0b0101000).unwrap();")]
+                ///
+                /// assert_eq!(n.trailing_zeros(), 3);
+                /// ```
+                #[unstable(feature = "nonzero_leading_trailing_zeros", issue = "79143")]
+                #[rustc_const_unstable(feature = "nonzero_leading_trailing_zeros", issue = "79143")]
+                #[inline]
+                pub const fn trailing_zeros(self) -> u32 {
+                    // SAFETY: since `self` can not be zero it is safe to call cttz_nonzero
+                    unsafe { intrinsics::cttz_nonzero(self.0 as $Uint) as u32 }
                 }
 
             }
@@ -263,3 +246,43 @@ pub const fn trailing_zeros(self) -> u32 {
     NonZeroI128(u128), -1i128;
     NonZeroIsize(usize), -1isize;
 }
+
+macro_rules! nonzero_integers_div {
+    ( $( $Ty: ident($Int: ty); )+ ) => {
+        $(
+            #[stable(feature = "nonzero_div", since = "1.51.0")]
+            impl Div<$Ty> for $Int {
+                type Output = $Int;
+                /// This operation rounds towards zero,
+                /// truncating any fractional part of the exact result, and cannot panic.
+                #[inline]
+                fn div(self, other: $Ty) -> $Int {
+                    // SAFETY: div by zero is checked because `other` is a nonzero,
+                    // and MIN/-1 is checked because `self` is an unsigned int.
+                    unsafe { crate::intrinsics::unchecked_div(self, other.get()) }
+                }
+            }
+
+            #[stable(feature = "nonzero_div", since = "1.51.0")]
+            impl Rem<$Ty> for $Int {
+                type Output = $Int;
+                /// This operation satisfies `n % d == n - (n / d) * d`, and cannot panic.
+                #[inline]
+                fn rem(self, other: $Ty) -> $Int {
+                    // SAFETY: rem by zero is checked because `other` is a nonzero,
+                    // and MIN/-1 is checked because `self` is an unsigned int.
+                    unsafe { crate::intrinsics::unchecked_rem(self, other.get()) }
+                }
+            }
+        )+
+    }
+}
+
+nonzero_integers_div! {
+    NonZeroU8(u8);
+    NonZeroU16(u16);
+    NonZeroU32(u32);
+    NonZeroU64(u64);
+    NonZeroU128(u128);
+    NonZeroUsize(usize);
+}
index ffd30b03f2109c677692713e06c203351aa89b09..5f8bb648d04ae1e92554b3f605c20c1aa981cf31 100644 (file)
@@ -1,49 +1,44 @@
 #![doc(hidden)]
 
-macro_rules! doc_comment {
-    ($x:expr, $($tt:tt)*) => {
-        #[doc = $x]
-        $($tt)*
-    };
-}
-
 macro_rules! int_module {
     ($T:ident) => (int_module!($T, #[stable(feature = "rust1", since = "1.0.0")]););
     ($T:ident, #[$attr:meta]) => (
-        doc_comment! {
-            concat!("The smallest value that can be represented by this integer type.
-Use [`", stringify!($T), "::MIN", "`](../../std/primitive.", stringify!($T), ".html#associatedconstant.MIN) instead.
-
-# Examples
-
-```rust
-// deprecated way
-let min = std::", stringify!($T), "::MIN;
-
-// intended way
-let min = ", stringify!($T), "::MIN;
-```
-"),
-            #[$attr]
-            pub const MIN: $T = $T::MIN;
-        }
-
-        doc_comment! {
-            concat!("The largest value that can be represented by this integer type.
-Use [`", stringify!($T), "::MAX", "`](../../std/primitive.", stringify!($T), ".html#associatedconstant.MAX) instead.
-
-# Examples
-
-```rust
-// deprecated way
-let max = std::", stringify!($T), "::MAX;
-
-// intended way
-let max = ", stringify!($T), "::MAX;
-```
-"),
-            #[$attr]
-            pub const MAX: $T = $T::MAX;
-        }
+        #[doc = concat!(
+            "The smallest value that can be represented by this integer type. Use ",
+            "[`", stringify!($T), "::MIN", "`](../../std/primitive.", stringify!($T), ".html#associatedconstant.MIN)",
+            " instead.",
+        )]
+        ///
+        /// # Examples
+        ///
+        /// ```rust
+        /// // deprecated way
+        #[doc = concat!("let min = std::", stringify!($T), "::MIN;")]
+        ///
+        /// // intended way
+        #[doc = concat!("let min = ", stringify!($T), "::MIN;")]
+        /// ```
+        ///
+        #[$attr]
+        pub const MIN: $T = $T::MIN;
+
+        #[doc = concat!(
+            "The largest value that can be represented by this integer type. Use ",
+            "[`", stringify!($T), "::MAX", "`](../../std/primitive.", stringify!($T), ".html#associatedconstant.MAX)",
+            " instead.",
+        )]
+        ///
+        /// # Examples
+        ///
+        /// ```rust
+        /// // deprecated way
+        #[doc = concat!("let max = std::", stringify!($T), "::MAX;")]
+        ///
+        /// // intended way
+        #[doc = concat!("let max = ", stringify!($T), "::MAX;")]
+        /// ```
+        ///
+        #[$attr]
+        pub const MAX: $T = $T::MAX;
     )
 }
index ae8fc18a83882adec91e0e542b95653975abb7e1..8f141a3ff9e97c5db11eb9f1e7fdaa1567e365b0 100644 (file)
 macro_rules! uint_impl {
-    ($SelfT:ty, $ActualT:ty, $BITS:expr, $MaxV:expr, $Feature:expr, $EndFeature:expr,
+    ($SelfT:ty, $ActualT:ty, $BITS:expr, $MaxV:expr,
         $rot:expr, $rot_op:expr, $rot_result:expr, $swap_op:expr, $swapped:expr,
         $reversed:expr, $le_bytes:expr, $be_bytes:expr,
         $to_xe_bytes_doc:expr, $from_xe_bytes_doc:expr) => {
-        doc_comment! {
-            concat!("The smallest value that can be represented by this integer type.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(", stringify!($SelfT), "::MIN, 0);", $EndFeature, "
-```"),
-            #[stable(feature = "assoc_int_consts", since = "1.43.0")]
-            pub const MIN: Self = 0;
-        }
-
-        doc_comment! {
-            concat!("The largest value that can be represented by this integer type.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(", stringify!($SelfT), "::MAX, ", stringify!($MaxV), ");",
-$EndFeature, "
-```"),
-            #[stable(feature = "assoc_int_consts", since = "1.43.0")]
-            pub const MAX: Self = !0;
-        }
-
-        doc_comment! {
-            concat!("The size of this integer type in bits.
-
-# Examples
-
-```
-", $Feature, "#![feature(int_bits_const)]
-assert_eq!(", stringify!($SelfT), "::BITS, ", stringify!($BITS), ");",
-$EndFeature, "
-```"),
-            #[unstable(feature = "int_bits_const", issue = "76904")]
-            pub const BITS: u32 = $BITS;
-        }
-
-        doc_comment! {
-            concat!("Converts a string slice in a given base to an integer.
-
-The string is expected to be an optional `+` sign
-followed by digits.
-Leading and trailing whitespace represent an error.
-Digits are a subset of these characters, depending on `radix`:
-
-* `0-9`
-* `a-z`
-* `A-Z`
-
-# Panics
-
-This function panics if `radix` is not in the range from 2 to 36.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(", stringify!($SelfT), "::from_str_radix(\"A\", 16), Ok(10));",
-$EndFeature, "
-```"),
-            #[stable(feature = "rust1", since = "1.0.0")]
-            pub fn from_str_radix(src: &str, radix: u32) -> Result<Self, ParseIntError> {
-                from_str_radix(src, radix)
-            }
-        }
-
-        doc_comment! {
-            concat!("Returns the number of ones in the binary representation of `self`.
-
-# Examples
+        /// The smallest value that can be represented by this integer type.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN, 0);")]
+        /// ```
+        #[stable(feature = "assoc_int_consts", since = "1.43.0")]
+        pub const MIN: Self = 0;
 
-Basic usage:
+        /// The largest value that can be represented by this integer type.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX, ", stringify!($MaxV), ");")]
+        /// ```
+        #[stable(feature = "assoc_int_consts", since = "1.43.0")]
+        pub const MAX: Self = !0;
 
-```
-", $Feature, "let n = 0b01001100", stringify!($SelfT), ";
+        /// The size of this integer type in bits.
+        ///
+        /// # Examples
+        ///
+        /// ```
+        /// #![feature(int_bits_const)]
+        #[doc = concat!("assert_eq!(", stringify!($SelfT), "::BITS, ", stringify!($BITS), ");")]
+        /// ```
+        #[unstable(feature = "int_bits_const", issue = "76904")]
+        pub const BITS: u32 = $BITS;
 
-assert_eq!(n.count_ones(), 3);", $EndFeature, "
-```"),
-            #[stable(feature = "rust1", since = "1.0.0")]
-            #[rustc_const_stable(feature = "const_math", since = "1.32.0")]
-            #[doc(alias = "popcount")]
-            #[doc(alias = "popcnt")]
-            #[inline]
-            pub const fn count_ones(self) -> u32 {
-                intrinsics::ctpop(self as $ActualT) as u32
-            }
+        /// Converts a string slice in a given base to an integer.
+        ///
+        /// The string is expected to be an optional `+` sign
+        /// followed by digits.
+        /// Leading and trailing whitespace represent an error.
+        /// Digits are a subset of these characters, depending on `radix`:
+        ///
+        /// * `0-9`
+        /// * `a-z`
+        /// * `A-Z`
+        ///
+        /// # Panics
+        ///
+        /// This function panics if `radix` is not in the range from 2 to 36.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("assert_eq!(", stringify!($SelfT), "::from_str_radix(\"A\", 16), Ok(10));")]
+        /// ```
+        #[stable(feature = "rust1", since = "1.0.0")]
+        pub fn from_str_radix(src: &str, radix: u32) -> Result<Self, ParseIntError> {
+            from_str_radix(src, radix)
         }
 
-        doc_comment! {
-            concat!("Returns the number of zeros in the binary representation of `self`.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(", stringify!($SelfT), "::MAX.count_zeros(), 0);", $EndFeature, "
-```"),
-            #[stable(feature = "rust1", since = "1.0.0")]
-            #[rustc_const_stable(feature = "const_math", since = "1.32.0")]
-            #[inline]
-            pub const fn count_zeros(self) -> u32 {
-                (!self).count_ones()
-            }
+        /// Returns the number of ones in the binary representation of `self`.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("let n = 0b01001100", stringify!($SelfT), ";")]
+        ///
+        /// assert_eq!(n.count_ones(), 3);
+        /// ```
+        #[stable(feature = "rust1", since = "1.0.0")]
+        #[rustc_const_stable(feature = "const_math", since = "1.32.0")]
+        #[doc(alias = "popcount")]
+        #[doc(alias = "popcnt")]
+        #[inline]
+        pub const fn count_ones(self) -> u32 {
+            intrinsics::ctpop(self as $ActualT) as u32
         }
 
-        doc_comment! {
-            concat!("Returns the number of leading zeros in the binary representation of `self`.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "let n = ", stringify!($SelfT), "::MAX >> 2;
-
-assert_eq!(n.leading_zeros(), 2);", $EndFeature, "
-```"),
-            #[stable(feature = "rust1", since = "1.0.0")]
-            #[rustc_const_stable(feature = "const_math", since = "1.32.0")]
-            #[inline]
-            pub const fn leading_zeros(self) -> u32 {
-                intrinsics::ctlz(self as $ActualT) as u32
-            }
+        /// Returns the number of zeros in the binary representation of `self`.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.count_zeros(), 0);")]
+        /// ```
+        #[stable(feature = "rust1", since = "1.0.0")]
+        #[rustc_const_stable(feature = "const_math", since = "1.32.0")]
+        #[inline]
+        pub const fn count_zeros(self) -> u32 {
+            (!self).count_ones()
         }
 
-        doc_comment! {
-            concat!("Returns the number of trailing zeros in the binary representation
-of `self`.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "let n = 0b0101000", stringify!($SelfT), ";
-
-assert_eq!(n.trailing_zeros(), 3);", $EndFeature, "
-```"),
-            #[stable(feature = "rust1", since = "1.0.0")]
-            #[rustc_const_stable(feature = "const_math", since = "1.32.0")]
-            #[inline]
-            pub const fn trailing_zeros(self) -> u32 {
-                intrinsics::cttz(self) as u32
-            }
+        /// Returns the number of leading zeros in the binary representation of `self`.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("let n = ", stringify!($SelfT), "::MAX >> 2;")]
+        ///
+        /// assert_eq!(n.leading_zeros(), 2);
+        /// ```
+        #[stable(feature = "rust1", since = "1.0.0")]
+        #[rustc_const_stable(feature = "const_math", since = "1.32.0")]
+        #[inline]
+        pub const fn leading_zeros(self) -> u32 {
+            intrinsics::ctlz(self as $ActualT) as u32
         }
 
-        doc_comment! {
-            concat!("Returns the number of leading ones in the binary representation of `self`.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "let n = !(", stringify!($SelfT), "::MAX >> 2);
-
-assert_eq!(n.leading_ones(), 2);", $EndFeature, "
-```"),
-            #[stable(feature = "leading_trailing_ones", since = "1.46.0")]
-            #[rustc_const_stable(feature = "leading_trailing_ones", since = "1.46.0")]
-            #[inline]
-            pub const fn leading_ones(self) -> u32 {
-                (!self).leading_zeros()
-            }
+        /// Returns the number of trailing zeros in the binary representation
+        /// of `self`.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("let n = 0b0101000", stringify!($SelfT), ";")]
+        ///
+        /// assert_eq!(n.trailing_zeros(), 3);
+        /// ```
+        #[stable(feature = "rust1", since = "1.0.0")]
+        #[rustc_const_stable(feature = "const_math", since = "1.32.0")]
+        #[inline]
+        pub const fn trailing_zeros(self) -> u32 {
+            intrinsics::cttz(self) as u32
         }
 
-        doc_comment! {
-            concat!("Returns the number of trailing ones in the binary representation
-of `self`.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "let n = 0b1010111", stringify!($SelfT), ";
-
-assert_eq!(n.trailing_ones(), 3);", $EndFeature, "
-```"),
-            #[stable(feature = "leading_trailing_ones", since = "1.46.0")]
-            #[rustc_const_stable(feature = "leading_trailing_ones", since = "1.46.0")]
-            #[inline]
-            pub const fn trailing_ones(self) -> u32 {
-                (!self).trailing_zeros()
-            }
+        /// Returns the number of leading ones in the binary representation of `self`.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("let n = !(", stringify!($SelfT), "::MAX >> 2);")]
+        ///
+        /// assert_eq!(n.leading_ones(), 2);
+        /// ```
+        #[stable(feature = "leading_trailing_ones", since = "1.46.0")]
+        #[rustc_const_stable(feature = "leading_trailing_ones", since = "1.46.0")]
+        #[inline]
+        pub const fn leading_ones(self) -> u32 {
+            (!self).leading_zeros()
         }
 
-        doc_comment! {
-            concat!("Shifts the bits to the left by a specified amount, `n`,
-wrapping the truncated bits to the end of the resulting integer.
-
-Please note this isn't the same operation as the `<<` shifting operator!
-
-# Examples
-
-Basic usage:
-
-```
-let n = ", $rot_op, stringify!($SelfT), ";
-let m = ", $rot_result, ";
-
-assert_eq!(n.rotate_left(", $rot, "), m);
-```"),
-            #[stable(feature = "rust1", since = "1.0.0")]
-            #[rustc_const_stable(feature = "const_math", since = "1.32.0")]
-            #[must_use = "this returns the result of the operation, \
-                          without modifying the original"]
-            #[inline]
-            pub const fn rotate_left(self, n: u32) -> Self {
-                intrinsics::rotate_left(self, n as $SelfT)
-            }
+        /// Returns the number of trailing ones in the binary representation
+        /// of `self`.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("let n = 0b1010111", stringify!($SelfT), ";")]
+        ///
+        /// assert_eq!(n.trailing_ones(), 3);
+        /// ```
+        #[stable(feature = "leading_trailing_ones", since = "1.46.0")]
+        #[rustc_const_stable(feature = "leading_trailing_ones", since = "1.46.0")]
+        #[inline]
+        pub const fn trailing_ones(self) -> u32 {
+            (!self).trailing_zeros()
         }
 
-        doc_comment! {
-            concat!("Shifts the bits to the right by a specified amount, `n`,
-wrapping the truncated bits to the beginning of the resulting
-integer.
-
-Please note this isn't the same operation as the `>>` shifting operator!
-
-# Examples
-
-Basic usage:
-
-```
-let n = ", $rot_result, stringify!($SelfT), ";
-let m = ", $rot_op, ";
-
-assert_eq!(n.rotate_right(", $rot, "), m);
-```"),
-            #[stable(feature = "rust1", since = "1.0.0")]
-            #[rustc_const_stable(feature = "const_math", since = "1.32.0")]
-            #[must_use = "this returns the result of the operation, \
-                          without modifying the original"]
-            #[inline]
-            pub const fn rotate_right(self, n: u32) -> Self {
-                intrinsics::rotate_right(self, n as $SelfT)
-            }
+        /// Shifts the bits to the left by a specified amount, `n`,
+        /// wrapping the truncated bits to the end of the resulting integer.
+        ///
+        /// Please note this isn't the same operation as the `<<` shifting operator!
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("let n = ", $rot_op, stringify!($SelfT), ";")]
+        #[doc = concat!("let m = ", $rot_result, ";")]
+        ///
+        #[doc = concat!("assert_eq!(n.rotate_left(", $rot, "), m);")]
+        /// ```
+        #[stable(feature = "rust1", since = "1.0.0")]
+        #[rustc_const_stable(feature = "const_math", since = "1.32.0")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const fn rotate_left(self, n: u32) -> Self {
+            intrinsics::rotate_left(self, n as $SelfT)
         }
 
-        doc_comment! {
-            concat!("
-Reverses the byte order of the integer.
-
-# Examples
-
-Basic usage:
-
-```
-let n = ", $swap_op, stringify!($SelfT), ";
-let m = n.swap_bytes();
-
-assert_eq!(m, ", $swapped, ");
-```"),
-            #[stable(feature = "rust1", since = "1.0.0")]
-            #[rustc_const_stable(feature = "const_math", since = "1.32.0")]
-            #[inline]
-            pub const fn swap_bytes(self) -> Self {
-                intrinsics::bswap(self as $ActualT) as Self
-            }
+        /// Shifts the bits to the right by a specified amount, `n`,
+        /// wrapping the truncated bits to the beginning of the resulting
+        /// integer.
+        ///
+        /// Please note this isn't the same operation as the `>>` shifting operator!
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("let n = ", $rot_result, stringify!($SelfT), ";")]
+        #[doc = concat!("let m = ", $rot_op, ";")]
+        ///
+        #[doc = concat!("assert_eq!(n.rotate_right(", $rot, "), m);")]
+        /// ```
+        #[stable(feature = "rust1", since = "1.0.0")]
+        #[rustc_const_stable(feature = "const_math", since = "1.32.0")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const fn rotate_right(self, n: u32) -> Self {
+            intrinsics::rotate_right(self, n as $SelfT)
         }
 
-        doc_comment! {
-            concat!("Reverses the order of bits in the integer. The least significant bit becomes the most significant bit,
-                second least-significant bit becomes second most-significant bit, etc.
-
-# Examples
-
-Basic usage:
-
-```
-let n = ", $swap_op, stringify!($SelfT), ";
-let m = n.reverse_bits();
-
-assert_eq!(m, ", $reversed, ");
-assert_eq!(0, 0", stringify!($SelfT), ".reverse_bits());
-```"),
-            #[stable(feature = "reverse_bits", since = "1.37.0")]
-            #[rustc_const_stable(feature = "const_math", since = "1.32.0")]
-            #[inline]
-            #[must_use]
-            pub const fn reverse_bits(self) -> Self {
-                intrinsics::bitreverse(self as $ActualT) as Self
-            }
+        /// Reverses the byte order of the integer.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("let n = ", $swap_op, stringify!($SelfT), ";")]
+        /// let m = n.swap_bytes();
+        ///
+        #[doc = concat!("assert_eq!(m, ", $swapped, ");")]
+        /// ```
+        #[stable(feature = "rust1", since = "1.0.0")]
+        #[rustc_const_stable(feature = "const_math", since = "1.32.0")]
+        #[inline]
+        pub const fn swap_bytes(self) -> Self {
+            intrinsics::bswap(self as $ActualT) as Self
         }
 
-        doc_comment! {
-            concat!("Converts an integer from big endian to the target's endianness.
-
-On big endian this is a no-op. On little endian the bytes are
-swapped.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "let n = 0x1A", stringify!($SelfT), ";
-
-if cfg!(target_endian = \"big\") {
-    assert_eq!(", stringify!($SelfT), "::from_be(n), n)
-} else {
-    assert_eq!(", stringify!($SelfT), "::from_be(n), n.swap_bytes())
-}", $EndFeature, "
-```"),
-            #[stable(feature = "rust1", since = "1.0.0")]
-            #[rustc_const_stable(feature = "const_math", since = "1.32.0")]
-            #[inline]
-            pub const fn from_be(x: Self) -> Self {
-                #[cfg(target_endian = "big")]
-                {
-                    x
-                }
-                #[cfg(not(target_endian = "big"))]
-                {
-                    x.swap_bytes()
-                }
-            }
+        /// Reverses the order of bits in the integer. The least significant bit becomes the most significant bit,
+        ///                 second least-significant bit becomes second most-significant bit, etc.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("let n = ", $swap_op, stringify!($SelfT), ";")]
+        /// let m = n.reverse_bits();
+        ///
+        #[doc = concat!("assert_eq!(m, ", $reversed, ");")]
+        #[doc = concat!("assert_eq!(0, 0", stringify!($SelfT), ".reverse_bits());")]
+        /// ```
+        #[stable(feature = "reverse_bits", since = "1.37.0")]
+        #[rustc_const_stable(feature = "const_math", since = "1.32.0")]
+        #[inline]
+        #[must_use]
+        pub const fn reverse_bits(self) -> Self {
+            intrinsics::bitreverse(self as $ActualT) as Self
         }
 
-        doc_comment! {
-            concat!("Converts an integer from little endian to the target's endianness.
-
-On little endian this is a no-op. On big endian the bytes are
-swapped.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "let n = 0x1A", stringify!($SelfT), ";
-
-if cfg!(target_endian = \"little\") {
-    assert_eq!(", stringify!($SelfT), "::from_le(n), n)
-} else {
-    assert_eq!(", stringify!($SelfT), "::from_le(n), n.swap_bytes())
-}", $EndFeature, "
-```"),
-            #[stable(feature = "rust1", since = "1.0.0")]
-            #[rustc_const_stable(feature = "const_math", since = "1.32.0")]
-            #[inline]
-            pub const fn from_le(x: Self) -> Self {
-                #[cfg(target_endian = "little")]
-                {
-                    x
-                }
-                #[cfg(not(target_endian = "little"))]
-                {
-                    x.swap_bytes()
-                }
+        /// Converts an integer from big endian to the target's endianness.
+        ///
+        /// On big endian this is a no-op. On little endian the bytes are
+        /// swapped.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("let n = 0x1A", stringify!($SelfT), ";")]
+        ///
+        /// if cfg!(target_endian = "big") {
+        #[doc = concat!("    assert_eq!(", stringify!($SelfT), "::from_be(n), n)")]
+        /// } else {
+        #[doc = concat!("    assert_eq!(", stringify!($SelfT), "::from_be(n), n.swap_bytes())")]
+        /// }
+        /// ```
+        #[stable(feature = "rust1", since = "1.0.0")]
+        #[rustc_const_stable(feature = "const_math", since = "1.32.0")]
+        #[inline]
+        pub const fn from_be(x: Self) -> Self {
+            #[cfg(target_endian = "big")]
+            {
+                x
             }
-        }
-
-        doc_comment! {
-            concat!("Converts `self` to big endian from the target's endianness.
-
-On big endian this is a no-op. On little endian the bytes are
-swapped.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "let n = 0x1A", stringify!($SelfT), ";
-
-if cfg!(target_endian = \"big\") {
-    assert_eq!(n.to_be(), n)
-} else {
-    assert_eq!(n.to_be(), n.swap_bytes())
-}", $EndFeature, "
-```"),
-            #[stable(feature = "rust1", since = "1.0.0")]
-            #[rustc_const_stable(feature = "const_math", since = "1.32.0")]
-            #[inline]
-            pub const fn to_be(self) -> Self { // or not to be?
-                #[cfg(target_endian = "big")]
-                {
-                    self
-                }
-                #[cfg(not(target_endian = "big"))]
-                {
-                    self.swap_bytes()
-                }
+            #[cfg(not(target_endian = "big"))]
+            {
+                x.swap_bytes()
             }
         }
 
-        doc_comment! {
-            concat!("Converts `self` to little endian from the target's endianness.
-
-On little endian this is a no-op. On big endian the bytes are
-swapped.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "let n = 0x1A", stringify!($SelfT), ";
-
-if cfg!(target_endian = \"little\") {
-    assert_eq!(n.to_le(), n)
-} else {
-    assert_eq!(n.to_le(), n.swap_bytes())
-}", $EndFeature, "
-```"),
-            #[stable(feature = "rust1", since = "1.0.0")]
-            #[rustc_const_stable(feature = "const_math", since = "1.32.0")]
-            #[inline]
-            pub const fn to_le(self) -> Self {
-                #[cfg(target_endian = "little")]
-                {
-                    self
-                }
-                #[cfg(not(target_endian = "little"))]
-                {
-                    self.swap_bytes()
-                }
+        /// Converts an integer from little endian to the target's endianness.
+        ///
+        /// On little endian this is a no-op. On big endian the bytes are
+        /// swapped.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("let n = 0x1A", stringify!($SelfT), ";")]
+        ///
+        /// if cfg!(target_endian = "little") {
+        #[doc = concat!("    assert_eq!(", stringify!($SelfT), "::from_le(n), n)")]
+        /// } else {
+        #[doc = concat!("    assert_eq!(", stringify!($SelfT), "::from_le(n), n.swap_bytes())")]
+        /// }
+        /// ```
+        #[stable(feature = "rust1", since = "1.0.0")]
+        #[rustc_const_stable(feature = "const_math", since = "1.32.0")]
+        #[inline]
+        pub const fn from_le(x: Self) -> Self {
+            #[cfg(target_endian = "little")]
+            {
+                x
             }
-        }
-
-        doc_comment! {
-            concat!("Checked integer addition. Computes `self + rhs`, returning `None`
-if overflow occurred.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!((", stringify!($SelfT), "::MAX - 2).checked_add(1), ",
-"Some(", stringify!($SelfT), "::MAX - 1));
-assert_eq!((", stringify!($SelfT), "::MAX - 2).checked_add(3), None);", $EndFeature, "
-```"),
-            #[stable(feature = "rust1", since = "1.0.0")]
-            #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")]
-            #[must_use = "this returns the result of the operation, \
-                          without modifying the original"]
-            #[inline]
-            pub const fn checked_add(self, rhs: Self) -> Option<Self> {
-                let (a, b) = self.overflowing_add(rhs);
-                if unlikely!(b) {None} else {Some(a)}
+            #[cfg(not(target_endian = "little"))]
+            {
+                x.swap_bytes()
             }
         }
 
-        doc_comment! {
-            concat!("Unchecked integer addition. Computes `self + rhs`, assuming overflow
-cannot occur. This results in undefined behavior when `self + rhs > ", stringify!($SelfT),
-"::MAX` or `self + rhs < ", stringify!($SelfT), "::MIN`."),
-            #[unstable(
-                feature = "unchecked_math",
-                reason = "niche optimization path",
-                issue = "none",
-            )]
-            #[must_use = "this returns the result of the operation, \
-                          without modifying the original"]
-            #[inline]
-            pub unsafe fn unchecked_add(self, rhs: Self) -> Self {
-                // SAFETY: the caller must uphold the safety contract for
-                // `unchecked_add`.
-                unsafe { intrinsics::unchecked_add(self, rhs) }
+        /// Converts `self` to big endian from the target's endianness.
+        ///
+        /// On big endian this is a no-op. On little endian the bytes are
+        /// swapped.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("let n = 0x1A", stringify!($SelfT), ";")]
+        ///
+        /// if cfg!(target_endian = "big") {
+        ///     assert_eq!(n.to_be(), n)
+        /// } else {
+        ///     assert_eq!(n.to_be(), n.swap_bytes())
+        /// }
+        /// ```
+        #[stable(feature = "rust1", since = "1.0.0")]
+        #[rustc_const_stable(feature = "const_math", since = "1.32.0")]
+        #[inline]
+        pub const fn to_be(self) -> Self { // or not to be?
+            #[cfg(target_endian = "big")]
+            {
+                self
             }
-        }
-
-        doc_comment! {
-            concat!("Checked integer subtraction. Computes `self - rhs`, returning
-`None` if overflow occurred.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(1", stringify!($SelfT), ".checked_sub(1), Some(0));
-assert_eq!(0", stringify!($SelfT), ".checked_sub(1), None);", $EndFeature, "
-```"),
-            #[stable(feature = "rust1", since = "1.0.0")]
-            #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")]
-            #[must_use = "this returns the result of the operation, \
-                          without modifying the original"]
-            #[inline]
-            pub const fn checked_sub(self, rhs: Self) -> Option<Self> {
-                let (a, b) = self.overflowing_sub(rhs);
-                if unlikely!(b) {None} else {Some(a)}
+            #[cfg(not(target_endian = "big"))]
+            {
+                self.swap_bytes()
             }
         }
 
-        doc_comment! {
-            concat!("Unchecked integer subtraction. Computes `self - rhs`, assuming overflow
-cannot occur. This results in undefined behavior when `self - rhs > ", stringify!($SelfT),
-"::MAX` or `self - rhs < ", stringify!($SelfT), "::MIN`."),
-            #[unstable(
-                feature = "unchecked_math",
-                reason = "niche optimization path",
-                issue = "none",
-            )]
-            #[must_use = "this returns the result of the operation, \
-                          without modifying the original"]
-            #[inline]
-            pub unsafe fn unchecked_sub(self, rhs: Self) -> Self {
-                // SAFETY: the caller must uphold the safety contract for
-                // `unchecked_sub`.
-                unsafe { intrinsics::unchecked_sub(self, rhs) }
+        /// Converts `self` to little endian from the target's endianness.
+        ///
+        /// On little endian this is a no-op. On big endian the bytes are
+        /// swapped.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("let n = 0x1A", stringify!($SelfT), ";")]
+        ///
+        /// if cfg!(target_endian = "little") {
+        ///     assert_eq!(n.to_le(), n)
+        /// } else {
+        ///     assert_eq!(n.to_le(), n.swap_bytes())
+        /// }
+        /// ```
+        #[stable(feature = "rust1", since = "1.0.0")]
+        #[rustc_const_stable(feature = "const_math", since = "1.32.0")]
+        #[inline]
+        pub const fn to_le(self) -> Self {
+            #[cfg(target_endian = "little")]
+            {
+                self
             }
-        }
-
-        doc_comment! {
-            concat!("Checked integer multiplication. Computes `self * rhs`, returning
-`None` if overflow occurred.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(5", stringify!($SelfT), ".checked_mul(1), Some(5));
-assert_eq!(", stringify!($SelfT), "::MAX.checked_mul(2), None);", $EndFeature, "
-```"),
-            #[stable(feature = "rust1", since = "1.0.0")]
-            #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")]
-            #[must_use = "this returns the result of the operation, \
-                          without modifying the original"]
-            #[inline]
-            pub const fn checked_mul(self, rhs: Self) -> Option<Self> {
-                let (a, b) = self.overflowing_mul(rhs);
-                if unlikely!(b) {None} else {Some(a)}
+            #[cfg(not(target_endian = "little"))]
+            {
+                self.swap_bytes()
             }
         }
 
-        doc_comment! {
-            concat!("Unchecked integer multiplication. Computes `self * rhs`, assuming overflow
-cannot occur. This results in undefined behavior when `self * rhs > ", stringify!($SelfT),
-"::MAX` or `self * rhs < ", stringify!($SelfT), "::MIN`."),
-            #[unstable(
-                feature = "unchecked_math",
-                reason = "niche optimization path",
-                issue = "none",
-            )]
-            #[must_use = "this returns the result of the operation, \
-                          without modifying the original"]
-            #[inline]
-            pub unsafe fn unchecked_mul(self, rhs: Self) -> Self {
-                // SAFETY: the caller must uphold the safety contract for
-                // `unchecked_mul`.
-                unsafe { intrinsics::unchecked_mul(self, rhs) }
-            }
+        /// Checked integer addition. Computes `self + rhs`, returning `None`
+        /// if overflow occurred.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!(
+            "assert_eq!((", stringify!($SelfT), "::MAX - 2).checked_add(1), ",
+            "Some(", stringify!($SelfT), "::MAX - 1));"
+        )]
+        #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).checked_add(3), None);")]
+        /// ```
+        #[stable(feature = "rust1", since = "1.0.0")]
+        #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const fn checked_add(self, rhs: Self) -> Option<Self> {
+            let (a, b) = self.overflowing_add(rhs);
+            if unlikely!(b) {None} else {Some(a)}
+        }
+
+        /// Unchecked integer addition. Computes `self + rhs`, assuming overflow
+        /// cannot occur. This results in undefined behavior when
+        #[doc = concat!("`self + rhs > ", stringify!($SelfT), "::MAX` or `self + rhs < ", stringify!($SelfT), "::MIN`.")]
+        #[unstable(
+            feature = "unchecked_math",
+            reason = "niche optimization path",
+            issue = "none",
+        )]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub unsafe fn unchecked_add(self, rhs: Self) -> Self {
+            // SAFETY: the caller must uphold the safety contract for
+            // `unchecked_add`.
+            unsafe { intrinsics::unchecked_add(self, rhs) }
         }
 
-        doc_comment! {
-            concat!("Checked integer division. Computes `self / rhs`, returning `None`
-if `rhs == 0`.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(128", stringify!($SelfT), ".checked_div(2), Some(64));
-assert_eq!(1", stringify!($SelfT), ".checked_div(0), None);", $EndFeature, "
-```"),
-            #[stable(feature = "rust1", since = "1.0.0")]
-            #[rustc_const_unstable(feature = "const_checked_int_methods", issue = "53718")]
-            #[must_use = "this returns the result of the operation, \
-                          without modifying the original"]
-            #[inline]
-            pub const fn checked_div(self, rhs: Self) -> Option<Self> {
-                if unlikely!(rhs == 0) {
-                    None
-                } else {
-                    // SAFETY: div by zero has been checked above and unsigned types have no other
-                    // failure modes for division
-                    Some(unsafe { intrinsics::unchecked_div(self, rhs) })
-                }
-            }
+        /// Checked integer subtraction. Computes `self - rhs`, returning
+        /// `None` if overflow occurred.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".checked_sub(1), Some(0));")]
+        #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".checked_sub(1), None);")]
+        /// ```
+        #[stable(feature = "rust1", since = "1.0.0")]
+        #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const fn checked_sub(self, rhs: Self) -> Option<Self> {
+            let (a, b) = self.overflowing_sub(rhs);
+            if unlikely!(b) {None} else {Some(a)}
+        }
+
+        /// Unchecked integer subtraction. Computes `self - rhs`, assuming overflow
+        /// cannot occur. This results in undefined behavior when
+        #[doc = concat!("`self - rhs > ", stringify!($SelfT), "::MAX` or `self - rhs < ", stringify!($SelfT), "::MIN`.")]
+        #[unstable(
+            feature = "unchecked_math",
+            reason = "niche optimization path",
+            issue = "none",
+        )]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub unsafe fn unchecked_sub(self, rhs: Self) -> Self {
+            // SAFETY: the caller must uphold the safety contract for
+            // `unchecked_sub`.
+            unsafe { intrinsics::unchecked_sub(self, rhs) }
         }
 
-        doc_comment! {
-            concat!("Checked Euclidean division. Computes `self.div_euclid(rhs)`, returning `None`
-if `rhs == 0`.
-
-# Examples
-
-Basic usage:
-
-```
-assert_eq!(128", stringify!($SelfT), ".checked_div_euclid(2), Some(64));
-assert_eq!(1", stringify!($SelfT), ".checked_div_euclid(0), None);
-```"),
-            #[stable(feature = "euclidean_division", since = "1.38.0")]
-            #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
-            #[must_use = "this returns the result of the operation, \
-                          without modifying the original"]
-            #[inline]
-            pub const fn checked_div_euclid(self, rhs: Self) -> Option<Self> {
-                if unlikely!(rhs == 0) {
-                    None
-                } else {
-                    Some(self.div_euclid(rhs))
-                }
-            }
+        /// Checked integer multiplication. Computes `self * rhs`, returning
+        /// `None` if overflow occurred.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".checked_mul(1), Some(5));")]
+        #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.checked_mul(2), None);")]
+        /// ```
+        #[stable(feature = "rust1", since = "1.0.0")]
+        #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const fn checked_mul(self, rhs: Self) -> Option<Self> {
+            let (a, b) = self.overflowing_mul(rhs);
+            if unlikely!(b) {None} else {Some(a)}
+        }
+
+        /// Unchecked integer multiplication. Computes `self * rhs`, assuming overflow
+        /// cannot occur. This results in undefined behavior when
+        #[doc = concat!("`self * rhs > ", stringify!($SelfT), "::MAX` or `self * rhs < ", stringify!($SelfT), "::MIN`.")]
+        #[unstable(
+            feature = "unchecked_math",
+            reason = "niche optimization path",
+            issue = "none",
+        )]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub unsafe fn unchecked_mul(self, rhs: Self) -> Self {
+            // SAFETY: the caller must uphold the safety contract for
+            // `unchecked_mul`.
+            unsafe { intrinsics::unchecked_mul(self, rhs) }
         }
 
-
-        doc_comment! {
-            concat!("Checked integer remainder. Computes `self % rhs`, returning `None`
-if `rhs == 0`.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(5", stringify!($SelfT), ".checked_rem(2), Some(1));
-assert_eq!(5", stringify!($SelfT), ".checked_rem(0), None);", $EndFeature, "
-```"),
-            #[stable(feature = "wrapping", since = "1.7.0")]
-            #[rustc_const_unstable(feature = "const_checked_int_methods", issue = "53718")]
-            #[must_use = "this returns the result of the operation, \
-                          without modifying the original"]
-            #[inline]
-            pub const fn checked_rem(self, rhs: Self) -> Option<Self> {
-                if unlikely!(rhs == 0) {
-                    None
-                } else {
-                    // SAFETY: div by zero has been checked above and unsigned types have no other
-                    // failure modes for division
-                    Some(unsafe { intrinsics::unchecked_rem(self, rhs) })
-                }
+        /// Checked integer division. Computes `self / rhs`, returning `None`
+        /// if `rhs == 0`.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("assert_eq!(128", stringify!($SelfT), ".checked_div(2), Some(64));")]
+        #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".checked_div(0), None);")]
+        /// ```
+        #[stable(feature = "rust1", since = "1.0.0")]
+        #[rustc_const_unstable(feature = "const_checked_int_methods", issue = "53718")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const fn checked_div(self, rhs: Self) -> Option<Self> {
+            if unlikely!(rhs == 0) {
+                None
+            } else {
+                // SAFETY: div by zero has been checked above and unsigned types have no other
+                // failure modes for division
+                Some(unsafe { intrinsics::unchecked_div(self, rhs) })
             }
         }
 
-        doc_comment! {
-            concat!("Checked Euclidean modulo. Computes `self.rem_euclid(rhs)`, returning `None`
-if `rhs == 0`.
-
-# Examples
-
-Basic usage:
-
-```
-assert_eq!(5", stringify!($SelfT), ".checked_rem_euclid(2), Some(1));
-assert_eq!(5", stringify!($SelfT), ".checked_rem_euclid(0), None);
-```"),
-            #[stable(feature = "euclidean_division", since = "1.38.0")]
-            #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
-            #[must_use = "this returns the result of the operation, \
-                          without modifying the original"]
-            #[inline]
-            pub const fn checked_rem_euclid(self, rhs: Self) -> Option<Self> {
-                if unlikely!(rhs == 0) {
-                    None
-                } else {
-                    Some(self.rem_euclid(rhs))
-                }
+        /// Checked Euclidean division. Computes `self.div_euclid(rhs)`, returning `None`
+        /// if `rhs == 0`.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("assert_eq!(128", stringify!($SelfT), ".checked_div_euclid(2), Some(64));")]
+        #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".checked_div_euclid(0), None);")]
+        /// ```
+        #[stable(feature = "euclidean_division", since = "1.38.0")]
+        #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const fn checked_div_euclid(self, rhs: Self) -> Option<Self> {
+            if unlikely!(rhs == 0) {
+                None
+            } else {
+                Some(self.div_euclid(rhs))
             }
         }
 
-        doc_comment! {
-            concat!("Checked negation. Computes `-self`, returning `None` unless `self ==
-0`.
-
-Note that negating any positive integer will overflow.
-
-# Examples
 
-Basic usage:
-
-```
-", $Feature, "assert_eq!(0", stringify!($SelfT), ".checked_neg(), Some(0));
-assert_eq!(1", stringify!($SelfT), ".checked_neg(), None);", $EndFeature, "
-```"),
-            #[stable(feature = "wrapping", since = "1.7.0")]
-            #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")]
-            #[inline]
-            pub const fn checked_neg(self) -> Option<Self> {
-                let (a, b) = self.overflowing_neg();
-                if unlikely!(b) {None} else {Some(a)}
+        /// Checked integer remainder. Computes `self % rhs`, returning `None`
+        /// if `rhs == 0`.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".checked_rem(2), Some(1));")]
+        #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".checked_rem(0), None);")]
+        /// ```
+        #[stable(feature = "wrapping", since = "1.7.0")]
+        #[rustc_const_unstable(feature = "const_checked_int_methods", issue = "53718")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const fn checked_rem(self, rhs: Self) -> Option<Self> {
+            if unlikely!(rhs == 0) {
+                None
+            } else {
+                // SAFETY: div by zero has been checked above and unsigned types have no other
+                // failure modes for division
+                Some(unsafe { intrinsics::unchecked_rem(self, rhs) })
             }
         }
 
-        doc_comment! {
-            concat!("Checked shift left. Computes `self << rhs`, returning `None`
-if `rhs` is larger than or equal to the number of bits in `self`.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(0x1", stringify!($SelfT), ".checked_shl(4), Some(0x10));
-assert_eq!(0x10", stringify!($SelfT), ".checked_shl(129), None);", $EndFeature, "
-```"),
-            #[stable(feature = "wrapping", since = "1.7.0")]
-            #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")]
-            #[must_use = "this returns the result of the operation, \
-                          without modifying the original"]
-            #[inline]
-            pub const fn checked_shl(self, rhs: u32) -> Option<Self> {
-                let (a, b) = self.overflowing_shl(rhs);
-                if unlikely!(b) {None} else {Some(a)}
+        /// Checked Euclidean modulo. Computes `self.rem_euclid(rhs)`, returning `None`
+        /// if `rhs == 0`.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".checked_rem_euclid(2), Some(1));")]
+        #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".checked_rem_euclid(0), None);")]
+        /// ```
+        #[stable(feature = "euclidean_division", since = "1.38.0")]
+        #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const fn checked_rem_euclid(self, rhs: Self) -> Option<Self> {
+            if unlikely!(rhs == 0) {
+                None
+            } else {
+                Some(self.rem_euclid(rhs))
             }
         }
 
-        doc_comment! {
-            concat!("Checked shift right. Computes `self >> rhs`, returning `None`
-if `rhs` is larger than or equal to the number of bits in `self`.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(0x10", stringify!($SelfT), ".checked_shr(4), Some(0x1));
-assert_eq!(0x10", stringify!($SelfT), ".checked_shr(129), None);", $EndFeature, "
-```"),
-            #[stable(feature = "wrapping", since = "1.7.0")]
-            #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")]
-            #[must_use = "this returns the result of the operation, \
-                          without modifying the original"]
-            #[inline]
-            pub const fn checked_shr(self, rhs: u32) -> Option<Self> {
-                let (a, b) = self.overflowing_shr(rhs);
-                if unlikely!(b) {None} else {Some(a)}
-            }
+        /// Checked negation. Computes `-self`, returning `None` unless `self ==
+        /// 0`.
+        ///
+        /// Note that negating any positive integer will overflow.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".checked_neg(), Some(0));")]
+        #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".checked_neg(), None);")]
+        /// ```
+        #[stable(feature = "wrapping", since = "1.7.0")]
+        #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")]
+        #[inline]
+        pub const fn checked_neg(self) -> Option<Self> {
+            let (a, b) = self.overflowing_neg();
+            if unlikely!(b) {None} else {Some(a)}
         }
 
-        doc_comment! {
-            concat!("Checked exponentiation. Computes `self.pow(exp)`, returning `None` if
-overflow occurred.
+        /// Checked shift left. Computes `self << rhs`, returning `None`
+        /// if `rhs` is larger than or equal to the number of bits in `self`.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".checked_shl(4), Some(0x10));")]
+        #[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".checked_shl(129), None);")]
+        /// ```
+        #[stable(feature = "wrapping", since = "1.7.0")]
+        #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const fn checked_shl(self, rhs: u32) -> Option<Self> {
+            let (a, b) = self.overflowing_shl(rhs);
+            if unlikely!(b) {None} else {Some(a)}
+        }
 
-# Examples
+        /// Checked shift right. Computes `self >> rhs`, returning `None`
+        /// if `rhs` is larger than or equal to the number of bits in `self`.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".checked_shr(4), Some(0x1));")]
+        #[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".checked_shr(129), None);")]
+        /// ```
+        #[stable(feature = "wrapping", since = "1.7.0")]
+        #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const fn checked_shr(self, rhs: u32) -> Option<Self> {
+            let (a, b) = self.overflowing_shr(rhs);
+            if unlikely!(b) {None} else {Some(a)}
+        }
 
-Basic usage:
+        /// Checked exponentiation. Computes `self.pow(exp)`, returning `None` if
+        /// overflow occurred.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".checked_pow(5), Some(32));")]
+        #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.checked_pow(2), None);")]
+        /// ```
+        #[stable(feature = "no_panic_pow", since = "1.34.0")]
+        #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const fn checked_pow(self, mut exp: u32) -> Option<Self> {
+            if exp == 0 {
+                return Some(1);
+            }
+            let mut base = self;
+            let mut acc: Self = 1;
 
-```
-", $Feature, "assert_eq!(2", stringify!($SelfT), ".checked_pow(5), Some(32));
-assert_eq!(", stringify!($SelfT), "::MAX.checked_pow(2), None);", $EndFeature, "
-```"),
-            #[stable(feature = "no_panic_pow", since = "1.34.0")]
-            #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")]
-            #[must_use = "this returns the result of the operation, \
-                          without modifying the original"]
-            #[inline]
-            pub const fn checked_pow(self, mut exp: u32) -> Option<Self> {
-                if exp == 0 {
-                    return Some(1);
-                }
-                let mut base = self;
-                let mut acc: Self = 1;
-
-                while exp > 1 {
-                    if (exp & 1) == 1 {
-                        acc = try_opt!(acc.checked_mul(base));
-                    }
-                    exp /= 2;
-                    base = try_opt!(base.checked_mul(base));
+            while exp > 1 {
+                if (exp & 1) == 1 {
+                    acc = try_opt!(acc.checked_mul(base));
                 }
-
-                // since exp!=0, finally the exp must be 1.
-                // Deal with the final bit of the exponent separately, since
-                // squaring the base afterwards is not necessary and may cause a
-                // needless overflow.
-
-                Some(try_opt!(acc.checked_mul(base)))
+                exp /= 2;
+                base = try_opt!(base.checked_mul(base));
             }
-        }
-
-        doc_comment! {
-            concat!("Saturating integer addition. Computes `self + rhs`, saturating at
-the numeric bounds instead of overflowing.
-
-# Examples
 
-Basic usage:
-
-```
-", $Feature, "assert_eq!(100", stringify!($SelfT), ".saturating_add(1), 101);
-assert_eq!(", stringify!($SelfT), "::MAX.saturating_add(127), ", stringify!($SelfT), "::MAX);",
-$EndFeature, "
-```"),
+            // since exp!=0, finally the exp must be 1.
+            // Deal with the final bit of the exponent separately, since
+            // squaring the base afterwards is not necessary and may cause a
+            // needless overflow.
 
-            #[stable(feature = "rust1", since = "1.0.0")]
-            #[must_use = "this returns the result of the operation, \
-                          without modifying the original"]
-            #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")]
-            #[inline]
-            pub const fn saturating_add(self, rhs: Self) -> Self {
-                intrinsics::saturating_add(self, rhs)
-            }
+            Some(try_opt!(acc.checked_mul(base)))
         }
 
-        doc_comment! {
-            concat!("Saturating integer subtraction. Computes `self - rhs`, saturating
-at the numeric bounds instead of overflowing.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(100", stringify!($SelfT), ".saturating_sub(27), 73);
-assert_eq!(13", stringify!($SelfT), ".saturating_sub(127), 0);", $EndFeature, "
-```"),
-            #[stable(feature = "rust1", since = "1.0.0")]
-            #[must_use = "this returns the result of the operation, \
-                          without modifying the original"]
-            #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")]
-            #[inline]
-            pub const fn saturating_sub(self, rhs: Self) -> Self {
-                intrinsics::saturating_sub(self, rhs)
-            }
+        /// Saturating integer addition. Computes `self + rhs`, saturating at
+        /// the numeric bounds instead of overflowing.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".saturating_add(1), 101);")]
+        #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.saturating_add(127), ", stringify!($SelfT), "::MAX);")]
+        /// ```
+        #[stable(feature = "rust1", since = "1.0.0")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")]
+        #[inline]
+        pub const fn saturating_add(self, rhs: Self) -> Self {
+            intrinsics::saturating_add(self, rhs)
         }
 
-        doc_comment! {
-            concat!("Saturating integer multiplication. Computes `self * rhs`,
-saturating at the numeric bounds instead of overflowing.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "
-assert_eq!(2", stringify!($SelfT), ".saturating_mul(10), 20);
-assert_eq!((", stringify!($SelfT), "::MAX).saturating_mul(10), ", stringify!($SelfT),
-"::MAX);", $EndFeature, "
-```"),
-            #[stable(feature = "wrapping", since = "1.7.0")]
-            #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")]
-            #[must_use = "this returns the result of the operation, \
-                          without modifying the original"]
-            #[inline]
-            pub const fn saturating_mul(self, rhs: Self) -> Self {
-                match self.checked_mul(rhs) {
-                    Some(x) => x,
-                    None => Self::MAX,
-                }
-            }
+        /// Saturating integer subtraction. Computes `self - rhs`, saturating
+        /// at the numeric bounds instead of overflowing.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".saturating_sub(27), 73);")]
+        #[doc = concat!("assert_eq!(13", stringify!($SelfT), ".saturating_sub(127), 0);")]
+        /// ```
+        #[stable(feature = "rust1", since = "1.0.0")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")]
+        #[inline]
+        pub const fn saturating_sub(self, rhs: Self) -> Self {
+            intrinsics::saturating_sub(self, rhs)
         }
 
-        doc_comment! {
-            concat!("Saturating integer exponentiation. Computes `self.pow(exp)`,
-saturating at the numeric bounds instead of overflowing.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "
-assert_eq!(4", stringify!($SelfT), ".saturating_pow(3), 64);
-assert_eq!(", stringify!($SelfT), "::MAX.saturating_pow(2), ", stringify!($SelfT), "::MAX);",
-$EndFeature, "
-```"),
-            #[stable(feature = "no_panic_pow", since = "1.34.0")]
-            #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")]
-            #[must_use = "this returns the result of the operation, \
-                          without modifying the original"]
-            #[inline]
-            pub const fn saturating_pow(self, exp: u32) -> Self {
-                match self.checked_pow(exp) {
-                    Some(x) => x,
-                    None => Self::MAX,
-                }
+        /// Saturating integer multiplication. Computes `self * rhs`,
+        /// saturating at the numeric bounds instead of overflowing.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".saturating_mul(10), 20);")]
+        #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX).saturating_mul(10), ", stringify!($SelfT),"::MAX);")]
+        /// ```
+        #[stable(feature = "wrapping", since = "1.7.0")]
+        #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const fn saturating_mul(self, rhs: Self) -> Self {
+            match self.checked_mul(rhs) {
+                Some(x) => x,
+                None => Self::MAX,
             }
         }
 
-        doc_comment! {
-            concat!("Wrapping (modular) addition. Computes `self + rhs`,
-wrapping around at the boundary of the type.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(200", stringify!($SelfT), ".wrapping_add(55), 255);
-assert_eq!(200", stringify!($SelfT), ".wrapping_add(", stringify!($SelfT), "::MAX), 199);",
-$EndFeature, "
-```"),
-            #[stable(feature = "rust1", since = "1.0.0")]
-            #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")]
-            #[must_use = "this returns the result of the operation, \
-                          without modifying the original"]
-            #[inline]
-            pub const fn wrapping_add(self, rhs: Self) -> Self {
-                intrinsics::wrapping_add(self, rhs)
+        /// Saturating integer exponentiation. Computes `self.pow(exp)`,
+        /// saturating at the numeric bounds instead of overflowing.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("assert_eq!(4", stringify!($SelfT), ".saturating_pow(3), 64);")]
+        #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.saturating_pow(2), ", stringify!($SelfT), "::MAX);")]
+        /// ```
+        #[stable(feature = "no_panic_pow", since = "1.34.0")]
+        #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const fn saturating_pow(self, exp: u32) -> Self {
+            match self.checked_pow(exp) {
+                Some(x) => x,
+                None => Self::MAX,
             }
         }
 
-        doc_comment! {
-            concat!("Wrapping (modular) subtraction. Computes `self - rhs`,
-wrapping around at the boundary of the type.
-
-# Examples
-
-Basic usage:
+        /// Wrapping (modular) addition. Computes `self + rhs`,
+        /// wrapping around at the boundary of the type.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("assert_eq!(200", stringify!($SelfT), ".wrapping_add(55), 255);")]
+        #[doc = concat!("assert_eq!(200", stringify!($SelfT), ".wrapping_add(", stringify!($SelfT), "::MAX), 199);")]
+        /// ```
+        #[stable(feature = "rust1", since = "1.0.0")]
+        #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const fn wrapping_add(self, rhs: Self) -> Self {
+            intrinsics::wrapping_add(self, rhs)
+        }
 
-```
-", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_sub(100), 0);
-assert_eq!(100", stringify!($SelfT), ".wrapping_sub(", stringify!($SelfT), "::MAX), 101);",
-$EndFeature, "
-```"),
-            #[stable(feature = "rust1", since = "1.0.0")]
-            #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")]
-            #[must_use = "this returns the result of the operation, \
-                          without modifying the original"]
-            #[inline]
-            pub const fn wrapping_sub(self, rhs: Self) -> Self {
-                intrinsics::wrapping_sub(self, rhs)
-            }
+        /// Wrapping (modular) subtraction. Computes `self - rhs`,
+        /// wrapping around at the boundary of the type.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".wrapping_sub(100), 0);")]
+        #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".wrapping_sub(", stringify!($SelfT), "::MAX), 101);")]
+        /// ```
+        #[stable(feature = "rust1", since = "1.0.0")]
+        #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const fn wrapping_sub(self, rhs: Self) -> Self {
+            intrinsics::wrapping_sub(self, rhs)
         }
 
         /// Wrapping (modular) multiplication. Computes `self *
@@ -936,120 +850,112 @@ pub const fn wrapping_sub(self, rhs: Self) -> Self {
         /// Which explains why `u8` is used here.
         ///
         /// ```
-        /// assert_eq!(10u8.wrapping_mul(12), 120);
-        /// assert_eq!(25u8.wrapping_mul(12), 44);
+        /// assert_eq!(10u8.wrapping_mul(12), 120);
+        /// assert_eq!(25u8.wrapping_mul(12), 44);
+        /// ```
+        #[stable(feature = "rust1", since = "1.0.0")]
+        #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")]
+        #[must_use = "this returns the result of the operation, \
+                          without modifying the original"]
+        #[inline]
+        pub const fn wrapping_mul(self, rhs: Self) -> Self {
+            intrinsics::wrapping_mul(self, rhs)
+        }
+
+        /// Wrapping (modular) division. Computes `self / rhs`.
+        /// Wrapped division on unsigned types is just normal division.
+        /// There's no way wrapping could ever happen.
+        /// This function exists, so that all operations
+        /// are accounted for in the wrapping operations.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".wrapping_div(10), 10);")]
+        /// ```
+        #[stable(feature = "num_wrapping", since = "1.2.0")]
+        #[rustc_const_unstable(feature = "const_wrapping_int_methods", issue = "53718")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const fn wrapping_div(self, rhs: Self) -> Self {
+            self / rhs
+        }
+
+        /// Wrapping Euclidean division. Computes `self.div_euclid(rhs)`.
+        /// Wrapped division on unsigned types is just normal division.
+        /// There's no way wrapping could ever happen.
+        /// This function exists, so that all operations
+        /// are accounted for in the wrapping operations.
+        /// Since, for the positive integers, all common
+        /// definitions of division are equal, this
+        /// is exactly equal to `self.wrapping_div(rhs)`.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".wrapping_div_euclid(10), 10);")]
+        /// ```
+        #[stable(feature = "euclidean_division", since = "1.38.0")]
+        #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const fn wrapping_div_euclid(self, rhs: Self) -> Self {
+            self / rhs
+        }
+
+        /// Wrapping (modular) remainder. Computes `self % rhs`.
+        /// Wrapped remainder calculation on unsigned types is
+        /// just the regular remainder calculation.
+        /// There's no way wrapping could ever happen.
+        /// This function exists, so that all operations
+        /// are accounted for in the wrapping operations.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".wrapping_rem(10), 0);")]
+        /// ```
+        #[stable(feature = "num_wrapping", since = "1.2.0")]
+        #[rustc_const_unstable(feature = "const_wrapping_int_methods", issue = "53718")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const fn wrapping_rem(self, rhs: Self) -> Self {
+            self % rhs
+        }
+
+        /// Wrapping Euclidean modulo. Computes `self.rem_euclid(rhs)`.
+        /// Wrapped modulo calculation on unsigned types is
+        /// just the regular remainder calculation.
+        /// There's no way wrapping could ever happen.
+        /// This function exists, so that all operations
+        /// are accounted for in the wrapping operations.
+        /// Since, for the positive integers, all common
+        /// definitions of division are equal, this
+        /// is exactly equal to `self.wrapping_rem(rhs)`.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".wrapping_rem_euclid(10), 0);")]
         /// ```
-        #[stable(feature = "rust1", since = "1.0.0")]
-        #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")]
+        #[stable(feature = "euclidean_division", since = "1.38.0")]
+        #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
         #[must_use = "this returns the result of the operation, \
-                          without modifying the original"]
+                      without modifying the original"]
         #[inline]
-        pub const fn wrapping_mul(self, rhs: Self) -> Self {
-            intrinsics::wrapping_mul(self, rhs)
-        }
-
-        doc_comment! {
-            concat!("Wrapping (modular) division. Computes `self / rhs`.
-Wrapped division on unsigned types is just normal division.
-There's no way wrapping could ever happen.
-This function exists, so that all operations
-are accounted for in the wrapping operations.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_div(10), 10);", $EndFeature, "
-```"),
-            #[stable(feature = "num_wrapping", since = "1.2.0")]
-            #[rustc_const_unstable(feature = "const_wrapping_int_methods", issue = "53718")]
-            #[must_use = "this returns the result of the operation, \
-                          without modifying the original"]
-            #[inline]
-            pub const fn wrapping_div(self, rhs: Self) -> Self {
-                self / rhs
-            }
-        }
-
-        doc_comment! {
-            concat!("Wrapping Euclidean division. Computes `self.div_euclid(rhs)`.
-Wrapped division on unsigned types is just normal division.
-There's no way wrapping could ever happen.
-This function exists, so that all operations
-are accounted for in the wrapping operations.
-Since, for the positive integers, all common
-definitions of division are equal, this
-is exactly equal to `self.wrapping_div(rhs)`.
-
-# Examples
-
-Basic usage:
-
-```
-assert_eq!(100", stringify!($SelfT), ".wrapping_div_euclid(10), 10);
-```"),
-            #[stable(feature = "euclidean_division", since = "1.38.0")]
-            #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
-            #[must_use = "this returns the result of the operation, \
-                          without modifying the original"]
-            #[inline]
-            pub const fn wrapping_div_euclid(self, rhs: Self) -> Self {
-                self / rhs
-            }
-        }
-
-        doc_comment! {
-            concat!("Wrapping (modular) remainder. Computes `self % rhs`.
-Wrapped remainder calculation on unsigned types is
-just the regular remainder calculation.
-There's no way wrapping could ever happen.
-This function exists, so that all operations
-are accounted for in the wrapping operations.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_rem(10), 0);", $EndFeature, "
-```"),
-            #[stable(feature = "num_wrapping", since = "1.2.0")]
-            #[rustc_const_unstable(feature = "const_wrapping_int_methods", issue = "53718")]
-            #[must_use = "this returns the result of the operation, \
-                          without modifying the original"]
-            #[inline]
-            pub const fn wrapping_rem(self, rhs: Self) -> Self {
-                self % rhs
-            }
-        }
-
-        doc_comment! {
-            concat!("Wrapping Euclidean modulo. Computes `self.rem_euclid(rhs)`.
-Wrapped modulo calculation on unsigned types is
-just the regular remainder calculation.
-There's no way wrapping could ever happen.
-This function exists, so that all operations
-are accounted for in the wrapping operations.
-Since, for the positive integers, all common
-definitions of division are equal, this
-is exactly equal to `self.wrapping_rem(rhs)`.
-
-# Examples
-
-Basic usage:
-
-```
-assert_eq!(100", stringify!($SelfT), ".wrapping_rem_euclid(10), 0);
-```"),
-            #[stable(feature = "euclidean_division", since = "1.38.0")]
-            #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
-            #[must_use = "this returns the result of the operation, \
-                          without modifying the original"]
-            #[inline]
-            pub const fn wrapping_rem_euclid(self, rhs: Self) -> Self {
-                self % rhs
-            }
+        pub const fn wrapping_rem_euclid(self, rhs: Self) -> Self {
+            self % rhs
         }
 
         /// Wrapping (modular) negation. Computes `-self`,
@@ -1080,167 +986,156 @@ pub const fn wrapping_neg(self) -> Self {
             self.overflowing_neg().0
         }
 
-        doc_comment! {
-            concat!("Panic-free bitwise shift-left; yields `self << mask(rhs)`,
-where `mask` removes any high-order bits of `rhs` that
-would cause the shift to exceed the bitwidth of the type.
-
-Note that this is *not* the same as a rotate-left; the
-RHS of a wrapping shift-left is restricted to the range
-of the type, rather than the bits shifted out of the LHS
-being returned to the other end. The primitive integer
-types all implement a [`rotate_left`](#method.rotate_left) function,
-which may be what you want instead.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(1", stringify!($SelfT), ".wrapping_shl(7), 128);
-assert_eq!(1", stringify!($SelfT), ".wrapping_shl(128), 1);", $EndFeature, "
-```"),
-            #[stable(feature = "num_wrapping", since = "1.2.0")]
-            #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")]
-            #[must_use = "this returns the result of the operation, \
-                          without modifying the original"]
-            #[inline]
-            pub const fn wrapping_shl(self, rhs: u32) -> Self {
-                // SAFETY: the masking by the bitsize of the type ensures that we do not shift
-                // out of bounds
-                unsafe {
-                    intrinsics::unchecked_shl(self, (rhs & ($BITS - 1)) as $SelfT)
-                }
+        /// Panic-free bitwise shift-left; yields `self << mask(rhs)`,
+        /// where `mask` removes any high-order bits of `rhs` that
+        /// would cause the shift to exceed the bitwidth of the type.
+        ///
+        /// Note that this is *not* the same as a rotate-left; the
+        /// RHS of a wrapping shift-left is restricted to the range
+        /// of the type, rather than the bits shifted out of the LHS
+        /// being returned to the other end. The primitive integer
+        /// types all implement a [`rotate_left`](#method.rotate_left) function,
+        /// which may be what you want instead.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".wrapping_shl(7), 128);")]
+        #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".wrapping_shl(128), 1);")]
+        /// ```
+        #[stable(feature = "num_wrapping", since = "1.2.0")]
+        #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const fn wrapping_shl(self, rhs: u32) -> Self {
+            // SAFETY: the masking by the bitsize of the type ensures that we do not shift
+            // out of bounds
+            unsafe {
+                intrinsics::unchecked_shl(self, (rhs & ($BITS - 1)) as $SelfT)
             }
         }
 
-        doc_comment! {
-            concat!("Panic-free bitwise shift-right; yields `self >> mask(rhs)`,
-where `mask` removes any high-order bits of `rhs` that
-would cause the shift to exceed the bitwidth of the type.
-
-Note that this is *not* the same as a rotate-right; the
-RHS of a wrapping shift-right is restricted to the range
-of the type, rather than the bits shifted out of the LHS
-being returned to the other end. The primitive integer
-types all implement a [`rotate_right`](#method.rotate_right) function,
-which may be what you want instead.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(128", stringify!($SelfT), ".wrapping_shr(7), 1);
-assert_eq!(128", stringify!($SelfT), ".wrapping_shr(128), 128);", $EndFeature, "
-```"),
-            #[stable(feature = "num_wrapping", since = "1.2.0")]
-            #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")]
-            #[must_use = "this returns the result of the operation, \
-                          without modifying the original"]
-            #[inline]
-            pub const fn wrapping_shr(self, rhs: u32) -> Self {
-                // SAFETY: the masking by the bitsize of the type ensures that we do not shift
-                // out of bounds
-                unsafe {
-                    intrinsics::unchecked_shr(self, (rhs & ($BITS - 1)) as $SelfT)
-                }
+        /// Panic-free bitwise shift-right; yields `self >> mask(rhs)`,
+        /// where `mask` removes any high-order bits of `rhs` that
+        /// would cause the shift to exceed the bitwidth of the type.
+        ///
+        /// Note that this is *not* the same as a rotate-right; the
+        /// RHS of a wrapping shift-right is restricted to the range
+        /// of the type, rather than the bits shifted out of the LHS
+        /// being returned to the other end. The primitive integer
+        /// types all implement a [`rotate_right`](#method.rotate_right) function,
+        /// which may be what you want instead.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("assert_eq!(128", stringify!($SelfT), ".wrapping_shr(7), 1);")]
+        #[doc = concat!("assert_eq!(128", stringify!($SelfT), ".wrapping_shr(128), 128);")]
+        /// ```
+        #[stable(feature = "num_wrapping", since = "1.2.0")]
+        #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const fn wrapping_shr(self, rhs: u32) -> Self {
+            // SAFETY: the masking by the bitsize of the type ensures that we do not shift
+            // out of bounds
+            unsafe {
+                intrinsics::unchecked_shr(self, (rhs & ($BITS - 1)) as $SelfT)
             }
         }
 
-        doc_comment! {
-            concat!("Wrapping (modular) exponentiation. Computes `self.pow(exp)`,
-wrapping around at the boundary of the type.
-
-# Examples
-
-Basic usage:
+        /// Wrapping (modular) exponentiation. Computes `self.pow(exp)`,
+        /// wrapping around at the boundary of the type.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("assert_eq!(3", stringify!($SelfT), ".wrapping_pow(5), 243);")]
+        /// assert_eq!(3u8.wrapping_pow(6), 217);
+        /// ```
+        #[stable(feature = "no_panic_pow", since = "1.34.0")]
+        #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const fn wrapping_pow(self, mut exp: u32) -> Self {
+            if exp == 0 {
+                return 1;
+            }
+            let mut base = self;
+            let mut acc: Self = 1;
 
-```
-", $Feature, "assert_eq!(3", stringify!($SelfT), ".wrapping_pow(5), 243);
-assert_eq!(3u8.wrapping_pow(6), 217);", $EndFeature, "
-```"),
-            #[stable(feature = "no_panic_pow", since = "1.34.0")]
-            #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")]
-            #[must_use = "this returns the result of the operation, \
-                          without modifying the original"]
-            #[inline]
-            pub const fn wrapping_pow(self, mut exp: u32) -> Self {
-                if exp == 0 {
-                    return 1;
-                }
-                let mut base = self;
-                let mut acc: Self = 1;
-
-                while exp > 1 {
-                    if (exp & 1) == 1 {
-                        acc = acc.wrapping_mul(base);
-                    }
-                    exp /= 2;
-                    base = base.wrapping_mul(base);
+            while exp > 1 {
+                if (exp & 1) == 1 {
+                    acc = acc.wrapping_mul(base);
                 }
-
-                // since exp!=0, finally the exp must be 1.
-                // Deal with the final bit of the exponent separately, since
-                // squaring the base afterwards is not necessary and may cause a
-                // needless overflow.
-                acc.wrapping_mul(base)
+                exp /= 2;
+                base = base.wrapping_mul(base);
             }
-        }
 
-        doc_comment! {
-            concat!("Calculates `self` + `rhs`
-
-Returns a tuple of the addition along with a boolean indicating
-whether an arithmetic overflow would occur. If an overflow would
-have occurred then the wrapped value is returned.
-
-# Examples
-
-Basic usage
-
-```
-", $Feature, "
-assert_eq!(5", stringify!($SelfT), ".overflowing_add(2), (7, false));
-assert_eq!(", stringify!($SelfT), "::MAX.overflowing_add(1), (0, true));", $EndFeature, "
-```"),
-            #[stable(feature = "wrapping", since = "1.7.0")]
-            #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")]
-            #[must_use = "this returns the result of the operation, \
-                          without modifying the original"]
-            #[inline]
-            pub const fn overflowing_add(self, rhs: Self) -> (Self, bool) {
-                let (a, b) = intrinsics::add_with_overflow(self as $ActualT, rhs as $ActualT);
-                (a as Self, b)
-            }
+            // since exp!=0, finally the exp must be 1.
+            // Deal with the final bit of the exponent separately, since
+            // squaring the base afterwards is not necessary and may cause a
+            // needless overflow.
+            acc.wrapping_mul(base)
         }
 
-        doc_comment! {
-            concat!("Calculates `self` - `rhs`
-
-Returns a tuple of the subtraction along with a boolean indicating
-whether an arithmetic overflow would occur. If an overflow would
-have occurred then the wrapped value is returned.
-
-# Examples
-
-Basic usage
+        /// Calculates `self` + `rhs`
+        ///
+        /// Returns a tuple of the addition along with a boolean indicating
+        /// whether an arithmetic overflow would occur. If an overflow would
+        /// have occurred then the wrapped value is returned.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage
+        ///
+        /// ```
+        ///
+        #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".overflowing_add(2), (7, false));")]
+        #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.overflowing_add(1), (0, true));")]
+        /// ```
+        #[stable(feature = "wrapping", since = "1.7.0")]
+        #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const fn overflowing_add(self, rhs: Self) -> (Self, bool) {
+            let (a, b) = intrinsics::add_with_overflow(self as $ActualT, rhs as $ActualT);
+            (a as Self, b)
+        }
 
-```
-", $Feature, "
-assert_eq!(5", stringify!($SelfT), ".overflowing_sub(2), (3, false));
-assert_eq!(0", stringify!($SelfT), ".overflowing_sub(1), (", stringify!($SelfT), "::MAX, true));",
-$EndFeature, "
-```"),
-            #[stable(feature = "wrapping", since = "1.7.0")]
-            #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")]
-            #[must_use = "this returns the result of the operation, \
-                          without modifying the original"]
-            #[inline]
-            pub const fn overflowing_sub(self, rhs: Self) -> (Self, bool) {
-                let (a, b) = intrinsics::sub_with_overflow(self as $ActualT, rhs as $ActualT);
-                (a as Self, b)
-            }
+        /// Calculates `self` - `rhs`
+        ///
+        /// Returns a tuple of the subtraction along with a boolean indicating
+        /// whether an arithmetic overflow would occur. If an overflow would
+        /// have occurred then the wrapped value is returned.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage
+        ///
+        /// ```
+        ///
+        #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".overflowing_sub(2), (3, false));")]
+        #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".overflowing_sub(1), (", stringify!($SelfT), "::MAX, true));")]
+        /// ```
+        #[stable(feature = "wrapping", since = "1.7.0")]
+        #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const fn overflowing_sub(self, rhs: Self) -> (Self, bool) {
+            let (a, b) = intrinsics::sub_with_overflow(self as $ActualT, rhs as $ActualT);
+            (a as Self, b)
         }
 
         /// Calculates the multiplication of `self` and `rhs`.
@@ -1270,269 +1165,251 @@ pub const fn overflowing_mul(self, rhs: Self) -> (Self, bool) {
             (a as Self, b)
         }
 
-        doc_comment! {
-            concat!("Calculates the divisor when `self` is divided by `rhs`.
-
-Returns a tuple of the divisor along with a boolean indicating
-whether an arithmetic overflow would occur. Note that for unsigned
-integers overflow never occurs, so the second value is always
-`false`.
-
-# Panics
-
-This function will panic if `rhs` is 0.
-
-# Examples
-
-Basic usage
-
-```
-", $Feature, "assert_eq!(5", stringify!($SelfT), ".overflowing_div(2), (2, false));", $EndFeature, "
-```"),
-            #[inline]
-            #[stable(feature = "wrapping", since = "1.7.0")]
-            #[rustc_const_unstable(feature = "const_overflowing_int_methods", issue = "53718")]
-            #[must_use = "this returns the result of the operation, \
-                          without modifying the original"]
-            pub const fn overflowing_div(self, rhs: Self) -> (Self, bool) {
-                (self / rhs, false)
-            }
-        }
-
-        doc_comment! {
-            concat!("Calculates the quotient of Euclidean division `self.div_euclid(rhs)`.
-
-Returns a tuple of the divisor along with a boolean indicating
-whether an arithmetic overflow would occur. Note that for unsigned
-integers overflow never occurs, so the second value is always
-`false`.
-Since, for the positive integers, all common
-definitions of division are equal, this
-is exactly equal to `self.overflowing_div(rhs)`.
-
-# Panics
-
-This function will panic if `rhs` is 0.
-
-# Examples
-
-Basic usage
-
-```
-assert_eq!(5", stringify!($SelfT), ".overflowing_div_euclid(2), (2, false));
-```"),
-            #[inline]
-            #[stable(feature = "euclidean_division", since = "1.38.0")]
-            #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
-            #[must_use = "this returns the result of the operation, \
-                          without modifying the original"]
-            pub const fn overflowing_div_euclid(self, rhs: Self) -> (Self, bool) {
-                (self / rhs, false)
-            }
+        /// Calculates the divisor when `self` is divided by `rhs`.
+        ///
+        /// Returns a tuple of the divisor along with a boolean indicating
+        /// whether an arithmetic overflow would occur. Note that for unsigned
+        /// integers overflow never occurs, so the second value is always
+        /// `false`.
+        ///
+        /// # Panics
+        ///
+        /// This function will panic if `rhs` is 0.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage
+        ///
+        /// ```
+        #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".overflowing_div(2), (2, false));")]
+        /// ```
+        #[inline]
+        #[stable(feature = "wrapping", since = "1.7.0")]
+        #[rustc_const_unstable(feature = "const_overflowing_int_methods", issue = "53718")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        pub const fn overflowing_div(self, rhs: Self) -> (Self, bool) {
+            (self / rhs, false)
         }
 
-        doc_comment! {
-            concat!("Calculates the remainder when `self` is divided by `rhs`.
-
-Returns a tuple of the remainder after dividing along with a boolean
-indicating whether an arithmetic overflow would occur. Note that for
-unsigned integers overflow never occurs, so the second value is
-always `false`.
-
-# Panics
-
-This function will panic if `rhs` is 0.
-
-# Examples
-
-Basic usage
-
-```
-", $Feature, "assert_eq!(5", stringify!($SelfT), ".overflowing_rem(2), (1, false));", $EndFeature, "
-```"),
-            #[inline]
-            #[stable(feature = "wrapping", since = "1.7.0")]
-            #[rustc_const_unstable(feature = "const_overflowing_int_methods", issue = "53718")]
-            #[must_use = "this returns the result of the operation, \
-                          without modifying the original"]
-            pub const fn overflowing_rem(self, rhs: Self) -> (Self, bool) {
-                (self % rhs, false)
-            }
+        /// Calculates the quotient of Euclidean division `self.div_euclid(rhs)`.
+        ///
+        /// Returns a tuple of the divisor along with a boolean indicating
+        /// whether an arithmetic overflow would occur. Note that for unsigned
+        /// integers overflow never occurs, so the second value is always
+        /// `false`.
+        /// Since, for the positive integers, all common
+        /// definitions of division are equal, this
+        /// is exactly equal to `self.overflowing_div(rhs)`.
+        ///
+        /// # Panics
+        ///
+        /// This function will panic if `rhs` is 0.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage
+        ///
+        /// ```
+        #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".overflowing_div_euclid(2), (2, false));")]
+        /// ```
+        #[inline]
+        #[stable(feature = "euclidean_division", since = "1.38.0")]
+        #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        pub const fn overflowing_div_euclid(self, rhs: Self) -> (Self, bool) {
+            (self / rhs, false)
         }
 
-        doc_comment! {
-            concat!("Calculates the remainder `self.rem_euclid(rhs)` as if by Euclidean division.
-
-Returns a tuple of the modulo after dividing along with a boolean
-indicating whether an arithmetic overflow would occur. Note that for
-unsigned integers overflow never occurs, so the second value is
-always `false`.
-Since, for the positive integers, all common
-definitions of division are equal, this operation
-is exactly equal to `self.overflowing_rem(rhs)`.
-
-# Panics
-
-This function will panic if `rhs` is 0.
-
-# Examples
-
-Basic usage
-
-```
-assert_eq!(5", stringify!($SelfT), ".overflowing_rem_euclid(2), (1, false));
-```"),
-            #[inline]
-            #[stable(feature = "euclidean_division", since = "1.38.0")]
-            #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
-            #[must_use = "this returns the result of the operation, \
-                          without modifying the original"]
-            pub const fn overflowing_rem_euclid(self, rhs: Self) -> (Self, bool) {
-                (self % rhs, false)
-            }
+        /// Calculates the remainder when `self` is divided by `rhs`.
+        ///
+        /// Returns a tuple of the remainder after dividing along with a boolean
+        /// indicating whether an arithmetic overflow would occur. Note that for
+        /// unsigned integers overflow never occurs, so the second value is
+        /// always `false`.
+        ///
+        /// # Panics
+        ///
+        /// This function will panic if `rhs` is 0.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage
+        ///
+        /// ```
+        #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".overflowing_rem(2), (1, false));")]
+        /// ```
+        #[inline]
+        #[stable(feature = "wrapping", since = "1.7.0")]
+        #[rustc_const_unstable(feature = "const_overflowing_int_methods", issue = "53718")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        pub const fn overflowing_rem(self, rhs: Self) -> (Self, bool) {
+            (self % rhs, false)
         }
 
-        doc_comment! {
-            concat!("Negates self in an overflowing fashion.
-
-Returns `!self + 1` using wrapping operations to return the value
-that represents the negation of this unsigned value. Note that for
-positive unsigned values overflow always occurs, but negating 0 does
-not overflow.
-
-# Examples
-
-Basic usage
-
-```
-", $Feature, "assert_eq!(0", stringify!($SelfT), ".overflowing_neg(), (0, false));
-assert_eq!(2", stringify!($SelfT), ".overflowing_neg(), (-2i32 as ", stringify!($SelfT),
-", true));", $EndFeature, "
-```"),
-            #[inline]
-            #[stable(feature = "wrapping", since = "1.7.0")]
-            #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")]
-            pub const fn overflowing_neg(self) -> (Self, bool) {
-                ((!self).wrapping_add(1), self != 0)
-            }
+        /// Calculates the remainder `self.rem_euclid(rhs)` as if by Euclidean division.
+        ///
+        /// Returns a tuple of the modulo after dividing along with a boolean
+        /// indicating whether an arithmetic overflow would occur. Note that for
+        /// unsigned integers overflow never occurs, so the second value is
+        /// always `false`.
+        /// Since, for the positive integers, all common
+        /// definitions of division are equal, this operation
+        /// is exactly equal to `self.overflowing_rem(rhs)`.
+        ///
+        /// # Panics
+        ///
+        /// This function will panic if `rhs` is 0.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage
+        ///
+        /// ```
+        #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".overflowing_rem_euclid(2), (1, false));")]
+        /// ```
+        #[inline]
+        #[stable(feature = "euclidean_division", since = "1.38.0")]
+        #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        pub const fn overflowing_rem_euclid(self, rhs: Self) -> (Self, bool) {
+            (self % rhs, false)
         }
 
-        doc_comment! {
-            concat!("Shifts self left by `rhs` bits.
-
-Returns a tuple of the shifted version of self along with a boolean
-indicating whether the shift value was larger than or equal to the
-number of bits. If the shift value is too large, then value is
-masked (N-1) where N is the number of bits, and this value is then
-used to perform the shift.
-
-# Examples
-
-Basic usage
-
-```
-", $Feature, "assert_eq!(0x1", stringify!($SelfT), ".overflowing_shl(4), (0x10, false));
-assert_eq!(0x1", stringify!($SelfT), ".overflowing_shl(132), (0x10, true));", $EndFeature, "
-```"),
-            #[stable(feature = "wrapping", since = "1.7.0")]
-            #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")]
-            #[must_use = "this returns the result of the operation, \
-                          without modifying the original"]
-            #[inline]
-            pub const fn overflowing_shl(self, rhs: u32) -> (Self, bool) {
-                (self.wrapping_shl(rhs), (rhs > ($BITS - 1)))
-            }
+        /// Negates self in an overflowing fashion.
+        ///
+        /// Returns `!self + 1` using wrapping operations to return the value
+        /// that represents the negation of this unsigned value. Note that for
+        /// positive unsigned values overflow always occurs, but negating 0 does
+        /// not overflow.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage
+        ///
+        /// ```
+        #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".overflowing_neg(), (0, false));")]
+        #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".overflowing_neg(), (-2i32 as ", stringify!($SelfT), ", true));")]
+        /// ```
+        #[inline]
+        #[stable(feature = "wrapping", since = "1.7.0")]
+        #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")]
+        pub const fn overflowing_neg(self) -> (Self, bool) {
+            ((!self).wrapping_add(1), self != 0)
         }
 
-        doc_comment! {
-            concat!("Shifts self right by `rhs` bits.
-
-Returns a tuple of the shifted version of self along with a boolean
-indicating whether the shift value was larger than or equal to the
-number of bits. If the shift value is too large, then value is
-masked (N-1) where N is the number of bits, and this value is then
-used to perform the shift.
-
-# Examples
-
-Basic usage
-
-```
-", $Feature, "assert_eq!(0x10", stringify!($SelfT), ".overflowing_shr(4), (0x1, false));
-assert_eq!(0x10", stringify!($SelfT), ".overflowing_shr(132), (0x1, true));", $EndFeature, "
-```"),
-            #[stable(feature = "wrapping", since = "1.7.0")]
-            #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")]
-            #[must_use = "this returns the result of the operation, \
-                          without modifying the original"]
-            #[inline]
-            pub const fn overflowing_shr(self, rhs: u32) -> (Self, bool) {
-                (self.wrapping_shr(rhs), (rhs > ($BITS - 1)))
-            }
+        /// Shifts self left by `rhs` bits.
+        ///
+        /// Returns a tuple of the shifted version of self along with a boolean
+        /// indicating whether the shift value was larger than or equal to the
+        /// number of bits. If the shift value is too large, then value is
+        /// masked (N-1) where N is the number of bits, and this value is then
+        /// used to perform the shift.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage
+        ///
+        /// ```
+        #[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".overflowing_shl(4), (0x10, false));")]
+        #[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".overflowing_shl(132), (0x10, true));")]
+        /// ```
+        #[stable(feature = "wrapping", since = "1.7.0")]
+        #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const fn overflowing_shl(self, rhs: u32) -> (Self, bool) {
+            (self.wrapping_shl(rhs), (rhs > ($BITS - 1)))
         }
 
-        doc_comment! {
-            concat!("Raises self to the power of `exp`, using exponentiation by squaring.
-
-Returns a tuple of the exponentiation along with a bool indicating
-whether an overflow happened.
-
-# Examples
+        /// Shifts self right by `rhs` bits.
+        ///
+        /// Returns a tuple of the shifted version of self along with a boolean
+        /// indicating whether the shift value was larger than or equal to the
+        /// number of bits. If the shift value is too large, then value is
+        /// masked (N-1) where N is the number of bits, and this value is then
+        /// used to perform the shift.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage
+        ///
+        /// ```
+        #[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".overflowing_shr(4), (0x1, false));")]
+        #[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".overflowing_shr(132), (0x1, true));")]
+        /// ```
+        #[stable(feature = "wrapping", since = "1.7.0")]
+        #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const fn overflowing_shr(self, rhs: u32) -> (Self, bool) {
+            (self.wrapping_shr(rhs), (rhs > ($BITS - 1)))
+        }
 
-Basic usage:
+        /// Raises self to the power of `exp`, using exponentiation by squaring.
+        ///
+        /// Returns a tuple of the exponentiation along with a bool indicating
+        /// whether an overflow happened.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("assert_eq!(3", stringify!($SelfT), ".overflowing_pow(5), (243, false));")]
+        /// assert_eq!(3u8.overflowing_pow(6), (217, true));
+        /// ```
+        #[stable(feature = "no_panic_pow", since = "1.34.0")]
+        #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const fn overflowing_pow(self, mut exp: u32) -> (Self, bool) {
+            if exp == 0{
+                return (1,false);
+            }
+            let mut base = self;
+            let mut acc: Self = 1;
+            let mut overflown = false;
+            // Scratch space for storing results of overflowing_mul.
+            let mut r;
 
-```
-", $Feature, "assert_eq!(3", stringify!($SelfT), ".overflowing_pow(5), (243, false));
-assert_eq!(3u8.overflowing_pow(6), (217, true));", $EndFeature, "
-```"),
-            #[stable(feature = "no_panic_pow", since = "1.34.0")]
-            #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")]
-            #[must_use = "this returns the result of the operation, \
-                          without modifying the original"]
-            #[inline]
-            pub const fn overflowing_pow(self, mut exp: u32) -> (Self, bool) {
-                if exp == 0{
-                    return (1,false);
-                }
-                let mut base = self;
-                let mut acc: Self = 1;
-                let mut overflown = false;
-                // Scratch space for storing results of overflowing_mul.
-                let mut r;
-
-                while exp > 1 {
-                    if (exp & 1) == 1 {
-                        r = acc.overflowing_mul(base);
-                        acc = r.0;
-                        overflown |= r.1;
-                    }
-                    exp /= 2;
-                    r = base.overflowing_mul(base);
-                    base = r.0;
+            while exp > 1 {
+                if (exp & 1) == 1 {
+                    r = acc.overflowing_mul(base);
+                    acc = r.0;
                     overflown |= r.1;
                 }
-
-                // since exp!=0, finally the exp must be 1.
-                // Deal with the final bit of the exponent separately, since
-                // squaring the base afterwards is not necessary and may cause a
-                // needless overflow.
-                r = acc.overflowing_mul(base);
-                r.1 |= overflown;
-
-                r
+                exp /= 2;
+                r = base.overflowing_mul(base);
+                base = r.0;
+                overflown |= r.1;
             }
-        }
-
-        doc_comment! {
-            concat!("Raises self to the power of `exp`, using exponentiation by squaring.
 
-# Examples
+            // since exp!=0, finally the exp must be 1.
+            // Deal with the final bit of the exponent separately, since
+            // squaring the base afterwards is not necessary and may cause a
+            // needless overflow.
+            r = acc.overflowing_mul(base);
+            r.1 |= overflown;
 
-Basic usage:
+            r
+        }
 
-```
-", $Feature, "assert_eq!(2", stringify!($SelfT), ".pow(5), 32);", $EndFeature, "
-```"),
+        /// Raises self to the power of `exp`, using exponentiation by squaring.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".pow(5), 32);")]
+        /// ```
         #[stable(feature = "rust1", since = "1.0.0")]
         #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")]
         #[must_use = "this returns the result of the operation, \
@@ -1560,84 +1437,77 @@ pub const fn pow(self, mut exp: u32) -> Self {
             // needless overflow.
             acc * base
         }
-    }
-
-        doc_comment! {
-            concat!("Performs Euclidean division.
-
-Since, for the positive integers, all common
-definitions of division are equal, this
-is exactly equal to `self / rhs`.
-
-# Panics
 
-This function will panic if `rhs` is 0.
-
-# Examples
-
-Basic usage:
-
-```
-assert_eq!(7", stringify!($SelfT), ".div_euclid(4), 1); // or any other integer type
-```"),
-            #[stable(feature = "euclidean_division", since = "1.38.0")]
-            #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
-            #[must_use = "this returns the result of the operation, \
-                          without modifying the original"]
-            #[inline]
-            #[rustc_inherit_overflow_checks]
-            pub const fn div_euclid(self, rhs: Self) -> Self {
-                self / rhs
-            }
+        /// Performs Euclidean division.
+        ///
+        /// Since, for the positive integers, all common
+        /// definitions of division are equal, this
+        /// is exactly equal to `self / rhs`.
+        ///
+        /// # Panics
+        ///
+        /// This function will panic if `rhs` is 0.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("assert_eq!(7", stringify!($SelfT), ".div_euclid(4), 1); // or any other integer type")]
+        /// ```
+        #[stable(feature = "euclidean_division", since = "1.38.0")]
+        #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        #[rustc_inherit_overflow_checks]
+        pub const fn div_euclid(self, rhs: Self) -> Self {
+            self / rhs
         }
 
 
-        doc_comment! {
-            concat!("Calculates the least remainder of `self (mod rhs)`.
-
-Since, for the positive integers, all common
-definitions of division are equal, this
-is exactly equal to `self % rhs`.
-
-# Panics
-
-This function will panic if `rhs` is 0.
-
-# Examples
-
-Basic usage:
-
-```
-assert_eq!(7", stringify!($SelfT), ".rem_euclid(4), 3); // or any other integer type
-```"),
-            #[stable(feature = "euclidean_division", since = "1.38.0")]
-            #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
-            #[must_use = "this returns the result of the operation, \
-                          without modifying the original"]
-            #[inline]
-            #[rustc_inherit_overflow_checks]
-            pub const fn rem_euclid(self, rhs: Self) -> Self {
-                self % rhs
-            }
+        /// Calculates the least remainder of `self (mod rhs)`.
+        ///
+        /// Since, for the positive integers, all common
+        /// definitions of division are equal, this
+        /// is exactly equal to `self % rhs`.
+        ///
+        /// # Panics
+        ///
+        /// This function will panic if `rhs` is 0.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("assert_eq!(7", stringify!($SelfT), ".rem_euclid(4), 3); // or any other integer type")]
+        /// ```
+        #[stable(feature = "euclidean_division", since = "1.38.0")]
+        #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        #[rustc_inherit_overflow_checks]
+        pub const fn rem_euclid(self, rhs: Self) -> Self {
+            self % rhs
         }
 
-        doc_comment! {
-            concat!("Returns `true` if and only if `self == 2^k` for some `k`.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert!(16", stringify!($SelfT), ".is_power_of_two());
-assert!(!10", stringify!($SelfT), ".is_power_of_two());", $EndFeature, "
-```"),
-            #[stable(feature = "rust1", since = "1.0.0")]
-            #[rustc_const_stable(feature = "const_is_power_of_two", since = "1.32.0")]
-            #[inline]
-            pub const fn is_power_of_two(self) -> bool {
-                self.count_ones() == 1
-            }
+        /// Returns `true` if and only if `self == 2^k` for some `k`.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("assert!(16", stringify!($SelfT), ".is_power_of_two());")]
+        #[doc = concat!("assert!(!10", stringify!($SelfT), ".is_power_of_two());")]
+        /// ```
+        #[stable(feature = "rust1", since = "1.0.0")]
+        #[rustc_const_stable(feature = "const_is_power_of_two", since = "1.32.0")]
+        #[inline]
+        pub const fn is_power_of_two(self) -> bool {
+            self.count_ones() == 1
         }
 
         // Returns one less than next power of two.
@@ -1663,332 +1533,302 @@ const fn one_less_than_next_power_of_two(self) -> Self {
             <$SelfT>::MAX >> z
         }
 
-        doc_comment! {
-            concat!("Returns the smallest power of two greater than or equal to `self`.
-
-When return value overflows (i.e., `self > (1 << (N-1))` for type
-`uN`), it panics in debug mode and return value is wrapped to 0 in
-release mode (the only situation in which method can return 0).
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(2", stringify!($SelfT), ".next_power_of_two(), 2);
-assert_eq!(3", stringify!($SelfT), ".next_power_of_two(), 4);", $EndFeature, "
-```"),
-            #[stable(feature = "rust1", since = "1.0.0")]
-            #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")]
-            #[inline]
-            #[rustc_inherit_overflow_checks]
-            pub const fn next_power_of_two(self) -> Self {
-                self.one_less_than_next_power_of_two() + 1
-            }
-        }
-
-        doc_comment! {
-            concat!("Returns the smallest power of two greater than or equal to `n`. If
-the next power of two is greater than the type's maximum value,
-`None` is returned, otherwise the power of two is wrapped in `Some`.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(2", stringify!($SelfT),
-".checked_next_power_of_two(), Some(2));
-assert_eq!(3", stringify!($SelfT), ".checked_next_power_of_two(), Some(4));
-assert_eq!(", stringify!($SelfT), "::MAX.checked_next_power_of_two(), None);",
-$EndFeature, "
-```"),
-            #[inline]
-            #[stable(feature = "rust1", since = "1.0.0")]
-            #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")]
-            pub const fn checked_next_power_of_two(self) -> Option<Self> {
-                self.one_less_than_next_power_of_two().checked_add(1)
-            }
+        /// Returns the smallest power of two greater than or equal to `self`.
+        ///
+        /// When return value overflows (i.e., `self > (1 << (N-1))` for type
+        /// `uN`), it panics in debug mode and return value is wrapped to 0 in
+        /// release mode (the only situation in which method can return 0).
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".next_power_of_two(), 2);")]
+        #[doc = concat!("assert_eq!(3", stringify!($SelfT), ".next_power_of_two(), 4);")]
+        /// ```
+        #[stable(feature = "rust1", since = "1.0.0")]
+        #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")]
+        #[inline]
+        #[rustc_inherit_overflow_checks]
+        pub const fn next_power_of_two(self) -> Self {
+            self.one_less_than_next_power_of_two() + 1
         }
 
-        doc_comment! {
-            concat!("Returns the smallest power of two greater than or equal to `n`. If
-the next power of two is greater than the type's maximum value,
-the return value is wrapped to `0`.
-
-# Examples
-
-Basic usage:
-
-```
-#![feature(wrapping_next_power_of_two)]
-", $Feature, "
-assert_eq!(2", stringify!($SelfT), ".wrapping_next_power_of_two(), 2);
-assert_eq!(3", stringify!($SelfT), ".wrapping_next_power_of_two(), 4);
-assert_eq!(", stringify!($SelfT), "::MAX.wrapping_next_power_of_two(), 0);",
-$EndFeature, "
-```"),
-            #[unstable(feature = "wrapping_next_power_of_two", issue = "32463",
-                       reason = "needs decision on wrapping behaviour")]
-            #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")]
-            pub const fn wrapping_next_power_of_two(self) -> Self {
-                self.one_less_than_next_power_of_two().wrapping_add(1)
-            }
+        /// Returns the smallest power of two greater than or equal to `n`. If
+        /// the next power of two is greater than the type's maximum value,
+        /// `None` is returned, otherwise the power of two is wrapped in `Some`.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".checked_next_power_of_two(), Some(2));")]
+        #[doc = concat!("assert_eq!(3", stringify!($SelfT), ".checked_next_power_of_two(), Some(4));")]
+        #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.checked_next_power_of_two(), None);")]
+        /// ```
+        #[inline]
+        #[stable(feature = "rust1", since = "1.0.0")]
+        #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")]
+        pub const fn checked_next_power_of_two(self) -> Option<Self> {
+            self.one_less_than_next_power_of_two().checked_add(1)
         }
 
-        doc_comment! {
-            concat!("Return the memory representation of this integer as a byte array in
-big-endian (network) byte order.
-",
-$to_xe_bytes_doc,
-"
-# Examples
-
-```
-let bytes = ", $swap_op, stringify!($SelfT), ".to_be_bytes();
-assert_eq!(bytes, ", $be_bytes, ");
-```"),
-            #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
-            #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")]
-            #[inline]
-            pub const fn to_be_bytes(self) -> [u8; mem::size_of::<Self>()] {
-                self.to_be().to_ne_bytes()
-            }
+        /// Returns the smallest power of two greater than or equal to `n`. If
+        /// the next power of two is greater than the type's maximum value,
+        /// the return value is wrapped to `0`.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        /// #![feature(wrapping_next_power_of_two)]
+        ///
+        #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".wrapping_next_power_of_two(), 2);")]
+        #[doc = concat!("assert_eq!(3", stringify!($SelfT), ".wrapping_next_power_of_two(), 4);")]
+        #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.wrapping_next_power_of_two(), 0);")]
+        /// ```
+        #[unstable(feature = "wrapping_next_power_of_two", issue = "32463",
+                   reason = "needs decision on wrapping behaviour")]
+        #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")]
+        pub const fn wrapping_next_power_of_two(self) -> Self {
+            self.one_less_than_next_power_of_two().wrapping_add(1)
         }
 
-        doc_comment! {
-            concat!("Return the memory representation of this integer as a byte array in
-little-endian byte order.
-",
-$to_xe_bytes_doc,
-"
-# Examples
-
-```
-let bytes = ", $swap_op, stringify!($SelfT), ".to_le_bytes();
-assert_eq!(bytes, ", $le_bytes, ");
-```"),
-            #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
-            #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")]
-            #[inline]
-            pub const fn to_le_bytes(self) -> [u8; mem::size_of::<Self>()] {
-                self.to_le().to_ne_bytes()
-            }
+        /// Return the memory representation of this integer as a byte array in
+        /// big-endian (network) byte order.
+        ///
+        #[doc = $to_xe_bytes_doc]
+        ///
+        /// # Examples
+        ///
+        /// ```
+        #[doc = concat!("let bytes = ", $swap_op, stringify!($SelfT), ".to_be_bytes();")]
+        #[doc = concat!("assert_eq!(bytes, ", $be_bytes, ");")]
+        /// ```
+        #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
+        #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")]
+        #[inline]
+        pub const fn to_be_bytes(self) -> [u8; mem::size_of::<Self>()] {
+            self.to_be().to_ne_bytes()
         }
 
-        doc_comment! {
-            concat!("
-Return the memory representation of this integer as a byte array in
-native byte order.
-
-As the target platform's native endianness is used, portable code
-should use [`to_be_bytes`] or [`to_le_bytes`], as appropriate,
-instead.
-",
-$to_xe_bytes_doc,
-"
-[`to_be_bytes`]: #method.to_be_bytes
-[`to_le_bytes`]: #method.to_le_bytes
-
-# Examples
-
-```
-let bytes = ", $swap_op, stringify!($SelfT), ".to_ne_bytes();
-assert_eq!(
-    bytes,
-    if cfg!(target_endian = \"big\") {
-        ", $be_bytes, "
-    } else {
-        ", $le_bytes, "
-    }
-);
-```"),
-            #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
-            #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")]
-            // SAFETY: const sound because integers are plain old datatypes so we can always
-            // transmute them to arrays of bytes
-            #[rustc_allow_const_fn_unstable(const_fn_transmute)]
-            #[inline]
-            pub const fn to_ne_bytes(self) -> [u8; mem::size_of::<Self>()] {
-                // SAFETY: integers are plain old datatypes so we can always transmute them to
-                // arrays of bytes
-                unsafe { mem::transmute(self) }
-            }
+        /// Return the memory representation of this integer as a byte array in
+        /// little-endian byte order.
+        ///
+        #[doc = $to_xe_bytes_doc]
+        ///
+        /// # Examples
+        ///
+        /// ```
+        #[doc = concat!("let bytes = ", $swap_op, stringify!($SelfT), ".to_le_bytes();")]
+        #[doc = concat!("assert_eq!(bytes, ", $le_bytes, ");")]
+        /// ```
+        #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
+        #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")]
+        #[inline]
+        pub const fn to_le_bytes(self) -> [u8; mem::size_of::<Self>()] {
+            self.to_le().to_ne_bytes()
         }
 
-        doc_comment! {
-            concat!("
-Return the memory representation of this integer as a byte array in
-native byte order.
-
-[`to_ne_bytes`] should be preferred over this whenever possible.
-
-[`to_ne_bytes`]: #method.to_ne_bytes
-",
-
-"
-# Examples
-
-```
-#![feature(num_as_ne_bytes)]
-let num = ", $swap_op, stringify!($SelfT), ";
-let bytes = num.as_ne_bytes();
-assert_eq!(
-    bytes,
-    if cfg!(target_endian = \"big\") {
-        &", $be_bytes, "
-    } else {
-        &", $le_bytes, "
-    }
-);
-```"),
-            #[unstable(feature = "num_as_ne_bytes", issue = "76976")]
-            #[inline]
-            pub fn as_ne_bytes(&self) -> &[u8; mem::size_of::<Self>()] {
-                // SAFETY: integers are plain old datatypes so we can always transmute them to
-                // arrays of bytes
-                unsafe { &*(self as *const Self as *const _) }
-            }
+        /// Return the memory representation of this integer as a byte array in
+        /// native byte order.
+        ///
+        /// As the target platform's native endianness is used, portable code
+        /// should use [`to_be_bytes`] or [`to_le_bytes`], as appropriate,
+        /// instead.
+        ///
+        #[doc = $to_xe_bytes_doc]
+        ///
+        /// [`to_be_bytes`]: #method.to_be_bytes
+        /// [`to_le_bytes`]: #method.to_le_bytes
+        ///
+        /// # Examples
+        ///
+        /// ```
+        #[doc = concat!("let bytes = ", $swap_op, stringify!($SelfT), ".to_ne_bytes();")]
+        /// assert_eq!(
+        ///     bytes,
+        ///     if cfg!(target_endian = "big") {
+        #[doc = concat!("        ", $be_bytes)]
+        ///     } else {
+        #[doc = concat!("        ", $le_bytes)]
+        ///     }
+        /// );
+        /// ```
+        #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
+        #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")]
+        // SAFETY: const sound because integers are plain old datatypes so we can always
+        // transmute them to arrays of bytes
+        #[rustc_allow_const_fn_unstable(const_fn_transmute)]
+        #[inline]
+        pub const fn to_ne_bytes(self) -> [u8; mem::size_of::<Self>()] {
+            // SAFETY: integers are plain old datatypes so we can always transmute them to
+            // arrays of bytes
+            unsafe { mem::transmute(self) }
         }
 
-        doc_comment! {
-            concat!("Create a native endian integer value from its representation
-as a byte array in big endian.
-",
-$from_xe_bytes_doc,
-"
-# Examples
-
-```
-let value = ", stringify!($SelfT), "::from_be_bytes(", $be_bytes, ");
-assert_eq!(value, ", $swap_op, ");
-```
-
-When starting from a slice rather than an array, fallible conversion APIs can be used:
-
-```
-use std::convert::TryInto;
-
-fn read_be_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " {
-    let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">());
-    *input = rest;
-    ", stringify!($SelfT), "::from_be_bytes(int_bytes.try_into().unwrap())
-}
-```"),
-            #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
-            #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")]
-            #[inline]
-            pub const fn from_be_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
-                Self::from_be(Self::from_ne_bytes(bytes))
-            }
+        /// Return the memory representation of this integer as a byte array in
+        /// native byte order.
+        ///
+        /// [`to_ne_bytes`] should be preferred over this whenever possible.
+        ///
+        /// [`to_ne_bytes`]: #method.to_ne_bytes
+        ///
+        /// # Examples
+        ///
+        /// ```
+        /// #![feature(num_as_ne_bytes)]
+        #[doc = concat!("let num = ", $swap_op, stringify!($SelfT), ";")]
+        /// let bytes = num.as_ne_bytes();
+        /// assert_eq!(
+        ///     bytes,
+        ///     if cfg!(target_endian = "big") {
+        #[doc = concat!("        &", $be_bytes)]
+        ///     } else {
+        #[doc = concat!("        &", $le_bytes)]
+        ///     }
+        /// );
+        /// ```
+        #[unstable(feature = "num_as_ne_bytes", issue = "76976")]
+        #[inline]
+        pub fn as_ne_bytes(&self) -> &[u8; mem::size_of::<Self>()] {
+            // SAFETY: integers are plain old datatypes so we can always transmute them to
+            // arrays of bytes
+            unsafe { &*(self as *const Self as *const _) }
         }
 
-        doc_comment! {
-            concat!("
-Create a native endian integer value from its representation
-as a byte array in little endian.
-",
-$from_xe_bytes_doc,
-"
-# Examples
-
-```
-let value = ", stringify!($SelfT), "::from_le_bytes(", $le_bytes, ");
-assert_eq!(value, ", $swap_op, ");
-```
-
-When starting from a slice rather than an array, fallible conversion APIs can be used:
-
-```
-use std::convert::TryInto;
-
-fn read_le_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " {
-    let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">());
-    *input = rest;
-    ", stringify!($SelfT), "::from_le_bytes(int_bytes.try_into().unwrap())
-}
-```"),
-            #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
-            #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")]
-            #[inline]
-            pub const fn from_le_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
-                Self::from_le(Self::from_ne_bytes(bytes))
-            }
+        /// Create a native endian integer value from its representation
+        /// as a byte array in big endian.
+        ///
+        #[doc = $from_xe_bytes_doc]
+        ///
+        /// # Examples
+        ///
+        /// ```
+        #[doc = concat!("let value = ", stringify!($SelfT), "::from_be_bytes(", $be_bytes, ");")]
+        #[doc = concat!("assert_eq!(value, ", $swap_op, ");")]
+        /// ```
+        ///
+        /// When starting from a slice rather than an array, fallible conversion APIs can be used:
+        ///
+        /// ```
+        /// use std::convert::TryInto;
+        ///
+        #[doc = concat!("fn read_be_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " {")]
+        #[doc = concat!("    let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">());")]
+        ///     *input = rest;
+        #[doc = concat!("    ", stringify!($SelfT), "::from_be_bytes(int_bytes.try_into().unwrap())")]
+        /// }
+        /// ```
+        #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
+        #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")]
+        #[inline]
+        pub const fn from_be_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
+            Self::from_be(Self::from_ne_bytes(bytes))
         }
 
-        doc_comment! {
-            concat!("Create a native endian integer value from its memory representation
-as a byte array in native endianness.
-
-As the target platform's native endianness is used, portable code
-likely wants to use [`from_be_bytes`] or [`from_le_bytes`], as
-appropriate instead.
-
-[`from_be_bytes`]: #method.from_be_bytes
-[`from_le_bytes`]: #method.from_le_bytes
-",
-$from_xe_bytes_doc,
-"
-# Examples
-
-```
-let value = ", stringify!($SelfT), "::from_ne_bytes(if cfg!(target_endian = \"big\") {
-    ", $be_bytes, "
-} else {
-    ", $le_bytes, "
-});
-assert_eq!(value, ", $swap_op, ");
-```
-
-When starting from a slice rather than an array, fallible conversion APIs can be used:
-
-```
-use std::convert::TryInto;
-
-fn read_ne_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " {
-    let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">());
-    *input = rest;
-    ", stringify!($SelfT), "::from_ne_bytes(int_bytes.try_into().unwrap())
-}
-```"),
-            #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
-            #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")]
-            // SAFETY: const sound because integers are plain old datatypes so we can always
-            // transmute to them
-            #[rustc_allow_const_fn_unstable(const_fn_transmute)]
-            #[inline]
-            pub const fn from_ne_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
-                // SAFETY: integers are plain old datatypes so we can always transmute to them
-                unsafe { mem::transmute(bytes) }
-            }
+        /// Create a native endian integer value from its representation
+        /// as a byte array in little endian.
+        ///
+        #[doc = $from_xe_bytes_doc]
+        ///
+        /// # Examples
+        ///
+        /// ```
+        #[doc = concat!("let value = ", stringify!($SelfT), "::from_le_bytes(", $le_bytes, ");")]
+        #[doc = concat!("assert_eq!(value, ", $swap_op, ");")]
+        /// ```
+        ///
+        /// When starting from a slice rather than an array, fallible conversion APIs can be used:
+        ///
+        /// ```
+        /// use std::convert::TryInto;
+        ///
+        #[doc = concat!("fn read_le_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " {")]
+        #[doc = concat!("    let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">());")]
+        ///     *input = rest;
+        #[doc = concat!("    ", stringify!($SelfT), "::from_le_bytes(int_bytes.try_into().unwrap())")]
+        /// }
+        /// ```
+        #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
+        #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")]
+        #[inline]
+        pub const fn from_le_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
+            Self::from_le(Self::from_ne_bytes(bytes))
         }
 
-        doc_comment! {
-            concat!("**This method is soft-deprecated.**
-
-Although using it won’t cause compilation warning,
-new code should use [`", stringify!($SelfT), "::MIN", "`](#associatedconstant.MIN) instead.
-
-Returns the smallest value that can be represented by this integer type."),
-            #[stable(feature = "rust1", since = "1.0.0")]
-            #[rustc_promotable]
-            #[inline(always)]
-            #[rustc_const_stable(feature = "const_max_value", since = "1.32.0")]
-            pub const fn min_value() -> Self { Self::MIN }
+        /// Create a native endian integer value from its memory representation
+        /// as a byte array in native endianness.
+        ///
+        /// As the target platform's native endianness is used, portable code
+        /// likely wants to use [`from_be_bytes`] or [`from_le_bytes`], as
+        /// appropriate instead.
+        ///
+        /// [`from_be_bytes`]: #method.from_be_bytes
+        /// [`from_le_bytes`]: #method.from_le_bytes
+        ///
+        #[doc = $from_xe_bytes_doc]
+        ///
+        /// # Examples
+        ///
+        /// ```
+        #[doc = concat!("let value = ", stringify!($SelfT), "::from_ne_bytes(if cfg!(target_endian = \"big\") {")]
+        #[doc = concat!("    ", $be_bytes, "")]
+        /// } else {
+        #[doc = concat!("    ", $le_bytes, "")]
+        /// });
+        #[doc = concat!("assert_eq!(value, ", $swap_op, ");")]
+        /// ```
+        ///
+        /// When starting from a slice rather than an array, fallible conversion APIs can be used:
+        ///
+        /// ```
+        /// use std::convert::TryInto;
+        ///
+        #[doc = concat!("fn read_ne_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " {")]
+        #[doc = concat!("    let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">());")]
+        ///     *input = rest;
+        #[doc = concat!("    ", stringify!($SelfT), "::from_ne_bytes(int_bytes.try_into().unwrap())")]
+        /// }
+        /// ```
+        #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
+        #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")]
+        // SAFETY: const sound because integers are plain old datatypes so we can always
+        // transmute to them
+        #[rustc_allow_const_fn_unstable(const_fn_transmute)]
+        #[inline]
+        pub const fn from_ne_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
+            // SAFETY: integers are plain old datatypes so we can always transmute to them
+            unsafe { mem::transmute(bytes) }
         }
 
-        doc_comment! {
-            concat!("**This method is soft-deprecated.**
-
-Although using it won’t cause compilation warning,
-new code should use [`", stringify!($SelfT), "::MAX", "`](#associatedconstant.MAX) instead.
+        /// **This method is soft-deprecated.**
+        ///
+        /// Although using it won’t cause compilation warning, new code should use
+        #[doc = concat!("[`", stringify!($SelfT), "::MIN", "`](#associatedconstant.MIN)")]
+        /// instead.
+        ///
+        /// Returns the smallest value that can be represented by this integer type.
+        #[stable(feature = "rust1", since = "1.0.0")]
+        #[rustc_promotable]
+        #[inline(always)]
+        #[rustc_const_stable(feature = "const_max_value", since = "1.32.0")]
+        pub const fn min_value() -> Self { Self::MIN }
 
-Returns the largest value that can be represented by this integer type."),
-            #[stable(feature = "rust1", since = "1.0.0")]
-            #[rustc_promotable]
-            #[inline(always)]
-            #[rustc_const_stable(feature = "const_max_value", since = "1.32.0")]
-            pub const fn max_value() -> Self { Self::MAX }
-        }
+        /// **This method is soft-deprecated.**
+        ///
+        /// Although using it won’t cause compilation warning, new code should use
+        #[doc = concat!("[`", stringify!($SelfT), "::MAX", "`](#associatedconstant.MAX)")]
+        /// instead.
+        ///
+        /// Returns the largest value that can be represented by this integer type.
+        #[stable(feature = "rust1", since = "1.0.0")]
+        #[rustc_promotable]
+        #[inline(always)]
+        #[rustc_const_stable(feature = "const_max_value", since = "1.32.0")]
+        pub const fn max_value() -> Self { Self::MAX }
     }
 }
index 77c9a93008c91c3e28354639532b111c1ba09e6e..f1b9dabe7d6b769bc8fb3d746eeccca150cd01fb 100644 (file)
@@ -403,105 +403,94 @@ fn neg(self) -> Self {
 macro_rules! wrapping_int_impl {
     ($($t:ty)*) => ($(
         impl Wrapping<$t> {
-            doc_comment! {
-                concat!("Returns the smallest value that can be represented by this integer type.
-
-# Examples
-
-Basic usage:
-
-```
-#![feature(wrapping_int_impl)]
-use std::num::Wrapping;
-
-assert_eq!(<Wrapping<", stringify!($t), ">>::MIN, Wrapping(", stringify!($t), "::MIN));
-```"),
-                #[unstable(feature = "wrapping_int_impl", issue = "32463")]
-                pub const MIN: Self = Self(<$t>::MIN);
-            }
-
-            doc_comment! {
-                concat!("Returns the largest value that can be represented by this integer type.
-
-# Examples
-
-Basic usage:
-
-```
-#![feature(wrapping_int_impl)]
-use std::num::Wrapping;
-
-assert_eq!(<Wrapping<", stringify!($t), ">>::MAX, Wrapping(", stringify!($t), "::MAX));
-```"),
-                #[unstable(feature = "wrapping_int_impl", issue = "32463")]
-                pub const MAX: Self = Self(<$t>::MAX);
-            }
-
-            doc_comment! {
-                concat!("Returns the number of ones in the binary representation of `self`.
-
-# Examples
-
-Basic usage:
-
-```
-#![feature(wrapping_int_impl)]
-use std::num::Wrapping;
+            /// Returns the smallest value that can be represented by this integer type.
+            ///
+            /// # Examples
+            ///
+            /// Basic usage:
+            ///
+            /// ```
+            /// #![feature(wrapping_int_impl)]
+            /// use std::num::Wrapping;
+            ///
+            #[doc = concat!("assert_eq!(<Wrapping<", stringify!($t), ">>::MIN, Wrapping(", stringify!($t), "::MIN));")]
+            /// ```
+            #[unstable(feature = "wrapping_int_impl", issue = "32463")]
+            pub const MIN: Self = Self(<$t>::MIN);
 
-let n = Wrapping(0b01001100", stringify!($t), ");
+            /// Returns the largest value that can be represented by this integer type.
+            ///
+            /// # Examples
+            ///
+            /// Basic usage:
+            ///
+            /// ```
+            /// #![feature(wrapping_int_impl)]
+            /// use std::num::Wrapping;
+            ///
+            #[doc = concat!("assert_eq!(<Wrapping<", stringify!($t), ">>::MAX, Wrapping(", stringify!($t), "::MAX));")]
+            /// ```
+            #[unstable(feature = "wrapping_int_impl", issue = "32463")]
+            pub const MAX: Self = Self(<$t>::MAX);
 
-assert_eq!(n.count_ones(), 3);
-```"),
-                #[inline]
-                #[doc(alias = "popcount")]
-                #[doc(alias = "popcnt")]
-                #[unstable(feature = "wrapping_int_impl", issue = "32463")]
-                pub const fn count_ones(self) -> u32 {
-                    self.0.count_ones()
-                }
+            /// Returns the number of ones in the binary representation of `self`.
+            ///
+            /// # Examples
+            ///
+            /// Basic usage:
+            ///
+            /// ```
+            /// #![feature(wrapping_int_impl)]
+            /// use std::num::Wrapping;
+            ///
+            #[doc = concat!("let n = Wrapping(0b01001100", stringify!($t), ");")]
+            ///
+            /// assert_eq!(n.count_ones(), 3);
+            /// ```
+            #[inline]
+            #[doc(alias = "popcount")]
+            #[doc(alias = "popcnt")]
+            #[unstable(feature = "wrapping_int_impl", issue = "32463")]
+            pub const fn count_ones(self) -> u32 {
+                self.0.count_ones()
             }
 
-            doc_comment! {
-                concat!("Returns the number of zeros in the binary representation of `self`.
-
-# Examples
-
-Basic usage:
-
-```
-#![feature(wrapping_int_impl)]
-use std::num::Wrapping;
-
-assert_eq!(Wrapping(!0", stringify!($t), ").count_zeros(), 0);
-```"),
-                #[inline]
-                #[unstable(feature = "wrapping_int_impl", issue = "32463")]
-                pub const fn count_zeros(self) -> u32 {
-                    self.0.count_zeros()
-                }
+            /// Returns the number of zeros in the binary representation of `self`.
+            ///
+            /// # Examples
+            ///
+            /// Basic usage:
+            ///
+            /// ```
+            /// #![feature(wrapping_int_impl)]
+            /// use std::num::Wrapping;
+            ///
+            #[doc = concat!("assert_eq!(Wrapping(!0", stringify!($t), ").count_zeros(), 0);")]
+            /// ```
+            #[inline]
+            #[unstable(feature = "wrapping_int_impl", issue = "32463")]
+            pub const fn count_zeros(self) -> u32 {
+                self.0.count_zeros()
             }
 
-            doc_comment! {
-                concat!("Returns the number of trailing zeros in the binary representation
-of `self`.
-
-# Examples
-
-Basic usage:
-
-```
-#![feature(wrapping_int_impl)]
-use std::num::Wrapping;
-
-let n = Wrapping(0b0101000", stringify!($t), ");
-
-assert_eq!(n.trailing_zeros(), 3);
-```"),
-                #[inline]
-                #[unstable(feature = "wrapping_int_impl", issue = "32463")]
-                pub const fn trailing_zeros(self) -> u32 {
-                    self.0.trailing_zeros()
-                }
+            /// Returns the number of trailing zeros in the binary representation of `self`.
+            ///
+            /// # Examples
+            ///
+            /// Basic usage:
+            ///
+            /// ```
+            /// #![feature(wrapping_int_impl)]
+            /// use std::num::Wrapping;
+            ///
+            #[doc = concat!("let n = Wrapping(0b0101000", stringify!($t), ");")]
+            ///
+            /// assert_eq!(n.trailing_zeros(), 3);
+            /// ```
+            #[inline]
+            #[unstable(feature = "wrapping_int_impl", issue = "32463")]
+            pub const fn trailing_zeros(self) -> u32 {
+                self.0.trailing_zeros()
             }
 
             /// Shifts the bits to the left by a specified amount, `n`,
@@ -608,150 +597,140 @@ pub const fn reverse_bits(self) -> Self {
                 Wrapping(self.0.reverse_bits())
             }
 
-            doc_comment! {
-                concat!("Converts an integer from big endian to the target's endianness.
-
-On big endian this is a no-op. On little endian the bytes are
-swapped.
-
-# Examples
-
-Basic usage:
-
-```
-#![feature(wrapping_int_impl)]
-use std::num::Wrapping;
-
-let n = Wrapping(0x1A", stringify!($t), ");
-
-if cfg!(target_endian = \"big\") {
-    assert_eq!(<Wrapping<", stringify!($t), ">>::from_be(n), n)
-} else {
-    assert_eq!(<Wrapping<", stringify!($t), ">>::from_be(n), n.swap_bytes())
-}
-```"),
-                #[inline]
-                #[unstable(feature = "wrapping_int_impl", issue = "32463")]
-                pub const fn from_be(x: Self) -> Self {
-                    Wrapping(<$t>::from_be(x.0))
-                }
+            /// Converts an integer from big endian to the target's endianness.
+            ///
+            /// On big endian this is a no-op. On little endian the bytes are
+            /// swapped.
+            ///
+            /// # Examples
+            ///
+            /// Basic usage:
+            ///
+            /// ```
+            /// #![feature(wrapping_int_impl)]
+            /// use std::num::Wrapping;
+            ///
+            #[doc = concat!("let n = Wrapping(0x1A", stringify!($t), ");")]
+            ///
+            /// if cfg!(target_endian = "big") {
+            #[doc = concat!("    assert_eq!(<Wrapping<", stringify!($t), ">>::from_be(n), n)")]
+            /// } else {
+            #[doc = concat!("    assert_eq!(<Wrapping<", stringify!($t), ">>::from_be(n), n.swap_bytes())")]
+            /// }
+            /// ```
+            #[inline]
+            #[unstable(feature = "wrapping_int_impl", issue = "32463")]
+            pub const fn from_be(x: Self) -> Self {
+                Wrapping(<$t>::from_be(x.0))
             }
 
-            doc_comment! {
-                concat!("Converts an integer from little endian to the target's endianness.
-
-On little endian this is a no-op. On big endian the bytes are
-swapped.
-
-# Examples
-
-Basic usage:
-
-```
-#![feature(wrapping_int_impl)]
-use std::num::Wrapping;
-
-let n = Wrapping(0x1A", stringify!($t), ");
-
-if cfg!(target_endian = \"little\") {
-    assert_eq!(<Wrapping<", stringify!($t), ">>::from_le(n), n)
-} else {
-    assert_eq!(<Wrapping<", stringify!($t), ">>::from_le(n), n.swap_bytes())
-}
-```"),
-                #[inline]
-                #[unstable(feature = "wrapping_int_impl", issue = "32463")]
-                pub const fn from_le(x: Self) -> Self {
-                    Wrapping(<$t>::from_le(x.0))
-                }
+            /// Converts an integer from little endian to the target's endianness.
+            ///
+            /// On little endian this is a no-op. On big endian the bytes are
+            /// swapped.
+            ///
+            /// # Examples
+            ///
+            /// Basic usage:
+            ///
+            /// ```
+            /// #![feature(wrapping_int_impl)]
+            /// use std::num::Wrapping;
+            ///
+            #[doc = concat!("let n = Wrapping(0x1A", stringify!($t), ");")]
+            ///
+            /// if cfg!(target_endian = "little") {
+            #[doc = concat!("    assert_eq!(<Wrapping<", stringify!($t), ">>::from_le(n), n)")]
+            /// } else {
+            #[doc = concat!("    assert_eq!(<Wrapping<", stringify!($t), ">>::from_le(n), n.swap_bytes())")]
+            /// }
+            /// ```
+            #[inline]
+            #[unstable(feature = "wrapping_int_impl", issue = "32463")]
+            pub const fn from_le(x: Self) -> Self {
+                Wrapping(<$t>::from_le(x.0))
             }
 
-            doc_comment! {
-                concat!("Converts `self` to big endian from the target's endianness.
-
-On big endian this is a no-op. On little endian the bytes are
-swapped.
-
-# Examples
-
-Basic usage:
-
-```
-#![feature(wrapping_int_impl)]
-use std::num::Wrapping;
-
-let n = Wrapping(0x1A", stringify!($t), ");
-
-if cfg!(target_endian = \"big\") {
-    assert_eq!(n.to_be(), n)
-} else {
-    assert_eq!(n.to_be(), n.swap_bytes())
-}
-```"),
-                #[inline]
-                #[unstable(feature = "wrapping_int_impl", issue = "32463")]
-                pub const fn to_be(self) -> Self {
-                    Wrapping(self.0.to_be())
-                }
+            /// Converts `self` to big endian from the target's endianness.
+            ///
+            /// On big endian this is a no-op. On little endian the bytes are
+            /// swapped.
+            ///
+            /// # Examples
+            ///
+            /// Basic usage:
+            ///
+            /// ```
+            /// #![feature(wrapping_int_impl)]
+            /// use std::num::Wrapping;
+            ///
+            #[doc = concat!("let n = Wrapping(0x1A", stringify!($t), ");")]
+            ///
+            /// if cfg!(target_endian = "big") {
+            ///     assert_eq!(n.to_be(), n)
+            /// } else {
+            ///     assert_eq!(n.to_be(), n.swap_bytes())
+            /// }
+            /// ```
+            #[inline]
+            #[unstable(feature = "wrapping_int_impl", issue = "32463")]
+            pub const fn to_be(self) -> Self {
+                Wrapping(self.0.to_be())
             }
 
-            doc_comment! {
-                concat!("Converts `self` to little endian from the target's endianness.
-
-On little endian this is a no-op. On big endian the bytes are
-swapped.
-
-# Examples
-
-Basic usage:
-
-```
-#![feature(wrapping_int_impl)]
-use std::num::Wrapping;
-
-let n = Wrapping(0x1A", stringify!($t), ");
-
-if cfg!(target_endian = \"little\") {
-    assert_eq!(n.to_le(), n)
-} else {
-    assert_eq!(n.to_le(), n.swap_bytes())
-}
-```"),
-                #[inline]
-                #[unstable(feature = "wrapping_int_impl", issue = "32463")]
-                pub const fn to_le(self) -> Self {
-                    Wrapping(self.0.to_le())
-                }
+            /// Converts `self` to little endian from the target's endianness.
+            ///
+            /// On little endian this is a no-op. On big endian the bytes are
+            /// swapped.
+            ///
+            /// # Examples
+            ///
+            /// Basic usage:
+            ///
+            /// ```
+            /// #![feature(wrapping_int_impl)]
+            /// use std::num::Wrapping;
+            ///
+            #[doc = concat!("let n = Wrapping(0x1A", stringify!($t), ");")]
+            ///
+            /// if cfg!(target_endian = "little") {
+            ///     assert_eq!(n.to_le(), n)
+            /// } else {
+            ///     assert_eq!(n.to_le(), n.swap_bytes())
+            /// }
+            /// ```
+            #[inline]
+            #[unstable(feature = "wrapping_int_impl", issue = "32463")]
+            pub const fn to_le(self) -> Self {
+                Wrapping(self.0.to_le())
             }
 
-        doc_comment! {
-            concat!("Raises self to the power of `exp`, using exponentiation by squaring.
-
-# Examples
-
-Basic usage:
-
-```
-#![feature(wrapping_int_impl)]
-use std::num::Wrapping;
-
-assert_eq!(Wrapping(3", stringify!($t), ").pow(4), Wrapping(81));
-```
-
-Results that are too large are wrapped:
-
-```
-#![feature(wrapping_int_impl)]
-use std::num::Wrapping;
-
-assert_eq!(Wrapping(3i8).pow(5), Wrapping(-13));
-assert_eq!(Wrapping(3i8).pow(6), Wrapping(-39));
-```"),
-                #[inline]
-                #[unstable(feature = "wrapping_int_impl", issue = "32463")]
-                pub fn pow(self, exp: u32) -> Self {
-                    Wrapping(self.0.wrapping_pow(exp))
-                }
+            /// Raises self to the power of `exp`, using exponentiation by squaring.
+            ///
+            /// # Examples
+            ///
+            /// Basic usage:
+            ///
+            /// ```
+            /// #![feature(wrapping_int_impl)]
+            /// use std::num::Wrapping;
+            ///
+            #[doc = concat!("assert_eq!(Wrapping(3", stringify!($t), ").pow(4), Wrapping(81));")]
+            /// ```
+            ///
+            /// Results that are too large are wrapped:
+            ///
+            /// ```
+            /// #![feature(wrapping_int_impl)]
+            /// use std::num::Wrapping;
+            ///
+            /// assert_eq!(Wrapping(3i8).pow(5), Wrapping(-13));
+            /// assert_eq!(Wrapping(3i8).pow(6), Wrapping(-39));
+            /// ```
+            #[inline]
+            #[unstable(feature = "wrapping_int_impl", issue = "32463")]
+            pub fn pow(self, exp: u32) -> Self {
+                Wrapping(self.0.wrapping_pow(exp))
             }
         }
     )*)
@@ -762,124 +741,114 @@ pub fn pow(self, exp: u32) -> Self {
 macro_rules! wrapping_int_impl_signed {
     ($($t:ty)*) => ($(
         impl Wrapping<$t> {
-            doc_comment! {
-                concat!("Returns the number of leading zeros in the binary representation of `self`.
-
-# Examples
-
-Basic usage:
-
-```
-#![feature(wrapping_int_impl)]
-use std::num::Wrapping;
-
-let n = Wrapping(", stringify!($t), "::MAX) >> 2;
-
-assert_eq!(n.leading_zeros(), 3);
-```"),
-                #[inline]
-                #[unstable(feature = "wrapping_int_impl", issue = "32463")]
-                pub const fn leading_zeros(self) -> u32 {
-                    self.0.leading_zeros()
-                }
+            /// Returns the number of leading zeros in the binary representation of `self`.
+            ///
+            /// # Examples
+            ///
+            /// Basic usage:
+            ///
+            /// ```
+            /// #![feature(wrapping_int_impl)]
+            /// use std::num::Wrapping;
+            ///
+            #[doc = concat!("let n = Wrapping(", stringify!($t), "::MAX) >> 2;")]
+            ///
+            /// assert_eq!(n.leading_zeros(), 3);
+            /// ```
+            #[inline]
+            #[unstable(feature = "wrapping_int_impl", issue = "32463")]
+            pub const fn leading_zeros(self) -> u32 {
+                self.0.leading_zeros()
             }
 
-            doc_comment! {
-                concat!("Computes the absolute value of `self`, wrapping around at
-the boundary of the type.
-
-The only case where such wrapping can occur is when one takes the absolute value of the negative
-minimal value for the type this is a positive value that is too large to represent in the type. In
-such a case, this function returns `MIN` itself.
-
-# Examples
-
-Basic usage:
-
-```
-#![feature(wrapping_int_impl)]
-use std::num::Wrapping;
-
-assert_eq!(Wrapping(100", stringify!($t), ").abs(), Wrapping(100));
-assert_eq!(Wrapping(-100", stringify!($t), ").abs(), Wrapping(100));
-assert_eq!(Wrapping(", stringify!($t), "::MIN).abs(), Wrapping(", stringify!($t), "::MIN));
-assert_eq!(Wrapping(-128i8).abs().0 as u8, 128u8);
-```"),
-                #[inline]
-                #[unstable(feature = "wrapping_int_impl", issue = "32463")]
-                pub fn abs(self) -> Wrapping<$t> {
-                    Wrapping(self.0.wrapping_abs())
-                }
+            /// Computes the absolute value of `self`, wrapping around at
+            /// the boundary of the type.
+            ///
+            /// The only case where such wrapping can occur is when one takes the absolute value of the negative
+            /// minimal value for the type this is a positive value that is too large to represent in the type. In
+            /// such a case, this function returns `MIN` itself.
+            ///
+            /// # Examples
+            ///
+            /// Basic usage:
+            ///
+            /// ```
+            /// #![feature(wrapping_int_impl)]
+            /// use std::num::Wrapping;
+            ///
+            #[doc = concat!("assert_eq!(Wrapping(100", stringify!($t), ").abs(), Wrapping(100));")]
+            #[doc = concat!("assert_eq!(Wrapping(-100", stringify!($t), ").abs(), Wrapping(100));")]
+            #[doc = concat!("assert_eq!(Wrapping(", stringify!($t), "::MIN).abs(), Wrapping(", stringify!($t), "::MIN));")]
+            /// assert_eq!(Wrapping(-128i8).abs().0 as u8, 128u8);
+            /// ```
+            #[inline]
+            #[unstable(feature = "wrapping_int_impl", issue = "32463")]
+            pub fn abs(self) -> Wrapping<$t> {
+                Wrapping(self.0.wrapping_abs())
             }
 
-            doc_comment! {
-                concat!("Returns a number representing sign of `self`.
-
- - `0` if the number is zero
- - `1` if the number is positive
- - `-1` if the number is negative
-
-# Examples
-
-Basic usage:
-
-```
-#![feature(wrapping_int_impl)]
-use std::num::Wrapping;
-
-assert_eq!(Wrapping(10", stringify!($t), ").signum(), Wrapping(1));
-assert_eq!(Wrapping(0", stringify!($t), ").signum(), Wrapping(0));
-assert_eq!(Wrapping(-10", stringify!($t), ").signum(), Wrapping(-1));
-```"),
-                #[inline]
-                #[unstable(feature = "wrapping_int_impl", issue = "32463")]
-                pub fn signum(self) -> Wrapping<$t> {
-                    Wrapping(self.0.signum())
-                }
+            /// Returns a number representing sign of `self`.
+            ///
+            ///  - `0` if the number is zero
+            ///  - `1` if the number is positive
+            ///  - `-1` if the number is negative
+            ///
+            /// # Examples
+            ///
+            /// Basic usage:
+            ///
+            /// ```
+            /// #![feature(wrapping_int_impl)]
+            /// use std::num::Wrapping;
+            ///
+            #[doc = concat!("assert_eq!(Wrapping(10", stringify!($t), ").signum(), Wrapping(1));")]
+            #[doc = concat!("assert_eq!(Wrapping(0", stringify!($t), ").signum(), Wrapping(0));")]
+            #[doc = concat!("assert_eq!(Wrapping(-10", stringify!($t), ").signum(), Wrapping(-1));")]
+            /// ```
+            #[inline]
+            #[unstable(feature = "wrapping_int_impl", issue = "32463")]
+            pub fn signum(self) -> Wrapping<$t> {
+                Wrapping(self.0.signum())
             }
 
-            doc_comment! {
-                concat!("Returns `true` if `self` is positive and `false` if the number is zero or
-negative.
-
-# Examples
-
-Basic usage:
-
-```
-#![feature(wrapping_int_impl)]
-use std::num::Wrapping;
-
-assert!(Wrapping(10", stringify!($t), ").is_positive());
-assert!(!Wrapping(-10", stringify!($t), ").is_positive());
-```"),
-                #[inline]
-                #[unstable(feature = "wrapping_int_impl", issue = "32463")]
-                pub const fn is_positive(self) -> bool {
-                    self.0.is_positive()
-                }
+            /// Returns `true` if `self` is positive and `false` if the number is zero or
+            /// negative.
+            ///
+            /// # Examples
+            ///
+            /// Basic usage:
+            ///
+            /// ```
+            /// #![feature(wrapping_int_impl)]
+            /// use std::num::Wrapping;
+            ///
+            #[doc = concat!("assert!(Wrapping(10", stringify!($t), ").is_positive());")]
+            #[doc = concat!("assert!(!Wrapping(-10", stringify!($t), ").is_positive());")]
+            /// ```
+            #[inline]
+            #[unstable(feature = "wrapping_int_impl", issue = "32463")]
+            pub const fn is_positive(self) -> bool {
+                self.0.is_positive()
             }
 
-            doc_comment! {
-                concat!("Returns `true` if `self` is negative and `false` if the number is zero or
-positive.
-
-# Examples
-
-Basic usage:
-
-```
-#![feature(wrapping_int_impl)]
-use std::num::Wrapping;
-
-assert!(Wrapping(-10", stringify!($t), ").is_negative());
-assert!(!Wrapping(10", stringify!($t), ").is_negative());
-```"),
-                #[inline]
-                #[unstable(feature = "wrapping_int_impl", issue = "32463")]
-                pub const fn is_negative(self) -> bool {
-                    self.0.is_negative()
-                }
+            /// Returns `true` if `self` is negative and `false` if the number is zero or
+            /// positive.
+            ///
+            /// # Examples
+            ///
+            /// Basic usage:
+            ///
+            /// ```
+            /// #![feature(wrapping_int_impl)]
+            /// use std::num::Wrapping;
+            ///
+            #[doc = concat!("assert!(Wrapping(-10", stringify!($t), ").is_negative());")]
+            #[doc = concat!("assert!(!Wrapping(10", stringify!($t), ").is_negative());")]
+            /// ```
+            #[inline]
+            #[unstable(feature = "wrapping_int_impl", issue = "32463")]
+            pub const fn is_negative(self) -> bool {
+                self.0.is_negative()
             }
         }
     )*)
@@ -890,73 +859,67 @@ pub const fn is_negative(self) -> bool {
 macro_rules! wrapping_int_impl_unsigned {
     ($($t:ty)*) => ($(
         impl Wrapping<$t> {
-            doc_comment! {
-                concat!("Returns the number of leading zeros in the binary representation of `self`.
-
-# Examples
-
-Basic usage:
-
-```
-#![feature(wrapping_int_impl)]
-use std::num::Wrapping;
-
-let n = Wrapping(", stringify!($t), "::MAX) >> 2;
-
-assert_eq!(n.leading_zeros(), 2);
-```"),
-                #[inline]
-                #[unstable(feature = "wrapping_int_impl", issue = "32463")]
-                pub const fn leading_zeros(self) -> u32 {
-                    self.0.leading_zeros()
-                }
+            /// Returns the number of leading zeros in the binary representation of `self`.
+            ///
+            /// # Examples
+            ///
+            /// Basic usage:
+            ///
+            /// ```
+            /// #![feature(wrapping_int_impl)]
+            /// use std::num::Wrapping;
+            ///
+            #[doc = concat!("let n = Wrapping(", stringify!($t), "::MAX) >> 2;")]
+            ///
+            /// assert_eq!(n.leading_zeros(), 2);
+            /// ```
+            #[inline]
+            #[unstable(feature = "wrapping_int_impl", issue = "32463")]
+            pub const fn leading_zeros(self) -> u32 {
+                self.0.leading_zeros()
             }
 
-            doc_comment! {
-                concat!("Returns `true` if and only if `self == 2^k` for some `k`.
-
-# Examples
-
-Basic usage:
-
-```
-#![feature(wrapping_int_impl)]
-use std::num::Wrapping;
-
-assert!(Wrapping(16", stringify!($t), ").is_power_of_two());
-assert!(!Wrapping(10", stringify!($t), ").is_power_of_two());
-```"),
-                #[inline]
-                #[unstable(feature = "wrapping_int_impl", issue = "32463")]
-                pub fn is_power_of_two(self) -> bool {
-                    self.0.is_power_of_two()
-                }
+            /// Returns `true` if and only if `self == 2^k` for some `k`.
+            ///
+            /// # Examples
+            ///
+            /// Basic usage:
+            ///
+            /// ```
+            /// #![feature(wrapping_int_impl)]
+            /// use std::num::Wrapping;
+            ///
+            #[doc = concat!("assert!(Wrapping(16", stringify!($t), ").is_power_of_two());")]
+            #[doc = concat!("assert!(!Wrapping(10", stringify!($t), ").is_power_of_two());")]
+            /// ```
+            #[inline]
+            #[unstable(feature = "wrapping_int_impl", issue = "32463")]
+            pub fn is_power_of_two(self) -> bool {
+                self.0.is_power_of_two()
             }
 
-            doc_comment! {
-                concat!("Returns the smallest power of two greater than or equal to `self`.
-
-When return value overflows (i.e., `self > (1 << (N-1))` for type
-`uN`), overflows to `2^N = 0`.
-
-# Examples
-
-Basic usage:
-
-```
-#![feature(wrapping_next_power_of_two)]
-use std::num::Wrapping;
-
-assert_eq!(Wrapping(2", stringify!($t), ").next_power_of_two(), Wrapping(2));
-assert_eq!(Wrapping(3", stringify!($t), ").next_power_of_two(), Wrapping(4));
-assert_eq!(Wrapping(200_u8).next_power_of_two(), Wrapping(0));
-```"),
-                #[inline]
-                #[unstable(feature = "wrapping_next_power_of_two", issue = "32463",
-                           reason = "needs decision on wrapping behaviour")]
-                pub fn next_power_of_two(self) -> Self {
-                    Wrapping(self.0.wrapping_next_power_of_two())
-                }
+            /// Returns the smallest power of two greater than or equal to `self`.
+            ///
+            /// When return value overflows (i.e., `self > (1 << (N-1))` for type
+            /// `uN`), overflows to `2^N = 0`.
+            ///
+            /// # Examples
+            ///
+            /// Basic usage:
+            ///
+            /// ```
+            /// #![feature(wrapping_next_power_of_two)]
+            /// use std::num::Wrapping;
+            ///
+            #[doc = concat!("assert_eq!(Wrapping(2", stringify!($t), ").next_power_of_two(), Wrapping(2));")]
+            #[doc = concat!("assert_eq!(Wrapping(3", stringify!($t), ").next_power_of_two(), Wrapping(4));")]
+            #[doc = concat!("assert_eq!(Wrapping(200_u8).next_power_of_two(), Wrapping(0));")]
+            /// ```
+            #[inline]
+            #[unstable(feature = "wrapping_next_power_of_two", issue = "32463",
+                       reason = "needs decision on wrapping behaviour")]
+            pub fn next_power_of_two(self) -> Self {
+                Wrapping(self.0.wrapping_next_power_of_two())
             }
         }
     )*)
index 8fd9ff768c4f4a4a23f027ad54445391d30a4e41..663001167865aaf90f0e550a96ea2ec7a271974e 100644 (file)
@@ -232,23 +232,27 @@ pub unsafe fn as_uninit_ref<'a>(self) -> Option<&'a MaybeUninit<T>>
     ///
     /// # Safety
     ///
-    /// The resulting pointer does not need to be in bounds, but it is
-    /// potentially hazardous to dereference (which requires `unsafe`).
+    /// This operation itself is always safe, but using the resulting pointer is not.
     ///
-    /// In particular, the resulting pointer remains attached to the same allocated
-    /// object that `self` points to. It may *not* be used to access a
-    /// different allocated object. Note that in Rust,
-    /// every (stack-allocated) variable is considered a separate allocated object.
+    /// The resulting pointer remains attached to the same allocated object that `self` points to.
+    /// It may *not* be used to access a different allocated object. Note that in Rust, every
+    /// (stack-allocated) variable is considered a separate allocated object.
     ///
-    /// In other words, `x.wrapping_offset((y as usize).wrapping_sub(x as usize) / size_of::<T>())`
-    /// is *not* the same as `y`, and dereferencing it is undefined behavior
-    /// unless `x` and `y` point into the same allocated object.
+    /// In other words, `let z = x.wrapping_offset((y as isize) - (x as isize))` does *not* make `z`
+    /// the same as `y` even if we assume `T` has size `1` and there is no overflow: `z` is still
+    /// attached to the object `x` is attached to, and dereferencing it is Undefined Behavior unless
+    /// `x` and `y` point into the same allocated object.
     ///
-    /// Compared to [`offset`], this method basically delays the requirement of staying
-    /// within the same allocated object: [`offset`] is immediate Undefined Behavior when
-    /// crossing object boundaries; `wrapping_offset` produces a pointer but still leads
-    /// to Undefined Behavior if that pointer is dereferenced. [`offset`] can be optimized
-    /// better and is thus preferable in performance-sensitive code.
+    /// Compared to [`offset`], this method basically delays the requirement of staying within the
+    /// same allocated object: [`offset`] is immediate Undefined Behavior when crossing object
+    /// boundaries; `wrapping_offset` produces a pointer but still leads to Undefined Behavior if a
+    /// pointer is dereferenced when it is out-of-bounds of the object it is attached to. [`offset`]
+    /// can be optimized better and is thus preferable in performance-sensitive code.
+    ///
+    /// The delayed check only considers the value of the pointer that was dereferenced, not the
+    /// intermediate values used during the computation of the final result. For example,
+    /// `x.wrapping_offset(o).wrapping_offset(o.wrapping_neg())` is always the same as `x`. In other
+    /// words, leaving the allocated object and then re-entering it later is permitted.
     ///
     /// If you need to cross object boundaries, cast the pointer to an integer and
     /// do the arithmetic there.
@@ -571,19 +575,27 @@ pub const fn guaranteed_ne(self, other: *const T) -> bool
     ///
     /// # Safety
     ///
-    /// The resulting pointer does not need to be in bounds, but it is
-    /// potentially hazardous to dereference (which requires `unsafe`).
+    /// This operation itself is always safe, but using the resulting pointer is not.
+    ///
+    /// The resulting pointer remains attached to the same allocated object that `self` points to.
+    /// It may *not* be used to access a different allocated object. Note that in Rust, every
+    /// (stack-allocated) variable is considered a separate allocated object.
+    ///
+    /// In other words, `let z = x.wrapping_add((y as usize) - (x as usize))` does *not* make `z`
+    /// the same as `y` even if we assume `T` has size `1` and there is no overflow: `z` is still
+    /// attached to the object `x` is attached to, and dereferencing it is Undefined Behavior unless
+    /// `x` and `y` point into the same allocated object.
     ///
-    /// In particular, the resulting pointer remains attached to the same allocated
-    /// object that `self` points to. It may *not* be used to access a
-    /// different allocated object. Note that in Rust,
-    /// every (stack-allocated) variable is considered a separate allocated object.
+    /// Compared to [`add`], this method basically delays the requirement of staying within the
+    /// same allocated object: [`add`] is immediate Undefined Behavior when crossing object
+    /// boundaries; `wrapping_add` produces a pointer but still leads to Undefined Behavior if a
+    /// pointer is dereferenced when it is out-of-bounds of the object it is attached to. [`add`]
+    /// can be optimized better and is thus preferable in performance-sensitive code.
     ///
-    /// Compared to [`add`], this method basically delays the requirement of staying
-    /// within the same allocated object: [`add`] is immediate Undefined Behavior when
-    /// crossing object boundaries; `wrapping_add` produces a pointer but still leads
-    /// to Undefined Behavior if that pointer is dereferenced. [`add`] can be optimized
-    /// better and is thus preferable in performance-sensitive code.
+    /// The delayed check only considers the value of the pointer that was dereferenced, not the
+    /// intermediate values used during the computation of the final result. For example,
+    /// `x.wrapping_add(o).wrapping_sub(o)` is always the same as `x`. In other words, leaving the
+    /// allocated object and then re-entering it later is permitted.
     ///
     /// If you need to cross object boundaries, cast the pointer to an integer and
     /// do the arithmetic there.
@@ -628,19 +640,27 @@ pub const fn wrapping_add(self, count: usize) -> Self
     ///
     /// # Safety
     ///
-    /// The resulting pointer does not need to be in bounds, but it is
-    /// potentially hazardous to dereference (which requires `unsafe`).
+    /// This operation itself is always safe, but using the resulting pointer is not.
+    ///
+    /// The resulting pointer remains attached to the same allocated object that `self` points to.
+    /// It may *not* be used to access a different allocated object. Note that in Rust, every
+    /// (stack-allocated) variable is considered a separate allocated object.
+    ///
+    /// In other words, `let z = x.wrapping_sub((x as usize) - (y as usize))` does *not* make `z`
+    /// the same as `y` even if we assume `T` has size `1` and there is no overflow: `z` is still
+    /// attached to the object `x` is attached to, and dereferencing it is Undefined Behavior unless
+    /// `x` and `y` point into the same allocated object.
     ///
-    /// In particular, the resulting pointer remains attached to the same allocated
-    /// object that `self` points to. It may *not* be used to access a
-    /// different allocated object. Note that in Rust,
-    /// every (stack-allocated) variable is considered a separate allocated object.
+    /// Compared to [`sub`], this method basically delays the requirement of staying within the
+    /// same allocated object: [`sub`] is immediate Undefined Behavior when crossing object
+    /// boundaries; `wrapping_sub` produces a pointer but still leads to Undefined Behavior if a
+    /// pointer is dereferenced when it is out-of-bounds of the object it is attached to. [`sub`]
+    /// can be optimized better and is thus preferable in performance-sensitive code.
     ///
-    /// Compared to [`sub`], this method basically delays the requirement of staying
-    /// within the same allocated object: [`sub`] is immediate Undefined Behavior when
-    /// crossing object boundaries; `wrapping_sub` produces a pointer but still leads
-    /// to Undefined Behavior if that pointer is dereferenced. [`sub`] can be optimized
-    /// better and is thus preferable in performance-sensitive code.
+    /// The delayed check only considers the value of the pointer that was dereferenced, not the
+    /// intermediate values used during the computation of the final result. For example,
+    /// `x.wrapping_add(o).wrapping_sub(o)` is always the same as `x`. In other words, leaving the
+    /// allocated object and then re-entering it later is permitted.
     ///
     /// If you need to cross object boundaries, cast the pointer to an integer and
     /// do the arithmetic there.
@@ -725,8 +745,9 @@ pub fn set_ptr_value(mut self, val: *const u8) -> Self {
     ///
     /// [`ptr::read`]: crate::ptr::read()
     #[stable(feature = "pointer_methods", since = "1.26.0")]
+    #[rustc_const_unstable(feature = "const_ptr_read", issue = "80377")]
     #[inline]
-    pub unsafe fn read(self) -> T
+    pub const unsafe fn read(self) -> T
     where
         T: Sized,
     {
@@ -763,8 +784,9 @@ pub unsafe fn read_volatile(self) -> T
     ///
     /// [`ptr::read_unaligned`]: crate::ptr::read_unaligned()
     #[stable(feature = "pointer_methods", since = "1.26.0")]
+    #[rustc_const_unstable(feature = "const_ptr_read", issue = "80377")]
     #[inline]
-    pub unsafe fn read_unaligned(self) -> T
+    pub const unsafe fn read_unaligned(self) -> T
     where
         T: Sized,
     {
index 27d49529a5ec20f13702df386b892c9d09e9ba06..807f114ea466c123ae1d073f20334f491476096c 100644 (file)
@@ -685,7 +685,8 @@ pub unsafe fn replace<T>(dst: *mut T, mut src: T) -> T {
 /// [valid]: self#safety
 #[inline]
 #[stable(feature = "rust1", since = "1.0.0")]
-pub unsafe fn read<T>(src: *const T) -> T {
+#[rustc_const_unstable(feature = "const_ptr_read", issue = "80377")]
+pub const unsafe fn read<T>(src: *const T) -> T {
     // `copy_nonoverlapping` takes care of debug_assert.
     let mut tmp = MaybeUninit::<T>::uninit();
     // SAFETY: the caller must guarantee that `src` is valid for reads.
@@ -784,7 +785,8 @@ pub unsafe fn read<T>(src: *const T) -> T {
 /// ```
 #[inline]
 #[stable(feature = "ptr_unaligned", since = "1.17.0")]
-pub unsafe fn read_unaligned<T>(src: *const T) -> T {
+#[rustc_const_unstable(feature = "const_ptr_read", issue = "80377")]
+pub const unsafe fn read_unaligned<T>(src: *const T) -> T {
     // `copy_nonoverlapping` takes care of debug_assert.
     let mut tmp = MaybeUninit::<T>::uninit();
     // SAFETY: the caller must guarantee that `src` is valid for reads.
index 5f94c2393aef33b90c0fe3b8666bc7ea1d77f4a3..785bf70c2992c4395fd2242933ee4c18d81beac4 100644 (file)
@@ -238,23 +238,27 @@ pub unsafe fn as_uninit_ref<'a>(self) -> Option<&'a MaybeUninit<T>>
     ///
     /// # Safety
     ///
-    /// The resulting pointer does not need to be in bounds, but it is
-    /// potentially hazardous to dereference (which requires `unsafe`).
+    /// This operation itself is always safe, but using the resulting pointer is not.
     ///
-    /// In particular, the resulting pointer remains attached to the same allocated
-    /// object that `self` points to. It may *not* be used to access a
-    /// different allocated object. Note that in Rust,
-    /// every (stack-allocated) variable is considered a separate allocated object.
+    /// The resulting pointer remains attached to the same allocated object that `self` points to.
+    /// It may *not* be used to access a different allocated object. Note that in Rust, every
+    /// (stack-allocated) variable is considered a separate allocated object.
     ///
-    /// In other words, `x.wrapping_offset((y as usize).wrapping_sub(x as usize) / size_of::<T>())`
-    /// is *not* the same as `y`, and dereferencing it is undefined behavior
-    /// unless `x` and `y` point into the same allocated object.
+    /// In other words, `let z = x.wrapping_offset((y as isize) - (x as isize))` does *not* make `z`
+    /// the same as `y` even if we assume `T` has size `1` and there is no overflow: `z` is still
+    /// attached to the object `x` is attached to, and dereferencing it is Undefined Behavior unless
+    /// `x` and `y` point into the same allocated object.
     ///
-    /// Compared to [`offset`], this method basically delays the requirement of staying
-    /// within the same allocated object: [`offset`] is immediate Undefined Behavior when
-    /// crossing object boundaries; `wrapping_offset` produces a pointer but still leads
-    /// to Undefined Behavior if that pointer is dereferenced. [`offset`] can be optimized
-    /// better and is thus preferable in performance-sensitive code.
+    /// Compared to [`offset`], this method basically delays the requirement of staying within the
+    /// same allocated object: [`offset`] is immediate Undefined Behavior when crossing object
+    /// boundaries; `wrapping_offset` produces a pointer but still leads to Undefined Behavior if a
+    /// pointer is dereferenced when it is out-of-bounds of the object it is attached to. [`offset`]
+    /// can be optimized better and is thus preferable in performance-sensitive code.
+    ///
+    /// The delayed check only considers the value of the pointer that was dereferenced, not the
+    /// intermediate values used during the computation of the final result. For example,
+    /// `x.wrapping_offset(o).wrapping_offset(o.wrapping_neg())` is always the same as `x`. In other
+    /// words, leaving the allocated object and then re-entering it later is permitted.
     ///
     /// If you need to cross object boundaries, cast the pointer to an integer and
     /// do the arithmetic there.
@@ -678,19 +682,27 @@ pub const fn guaranteed_eq(self, other: *mut T) -> bool
     ///
     /// # Safety
     ///
-    /// The resulting pointer does not need to be in bounds, but it is
-    /// potentially hazardous to dereference (which requires `unsafe`).
+    /// This operation itself is always safe, but using the resulting pointer is not.
+    ///
+    /// The resulting pointer remains attached to the same allocated object that `self` points to.
+    /// It may *not* be used to access a different allocated object. Note that in Rust, every
+    /// (stack-allocated) variable is considered a separate allocated object.
+    ///
+    /// In other words, `let z = x.wrapping_add((y as usize) - (x as usize))` does *not* make `z`
+    /// the same as `y` even if we assume `T` has size `1` and there is no overflow: `z` is still
+    /// attached to the object `x` is attached to, and dereferencing it is Undefined Behavior unless
+    /// `x` and `y` point into the same allocated object.
     ///
-    /// In particular, the resulting pointer remains attached to the same allocated
-    /// object that `self` points to. It may *not* be used to access a
-    /// different allocated object. Note that in Rust,
-    /// every (stack-allocated) variable is considered a separate allocated object.
+    /// Compared to [`add`], this method basically delays the requirement of staying within the
+    /// same allocated object: [`add`] is immediate Undefined Behavior when crossing object
+    /// boundaries; `wrapping_add` produces a pointer but still leads to Undefined Behavior if a
+    /// pointer is dereferenced when it is out-of-bounds of the object it is attached to. [`add`]
+    /// can be optimized better and is thus preferable in performance-sensitive code.
     ///
-    /// Compared to [`add`], this method basically delays the requirement of staying
-    /// within the same allocated object: [`add`] is immediate Undefined Behavior when
-    /// crossing object boundaries; `wrapping_add` produces a pointer but still leads
-    /// to Undefined Behavior if that pointer is dereferenced. [`add`] can be optimized
-    /// better and is thus preferable in performance-sensitive code.
+    /// The delayed check only considers the value of the pointer that was dereferenced, not the
+    /// intermediate values used during the computation of the final result. For example,
+    /// `x.wrapping_add(o).wrapping_sub(o)` is always the same as `x`. In other words, leaving the
+    /// allocated object and then re-entering it later is permitted.
     ///
     /// If you need to cross object boundaries, cast the pointer to an integer and
     /// do the arithmetic there.
@@ -735,19 +747,27 @@ pub const fn wrapping_add(self, count: usize) -> Self
     ///
     /// # Safety
     ///
-    /// The resulting pointer does not need to be in bounds, but it is
-    /// potentially hazardous to dereference (which requires `unsafe`).
+    /// This operation itself is always safe, but using the resulting pointer is not.
+    ///
+    /// The resulting pointer remains attached to the same allocated object that `self` points to.
+    /// It may *not* be used to access a different allocated object. Note that in Rust, every
+    /// (stack-allocated) variable is considered a separate allocated object.
+    ///
+    /// In other words, `let z = x.wrapping_sub((x as usize) - (y as usize))` does *not* make `z`
+    /// the same as `y` even if we assume `T` has size `1` and there is no overflow: `z` is still
+    /// attached to the object `x` is attached to, and dereferencing it is Undefined Behavior unless
+    /// `x` and `y` point into the same allocated object.
     ///
-    /// In particular, the resulting pointer remains attached to the same allocated
-    /// object that `self` points to. It may *not* be used to access a
-    /// different allocated object. Note that in Rust,
-    /// every (stack-allocated) variable is considered a separate allocated object.
+    /// Compared to [`sub`], this method basically delays the requirement of staying within the
+    /// same allocated object: [`sub`] is immediate Undefined Behavior when crossing object
+    /// boundaries; `wrapping_sub` produces a pointer but still leads to Undefined Behavior if a
+    /// pointer is dereferenced when it is out-of-bounds of the object it is attached to. [`sub`]
+    /// can be optimized better and is thus preferable in performance-sensitive code.
     ///
-    /// Compared to [`sub`], this method basically delays the requirement of staying
-    /// within the same allocated object: [`sub`] is immediate Undefined Behavior when
-    /// crossing object boundaries; `wrapping_sub` produces a pointer but still leads
-    /// to Undefined Behavior if that pointer is dereferenced. [`sub`] can be optimized
-    /// better and is thus preferable in performance-sensitive code.
+    /// The delayed check only considers the value of the pointer that was dereferenced, not the
+    /// intermediate values used during the computation of the final result. For example,
+    /// `x.wrapping_add(o).wrapping_sub(o)` is always the same as `x`. In other words, leaving the
+    /// allocated object and then re-entering it later is permitted.
     ///
     /// If you need to cross object boundaries, cast the pointer to an integer and
     /// do the arithmetic there.
@@ -832,8 +852,9 @@ pub fn set_ptr_value(mut self, val: *mut u8) -> Self {
     ///
     /// [`ptr::read`]: crate::ptr::read()
     #[stable(feature = "pointer_methods", since = "1.26.0")]
+    #[rustc_const_unstable(feature = "const_ptr_read", issue = "80377")]
     #[inline]
-    pub unsafe fn read(self) -> T
+    pub const unsafe fn read(self) -> T
     where
         T: Sized,
     {
@@ -870,8 +891,9 @@ pub unsafe fn read_volatile(self) -> T
     ///
     /// [`ptr::read_unaligned`]: crate::ptr::read_unaligned()
     #[stable(feature = "pointer_methods", since = "1.26.0")]
+    #[rustc_const_unstable(feature = "const_ptr_read", issue = "80377")]
     #[inline]
-    pub unsafe fn read_unaligned(self) -> T
+    pub const unsafe fn read_unaligned(self) -> T
     where
         T: Sized,
     {
index 18073f4afedf74fafc3d9e11259aca9ff96ee3e6..72af47c71dd64333b9c4d4e12c9104540678736b 100644 (file)
@@ -75,28 +75,6 @@ impl<A, B> SlicePartialEq<B> for [A]
     }
 }
 
-// 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
@@ -107,11 +85,6 @@ fn equal(&self, other: &[B]) -> bool {
             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 {
index 44fe2ca88596f8dc63654f09eab4a7ac2cd6aa98..bb1014332a1cf2c58d24b5dce0f8944ffc889509 100644 (file)
@@ -84,6 +84,7 @@ impl<T> [T] {
     /// let a = [1, 2, 3];
     /// assert_eq!(a.len(), 3);
     /// ```
+    #[doc(alias = "length")]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_const_stable(feature = "const_slice_len", since = "1.32.0")]
     #[inline]
@@ -2581,14 +2582,12 @@ pub fn rotate_right(&mut self, k: usize) {
     /// # Examples
     ///
     /// ```
-    /// #![feature(slice_fill)]
-    ///
     /// let mut buf = vec![0; 10];
     /// buf.fill(1);
     /// assert_eq!(buf, vec![1; 10]);
     /// ```
     #[doc(alias = "memset")]
-    #[unstable(feature = "slice_fill", issue = "70758")]
+    #[stable(feature = "slice_fill", since = "1.50.0")]
     pub fn fill(&mut self, value: T)
     where
         T: Clone,
index 83cf47c8c8f61edbde4661068275e210d55a50ae..ba495a1a9fbe4b6421315e526543efee6ae35702 100644 (file)
@@ -138,6 +138,7 @@ impl str {
     /// assert_eq!("Æ’oo".len(), 4); // fancy f!
     /// assert_eq!("Æ’oo".chars().count(), 3);
     /// ```
+    #[doc(alias = "length")]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_const_stable(feature = "const_str_len", since = "1.32.0")]
     #[inline]
index a96da9aa6dc73c3879acbffcab9a0fc082c3ed3d..d03c19e51f3fa4eca22579d43895cf9e011b4bfd 100644 (file)
@@ -464,6 +464,23 @@ pub fn swap(&self, val: bool, order: Ordering) -> bool {
     /// **Note:** This method is only available on platforms that support atomic
     /// operations on `u8`.
     ///
+    /// # Migrating to `compare_exchange` and `compare_exchange_weak`
+    ///
+    /// `compare_and_swap` is equivalent to `compare_exchange` with the following mapping for
+    /// memory orderings:
+    ///
+    /// Original | Success | Failure
+    /// -------- | ------- | -------
+    /// Relaxed  | Relaxed | Relaxed
+    /// Acquire  | Acquire | Acquire
+    /// Release  | Release | Relaxed
+    /// AcqRel   | AcqRel  | Acquire
+    /// SeqCst   | SeqCst  | SeqCst
+    ///
+    /// `compare_exchange_weak` is allowed to fail spuriously even when the comparison succeeds,
+    /// which allows the compiler to generate better assembly code when the compare and swap
+    /// is used in a loop.
+    ///
     /// # Examples
     ///
     /// ```
@@ -479,6 +496,10 @@ pub fn swap(&self, val: bool, order: Ordering) -> bool {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_deprecated(
+        since = "1.50.0",
+        reason = "Use `compare_exchange` or `compare_exchange_weak` instead"
+    )]
     #[cfg(target_has_atomic = "8")]
     pub fn compare_and_swap(&self, current: bool, new: bool, order: Ordering) -> bool {
         match self.compare_exchange(current, new, order, strongest_failure_ordering(order)) {
@@ -493,9 +514,10 @@ pub fn compare_and_swap(&self, current: bool, new: bool, order: Ordering) -> boo
     /// the previous value. On success this value is guaranteed to be equal to `current`.
     ///
     /// `compare_exchange` takes two [`Ordering`] arguments to describe the memory
-    /// ordering of this operation. The first describes the required ordering if the
-    /// operation succeeds while the second describes the required ordering when the
-    /// operation fails. Using [`Acquire`] as success ordering makes the store part
+    /// ordering of this operation. `success` describes the required ordering for the
+    /// read-modify-write operation that takes place if the comparison with `current` succeeds.
+    /// `failure` describes the required ordering for the load operation that takes place when
+    /// the comparison fails. Using [`Acquire`] as success ordering makes the store part
     /// of this operation [`Relaxed`], and using [`Release`] makes the successful load
     /// [`Relaxed`]. The failure ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`]
     /// and must be equivalent to or weaker than the success ordering.
@@ -525,6 +547,7 @@ pub fn compare_and_swap(&self, current: bool, new: bool, order: Ordering) -> boo
     /// ```
     #[inline]
     #[stable(feature = "extended_compare_and_swap", since = "1.10.0")]
+    #[doc(alias = "compare_and_swap")]
     #[cfg(target_has_atomic = "8")]
     pub fn compare_exchange(
         &self,
@@ -550,9 +573,10 @@ pub fn compare_exchange(
     /// previous value.
     ///
     /// `compare_exchange_weak` takes two [`Ordering`] arguments to describe the memory
-    /// ordering of this operation. The first describes the required ordering if the
-    /// operation succeeds while the second describes the required ordering when the
-    /// operation fails. Using [`Acquire`] as success ordering makes the store part
+    /// ordering of this operation. `success` describes the required ordering for the
+    /// read-modify-write operation that takes place if the comparison with `current` succeeds.
+    /// `failure` describes the required ordering for the load operation that takes place when
+    /// the comparison fails. Using [`Acquire`] as success ordering makes the store part
     /// of this operation [`Relaxed`], and using [`Release`] makes the successful load
     /// [`Relaxed`]. The failure ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`]
     /// and must be equivalent to or weaker than the success ordering.
@@ -578,6 +602,7 @@ pub fn compare_exchange(
     /// ```
     #[inline]
     #[stable(feature = "extended_compare_and_swap", since = "1.10.0")]
+    #[doc(alias = "compare_and_swap")]
     #[cfg(target_has_atomic = "8")]
     pub fn compare_exchange_weak(
         &self,
@@ -966,16 +991,8 @@ pub const fn into_inner(self) -> *mut T {
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn load(&self, order: Ordering) -> *mut T {
-        #[cfg(not(bootstrap))]
-        // SAFETY: data races are prevented by atomic intrinsics.
-        unsafe {
-            atomic_load(self.p.get(), order)
-        }
-        #[cfg(bootstrap)]
         // SAFETY: data races are prevented by atomic intrinsics.
-        unsafe {
-            atomic_load(self.p.get() as *mut usize, order) as *mut T
-        }
+        unsafe { atomic_load(self.p.get(), order) }
     }
 
     /// Stores a value into the pointer.
@@ -1002,16 +1019,10 @@ pub fn load(&self, order: Ordering) -> *mut T {
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn store(&self, ptr: *mut T, order: Ordering) {
-        #[cfg(not(bootstrap))]
         // SAFETY: data races are prevented by atomic intrinsics.
         unsafe {
             atomic_store(self.p.get(), ptr, order);
         }
-        #[cfg(bootstrap)]
-        // SAFETY: data races are prevented by atomic intrinsics.
-        unsafe {
-            atomic_store(self.p.get() as *mut usize, ptr as usize, order);
-        }
     }
 
     /// Stores a value into the pointer, returning the previous value.
@@ -1040,16 +1051,8 @@ pub fn store(&self, ptr: *mut T, order: Ordering) {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[cfg(target_has_atomic = "ptr")]
     pub fn swap(&self, ptr: *mut T, order: Ordering) -> *mut T {
-        #[cfg(bootstrap)]
         // SAFETY: data races are prevented by atomic intrinsics.
-        unsafe {
-            atomic_swap(self.p.get() as *mut usize, ptr as usize, order) as *mut T
-        }
-        #[cfg(not(bootstrap))]
-        // SAFETY: data races are prevented by atomic intrinsics.
-        unsafe {
-            atomic_swap(self.p.get(), ptr, order)
-        }
+        unsafe { atomic_swap(self.p.get(), ptr, order) }
     }
 
     /// Stores a value into the pointer if the current value is the same as the `current` value.
@@ -1066,6 +1069,23 @@ pub fn swap(&self, ptr: *mut T, order: Ordering) -> *mut T {
     /// **Note:** This method is only available on platforms that support atomic
     /// operations on pointers.
     ///
+    /// # Migrating to `compare_exchange` and `compare_exchange_weak`
+    ///
+    /// `compare_and_swap` is equivalent to `compare_exchange` with the following mapping for
+    /// memory orderings:
+    ///
+    /// Original | Success | Failure
+    /// -------- | ------- | -------
+    /// Relaxed  | Relaxed | Relaxed
+    /// Acquire  | Acquire | Acquire
+    /// Release  | Release | Relaxed
+    /// AcqRel   | AcqRel  | Acquire
+    /// SeqCst   | SeqCst  | SeqCst
+    ///
+    /// `compare_exchange_weak` is allowed to fail spuriously even when the comparison succeeds,
+    /// which allows the compiler to generate better assembly code when the compare and swap
+    /// is used in a loop.
+    ///
     /// # Examples
     ///
     /// ```
@@ -1080,6 +1100,10 @@ pub fn swap(&self, ptr: *mut T, order: Ordering) -> *mut T {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_deprecated(
+        since = "1.50.0",
+        reason = "Use `compare_exchange` or `compare_exchange_weak` instead"
+    )]
     #[cfg(target_has_atomic = "ptr")]
     pub fn compare_and_swap(&self, current: *mut T, new: *mut T, order: Ordering) -> *mut T {
         match self.compare_exchange(current, new, order, strongest_failure_ordering(order)) {
@@ -1094,9 +1118,10 @@ pub fn compare_and_swap(&self, current: *mut T, new: *mut T, order: Ordering) ->
     /// the previous value. On success this value is guaranteed to be equal to `current`.
     ///
     /// `compare_exchange` takes two [`Ordering`] arguments to describe the memory
-    /// ordering of this operation. The first describes the required ordering if the
-    /// operation succeeds while the second describes the required ordering when the
-    /// operation fails. Using [`Acquire`] as success ordering makes the store part
+    /// ordering of this operation. `success` describes the required ordering for the
+    /// read-modify-write operation that takes place if the comparison with `current` succeeds.
+    /// `failure` describes the required ordering for the load operation that takes place when
+    /// the comparison fails. Using [`Acquire`] as success ordering makes the store part
     /// of this operation [`Relaxed`], and using [`Release`] makes the successful load
     /// [`Relaxed`]. The failure ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`]
     /// and must be equivalent to or weaker than the success ordering.
@@ -1127,26 +1152,8 @@ pub fn compare_exchange(
         success: Ordering,
         failure: Ordering,
     ) -> Result<*mut T, *mut T> {
-        #[cfg(bootstrap)]
-        // SAFETY: data races are prevented by atomic intrinsics.
-        unsafe {
-            let res = atomic_compare_exchange(
-                self.p.get() as *mut usize,
-                current as usize,
-                new as usize,
-                success,
-                failure,
-            );
-            match res {
-                Ok(x) => Ok(x as *mut T),
-                Err(x) => Err(x as *mut T),
-            }
-        }
-        #[cfg(not(bootstrap))]
         // SAFETY: data races are prevented by atomic intrinsics.
-        unsafe {
-            atomic_compare_exchange(self.p.get(), current, new, success, failure)
-        }
+        unsafe { atomic_compare_exchange(self.p.get(), current, new, success, failure) }
     }
 
     /// Stores a value into the pointer if the current value is the same as the `current` value.
@@ -1157,9 +1164,10 @@ pub fn compare_exchange(
     /// previous value.
     ///
     /// `compare_exchange_weak` takes two [`Ordering`] arguments to describe the memory
-    /// ordering of this operation. The first describes the required ordering if the
-    /// operation succeeds while the second describes the required ordering when the
-    /// operation fails. Using [`Acquire`] as success ordering makes the store part
+    /// ordering of this operation. `success` describes the required ordering for the
+    /// read-modify-write operation that takes place if the comparison with `current` succeeds.
+    /// `failure` describes the required ordering for the load operation that takes place when
+    /// the comparison fails. Using [`Acquire`] as success ordering makes the store part
     /// of this operation [`Relaxed`], and using [`Release`] makes the successful load
     /// [`Relaxed`]. The failure ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`]
     /// and must be equivalent to or weaker than the success ordering.
@@ -1193,29 +1201,11 @@ pub fn compare_exchange_weak(
         success: Ordering,
         failure: Ordering,
     ) -> Result<*mut T, *mut T> {
-        #[cfg(bootstrap)]
-        // SAFETY: data races are prevented by atomic intrinsics.
-        unsafe {
-            let res = atomic_compare_exchange_weak(
-                self.p.get() as *mut usize,
-                current as usize,
-                new as usize,
-                success,
-                failure,
-            );
-            match res {
-                Ok(x) => Ok(x as *mut T),
-                Err(x) => Err(x as *mut T),
-            }
-        }
-        #[cfg(not(bootstrap))]
         // SAFETY: This intrinsic is unsafe because it operates on a raw pointer
         // but we know for sure that the pointer is valid (we just got it from
         // an `UnsafeCell` that we have by reference) and the atomic operation
         // itself allows us to safely mutate the `UnsafeCell` contents.
-        unsafe {
-            atomic_compare_exchange_weak(self.p.get(), current, new, success, failure)
-        }
+        unsafe { atomic_compare_exchange_weak(self.p.get(), current, new, success, failure) }
     }
 
     /// Fetches the value, and applies a function to it that returns an optional
@@ -1382,12 +1372,9 @@ fn default() -> Self {
 
         #[$stable_from]
         impl From<$int_type> for $atomic_type {
-            doc_comment! {
-                concat!(
-"Converts an `", stringify!($int_type), "` into an `", stringify!($atomic_type), "`."),
-                #[inline]
-                fn from(v: $int_type) -> Self { Self::new(v) }
-            }
+            #[doc = concat!("Converts an `", stringify!($int_type), "` into an `", stringify!($atomic_type), "`.")]
+            #[inline]
+            fn from(v: $int_type) -> Self { Self::new(v) }
         }
 
         #[$stable_debug]
@@ -1402,721 +1389,703 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         unsafe impl Sync for $atomic_type {}
 
         impl $atomic_type {
-            doc_comment! {
-                concat!("Creates a new atomic integer.
-
-# Examples
-
-```
-", $extra_feature, "use std::sync::atomic::", stringify!($atomic_type), ";
-
-let atomic_forty_two = ", stringify!($atomic_type), "::new(42);
-```"),
-                #[inline]
-                #[$stable]
-                #[$const_stable]
-                pub const fn new(v: $int_type) -> Self {
-                    Self {v: UnsafeCell::new(v)}
-                }
+            /// Creates a new atomic integer.
+            ///
+            /// # Examples
+            ///
+            /// ```
+            #[doc = concat!($extra_feature, "use std::sync::atomic::", stringify!($atomic_type), ";")]
+            ///
+            #[doc = concat!("let atomic_forty_two = ", stringify!($atomic_type), "::new(42);")]
+            /// ```
+            #[inline]
+            #[$stable]
+            #[$const_stable]
+            pub const fn new(v: $int_type) -> Self {
+                Self {v: UnsafeCell::new(v)}
             }
 
-            doc_comment! {
-                concat!("Returns a mutable reference to the underlying integer.
-
-This is safe because the mutable reference guarantees that no other threads are
-concurrently accessing the atomic data.
-
-# Examples
-
-```
-", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};
-
-let mut some_var = ", stringify!($atomic_type), "::new(10);
-assert_eq!(*some_var.get_mut(), 10);
-*some_var.get_mut() = 5;
-assert_eq!(some_var.load(Ordering::SeqCst), 5);
-```"),
-                #[inline]
-                #[$stable_access]
-                pub fn get_mut(&mut self) -> &mut $int_type {
-                    self.v.get_mut()
-                }
+            /// Returns a mutable reference to the underlying integer.
+            ///
+            /// This is safe because the mutable reference guarantees that no other threads are
+            /// concurrently accessing the atomic data.
+            ///
+            /// # Examples
+            ///
+            /// ```
+            #[doc = concat!($extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};")]
+            ///
+            #[doc = concat!("let mut some_var = ", stringify!($atomic_type), "::new(10);")]
+            /// assert_eq!(*some_var.get_mut(), 10);
+            /// *some_var.get_mut() = 5;
+            /// assert_eq!(some_var.load(Ordering::SeqCst), 5);
+            /// ```
+            #[inline]
+            #[$stable_access]
+            pub fn get_mut(&mut self) -> &mut $int_type {
+                self.v.get_mut()
             }
 
-            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_align]
-                #[unstable(feature = "atomic_from_mut", issue = "76314")]
-                pub fn from_mut(v: &mut $int_type) -> &Self {
-                    use crate::mem::align_of;
-                    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, as promised by $cfg_align and verified above.
-                    unsafe { &*(v as *mut $int_type as *mut Self) }
-                }
+            #[doc = concat!("Get atomic access to a `&mut ", stringify!($int_type), "`.")]
+            ///
+            #[doc = 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)]
+            #[doc = concat!($extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};")]
+            ///
+            /// let mut some_int = 123;
+            #[doc = concat!("let a = ", stringify!($atomic_type), "::from_mut(&mut some_int);")]
+            /// a.store(100, Ordering::Relaxed);
+            /// assert_eq!(some_int, 100);
+            /// ```
+            ///
+            #[inline]
+            #[$cfg_align]
+            #[unstable(feature = "atomic_from_mut", issue = "76314")]
+            pub fn from_mut(v: &mut $int_type) -> &Self {
+                use crate::mem::align_of;
+                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, as promised by $cfg_align and verified above.
+                unsafe { &*(v as *mut $int_type as *mut Self) }
             }
 
-            doc_comment! {
-                concat!("Consumes the atomic and returns the contained value.
-
-This is safe because passing `self` by value guarantees that no other threads are
-concurrently accessing the atomic data.
-
-# Examples
-
-```
-", $extra_feature, "use std::sync::atomic::", stringify!($atomic_type), ";
-
-let some_var = ", stringify!($atomic_type), "::new(5);
-assert_eq!(some_var.into_inner(), 5);
-```"),
-                #[inline]
-                #[$stable_access]
-                #[rustc_const_unstable(feature = "const_cell_into_inner", issue = "78729")]
-                pub const fn into_inner(self) -> $int_type {
-                    self.v.into_inner()
-                }
+            /// Consumes the atomic and returns the contained value.
+            ///
+            /// This is safe because passing `self` by value guarantees that no other threads are
+            /// concurrently accessing the atomic data.
+            ///
+            /// # Examples
+            ///
+            /// ```
+            #[doc = concat!($extra_feature, "use std::sync::atomic::", stringify!($atomic_type), ";")]
+            ///
+            #[doc = concat!("let some_var = ", stringify!($atomic_type), "::new(5);")]
+            /// assert_eq!(some_var.into_inner(), 5);
+            /// ```
+            #[inline]
+            #[$stable_access]
+            #[rustc_const_unstable(feature = "const_cell_into_inner", issue = "78729")]
+            pub const fn into_inner(self) -> $int_type {
+                self.v.into_inner()
             }
 
-            doc_comment! {
-                concat!("Loads a value from the atomic integer.
-
-`load` takes an [`Ordering`] argument which describes the memory ordering of this operation.
-Possible values are [`SeqCst`], [`Acquire`] and [`Relaxed`].
-
-# Panics
-
-Panics if `order` is [`Release`] or [`AcqRel`].
-
-# Examples
-
-```
-", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};
-
-let some_var = ", stringify!($atomic_type), "::new(5);
-
-assert_eq!(some_var.load(Ordering::Relaxed), 5);
-```"),
-                #[inline]
-                #[$stable]
-                pub fn load(&self, order: Ordering) -> $int_type {
-                    // SAFETY: data races are prevented by atomic intrinsics.
-                    unsafe { atomic_load(self.v.get(), order) }
-                }
+            /// Loads a value from the atomic integer.
+            ///
+            /// `load` takes an [`Ordering`] argument which describes the memory ordering of this operation.
+            /// Possible values are [`SeqCst`], [`Acquire`] and [`Relaxed`].
+            ///
+            /// # Panics
+            ///
+            /// Panics if `order` is [`Release`] or [`AcqRel`].
+            ///
+            /// # Examples
+            ///
+            /// ```
+            #[doc = concat!($extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};")]
+            ///
+            #[doc = concat!("let some_var = ", stringify!($atomic_type), "::new(5);")]
+            ///
+            /// assert_eq!(some_var.load(Ordering::Relaxed), 5);
+            /// ```
+            #[inline]
+            #[$stable]
+            pub fn load(&self, order: Ordering) -> $int_type {
+                // SAFETY: data races are prevented by atomic intrinsics.
+                unsafe { atomic_load(self.v.get(), order) }
             }
 
-            doc_comment! {
-                concat!("Stores a value into the atomic integer.
-
-`store` takes an [`Ordering`] argument which describes the memory ordering of this operation.
- Possible values are [`SeqCst`], [`Release`] and [`Relaxed`].
-
-# Panics
-
-Panics if `order` is [`Acquire`] or [`AcqRel`].
-
-# Examples
-
-```
-", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};
-
-let some_var = ", stringify!($atomic_type), "::new(5);
-
-some_var.store(10, Ordering::Relaxed);
-assert_eq!(some_var.load(Ordering::Relaxed), 10);
-```"),
-                #[inline]
-                #[$stable]
-                pub fn store(&self, val: $int_type, order: Ordering) {
-                    // SAFETY: data races are prevented by atomic intrinsics.
-                    unsafe { atomic_store(self.v.get(), val, order); }
-                }
+            /// Stores a value into the atomic integer.
+            ///
+            /// `store` takes an [`Ordering`] argument which describes the memory ordering of this operation.
+            ///  Possible values are [`SeqCst`], [`Release`] and [`Relaxed`].
+            ///
+            /// # Panics
+            ///
+            /// Panics if `order` is [`Acquire`] or [`AcqRel`].
+            ///
+            /// # Examples
+            ///
+            /// ```
+            #[doc = concat!($extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};")]
+            ///
+            #[doc = concat!("let some_var = ", stringify!($atomic_type), "::new(5);")]
+            ///
+            /// some_var.store(10, Ordering::Relaxed);
+            /// assert_eq!(some_var.load(Ordering::Relaxed), 10);
+            /// ```
+            #[inline]
+            #[$stable]
+            pub fn store(&self, val: $int_type, order: Ordering) {
+                // SAFETY: data races are prevented by atomic intrinsics.
+                unsafe { atomic_store(self.v.get(), val, order); }
             }
 
-            doc_comment! {
-                concat!("Stores a value into the atomic integer, returning the previous value.
-
-`swap` takes an [`Ordering`] argument which describes the memory ordering
-of this operation. All ordering modes are possible. Note that using
-[`Acquire`] makes the store part of this operation [`Relaxed`], and
-using [`Release`] makes the load part [`Relaxed`].
-
-**Note**: This method is only available on platforms that support atomic
-operations on [`", $s_int_type, "`](", $int_ref, ").
-
-# Examples
-
-```
-", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};
-
-let some_var = ", stringify!($atomic_type), "::new(5);
-
-assert_eq!(some_var.swap(10, Ordering::Relaxed), 5);
-```"),
-                #[inline]
-                #[$stable]
-                #[$cfg_cas]
-                pub fn swap(&self, val: $int_type, order: Ordering) -> $int_type {
-                    // SAFETY: data races are prevented by atomic intrinsics.
-                    unsafe { atomic_swap(self.v.get(), val, order) }
-                }
+            /// Stores a value into the atomic integer, returning the previous value.
+            ///
+            /// `swap` takes an [`Ordering`] argument which describes the memory ordering
+            /// of this operation. All ordering modes are possible. Note that using
+            /// [`Acquire`] makes the store part of this operation [`Relaxed`], and
+            /// using [`Release`] makes the load part [`Relaxed`].
+            ///
+            /// **Note**: This method is only available on platforms that support atomic operations on
+            #[doc = concat!("[`", $s_int_type, "`](", $int_ref, ").")]
+            ///
+            /// # Examples
+            ///
+            /// ```
+            #[doc = concat!($extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};")]
+            ///
+            #[doc = concat!("let some_var = ", stringify!($atomic_type), "::new(5);")]
+            ///
+            /// assert_eq!(some_var.swap(10, Ordering::Relaxed), 5);
+            /// ```
+            #[inline]
+            #[$stable]
+            #[$cfg_cas]
+            pub fn swap(&self, val: $int_type, order: Ordering) -> $int_type {
+                // SAFETY: data races are prevented by atomic intrinsics.
+                unsafe { atomic_swap(self.v.get(), val, order) }
             }
 
-            doc_comment! {
-                concat!("Stores a value into the atomic integer if the current value is the same as
-the `current` value.
-
-The return value is always the previous value. If it is equal to `current`, then the
-value was updated.
-
-`compare_and_swap` also takes an [`Ordering`] argument which describes the memory
-ordering of this operation. Notice that even when using [`AcqRel`], the operation
-might fail and hence just perform an `Acquire` load, but not have `Release` semantics.
-Using [`Acquire`] makes the store part of this operation [`Relaxed`] if it
-happens, and using [`Release`] makes the load part [`Relaxed`].
-
-**Note**: This method is only available on platforms that support atomic
-operations on [`", $s_int_type, "`](", $int_ref, ").
-
-# Examples
-
-```
-", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};
-
-let some_var = ", stringify!($atomic_type), "::new(5);
-
-assert_eq!(some_var.compare_and_swap(5, 10, Ordering::Relaxed), 5);
-assert_eq!(some_var.load(Ordering::Relaxed), 10);
-
-assert_eq!(some_var.compare_and_swap(6, 12, Ordering::Relaxed), 10);
-assert_eq!(some_var.load(Ordering::Relaxed), 10);
-```"),
-                #[inline]
-                #[$stable]
-                #[$cfg_cas]
-                pub fn compare_and_swap(&self,
-                                        current: $int_type,
-                                        new: $int_type,
-                                        order: Ordering) -> $int_type {
-                    match self.compare_exchange(current,
-                                                new,
-                                                order,
-                                                strongest_failure_ordering(order)) {
-                        Ok(x) => x,
-                        Err(x) => x,
-                    }
+            /// Stores a value into the atomic integer if the current value is the same as
+            /// the `current` value.
+            ///
+            /// The return value is always the previous value. If it is equal to `current`, then the
+            /// value was updated.
+            ///
+            /// `compare_and_swap` also takes an [`Ordering`] argument which describes the memory
+            /// ordering of this operation. Notice that even when using [`AcqRel`], the operation
+            /// might fail and hence just perform an `Acquire` load, but not have `Release` semantics.
+            /// Using [`Acquire`] makes the store part of this operation [`Relaxed`] if it
+            /// happens, and using [`Release`] makes the load part [`Relaxed`].
+            ///
+            /// **Note**: This method is only available on platforms that support atomic operations on
+            #[doc = concat!("[`", $s_int_type, "`](", $int_ref, ").")]
+            ///
+            /// # Migrating to `compare_exchange` and `compare_exchange_weak`
+            ///
+            /// `compare_and_swap` is equivalent to `compare_exchange` with the following mapping for
+            /// memory orderings:
+            ///
+            /// Original | Success | Failure
+            /// -------- | ------- | -------
+            /// Relaxed  | Relaxed | Relaxed
+            /// Acquire  | Acquire | Acquire
+            /// Release  | Release | Relaxed
+            /// AcqRel   | AcqRel  | Acquire
+            /// SeqCst   | SeqCst  | SeqCst
+            ///
+            /// `compare_exchange_weak` is allowed to fail spuriously even when the comparison succeeds,
+            /// which allows the compiler to generate better assembly code when the compare and swap
+            /// is used in a loop.
+            ///
+            /// # Examples
+            ///
+            /// ```
+            #[doc = concat!($extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};")]
+            ///
+            #[doc = concat!("let some_var = ", stringify!($atomic_type), "::new(5);")]
+            ///
+            /// assert_eq!(some_var.compare_and_swap(5, 10, Ordering::Relaxed), 5);
+            /// assert_eq!(some_var.load(Ordering::Relaxed), 10);
+            ///
+            /// assert_eq!(some_var.compare_and_swap(6, 12, Ordering::Relaxed), 10);
+            /// assert_eq!(some_var.load(Ordering::Relaxed), 10);
+            /// ```
+            #[inline]
+            #[$stable]
+            #[rustc_deprecated(
+                since = "1.50.0",
+                reason = "Use `compare_exchange` or `compare_exchange_weak` instead")
+            ]
+            #[$cfg_cas]
+            pub fn compare_and_swap(&self,
+                                    current: $int_type,
+                                    new: $int_type,
+                                    order: Ordering) -> $int_type {
+                match self.compare_exchange(current,
+                                            new,
+                                            order,
+                                            strongest_failure_ordering(order)) {
+                    Ok(x) => x,
+                    Err(x) => x,
                 }
             }
 
-            doc_comment! {
-                concat!("Stores a value into the atomic integer if the current value is the same as
-the `current` value.
-
-The return value is a result indicating whether the new value was written and
-containing the previous value. On success this value is guaranteed to be equal to
-`current`.
-
-`compare_exchange` takes two [`Ordering`] arguments to describe the memory
-ordering of this operation. The first describes the required ordering if the
-operation succeeds while the second describes the required ordering when the
-operation fails. Using [`Acquire`] as success ordering makes the store part
-of this operation [`Relaxed`], and using [`Release`] makes the successful load
-[`Relaxed`]. The failure ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`]
-and must be equivalent to or weaker than the success ordering.
-
-**Note**: This method is only available on platforms that support atomic
-operations on [`", $s_int_type, "`](", $int_ref, ").
-
-# Examples
-
-```
-", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};
-
-let some_var = ", stringify!($atomic_type), "::new(5);
-
-assert_eq!(some_var.compare_exchange(5, 10,
-                                     Ordering::Acquire,
-                                     Ordering::Relaxed),
-           Ok(5));
-assert_eq!(some_var.load(Ordering::Relaxed), 10);
-
-assert_eq!(some_var.compare_exchange(6, 12,
-                                     Ordering::SeqCst,
-                                     Ordering::Acquire),
-           Err(10));
-assert_eq!(some_var.load(Ordering::Relaxed), 10);
-```"),
-                #[inline]
-                #[$stable_cxchg]
-                #[$cfg_cas]
-                pub fn compare_exchange(&self,
-                                        current: $int_type,
-                                        new: $int_type,
-                                        success: Ordering,
-                                        failure: Ordering) -> Result<$int_type, $int_type> {
-                    // SAFETY: data races are prevented by atomic intrinsics.
-                    unsafe { atomic_compare_exchange(self.v.get(), current, new, success, failure) }
-                }
+            /// Stores a value into the atomic integer if the current value is the same as
+            /// the `current` value.
+            ///
+            /// The return value is a result indicating whether the new value was written and
+            /// containing the previous value. On success this value is guaranteed to be equal to
+            /// `current`.
+            ///
+            /// `compare_exchange` takes two [`Ordering`] arguments to describe the memory
+            /// ordering of this operation. `success` describes the required ordering for the
+            /// read-modify-write operation that takes place if the comparison with `current` succeeds.
+            /// `failure` describes the required ordering for the load operation that takes place when
+            /// the comparison fails. Using [`Acquire`] as success ordering makes the store part
+            /// of this operation [`Relaxed`], and using [`Release`] makes the successful load
+            /// [`Relaxed`]. The failure ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`]
+            /// and must be equivalent to or weaker than the success ordering.
+            ///
+            /// **Note**: This method is only available on platforms that support atomic operations on
+            #[doc = concat!("[`", $s_int_type, "`](", $int_ref, ").")]
+            ///
+            /// # Examples
+            ///
+            /// ```
+            #[doc = concat!($extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};")]
+            ///
+            #[doc = concat!("let some_var = ", stringify!($atomic_type), "::new(5);")]
+            ///
+            /// assert_eq!(some_var.compare_exchange(5, 10,
+            ///                                      Ordering::Acquire,
+            ///                                      Ordering::Relaxed),
+            ///            Ok(5));
+            /// assert_eq!(some_var.load(Ordering::Relaxed), 10);
+            ///
+            /// assert_eq!(some_var.compare_exchange(6, 12,
+            ///                                      Ordering::SeqCst,
+            ///                                      Ordering::Acquire),
+            ///            Err(10));
+            /// assert_eq!(some_var.load(Ordering::Relaxed), 10);
+            /// ```
+            #[inline]
+            #[$stable_cxchg]
+            #[$cfg_cas]
+            pub fn compare_exchange(&self,
+                                    current: $int_type,
+                                    new: $int_type,
+                                    success: Ordering,
+                                    failure: Ordering) -> Result<$int_type, $int_type> {
+                // SAFETY: data races are prevented by atomic intrinsics.
+                unsafe { atomic_compare_exchange(self.v.get(), current, new, success, failure) }
             }
 
-            doc_comment! {
-                concat!("Stores a value into the atomic integer if the current value is the same as
-the `current` value.
-
-Unlike [`", stringify!($atomic_type), "::compare_exchange`], this function is allowed to spuriously fail even
-when the comparison succeeds, which can result in more efficient code on some
-platforms. The return value is a result indicating whether the new value was
-written and containing the previous value.
-
-`compare_exchange_weak` takes two [`Ordering`] arguments to describe the memory
-ordering of this operation. The first describes the required ordering if the
-operation succeeds while the second describes the required ordering when the
-operation fails. Using [`Acquire`] as success ordering makes the store part
-of this operation [`Relaxed`], and using [`Release`] makes the successful load
-[`Relaxed`]. The failure ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`]
-and must be equivalent to or weaker than the success ordering.
-
-**Note**: This method is only available on platforms that support atomic
-operations on [`", $s_int_type, "`](", $int_ref, ").
-
-# Examples
-
-```
-", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};
-
-let val = ", stringify!($atomic_type), "::new(4);
-
-let mut old = val.load(Ordering::Relaxed);
-loop {
-    let new = old * 2;
-    match val.compare_exchange_weak(old, new, Ordering::SeqCst, Ordering::Relaxed) {
-        Ok(_) => break,
-        Err(x) => old = x,
-    }
-}
-```"),
-                #[inline]
-                #[$stable_cxchg]
-                #[$cfg_cas]
-                pub fn compare_exchange_weak(&self,
-                                             current: $int_type,
-                                             new: $int_type,
-                                             success: Ordering,
-                                             failure: Ordering) -> Result<$int_type, $int_type> {
-                    // SAFETY: data races are prevented by atomic intrinsics.
-                    unsafe {
-                        atomic_compare_exchange_weak(self.v.get(), current, new, success, failure)
-                    }
+            /// Stores a value into the atomic integer if the current value is the same as
+            /// the `current` value.
+            ///
+            #[doc = concat!("Unlike [`", stringify!($atomic_type), "::compare_exchange`],")]
+            /// this function is allowed to spuriously fail even
+            /// when the comparison succeeds, which can result in more efficient code on some
+            /// platforms. The return value is a result indicating whether the new value was
+            /// written and containing the previous value.
+            ///
+            /// `compare_exchange_weak` takes two [`Ordering`] arguments to describe the memory
+            /// ordering of this operation. `success` describes the required ordering for the
+            /// read-modify-write operation that takes place if the comparison with `current` succeeds.
+            /// `failure` describes the required ordering for the load operation that takes place when
+            /// the comparison fails. Using [`Acquire`] as success ordering makes the store part
+            /// of this operation [`Relaxed`], and using [`Release`] makes the successful load
+            /// [`Relaxed`]. The failure ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`]
+            /// and must be equivalent to or weaker than the success ordering.
+            ///
+            /// **Note**: This method is only available on platforms that support atomic operations on
+            #[doc = concat!("[`", $s_int_type, "`](", $int_ref, ").")]
+            ///
+            /// # Examples
+            ///
+            /// ```
+            #[doc = concat!($extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};")]
+            ///
+            #[doc = concat!("let val = ", stringify!($atomic_type), "::new(4);")]
+            ///
+            /// let mut old = val.load(Ordering::Relaxed);
+            /// loop {
+            ///     let new = old * 2;
+            ///     match val.compare_exchange_weak(old, new, Ordering::SeqCst, Ordering::Relaxed) {
+            ///         Ok(_) => break,
+            ///         Err(x) => old = x,
+            ///     }
+            /// }
+            /// ```
+            #[inline]
+            #[$stable_cxchg]
+            #[$cfg_cas]
+            pub fn compare_exchange_weak(&self,
+                                         current: $int_type,
+                                         new: $int_type,
+                                         success: Ordering,
+                                         failure: Ordering) -> Result<$int_type, $int_type> {
+                // SAFETY: data races are prevented by atomic intrinsics.
+                unsafe {
+                    atomic_compare_exchange_weak(self.v.get(), current, new, success, failure)
                 }
             }
 
-            doc_comment! {
-                concat!("Adds to the current value, returning the previous value.
-
-This operation wraps around on overflow.
-
-`fetch_add` takes an [`Ordering`] argument which describes the memory ordering
-of this operation. All ordering modes are possible. Note that using
-[`Acquire`] makes the store part of this operation [`Relaxed`], and
-using [`Release`] makes the load part [`Relaxed`].
-
-**Note**: This method is only available on platforms that support atomic
-operations on [`", $s_int_type, "`](", $int_ref, ").
-
-# Examples
-
-```
-", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};
-
-let foo = ", stringify!($atomic_type), "::new(0);
-assert_eq!(foo.fetch_add(10, Ordering::SeqCst), 0);
-assert_eq!(foo.load(Ordering::SeqCst), 10);
-```"),
-                #[inline]
-                #[$stable]
-                #[$cfg_cas]
-                pub fn fetch_add(&self, val: $int_type, order: Ordering) -> $int_type {
-                    // SAFETY: data races are prevented by atomic intrinsics.
-                    unsafe { atomic_add(self.v.get(), val, order) }
-                }
+            /// Adds to the current value, returning the previous value.
+            ///
+            /// This operation wraps around on overflow.
+            ///
+            /// `fetch_add` takes an [`Ordering`] argument which describes the memory ordering
+            /// of this operation. All ordering modes are possible. Note that using
+            /// [`Acquire`] makes the store part of this operation [`Relaxed`], and
+            /// using [`Release`] makes the load part [`Relaxed`].
+            ///
+            /// **Note**: This method is only available on platforms that support atomic operations on
+            #[doc = concat!("[`", $s_int_type, "`](", $int_ref, ").")]
+            ///
+            /// # Examples
+            ///
+            /// ```
+            #[doc = concat!($extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};")]
+            ///
+            #[doc = concat!("let foo = ", stringify!($atomic_type), "::new(0);")]
+            /// assert_eq!(foo.fetch_add(10, Ordering::SeqCst), 0);
+            /// assert_eq!(foo.load(Ordering::SeqCst), 10);
+            /// ```
+            #[inline]
+            #[$stable]
+            #[$cfg_cas]
+            pub fn fetch_add(&self, val: $int_type, order: Ordering) -> $int_type {
+                // SAFETY: data races are prevented by atomic intrinsics.
+                unsafe { atomic_add(self.v.get(), val, order) }
             }
 
-            doc_comment! {
-                concat!("Subtracts from the current value, returning the previous value.
-
-This operation wraps around on overflow.
-
-`fetch_sub` takes an [`Ordering`] argument which describes the memory ordering
-of this operation. All ordering modes are possible. Note that using
-[`Acquire`] makes the store part of this operation [`Relaxed`], and
-using [`Release`] makes the load part [`Relaxed`].
-
-**Note**: This method is only available on platforms that support atomic
-operations on [`", $s_int_type, "`](", $int_ref, ").
-
-# Examples
-
-```
-", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};
-
-let foo = ", stringify!($atomic_type), "::new(20);
-assert_eq!(foo.fetch_sub(10, Ordering::SeqCst), 20);
-assert_eq!(foo.load(Ordering::SeqCst), 10);
-```"),
-                #[inline]
-                #[$stable]
-                #[$cfg_cas]
-                pub fn fetch_sub(&self, val: $int_type, order: Ordering) -> $int_type {
-                    // SAFETY: data races are prevented by atomic intrinsics.
-                    unsafe { atomic_sub(self.v.get(), val, order) }
-                }
+            /// Subtracts from the current value, returning the previous value.
+            ///
+            /// This operation wraps around on overflow.
+            ///
+            /// `fetch_sub` takes an [`Ordering`] argument which describes the memory ordering
+            /// of this operation. All ordering modes are possible. Note that using
+            /// [`Acquire`] makes the store part of this operation [`Relaxed`], and
+            /// using [`Release`] makes the load part [`Relaxed`].
+            ///
+            /// **Note**: This method is only available on platforms that support atomic operations on
+            #[doc = concat!("[`", $s_int_type, "`](", $int_ref, ").")]
+            ///
+            /// # Examples
+            ///
+            /// ```
+            #[doc = concat!($extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};")]
+            ///
+            #[doc = concat!("let foo = ", stringify!($atomic_type), "::new(20);")]
+            /// assert_eq!(foo.fetch_sub(10, Ordering::SeqCst), 20);
+            /// assert_eq!(foo.load(Ordering::SeqCst), 10);
+            /// ```
+            #[inline]
+            #[$stable]
+            #[$cfg_cas]
+            pub fn fetch_sub(&self, val: $int_type, order: Ordering) -> $int_type {
+                // SAFETY: data races are prevented by atomic intrinsics.
+                unsafe { atomic_sub(self.v.get(), val, order) }
             }
 
-            doc_comment! {
-                concat!("Bitwise \"and\" with the current value.
-
-Performs a bitwise \"and\" operation on the current value and the argument `val`, and
-sets the new value to the result.
-
-Returns the previous value.
-
-`fetch_and` takes an [`Ordering`] argument which describes the memory ordering
-of this operation. All ordering modes are possible. Note that using
-[`Acquire`] makes the store part of this operation [`Relaxed`], and
-using [`Release`] makes the load part [`Relaxed`].
-
-**Note**: This method is only available on platforms that support atomic
-operations on [`", $s_int_type, "`](", $int_ref, ").
-
-# Examples
-
-```
-", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};
-
-let foo = ", stringify!($atomic_type), "::new(0b101101);
-assert_eq!(foo.fetch_and(0b110011, Ordering::SeqCst), 0b101101);
-assert_eq!(foo.load(Ordering::SeqCst), 0b100001);
-```"),
-                #[inline]
-                #[$stable]
-                #[$cfg_cas]
-                pub fn fetch_and(&self, val: $int_type, order: Ordering) -> $int_type {
-                    // SAFETY: data races are prevented by atomic intrinsics.
-                    unsafe { atomic_and(self.v.get(), val, order) }
-                }
+            /// Bitwise "and" with the current value.
+            ///
+            /// Performs a bitwise "and" operation on the current value and the argument `val`, and
+            /// sets the new value to the result.
+            ///
+            /// Returns the previous value.
+            ///
+            /// `fetch_and` takes an [`Ordering`] argument which describes the memory ordering
+            /// of this operation. All ordering modes are possible. Note that using
+            /// [`Acquire`] makes the store part of this operation [`Relaxed`], and
+            /// using [`Release`] makes the load part [`Relaxed`].
+            ///
+            /// **Note**: This method is only available on platforms that support atomic operations on
+            #[doc = concat!("[`", $s_int_type, "`](", $int_ref, ").")]
+            ///
+            /// # Examples
+            ///
+            /// ```
+            #[doc = concat!($extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};")]
+            ///
+            #[doc = concat!("let foo = ", stringify!($atomic_type), "::new(0b101101);")]
+            /// assert_eq!(foo.fetch_and(0b110011, Ordering::SeqCst), 0b101101);
+            /// assert_eq!(foo.load(Ordering::SeqCst), 0b100001);
+            /// ```
+            #[inline]
+            #[$stable]
+            #[$cfg_cas]
+            pub fn fetch_and(&self, val: $int_type, order: Ordering) -> $int_type {
+                // SAFETY: data races are prevented by atomic intrinsics.
+                unsafe { atomic_and(self.v.get(), val, order) }
             }
 
-            doc_comment! {
-                concat!("Bitwise \"nand\" with the current value.
-
-Performs a bitwise \"nand\" operation on the current value and the argument `val`, and
-sets the new value to the result.
-
-Returns the previous value.
-
-`fetch_nand` takes an [`Ordering`] argument which describes the memory ordering
-of this operation. All ordering modes are possible. Note that using
-[`Acquire`] makes the store part of this operation [`Relaxed`], and
-using [`Release`] makes the load part [`Relaxed`].
-
-**Note**: This method is only available on platforms that support atomic
-operations on [`", $s_int_type, "`](", $int_ref, ").
-
-# Examples
-
-```
-", $extra_feature, "
-use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};
-
-let foo = ", stringify!($atomic_type), "::new(0x13);
-assert_eq!(foo.fetch_nand(0x31, Ordering::SeqCst), 0x13);
-assert_eq!(foo.load(Ordering::SeqCst), !(0x13 & 0x31));
-```"),
-                #[inline]
-                #[$stable_nand]
-                #[$cfg_cas]
-                pub fn fetch_nand(&self, val: $int_type, order: Ordering) -> $int_type {
-                    // SAFETY: data races are prevented by atomic intrinsics.
-                    unsafe { atomic_nand(self.v.get(), val, order) }
-                }
+            /// Bitwise "nand" with the current value.
+            ///
+            /// Performs a bitwise "nand" operation on the current value and the argument `val`, and
+            /// sets the new value to the result.
+            ///
+            /// Returns the previous value.
+            ///
+            /// `fetch_nand` takes an [`Ordering`] argument which describes the memory ordering
+            /// of this operation. All ordering modes are possible. Note that using
+            /// [`Acquire`] makes the store part of this operation [`Relaxed`], and
+            /// using [`Release`] makes the load part [`Relaxed`].
+            ///
+            /// **Note**: This method is only available on platforms that support atomic operations on
+            #[doc = concat!("[`", $s_int_type, "`](", $int_ref, ").")]
+            ///
+            /// # Examples
+            ///
+            /// ```
+            #[doc = concat!($extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};")]
+            ///
+            #[doc = concat!("let foo = ", stringify!($atomic_type), "::new(0x13);")]
+            /// assert_eq!(foo.fetch_nand(0x31, Ordering::SeqCst), 0x13);
+            /// assert_eq!(foo.load(Ordering::SeqCst), !(0x13 & 0x31));
+            /// ```
+            #[inline]
+            #[$stable_nand]
+            #[$cfg_cas]
+            pub fn fetch_nand(&self, val: $int_type, order: Ordering) -> $int_type {
+                // SAFETY: data races are prevented by atomic intrinsics.
+                unsafe { atomic_nand(self.v.get(), val, order) }
             }
 
-            doc_comment! {
-                concat!("Bitwise \"or\" with the current value.
-
-Performs a bitwise \"or\" operation on the current value and the argument `val`, and
-sets the new value to the result.
-
-Returns the previous value.
-
-`fetch_or` takes an [`Ordering`] argument which describes the memory ordering
-of this operation. All ordering modes are possible. Note that using
-[`Acquire`] makes the store part of this operation [`Relaxed`], and
-using [`Release`] makes the load part [`Relaxed`].
-
-**Note**: This method is only available on platforms that support atomic
-operations on [`", $s_int_type, "`](", $int_ref, ").
-
-# Examples
-
-```
-", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};
-
-let foo = ", stringify!($atomic_type), "::new(0b101101);
-assert_eq!(foo.fetch_or(0b110011, Ordering::SeqCst), 0b101101);
-assert_eq!(foo.load(Ordering::SeqCst), 0b111111);
-```"),
-                #[inline]
-                #[$stable]
-                #[$cfg_cas]
-                pub fn fetch_or(&self, val: $int_type, order: Ordering) -> $int_type {
-                    // SAFETY: data races are prevented by atomic intrinsics.
-                    unsafe { atomic_or(self.v.get(), val, order) }
-                }
+            /// Bitwise "or" with the current value.
+            ///
+            /// Performs a bitwise "or" operation on the current value and the argument `val`, and
+            /// sets the new value to the result.
+            ///
+            /// Returns the previous value.
+            ///
+            /// `fetch_or` takes an [`Ordering`] argument which describes the memory ordering
+            /// of this operation. All ordering modes are possible. Note that using
+            /// [`Acquire`] makes the store part of this operation [`Relaxed`], and
+            /// using [`Release`] makes the load part [`Relaxed`].
+            ///
+            /// **Note**: This method is only available on platforms that support atomic operations on
+            #[doc = concat!("[`", $s_int_type, "`](", $int_ref, ").")]
+            ///
+            /// # Examples
+            ///
+            /// ```
+            #[doc = concat!($extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};")]
+            ///
+            #[doc = concat!("let foo = ", stringify!($atomic_type), "::new(0b101101);")]
+            /// assert_eq!(foo.fetch_or(0b110011, Ordering::SeqCst), 0b101101);
+            /// assert_eq!(foo.load(Ordering::SeqCst), 0b111111);
+            /// ```
+            #[inline]
+            #[$stable]
+            #[$cfg_cas]
+            pub fn fetch_or(&self, val: $int_type, order: Ordering) -> $int_type {
+                // SAFETY: data races are prevented by atomic intrinsics.
+                unsafe { atomic_or(self.v.get(), val, order) }
             }
 
-            doc_comment! {
-                concat!("Bitwise \"xor\" with the current value.
-
-Performs a bitwise \"xor\" operation on the current value and the argument `val`, and
-sets the new value to the result.
-
-Returns the previous value.
-
-`fetch_xor` takes an [`Ordering`] argument which describes the memory ordering
-of this operation. All ordering modes are possible. Note that using
-[`Acquire`] makes the store part of this operation [`Relaxed`], and
-using [`Release`] makes the load part [`Relaxed`].
-
-**Note**: This method is only available on platforms that support atomic
-operations on [`", $s_int_type, "`](", $int_ref, ").
-
-# Examples
-
-```
-", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};
-
-let foo = ", stringify!($atomic_type), "::new(0b101101);
-assert_eq!(foo.fetch_xor(0b110011, Ordering::SeqCst), 0b101101);
-assert_eq!(foo.load(Ordering::SeqCst), 0b011110);
-```"),
-                #[inline]
-                #[$stable]
-                #[$cfg_cas]
-                pub fn fetch_xor(&self, val: $int_type, order: Ordering) -> $int_type {
-                    // SAFETY: data races are prevented by atomic intrinsics.
-                    unsafe { atomic_xor(self.v.get(), val, order) }
-                }
+            /// Bitwise "xor" with the current value.
+            ///
+            /// Performs a bitwise "xor" operation on the current value and the argument `val`, and
+            /// sets the new value to the result.
+            ///
+            /// Returns the previous value.
+            ///
+            /// `fetch_xor` takes an [`Ordering`] argument which describes the memory ordering
+            /// of this operation. All ordering modes are possible. Note that using
+            /// [`Acquire`] makes the store part of this operation [`Relaxed`], and
+            /// using [`Release`] makes the load part [`Relaxed`].
+            ///
+            /// **Note**: This method is only available on platforms that support atomic operations on
+            #[doc = concat!("[`", $s_int_type, "`](", $int_ref, ").")]
+            ///
+            /// # Examples
+            ///
+            /// ```
+            #[doc = concat!($extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};")]
+            ///
+            #[doc = concat!("let foo = ", stringify!($atomic_type), "::new(0b101101);")]
+            /// assert_eq!(foo.fetch_xor(0b110011, Ordering::SeqCst), 0b101101);
+            /// assert_eq!(foo.load(Ordering::SeqCst), 0b011110);
+            /// ```
+            #[inline]
+            #[$stable]
+            #[$cfg_cas]
+            pub fn fetch_xor(&self, val: $int_type, order: Ordering) -> $int_type {
+                // SAFETY: data races are prevented by atomic intrinsics.
+                unsafe { atomic_xor(self.v.get(), val, order) }
             }
 
-            doc_comment! {
-                concat!("Fetches the value, and applies a function to it that returns an optional
-new value. Returns a `Result` of `Ok(previous_value)` if the function returned `Some(_)`, else
-`Err(previous_value)`.
-
-Note: This may call the function multiple times if the value has been changed from other threads in
-the meantime, as long as the function returns `Some(_)`, but the function will have been applied
-only once to the stored value.
-
-`fetch_update` takes two [`Ordering`] arguments to describe the memory ordering of this operation.
-The first describes the required ordering for when the operation finally succeeds while the second
-describes the required ordering for loads. These correspond to the success and failure orderings of
-[`", stringify!($atomic_type), "::compare_exchange`] respectively.
-
-Using [`Acquire`] as success ordering makes the store part
-of this operation [`Relaxed`], and using [`Release`] makes the final successful load
-[`Relaxed`]. The (failed) load ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`]
-and must be equivalent to or weaker than the success ordering.
-
-**Note**: This method is only available on platforms that support atomic
-operations on [`", $s_int_type, "`](", $int_ref, ").
-
-# Examples
-
-```rust
-", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};
-
-let x = ", stringify!($atomic_type), "::new(7);
-assert_eq!(x.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |_| None), Err(7));
-assert_eq!(x.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |x| Some(x + 1)), Ok(7));
-assert_eq!(x.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |x| Some(x + 1)), Ok(8));
-assert_eq!(x.load(Ordering::SeqCst), 9);
-```"),
-                #[inline]
-                #[stable(feature = "no_more_cas", since = "1.45.0")]
-                #[$cfg_cas]
-                pub fn fetch_update<F>(&self,
-                                       set_order: Ordering,
-                                       fetch_order: Ordering,
-                                       mut f: F) -> Result<$int_type, $int_type>
-                where F: FnMut($int_type) -> Option<$int_type> {
-                    let mut prev = self.load(fetch_order);
-                    while let Some(next) = f(prev) {
-                        match self.compare_exchange_weak(prev, next, set_order, fetch_order) {
-                            x @ Ok(_) => return x,
-                            Err(next_prev) => prev = next_prev
-                        }
+            /// Fetches the value, and applies a function to it that returns an optional
+            /// new value. Returns a `Result` of `Ok(previous_value)` if the function returned `Some(_)`, else
+            /// `Err(previous_value)`.
+            ///
+            /// Note: This may call the function multiple times if the value has been changed from other threads in
+            /// the meantime, as long as the function returns `Some(_)`, but the function will have been applied
+            /// only once to the stored value.
+            ///
+            /// `fetch_update` takes two [`Ordering`] arguments to describe the memory ordering of this operation.
+            /// The first describes the required ordering for when the operation finally succeeds while the second
+            /// describes the required ordering for loads. These correspond to the success and failure orderings of
+            #[doc = concat!("[`", stringify!($atomic_type), "::compare_exchange`]")]
+            /// respectively.
+            ///
+            /// Using [`Acquire`] as success ordering makes the store part
+            /// of this operation [`Relaxed`], and using [`Release`] makes the final successful load
+            /// [`Relaxed`]. The (failed) load ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`]
+            /// and must be equivalent to or weaker than the success ordering.
+            ///
+            /// **Note**: This method is only available on platforms that support atomic operations on
+            #[doc = concat!("[`", $s_int_type, "`](", $int_ref, ").")]
+            ///
+            /// # Examples
+            ///
+            /// ```rust
+            #[doc = concat!($extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};")]
+            ///
+            #[doc = concat!("let x = ", stringify!($atomic_type), "::new(7);")]
+            /// assert_eq!(x.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |_| None), Err(7));
+            /// assert_eq!(x.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |x| Some(x + 1)), Ok(7));
+            /// assert_eq!(x.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |x| Some(x + 1)), Ok(8));
+            /// assert_eq!(x.load(Ordering::SeqCst), 9);
+            /// ```
+            #[inline]
+            #[stable(feature = "no_more_cas", since = "1.45.0")]
+            #[$cfg_cas]
+            pub fn fetch_update<F>(&self,
+                                   set_order: Ordering,
+                                   fetch_order: Ordering,
+                                   mut f: F) -> Result<$int_type, $int_type>
+            where F: FnMut($int_type) -> Option<$int_type> {
+                let mut prev = self.load(fetch_order);
+                while let Some(next) = f(prev) {
+                    match self.compare_exchange_weak(prev, next, set_order, fetch_order) {
+                        x @ Ok(_) => return x,
+                        Err(next_prev) => prev = next_prev
                     }
-                    Err(prev)
                 }
+                Err(prev)
             }
 
-            doc_comment! {
-                concat!("Maximum with the current value.
-
-Finds the maximum of the current value and the argument `val`, and
-sets the new value to the result.
-
-Returns the previous value.
-
-`fetch_max` takes an [`Ordering`] argument which describes the memory ordering
-of this operation. All ordering modes are possible. Note that using
-[`Acquire`] makes the store part of this operation [`Relaxed`], and
-using [`Release`] makes the load part [`Relaxed`].
-
-**Note**: This method is only available on platforms that support atomic
-operations on [`", $s_int_type, "`](", $int_ref, ").
-
-# Examples
-
-```
-", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};
-
-let foo = ", stringify!($atomic_type), "::new(23);
-assert_eq!(foo.fetch_max(42, Ordering::SeqCst), 23);
-assert_eq!(foo.load(Ordering::SeqCst), 42);
-```
-
-If you want to obtain the maximum value in one step, you can use the following:
-
-```
-", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};
-
-let foo = ", stringify!($atomic_type), "::new(23);
-let bar = 42;
-let max_foo = foo.fetch_max(bar, Ordering::SeqCst).max(bar);
-assert!(max_foo == 42);
-```"),
-                #[inline]
-                #[stable(feature = "atomic_min_max", since = "1.45.0")]
-                #[$cfg_cas]
-                pub fn fetch_max(&self, val: $int_type, order: Ordering) -> $int_type {
-                    // SAFETY: data races are prevented by atomic intrinsics.
-                    unsafe { $max_fn(self.v.get(), val, order) }
-                }
+            /// Maximum with the current value.
+            ///
+            /// Finds the maximum of the current value and the argument `val`, and
+            /// sets the new value to the result.
+            ///
+            /// Returns the previous value.
+            ///
+            /// `fetch_max` takes an [`Ordering`] argument which describes the memory ordering
+            /// of this operation. All ordering modes are possible. Note that using
+            /// [`Acquire`] makes the store part of this operation [`Relaxed`], and
+            /// using [`Release`] makes the load part [`Relaxed`].
+            ///
+            /// **Note**: This method is only available on platforms that support atomic operations on
+            #[doc = concat!("[`", $s_int_type, "`](", $int_ref, ").")]
+            ///
+            /// # Examples
+            ///
+            /// ```
+            #[doc = concat!($extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};")]
+            ///
+            #[doc = concat!("let foo = ", stringify!($atomic_type), "::new(23);")]
+            /// assert_eq!(foo.fetch_max(42, Ordering::SeqCst), 23);
+            /// assert_eq!(foo.load(Ordering::SeqCst), 42);
+            /// ```
+            ///
+            /// If you want to obtain the maximum value in one step, you can use the following:
+            ///
+            /// ```
+            #[doc = concat!($extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};")]
+            ///
+            #[doc = concat!("let foo = ", stringify!($atomic_type), "::new(23);")]
+            /// let bar = 42;
+            /// let max_foo = foo.fetch_max(bar, Ordering::SeqCst).max(bar);
+            /// assert!(max_foo == 42);
+            /// ```
+            #[inline]
+            #[stable(feature = "atomic_min_max", since = "1.45.0")]
+            #[$cfg_cas]
+            pub fn fetch_max(&self, val: $int_type, order: Ordering) -> $int_type {
+                // SAFETY: data races are prevented by atomic intrinsics.
+                unsafe { $max_fn(self.v.get(), val, order) }
             }
 
-            doc_comment! {
-                concat!("Minimum with the current value.
-
-Finds the minimum of the current value and the argument `val`, and
-sets the new value to the result.
-
-Returns the previous value.
-
-`fetch_min` takes an [`Ordering`] argument which describes the memory ordering
-of this operation. All ordering modes are possible. Note that using
-[`Acquire`] makes the store part of this operation [`Relaxed`], and
-using [`Release`] makes the load part [`Relaxed`].
-
-**Note**: This method is only available on platforms that support atomic
-operations on [`", $s_int_type, "`](", $int_ref, ").
-
-# Examples
-
-```
-", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};
-
-let foo = ", stringify!($atomic_type), "::new(23);
-assert_eq!(foo.fetch_min(42, Ordering::Relaxed), 23);
-assert_eq!(foo.load(Ordering::Relaxed), 23);
-assert_eq!(foo.fetch_min(22, Ordering::Relaxed), 23);
-assert_eq!(foo.load(Ordering::Relaxed), 22);
-```
-
-If you want to obtain the minimum value in one step, you can use the following:
-
-```
-", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};
-
-let foo = ", stringify!($atomic_type), "::new(23);
-let bar = 12;
-let min_foo = foo.fetch_min(bar, Ordering::SeqCst).min(bar);
-assert_eq!(min_foo, 12);
-```"),
-                #[inline]
-                #[stable(feature = "atomic_min_max", since = "1.45.0")]
-                #[$cfg_cas]
-                pub fn fetch_min(&self, val: $int_type, order: Ordering) -> $int_type {
-                    // SAFETY: data races are prevented by atomic intrinsics.
-                    unsafe { $min_fn(self.v.get(), val, order) }
-                }
+            /// Minimum with the current value.
+            ///
+            /// Finds the minimum of the current value and the argument `val`, and
+            /// sets the new value to the result.
+            ///
+            /// Returns the previous value.
+            ///
+            /// `fetch_min` takes an [`Ordering`] argument which describes the memory ordering
+            /// of this operation. All ordering modes are possible. Note that using
+            /// [`Acquire`] makes the store part of this operation [`Relaxed`], and
+            /// using [`Release`] makes the load part [`Relaxed`].
+            ///
+            /// **Note**: This method is only available on platforms that support atomic operations on
+            #[doc = concat!("[`", $s_int_type, "`](", $int_ref, ").")]
+            ///
+            /// # Examples
+            ///
+            /// ```
+            #[doc = concat!($extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};")]
+            ///
+            #[doc = concat!("let foo = ", stringify!($atomic_type), "::new(23);")]
+            /// assert_eq!(foo.fetch_min(42, Ordering::Relaxed), 23);
+            /// assert_eq!(foo.load(Ordering::Relaxed), 23);
+            /// assert_eq!(foo.fetch_min(22, Ordering::Relaxed), 23);
+            /// assert_eq!(foo.load(Ordering::Relaxed), 22);
+            /// ```
+            ///
+            /// If you want to obtain the minimum value in one step, you can use the following:
+            ///
+            /// ```
+            #[doc = concat!($extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};")]
+            ///
+            #[doc = concat!("let foo = ", stringify!($atomic_type), "::new(23);")]
+            /// let bar = 12;
+            /// let min_foo = foo.fetch_min(bar, Ordering::SeqCst).min(bar);
+            /// assert_eq!(min_foo, 12);
+            /// ```
+            #[inline]
+            #[stable(feature = "atomic_min_max", since = "1.45.0")]
+            #[$cfg_cas]
+            pub fn fetch_min(&self, val: $int_type, order: Ordering) -> $int_type {
+                // SAFETY: data races are prevented by atomic intrinsics.
+                unsafe { $min_fn(self.v.get(), val, order) }
             }
 
-            doc_comment! {
-                concat!("Returns a mutable pointer to the underlying integer.
-
-Doing non-atomic reads and writes on the resulting integer can be a data race.
-This method is mostly useful for FFI, where the function signature may use
-`*mut ", stringify!($int_type), "` instead of `&", stringify!($atomic_type), "`.
-
-Returning an `*mut` pointer from a shared reference to this atomic is safe because the
-atomic types work with interior mutability. All modifications of an atomic change the value
-through a shared reference, and can do so safely as long as they use atomic operations. Any
-use of the returned raw pointer requires an `unsafe` block and still has to uphold the same
-restriction: operations on it must be atomic.
-
-# Examples
-
-```ignore (extern-declaration)
-# fn main() {
-", $extra_feature, "use std::sync::atomic::", stringify!($atomic_type), ";
-
-extern {
-    fn my_atomic_op(arg: *mut ", stringify!($int_type), ");
-}
-
-let mut atomic = ", stringify!($atomic_type), "::new(1);
-",
-// SAFETY: Safe as long as `my_atomic_op` is atomic.
-"unsafe {
-    my_atomic_op(atomic.as_mut_ptr());
-}
-# }
-```"),
-                #[inline]
-                #[unstable(feature = "atomic_mut_ptr",
-                       reason = "recently added",
-                       issue = "66893")]
-                pub fn as_mut_ptr(&self) -> *mut $int_type {
-                    self.v.get()
-                }
+            /// Returns a mutable pointer to the underlying integer.
+            ///
+            /// Doing non-atomic reads and writes on the resulting integer can be a data race.
+            /// This method is mostly useful for FFI, where the function signature may use
+            #[doc = concat!("`*mut ", stringify!($int_type), "` instead of `&", stringify!($atomic_type), "`.")]
+            ///
+            /// Returning an `*mut` pointer from a shared reference to this atomic is safe because the
+            /// atomic types work with interior mutability. All modifications of an atomic change the value
+            /// through a shared reference, and can do so safely as long as they use atomic operations. Any
+            /// use of the returned raw pointer requires an `unsafe` block and still has to uphold the same
+            /// restriction: operations on it must be atomic.
+            ///
+            /// # Examples
+            ///
+            /// ```ignore (extern-declaration)
+            /// # fn main() {
+            #[doc = concat!($extra_feature, "use std::sync::atomic::", stringify!($atomic_type), ";")]
+            ///
+            /// extern {
+            #[doc = concat!("    fn my_atomic_op(arg: *mut ", stringify!($int_type), ");")]
+            /// }
+            ///
+            #[doc = concat!("let mut atomic = ", stringify!($atomic_type), "::new(1);")]
+            ///
+            // SAFETY: Safe as long as `my_atomic_op` is atomic.
+            /// unsafe {
+            ///     my_atomic_op(atomic.as_mut_ptr());
+            /// }
+            /// # }
+            /// ```
+            #[inline]
+            #[unstable(feature = "atomic_mut_ptr",
+                   reason = "recently added",
+                   issue = "66893")]
+            pub fn as_mut_ptr(&self) -> *mut $int_type {
+                self.v.get()
             }
         }
     }
index 75528ebb54eafdeebef52ac4d6c0030739ad3868..2d1e4496aeef7496cad65c4b2c429ef348fa3306 100644 (file)
@@ -4,11 +4,11 @@
 #[test]
 fn bool_() {
     let a = AtomicBool::new(false);
-    assert_eq!(a.compare_and_swap(false, true, SeqCst), false);
-    assert_eq!(a.compare_and_swap(false, true, SeqCst), true);
+    assert_eq!(a.compare_exchange(false, true, SeqCst, SeqCst), Ok(false));
+    assert_eq!(a.compare_exchange(false, true, SeqCst, SeqCst), Err(true));
 
     a.store(false, SeqCst);
-    assert_eq!(a.compare_and_swap(false, true, SeqCst), false);
+    assert_eq!(a.compare_exchange(false, true, SeqCst, SeqCst), Ok(false));
 }
 
 #[test]
diff --git a/library/core/tests/const_ptr.rs b/library/core/tests/const_ptr.rs
new file mode 100644 (file)
index 0000000..4acd059
--- /dev/null
@@ -0,0 +1,51 @@
+// Aligned to two bytes
+const DATA: [u16; 2] = [u16::from_ne_bytes([0x01, 0x23]), u16::from_ne_bytes([0x45, 0x67])];
+
+const fn unaligned_ptr() -> *const u16 {
+    // Since DATA.as_ptr() is aligned to two bytes, adding 1 byte to that produces an unaligned *const u16
+    unsafe { (DATA.as_ptr() as *const u8).add(1) as *const u16 }
+}
+
+#[test]
+fn read() {
+    use core::ptr;
+
+    const FOO: i32 = unsafe { ptr::read(&42 as *const i32) };
+    assert_eq!(FOO, 42);
+
+    const ALIGNED: i32 = unsafe { ptr::read_unaligned(&42 as *const i32) };
+    assert_eq!(ALIGNED, 42);
+
+    const UNALIGNED_PTR: *const u16 = unaligned_ptr();
+
+    const UNALIGNED: u16 = unsafe { ptr::read_unaligned(UNALIGNED_PTR) };
+    assert_eq!(UNALIGNED, u16::from_ne_bytes([0x23, 0x45]));
+}
+
+#[test]
+fn const_ptr_read() {
+    const FOO: i32 = unsafe { (&42 as *const i32).read() };
+    assert_eq!(FOO, 42);
+
+    const ALIGNED: i32 = unsafe { (&42 as *const i32).read_unaligned() };
+    assert_eq!(ALIGNED, 42);
+
+    const UNALIGNED_PTR: *const u16 = unaligned_ptr();
+
+    const UNALIGNED: u16 = unsafe { UNALIGNED_PTR.read_unaligned() };
+    assert_eq!(UNALIGNED, u16::from_ne_bytes([0x23, 0x45]));
+}
+
+#[test]
+fn mut_ptr_read() {
+    const FOO: i32 = unsafe { (&42 as *const i32 as *mut i32).read() };
+    assert_eq!(FOO, 42);
+
+    const ALIGNED: i32 = unsafe { (&42 as *const i32 as *mut i32).read_unaligned() };
+    assert_eq!(ALIGNED, 42);
+
+    const UNALIGNED_PTR: *mut u16 = unaligned_ptr() as *mut u16;
+
+    const UNALIGNED: u16 = unsafe { UNALIGNED_PTR.read_unaligned() };
+    assert_eq!(UNALIGNED, u16::from_ne_bytes([0x23, 0x45]));
+}
index ec4b49da384c3da21c29feda2540d12704f16d32..7376e7848eff540a50832bf8a6eea4e1cdc08639 100644 (file)
@@ -3505,3 +3505,85 @@ pub fn extend_for_unit() {
     }
     assert_eq!(x, 5);
 }
+
+#[test]
+fn test_intersperse() {
+    let xs = ["a", "", "b", "c"];
+    let v: Vec<&str> = xs.iter().map(|x| x.clone()).intersperse(", ").collect();
+    let text: String = v.concat();
+    assert_eq!(text, "a, , b, c".to_string());
+
+    let ys = [0, 1, 2, 3];
+    let mut it = ys[..0].iter().map(|x| *x).intersperse(1);
+    assert!(it.next() == None);
+}
+
+#[test]
+fn test_intersperse_size_hint() {
+    let xs = ["a", "", "b", "c"];
+    let mut iter = xs.iter().map(|x| x.clone()).intersperse(", ");
+    assert_eq!(iter.size_hint(), (7, Some(7)));
+
+    assert_eq!(iter.next(), Some("a"));
+    assert_eq!(iter.size_hint(), (6, Some(6)));
+    assert_eq!(iter.next(), Some(", "));
+    assert_eq!(iter.size_hint(), (5, Some(5)));
+
+    assert_eq!([].iter().intersperse(&()).size_hint(), (0, Some(0)));
+}
+
+#[test]
+fn test_fold_specialization_intersperse() {
+    let mut iter = (1..2).intersperse(0);
+    iter.clone().for_each(|x| assert_eq!(Some(x), iter.next()));
+
+    let mut iter = (1..3).intersperse(0);
+    iter.clone().for_each(|x| assert_eq!(Some(x), iter.next()));
+
+    let mut iter = (1..4).intersperse(0);
+    iter.clone().for_each(|x| assert_eq!(Some(x), iter.next()));
+}
+
+#[test]
+fn test_try_fold_specialization_intersperse_ok() {
+    let mut iter = (1..2).intersperse(0);
+    iter.clone().try_for_each(|x| {
+        assert_eq!(Some(x), iter.next());
+        Some(())
+    });
+
+    let mut iter = (1..3).intersperse(0);
+    iter.clone().try_for_each(|x| {
+        assert_eq!(Some(x), iter.next());
+        Some(())
+    });
+
+    let mut iter = (1..4).intersperse(0);
+    iter.clone().try_for_each(|x| {
+        assert_eq!(Some(x), iter.next());
+        Some(())
+    });
+}
+
+#[test]
+fn test_try_fold_specialization_intersperse_err() {
+    let orig_iter = ["a", "b"].iter().copied().intersperse("-");
+
+    // Abort after the first item.
+    let mut iter = orig_iter.clone();
+    iter.try_for_each(|_| None::<()>);
+    assert_eq!(iter.next(), Some("-"));
+    assert_eq!(iter.next(), Some("b"));
+    assert_eq!(iter.next(), None);
+
+    // Abort after the second item.
+    let mut iter = orig_iter.clone();
+    iter.try_for_each(|item| if item == "-" { None } else { Some(()) });
+    assert_eq!(iter.next(), Some("b"));
+    assert_eq!(iter.next(), None);
+
+    // Abort after the third item.
+    let mut iter = orig_iter.clone();
+    iter.try_for_each(|item| if item == "b" { None } else { Some(()) });
+    assert_eq!(iter.next(), None);
+}
index 2828235c3e38deb237f572f949f359421d0aedaf..fba3294e0bbdb1f5fdf3e3efef9fbc1d4dc23b7e 100644 (file)
@@ -13,6 +13,8 @@
 #![feature(const_assume)]
 #![feature(const_cell_into_inner)]
 #![feature(const_maybe_uninit_assume_init)]
+#![feature(const_ptr_read)]
+#![feature(const_ptr_offset)]
 #![feature(core_intrinsics)]
 #![feature(core_private_bignum)]
 #![feature(core_private_diy_float)]
@@ -34,6 +36,7 @@
 #![feature(raw)]
 #![feature(sort_internals)]
 #![feature(slice_partition_at_index)]
+#![feature(maybe_uninit_extra)]
 #![feature(maybe_uninit_write_slice)]
 #![feature(min_specialization)]
 #![feature(step_trait)]
@@ -48,6 +51,7 @@
 #![feature(array_value_iter)]
 #![feature(iter_advance_by)]
 #![feature(iter_partition_in_place)]
+#![feature(iter_intersperse)]
 #![feature(iter_is_partitioned)]
 #![feature(iter_order_by)]
 #![feature(cmp_min_max_by)]
 mod char;
 mod clone;
 mod cmp;
+
+#[cfg(not(bootstrap))]
+mod const_ptr;
+
 mod fmt;
 mod hash;
 mod intrinsics;
index 5d0fedd4d9ccc2676fa063c6e6e7ff9c42ba8fcd..79ca2bba40388a830bb15e5fa2244eb3856e302e 100644 (file)
@@ -134,7 +134,6 @@ fn is_send_sync<T: Send + Sync>() {}
 }
 
 #[test]
-#[cfg(not(bootstrap))]
 fn assume_init_good() {
     const TRUE: bool = unsafe { MaybeUninit::<bool>::new(true).assume_init() };
 
@@ -267,3 +266,10 @@ fn drop(&mut self) {
 
     forget(src);
 }
+
+#[test]
+#[cfg(not(bootstrap))]
+fn uninit_const_assume_init_read() {
+    const FOO: u32 = unsafe { MaybeUninit::new(42).assume_init_read() };
+    assert_eq!(FOO, 42);
+}
index b66c482c5e5e37622cc60a17850395e9409aa647..c2c08522d0cae13d058b3f32d94f0040d071cb9b 100644 (file)
@@ -312,3 +312,19 @@ fn nonzero_trailing_zeros() {
     const TRAILING_ZEROS: u32 = NonZeroU16::new(1 << 2).unwrap().trailing_zeros();
     assert_eq!(TRAILING_ZEROS, 2);
 }
+
+#[test]
+fn test_nonzero_uint_div() {
+    let nz = NonZeroU32::new(1).unwrap();
+
+    let x: u32 = 42u32 / nz;
+    assert_eq!(x, 42u32);
+}
+
+#[test]
+fn test_nonzero_uint_rem() {
+    let nz = NonZeroU32::new(10).unwrap();
+
+    let x: u32 = 42u32 % nz;
+    assert_eq!(x, 2u32);
+}
index a8ebb4b3219f79601c10a91feb431dd43317eb7d..eb2277d8baacde22ad18f6c83d881a11773b5432 100644 (file)
 #![feature(core_intrinsics)]
 #![feature(nll)]
 #![feature(panic_runtime)]
+#![feature(std_internals)]
 #![feature(staged_api)]
 #![feature(rustc_attrs)]
 #![feature(asm)]
 
 use core::any::Any;
+use core::panic::BoxMeUp;
 
 #[rustc_std_internal_symbol]
 #[allow(improper_ctypes_definitions)]
@@ -28,7 +30,7 @@
 
 // "Leak" the payload and shim to the relevant abort on the platform in question.
 #[rustc_std_internal_symbol]
-pub unsafe extern "C" fn __rust_start_panic(_payload: usize) -> u32 {
+pub unsafe extern "C" fn __rust_start_panic(_payload: *mut &mut dyn BoxMeUp) -> u32 {
     abort();
 
     cfg_if::cfg_if! {
index 0b74a844fec6ee6d828f2bbd89161a1adb6b41ac..9ce9c477ec0f0ae18f8722fb6062ab0d1d936b6d 100644 (file)
 // implementation.
 #[rustc_std_internal_symbol]
 #[unwind(allowed)]
-pub unsafe extern "C" fn __rust_start_panic(payload: usize) -> u32 {
-    let payload = payload as *mut &mut dyn BoxMeUp;
-    let payload = (*payload).take_box();
+pub unsafe extern "C" fn __rust_start_panic(payload: *mut &mut dyn BoxMeUp) -> u32 {
+    let payload = Box::from_raw((*payload).take_box());
 
-    imp::panic(Box::from_raw(payload))
+    imp::panic(payload)
 }
index ca40293ed58214abacbe24e1688a5d0dd53ffa26..a89e7b53e43c4fbc1c0b06cad12a16fd58b458eb 100644 (file)
@@ -28,8 +28,7 @@
 #![feature(extern_types)]
 #![feature(in_band_lifetimes)]
 #![feature(negative_impls)]
-#![cfg_attr(bootstrap, feature(optin_builtin_traits))]
-#![cfg_attr(not(bootstrap), feature(auto_traits))]
+#![feature(auto_traits)]
 #![feature(restricted_std)]
 #![feature(rustc_attrs)]
 #![feature(min_specialization)]
index b64f13dba4c2ea751b9bd404e827f69cb05469bf..c6a4548ec0c2d532e8cfed38a4c2b29c5474fe78 100644 (file)
@@ -14,8 +14,7 @@
 
 #![feature(no_core)]
 #![feature(lang_items)]
-#![cfg_attr(bootstrap, feature(optin_builtin_traits))]
-#![cfg_attr(not(bootstrap), feature(auto_traits))]
+#![feature(auto_traits)]
 #![crate_type = "rlib"]
 #![no_core]
 #![allow(non_camel_case_types)]
index 18ee7c19ba0f9a89ba694c955142b089aa849cbf..d5aca80edf9e00d5cfcc8468e8354215f554e7d8 100644 (file)
@@ -2,8 +2,7 @@
 
 #![feature(no_core)]
 #![feature(lang_items)]
-#![cfg_attr(bootstrap, feature(optin_builtin_traits))]
-#![cfg_attr(not(bootstrap), feature(auto_traits))]
+#![feature(auto_traits)]
 #![crate_type = "rlib"]
 #![no_core]
 
index 9c2b1fa91d3b3ed5c5cbbb7656404c0cb0ff1064..40e0b62afabfbd34389018132acca990e208f89a 100644 (file)
@@ -4,12 +4,12 @@ This crate is a shim and empty crate which simply depends on `libcore` and
 reexports all of its contents. The crate is the crux of empowering the standard
 library to depend on crates from crates.io
 
-Crates on crates.io that the standard library depend on the
-`rustc-std-workspace-core` crate from crates.io. On crates.io, however, this
-crate is empty. We use `[patch]` to override it to this crate in this
-repository. As a result, crates on crates.io will draw a dependency edge to
-`libcore`, the version defined in this repository. That should draw all the
-dependency edges to ensure Cargo builds crates successfully!
+Crates on crates.io that the standard library depend on need to depend on the
+`rustc-std-workspace-core` crate from crates.io, which is empty. We use
+`[patch]` to override it to this crate in this repository. As a result, crates
+on crates.io will draw a dependency edge to `libcore`, the version defined in
+this repository. That should draw all the dependency edges to ensure Cargo
+builds crates successfully!
 
 Note that crates on crates.io need to depend on this crate with the name `core`
 for everything to work correctly. To do that they can use:
index ac72345dad425fcc604df457130eab703b242225..0680b1fc32975ea2b4b533e4913e7bdec989213f 100644 (file)
 /// // use the values stored in map
 /// ```
 
-#[derive(Clone)]
 #[cfg_attr(not(test), rustc_diagnostic_item = "hashmap_type")]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct HashMap<K, V, S = RandomState> {
@@ -449,6 +448,7 @@ pub fn iter_mut(&mut self) -> IterMut<'_, K, V> {
     /// a.insert(1, "a");
     /// assert_eq!(a.len(), 1);
     /// ```
+    #[doc(alias = "length")]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn len(&self) -> usize {
         self.base.len()
@@ -1029,6 +1029,24 @@ pub fn raw_entry(&self) -> RawEntryBuilder<'_, K, V, S> {
     }
 }
 
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<K, V, S> Clone for HashMap<K, V, S>
+where
+    K: Clone,
+    V: Clone,
+    S: Clone,
+{
+    #[inline]
+    fn clone(&self) -> Self {
+        Self { base: self.base.clone() }
+    }
+
+    #[inline]
+    fn clone_from(&mut self, other: &Self) {
+        self.base.clone_from(&other.base);
+    }
+}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<K, V, S> PartialEq for HashMap<K, V, S>
 where
index 3299fd12e024e97e8f60f0d9cd13650e8f80eedc..f49e5801c353516adfcd018819a86e087d1c6274 100644 (file)
 /// [`HashMap`]: crate::collections::HashMap
 /// [`RefCell`]: crate::cell::RefCell
 /// [`Cell`]: crate::cell::Cell
-#[derive(Clone)]
 #[cfg_attr(not(test), rustc_diagnostic_item = "hashset_type")]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct HashSet<T, S = RandomState> {
@@ -200,6 +199,7 @@ pub fn iter(&self) -> Iter<'_, T> {
     /// v.insert(1);
     /// assert_eq!(v.len(), 1);
     /// ```
+    #[doc(alias = "length")]
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn len(&self) -> usize {
@@ -932,6 +932,23 @@ pub fn retain<F>(&mut self, f: F)
     }
 }
 
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T, S> Clone for HashSet<T, S>
+where
+    T: Clone,
+    S: Clone,
+{
+    #[inline]
+    fn clone(&self) -> Self {
+        Self { base: self.base.clone() }
+    }
+
+    #[inline]
+    fn clone_from(&mut self, other: &Self) {
+        self.base.clone_from(&other.base);
+    }
+}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T, S> PartialEq for HashSet<T, S>
 where
index 5d93016cadb37ec9efe4c6050d155a0447fac645..2eef4d58507c002209893d7468a8b727c3eb89cb 100644 (file)
@@ -653,6 +653,7 @@ pub fn is_empty(&self) -> bool {
     /// let os_str = OsStr::new("foo");
     /// assert_eq!(os_str.len(), 3);
     /// ```
+    #[doc(alias = "length")]
     #[stable(feature = "osstring_simple_functions", since = "1.9.0")]
     pub fn len(&self) -> usize {
         self.inner.inner.len()
index 39b0ca63301e2998b2361a00ae0406593000a39a..2c6f03fe2240688caeaf7f4b82adc91cec668779 100644 (file)
 //! [`str`]: prim@str
 //! [`mpsc`]: sync::mpsc
 //! [`std::cmp`]: cmp
-//! [`std::slice`]: slice
+//! [`std::slice`]: mod@slice
 //! [`use std::env`]: env/index.html
 //! [`use`]: ../book/ch07-02-defining-modules-to-control-scope-and-privacy.html
 //! [crates.io]: https://crates.io
 //! [other]: #what-is-in-the-standard-library-documentation
 //! [primitive types]: ../book/ch03-02-data-types.html
 //! [rust-discord]: https://discord.gg/rust-lang
-
+#![cfg_attr(not(bootstrap), doc = "[array]: prim@array")]
+#![cfg_attr(not(bootstrap), doc = "[slice]: prim@slice")]
 #![cfg_attr(not(feature = "restricted-std"), stable(feature = "rust1", since = "1.0.0"))]
 #![cfg_attr(feature = "restricted-std", unstable(feature = "restricted_std", issue = "none"))]
 #![doc(
 #![feature(nll)]
 #![feature(nonnull_slice_from_raw_parts)]
 #![feature(once_cell)]
-#![cfg_attr(bootstrap, feature(optin_builtin_traits))]
-#![cfg_attr(not(bootstrap), feature(auto_traits))]
+#![feature(auto_traits)]
 #![feature(or_patterns)]
 #![feature(panic_info_message)]
 #![feature(panic_internals)]
 #![feature(rustc_private)]
 #![feature(shrink_to)]
 #![feature(slice_concat_ext)]
-#![feature(slice_fill)]
 #![feature(slice_internals)]
 #![feature(slice_ptr_get)]
 #![feature(slice_ptr_len)]
index de072e83dfc419c1f181b44947ff41b4d83461ee..5a70aa070e87043fed042c70c0f1f018319157b5 100644 (file)
@@ -8,7 +8,7 @@
 #[macro_export]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[allow_internal_unstable(libstd_sys_internals)]
-#[cfg_attr(not(any(bootstrap, test)), rustc_diagnostic_item = "std_panic_macro")]
+#[cfg_attr(not(test), rustc_diagnostic_item = "std_panic_macro")]
 macro_rules! panic {
     () => ({ $crate::panic!("explicit panic") });
     ($msg:expr $(,)?) => ({ $crate::rt::begin_panic($msg) });
index 8ba3feccb6bcc8f817efa43cd0b373124c27bcd8..6cd572cbe87c131b661d56d7483d62df2e2c551e 100644 (file)
 extern "C" {
     fn __rust_panic_cleanup(payload: *mut u8) -> *mut (dyn Any + Send + 'static);
 
-    /// `payload` is actually a `*mut &mut dyn BoxMeUp` but that would cause FFI warnings.
-    /// It cannot be `Box<dyn BoxMeUp>` because the other end of this call does not depend
-    /// on liballoc, and thus cannot use `Box`.
+    /// `payload` is passed through another layer of raw pointers as `&mut dyn Trait` is not
+    /// FFI-safe. `BoxMeUp` lazily performs allocation only when needed (this avoids allocations
+    /// when using the "abort" panic runtime).
     #[unwind(allowed)]
-    fn __rust_start_panic(payload: usize) -> u32;
+    fn __rust_start_panic(payload: *mut &mut dyn BoxMeUp) -> u32;
 }
 
 /// This function is called by the panic runtime if FFI code catches a Rust
@@ -637,7 +637,7 @@ fn get(&mut self) -> &(dyn Any + Send) {
 fn rust_panic(mut msg: &mut dyn BoxMeUp) -> ! {
     let code = unsafe {
         let obj = &mut msg as *mut &mut dyn BoxMeUp;
-        __rust_start_panic(obj as usize)
+        __rust_start_panic(obj)
     };
     rtabort!("failed to initiate panic, error {}", code)
 }
index d34de6a4fac3e9bfe87f62449f23c12b37f7c5b8..4c852b8ee812f1f7a6b25c36e12ea3f496a72c42 100644 (file)
@@ -36,7 +36,11 @@ pub fn tokens() -> (WaitToken, SignalToken) {
 
 impl SignalToken {
     pub fn signal(&self) -> bool {
-        let wake = !self.inner.woken.compare_and_swap(false, true, Ordering::SeqCst);
+        let wake = self
+            .inner
+            .woken
+            .compare_exchange(false, true, Ordering::SeqCst, Ordering::SeqCst)
+            .is_ok();
         if wake {
             self.inner.thread.unpark();
         }
index 75f5621fa127e210783ae1a154cb749291dafdfd..3dcf03f579a0f32f0f5dd00ceba42b1057913f2c 100644 (file)
@@ -129,7 +129,7 @@ pub fn recv(&self, deadline: Option<Instant>) -> Result<T, Failure<T>> {
             let ptr = unsafe { signal_token.cast_to_usize() };
 
             // race with senders to enter the blocking state
-            if self.state.compare_and_swap(EMPTY, ptr, Ordering::SeqCst) == EMPTY {
+            if self.state.compare_exchange(EMPTY, ptr, Ordering::SeqCst, Ordering::SeqCst).is_ok() {
                 if let Some(deadline) = deadline {
                     let timed_out = !wait_token.wait_max_until(deadline);
                     // Try to reset the state
@@ -161,7 +161,12 @@ pub fn try_recv(&self) -> Result<T, Failure<T>> {
                 // the state changes under our feet we'd rather just see that state
                 // change.
                 DATA => {
-                    self.state.compare_and_swap(DATA, EMPTY, Ordering::SeqCst);
+                    let _ = self.state.compare_exchange(
+                        DATA,
+                        EMPTY,
+                        Ordering::SeqCst,
+                        Ordering::SeqCst,
+                    );
                     match (&mut *self.data.get()).take() {
                         Some(data) => Ok(data),
                         None => unreachable!(),
@@ -264,7 +269,10 @@ pub fn abort_selection(&self) -> Result<bool, Receiver<T>> {
 
             // If we've got a blocked thread, then use an atomic to gain ownership
             // of it (may fail)
-            ptr => self.state.compare_and_swap(ptr, EMPTY, Ordering::SeqCst),
+            ptr => self
+                .state
+                .compare_exchange(ptr, EMPTY, Ordering::SeqCst, Ordering::SeqCst)
+                .unwrap_or_else(|x| x),
         };
 
         // Now that we've got ownership of our state, figure out what to do
index 898654f21f2ea11e5a90ac3ec453454644beabbd..0c32e636a563357ce39cac0f6313c422b4915c1c 100644 (file)
@@ -385,8 +385,15 @@ pub fn drop_port(&self) {
         self.port_dropped.store(true, Ordering::SeqCst);
         let mut steals = unsafe { *self.steals.get() };
         while {
-            let cnt = self.cnt.compare_and_swap(steals, DISCONNECTED, Ordering::SeqCst);
-            cnt != DISCONNECTED && cnt != steals
+            match self.cnt.compare_exchange(
+                steals,
+                DISCONNECTED,
+                Ordering::SeqCst,
+                Ordering::SeqCst,
+            ) {
+                Ok(_) => false,
+                Err(old) => old != DISCONNECTED,
+            }
         } {
             // See the discussion in 'try_recv' for why we yield
             // control of this thread.
index 9f7c1af8951991500723eafd6e6ed16b27d1134c..a652f24c58a19cd986563a22b9d04b2ed2b681d9 100644 (file)
@@ -322,12 +322,15 @@ pub fn drop_port(&self) {
         // (because there is a bounded number of senders).
         let mut steals = unsafe { *self.queue.consumer_addition().steals.get() };
         while {
-            let cnt = self.queue.producer_addition().cnt.compare_and_swap(
+            match self.queue.producer_addition().cnt.compare_exchange(
                 steals,
                 DISCONNECTED,
                 Ordering::SeqCst,
-            );
-            cnt != DISCONNECTED && cnt != steals
+                Ordering::SeqCst,
+            ) {
+                Ok(_) => false,
+                Err(old) => old != DISCONNECTED,
+            }
         } {
             while self.queue.pop().is_some() {
                 steals += 1;
index de5ddf1daf27b5d76e1cc46d075a4658518c1421..6a330834489df9ca1716b8b46f0c3fb4d7f4581f 100644 (file)
@@ -65,7 +65,7 @@
 //       must do so with Release ordering to make the result available.
 //     - `wait` inserts `Waiter` nodes as a pointer in `state_and_queue`, and
 //       needs to make the nodes available with Release ordering. The load in
-//       its `compare_and_swap` can be Relaxed because it only has to compare
+//       its `compare_exchange` can be Relaxed because it only has to compare
 //       the atomic, not to read other data.
 //     - `WaiterQueue::Drop` must see the `Waiter` nodes, so it must load
 //       `state_and_queue` with Acquire ordering.
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Once {
-    // `state_and_queue` is actually an a pointer to a `Waiter` with extra state
+    // `state_and_queue` is actually a pointer to a `Waiter` with extra state
     // bits, so we add the `PhantomData` appropriately.
     state_and_queue: AtomicUsize,
     _marker: marker::PhantomData<*const Waiter>,
@@ -395,12 +395,13 @@ fn call_inner(&self, ignore_poisoning: bool, init: &mut dyn FnMut(&OnceState)) {
                 }
                 POISONED | INCOMPLETE => {
                     // Try to register this thread as the one RUNNING.
-                    let old = self.state_and_queue.compare_and_swap(
+                    let exchange_result = self.state_and_queue.compare_exchange(
                         state_and_queue,
                         RUNNING,
                         Ordering::Acquire,
+                        Ordering::Acquire,
                     );
-                    if old != state_and_queue {
+                    if let Err(old) = exchange_result {
                         state_and_queue = old;
                         continue;
                     }
@@ -452,8 +453,13 @@ fn wait(state_and_queue: &AtomicUsize, mut current_state: usize) {
 
         // Try to slide in the node at the head of the linked list, making sure
         // that another thread didn't just replace the head of the linked list.
-        let old = state_and_queue.compare_and_swap(current_state, me | RUNNING, Ordering::Release);
-        if old != current_state {
+        let exchange_result = state_and_queue.compare_exchange(
+            current_state,
+            me | RUNNING,
+            Ordering::Release,
+            Ordering::Relaxed,
+        );
+        if let Err(old) = exchange_result {
             current_state = old;
             continue;
         }
index a0eb12c3d154a7148abc7a45a0731ffe7db675d8..a5e453034762c16d5d9dac37d898f41319a8df92 100644 (file)
     }
 
     // Try to atomically swap UNINIT with BUSY. The returned state can be:
-    match RELOC_STATE.compare_and_swap(UNINIT, BUSY, Ordering::Acquire) {
+    match RELOC_STATE.compare_exchange(UNINIT, BUSY, Ordering::Acquire, Ordering::Acquire) {
         // This thread just obtained the lock and other threads will observe BUSY
-        UNINIT => {
+        Ok(_) => {
             reloc::relocate_elf_rela();
             RELOC_STATE.store(DONE, Ordering::Release);
         }
         // We need to wait until the initialization is done.
-        BUSY => {
+        Err(BUSY) => {
             while RELOC_STATE.load(Ordering::Acquire) == BUSY {
                 core::hint::spin_loop();
             }
         }
         // Initialization is done.
-        DONE => {}
+        Err(DONE) => {}
         _ => unreachable!(),
     }
 }
index d99ce895da59421b701533dccfedba2387cd319f..9140041c58414754a8a6b245269584450070103a 100644 (file)
@@ -42,7 +42,7 @@ pub fn lock(&self) -> SpinMutexGuard<'_, T> {
 
     #[inline(always)]
     pub fn try_lock(&self) -> Option<SpinMutexGuard<'_, T>> {
-        if !self.lock.compare_and_swap(false, true, Ordering::Acquire) {
+        if self.lock.compare_exchange(false, true, Ordering::Acquire, Ordering::Acquire).is_ok() {
             Some(SpinMutexGuard { mutex: self })
         } else {
             None
index fac4b05ad0b5f5ec8ffd1b2beee789061c76cdc5..23a5c81c0053bb4abdf8b2cc2c4f520dcc035b0c 100644 (file)
@@ -237,7 +237,7 @@ fn info() -> mach_timebase_info {
         // `denom` field.
         //
         // Encoding this as a single `AtomicU64` allows us to use `Relaxed`
-        // operations, as we are only interested in in the effects on a single
+        // operations, as we are only interested in the effects on a single
         // memory location.
         static INFO_BITS: AtomicU64 = AtomicU64::new(0);
 
index fa51b006c346fe10297c8165b593da4a7c5c86c8..d4cc56d4cb3efa244a259345495c3bd4d8e29f64 100644 (file)
@@ -123,9 +123,9 @@ unsafe fn inner(&self) -> *const Inner {
         let inner = box Inner { remutex: ReentrantMutex::uninitialized(), held: Cell::new(false) };
         inner.remutex.init();
         let inner = Box::into_raw(inner);
-        match self.lock.compare_and_swap(0, inner as usize, Ordering::SeqCst) {
-            0 => inner,
-            n => {
+        match self.lock.compare_exchange(0, inner as usize, Ordering::SeqCst, Ordering::SeqCst) {
+            Ok(_) => inner,
+            Err(n) => {
                 Box::from_raw(inner).remutex.destroy();
                 n as *const _
             }
index 701c6e2e9bec7ccac6fc2f3ec0c392e23e072fd7..9e4c9aa0a512c4fb6c211fa0b50d791eb1dd9b5d 100644 (file)
@@ -113,7 +113,7 @@ pub unsafe fn park(&self) {
                 // Wait for something to happen, assuming it's still set to PARKED.
                 c::WaitOnAddress(self.ptr(), &PARKED as *const _ as c::LPVOID, 1, c::INFINITE);
                 // Change NOTIFIED=>EMPTY but leave PARKED alone.
-                if self.state.compare_and_swap(NOTIFIED, EMPTY, Acquire) == NOTIFIED {
+                if self.state.compare_exchange(NOTIFIED, EMPTY, Acquire, Acquire).is_ok() {
                     // Actually woken up by unpark().
                     return;
                 } else {
index fecb732b910cedf3d84bc3da98c1a75a409e122a..1578a2de60cefde982fc76f594b82a4a6c560bb0 100644 (file)
@@ -23,9 +23,9 @@ pub const fn new() -> Self {
     }
     pub fn verify(&self, mutex: &MovableMutex) {
         let addr = mutex.raw() as *const mutex_imp::Mutex as usize;
-        match self.addr.compare_and_swap(0, addr, Ordering::SeqCst) {
-            0 => {}              // Stored the address
-            n if n == addr => {} // Lost a race to store the same address
+        match self.addr.compare_exchange(0, addr, Ordering::SeqCst, Ordering::SeqCst) {
+            Ok(_) => {}               // Stored the address
+            Err(n) if n == addr => {} // Lost a race to store the same address
             _ => panic!("attempted to use a condition variable with two mutexes"),
         }
     }
index dbcb7b36265f5941c929b6eb2be8df3c823dacc1..32cd56416655f18a4157684ac35ab1a85c0acddd 100644 (file)
@@ -168,7 +168,7 @@ unsafe fn lazy_init(&self) -> usize {
             return key;
         }
 
-        // POSIX allows the key created here to be 0, but the compare_and_swap
+        // POSIX allows the key created here to be 0, but the compare_exchange
         // below relies on using 0 as a sentinel value to check who won the
         // race to set the shared TLS key. As far as I know, there is no
         // guaranteed value that cannot be returned as a posix_key_create key,
@@ -186,11 +186,11 @@ unsafe fn lazy_init(&self) -> usize {
             key2
         };
         rtassert!(key != 0);
-        match self.key.compare_and_swap(0, key as usize, Ordering::SeqCst) {
+        match self.key.compare_exchange(0, key as usize, Ordering::SeqCst, Ordering::SeqCst) {
             // The CAS succeeded, so we've created the actual key
-            0 => key as usize,
+            Ok(_) => key as usize,
             // If someone beat us to the punch, use their key instead
-            n => {
+            Err(n) => {
                 imp::destroy(key);
                 n
             }
index a5d4927dcc5cac841b370c4f8c072f096975d433..0132743b244048cfa48e8388e872ceac3e7c3edf 100644 (file)
@@ -49,7 +49,7 @@ pub unsafe fn park(&self) {
             // Wait for something to happen, assuming it's still set to PARKED.
             futex_wait(&self.state, PARKED, None);
             // Change NOTIFIED=>EMPTY and return in that case.
-            if self.state.compare_and_swap(NOTIFIED, EMPTY, Acquire) == NOTIFIED {
+            if self.state.compare_exchange(NOTIFIED, EMPTY, Acquire, Acquire).is_ok() {
                 return;
             } else {
                 // Spurious wake up. We loop to try again.
index f1ed22803f09e3b2c2b86d773db07ce70804987a..9c732a56f67f54d12a0b4fd99993154906c95ea6 160000 (submodule)
@@ -1 +1 @@
-Subproject commit f1ed22803f09e3b2c2b86d773db07ce70804987a
+Subproject commit 9c732a56f67f54d12a0b4fd99993154906c95ea6
index a103c9fb0b78c05d6bafba8d47abaa2b6cd9b3d1..f899f21080ebee6fa1da91eb764aeb6452c3b0b8 100644 (file)
@@ -4,7 +4,12 @@ All notable changes to bootstrap will be documented in this file.
 
 The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
 
-## [Non-breaking changes since the last major version]
+
+## [Changes since the last major version]
+
+- `llvm-libunwind` now accepts `in-tree` (formerly true), `system` or `no` (formerly false) [#77703](https://github.com/rust-lang/rust/pull/77703)
+
+### Non-breaking changes
 
 - `x.py check` needs opt-in to check tests (--all-targets) [#77473](https://github.com/rust-lang/rust/pull/77473)
 - The default bootstrap profiles are now located at `bootstrap/defaults/config.$PROFILE.toml` (previously they were located at `bootstrap/defaults/config.toml.$PROFILE`) [#77558](https://github.com/rust-lang/rust/pull/77558)
index 84ed9446ae73fc98799d1fedd7d71abe76d14cb1..a2e596bf4e958824c112fbdc28930c4f04f9191d 100644 (file)
@@ -201,7 +201,6 @@ build/
     # Output for all compiletest-based test suites
     test/
       ui/
-      compile-fail/
       debuginfo/
       ...
 
index 97f40815b87b421d9e9f4357782f3148da27fd04..b8bae69d063309cb82ef44ba4cb559a868a3fe10 100644 (file)
@@ -351,11 +351,13 @@ def output(filepath):
     with open(tmp, 'w') as f:
         yield f
     try:
-        os.remove(filepath)  # PermissionError/OSError on Win32 if in use
-        os.rename(tmp, filepath)
+        if os.path.exists(filepath):
+            os.remove(filepath)  # PermissionError/OSError on Win32 if in use
     except OSError:
         shutil.copy2(tmp, filepath)
         os.remove(tmp)
+        return
+    os.rename(tmp, filepath)
 
 
 class RustBuild(object):
index ab0c4a5c31b05ce84d9525d71180ebacb691ceb0..c2abb01fa8c95f5723a16ef6ca3ba2456378c330 100644 (file)
@@ -384,7 +384,6 @@ macro_rules! describe {
                 test::ExpandYamlAnchors,
                 test::Tidy,
                 test::Ui,
-                test::CompileFail,
                 test::RunPassValgrind,
                 test::MirOpt,
                 test::Codegen,
@@ -471,6 +470,7 @@ macro_rules! describe {
                 dist::RustDev,
                 dist::Extended,
                 dist::BuildManifest,
+                dist::ReproducibleArtifacts,
             ),
             Kind::Install => describe!(
                 install::Docs,
@@ -736,10 +736,7 @@ pub fn rustdoc_cmd(&self, compiler: Compiler) -> Command {
         if self.config.deny_warnings {
             cmd.arg("-Dwarnings");
         }
-        // cfg(not(bootstrap)), can be removed on the next beta bump
-        if compiler.stage != 0 {
-            cmd.arg("-Znormalize-docs");
-        }
+        cmd.arg("-Znormalize-docs");
 
         // Remove make-related flags that can cause jobserver problems.
         cmd.env_remove("MAKEFLAGS");
index fbebb26c746206cc31e20d8240da5bd4895b2b4d..2707a640457b5ef9925b2a8711adc164018e0a84 100644 (file)
@@ -7,6 +7,7 @@
 //! goes along from the output of the previous stage.
 
 use std::borrow::Cow;
+use std::collections::HashSet;
 use std::env;
 use std::fs;
 use std::io::prelude::*;
@@ -501,6 +502,41 @@ fn run(self, builder: &Builder<'_>) {
         let mut cargo = builder.cargo(compiler, Mode::Rustc, SourceType::InTree, target, "build");
         rustc_cargo(builder, &mut cargo, target);
 
+        if builder.config.rust_profile_use.is_some()
+            && builder.config.rust_profile_generate.is_some()
+        {
+            panic!("Cannot use and generate PGO profiles at the same time");
+        }
+
+        let is_collecting = if let Some(path) = &builder.config.rust_profile_generate {
+            if compiler.stage == 1 {
+                cargo.rustflag(&format!("-Cprofile-generate={}", path));
+                // Apparently necessary to avoid overflowing the counters during
+                // a Cargo build profile
+                cargo.rustflag("-Cllvm-args=-vp-counters-per-site=4");
+                true
+            } else {
+                false
+            }
+        } else if let Some(path) = &builder.config.rust_profile_use {
+            if compiler.stage == 1 {
+                cargo.rustflag(&format!("-Cprofile-use={}", path));
+                cargo.rustflag("-Cllvm-args=-pgo-warn-missing-function");
+                true
+            } else {
+                false
+            }
+        } else {
+            false
+        };
+        if is_collecting {
+            // Ensure paths to Rust sources are relative, not absolute.
+            cargo.rustflag(&format!(
+                "-Cllvm-args=-static-func-strip-dirname-prefix={}",
+                builder.config.src.components().count()
+            ));
+        }
+
         builder.info(&format!(
             "Building stage{} compiler artifacts ({} -> {})",
             compiler.stage, &compiler.host, target
@@ -752,7 +788,7 @@ fn copy_codegen_backends_to_sysroot(
     // Here we're looking for the output dylib of the `CodegenBackend` step and
     // we're copying that into the `codegen-backends` folder.
     let dst = builder.sysroot_codegen_backends(target_compiler);
-    t!(fs::create_dir_all(&dst));
+    t!(fs::create_dir_all(&dst), dst);
 
     if builder.config.dry_run {
         return;
@@ -956,13 +992,26 @@ fn run(self, builder: &Builder<'_>) -> Compiler {
         builder.info(&format!("Assembling stage{} compiler ({})", stage, host));
 
         // Link in all dylibs to the libdir
+        let stamp = librustc_stamp(builder, build_compiler, target_compiler.host);
+        let proc_macros = builder
+            .read_stamp_file(&stamp)
+            .into_iter()
+            .filter_map(|(path, dependency_type)| {
+                if dependency_type == DependencyType::Host {
+                    Some(path.file_name().unwrap().to_owned().into_string().unwrap())
+                } else {
+                    None
+                }
+            })
+            .collect::<HashSet<_>>();
+
         let sysroot = builder.sysroot(target_compiler);
         let rustc_libdir = builder.rustc_libdir(target_compiler);
         t!(fs::create_dir_all(&rustc_libdir));
         let src_libdir = builder.sysroot_libdir(build_compiler, host);
         for f in builder.read_dir(&src_libdir) {
             let filename = f.file_name().into_string().unwrap();
-            if is_dylib(&filename) {
+            if is_dylib(&filename) && !proc_macros.contains(&filename) {
                 builder.copy(&f.path(), &rustc_libdir.join(&filename));
             }
         }
index ece8a7494b50a094ae0292622e8dd164e40e442f..8a3b936d80d5c58340686465b11987a28aa0ccee 100644 (file)
@@ -134,6 +134,8 @@ pub struct Config {
     pub rust_thin_lto_import_instr_limit: Option<u32>,
     pub rust_remap_debuginfo: bool,
     pub rust_new_symbol_mangling: bool,
+    pub rust_profile_use: Option<String>,
+    pub rust_profile_generate: Option<String>,
 
     pub build: TargetSelection,
     pub hosts: Vec<TargetSelection>,
@@ -146,6 +148,7 @@ pub struct Config {
     pub dist_sign_folder: Option<PathBuf>,
     pub dist_upload_addr: Option<String>,
     pub dist_gpg_password_file: Option<PathBuf>,
+    pub dist_compression_formats: Option<Vec<String>>,
 
     // libstd features
     pub backtrace: bool, // support for RUST_BACKTRACE
@@ -436,6 +439,7 @@ struct Dist {
     upload_addr: Option<String>,
     src_tarball: Option<bool>,
     missing_tools: Option<bool>,
+    compression_formats: Option<Vec<String>>,
 }
 
 #[derive(Deserialize)]
@@ -496,6 +500,8 @@ struct Rust {
     llvm_libunwind: Option<String>,
     control_flow_guard: Option<bool>,
     new_symbol_mangling: Option<bool>,
+    profile_generate: Option<String>,
+    profile_use: Option<String>,
 }
 
 /// TOML representation of how each build target is configured.
@@ -874,6 +880,11 @@ pub fn parse(args: &[String]) -> Config {
 
             config.rust_codegen_units = rust.codegen_units.map(threads_from_config);
             config.rust_codegen_units_std = rust.codegen_units_std.map(threads_from_config);
+            config.rust_profile_use = flags.rust_profile_use.or(rust.profile_use);
+            config.rust_profile_generate = flags.rust_profile_generate.or(rust.profile_generate);
+        } else {
+            config.rust_profile_use = flags.rust_profile_use;
+            config.rust_profile_generate = flags.rust_profile_generate;
         }
 
         if let Some(t) = toml.target {
@@ -927,6 +938,7 @@ pub fn parse(args: &[String]) -> Config {
             config.dist_sign_folder = t.sign_folder.map(PathBuf::from);
             config.dist_gpg_password_file = t.gpg_password_file.map(PathBuf::from);
             config.dist_upload_addr = t.upload_addr;
+            config.dist_compression_formats = t.compression_formats;
             set(&mut config.rust_dist_src, t.src_tarball);
             set(&mut config.missing_tools, t.missing_tools);
         }
index 42f00ce9621743cb3a283355074b07a10b7f4e77..2cabaee68ea670b632e60d5f9312be9451315f55 100755 (executable)
@@ -147,6 +147,8 @@ v("experimental-targets", "llvm.experimental-targets",
   "experimental LLVM targets to build")
 v("release-channel", "rust.channel", "the name of the release channel to build")
 v("release-description", "rust.description", "optional descriptive string for version output")
+v("dist-compression-formats", None,
+  "comma-separated list of compression formats to use")
 
 # Used on systems where "cc" is unavailable
 v("default-linker", "rust.default-linker", "the default linker")
@@ -349,6 +351,8 @@ for key in known_args:
     elif option.name == 'option-checking':
         # this was handled above
         pass
+    elif option.name == 'dist-compression-formats':
+        set('dist.compression-formats', value.split(','))
     else:
         raise RuntimeError("unhandled option {}".format(option.name))
 
index 9ebf76dceef8256c7d34f5e6d48c845a69e11351..0a79d09b27fed29598f66cbe41e7ac28a0b215c0 100644 (file)
@@ -19,6 +19,7 @@
 use crate::cache::{Interned, INTERNER};
 use crate::compile;
 use crate::config::TargetSelection;
+use crate::tarball::{OverlayKind, Tarball};
 use crate::tool::{self, Tool};
 use crate::util::{exe, is_dylib, timeit};
 use crate::{Compiler, DependencyType, Mode, LLVM_TOOLS};
@@ -36,10 +37,6 @@ pub fn tmpdir(builder: &Builder<'_>) -> PathBuf {
     builder.out.join("tmp/dist")
 }
 
-fn rust_installer(builder: &Builder<'_>) -> Command {
-    builder.tool_cmd(Tool::RustInstaller)
-}
-
 fn missing_tool(tool_name: &str, skip: bool) {
     if skip {
         println!("Unable to build {}, skipping dist", tool_name)
@@ -54,7 +51,7 @@ pub struct Docs {
 }
 
 impl Step for Docs {
-    type Output = PathBuf;
+    type Output = Option<PathBuf>;
     const DEFAULT: bool = true;
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
@@ -66,48 +63,20 @@ fn make_run(run: RunConfig<'_>) {
     }
 
     /// Builds the `rust-docs` installer component.
-    fn run(self, builder: &Builder<'_>) -> PathBuf {
+    fn run(self, builder: &Builder<'_>) -> Option<PathBuf> {
         let host = self.host;
-
-        let name = pkgname(builder, "rust-docs");
-
         if !builder.config.docs {
-            return distdir(builder).join(format!("{}-{}.tar.gz", name, host.triple));
+            return None;
         }
-
         builder.default_doc(None);
 
-        builder.info(&format!("Dist docs ({})", host));
-        let _time = timeit(builder);
+        let dest = "share/doc/rust/html";
 
-        let image = tmpdir(builder).join(format!("{}-{}-image", name, host.triple));
-        let _ = fs::remove_dir_all(&image);
-
-        let dst = image.join("share/doc/rust/html");
-        t!(fs::create_dir_all(&dst));
-        let src = builder.doc_out(host);
-        builder.cp_r(&src, &dst);
-        builder.install(&builder.src.join("src/doc/robots.txt"), &dst, 0o644);
-
-        let mut cmd = rust_installer(builder);
-        cmd.arg("generate")
-            .arg("--product-name=Rust-Documentation")
-            .arg("--rel-manifest-dir=rustlib")
-            .arg("--success-message=Rust-documentation-is-installed.")
-            .arg("--image-dir")
-            .arg(&image)
-            .arg("--work-dir")
-            .arg(&tmpdir(builder))
-            .arg("--output-dir")
-            .arg(&distdir(builder))
-            .arg(format!("--package-name={}-{}", name, host.triple))
-            .arg("--component-name=rust-docs")
-            .arg("--legacy-manifest-dirs=rustlib,cargo")
-            .arg("--bulk-dirs=share/doc/rust/html");
-        builder.run(&mut cmd);
-        builder.remove_dir(&image);
-
-        distdir(builder).join(format!("{}-{}.tar.gz", name, host.triple))
+        let mut tarball = Tarball::new(builder, "rust-docs", &host.triple);
+        tarball.set_product_name("Rust Documentation");
+        tarball.add_dir(&builder.doc_out(host), dest);
+        tarball.add_file(&builder.src.join("src/doc/robots.txt"), dest, 0o644);
+        Some(tarball.generate())
     }
 }
 
@@ -117,7 +86,7 @@ pub struct RustcDocs {
 }
 
 impl Step for RustcDocs {
-    type Output = PathBuf;
+    type Output = Option<PathBuf>;
     const DEFAULT: bool = true;
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
@@ -129,47 +98,17 @@ fn make_run(run: RunConfig<'_>) {
     }
 
     /// Builds the `rustc-docs` installer component.
-    fn run(self, builder: &Builder<'_>) -> PathBuf {
+    fn run(self, builder: &Builder<'_>) -> Option<PathBuf> {
         let host = self.host;
-
-        let name = pkgname(builder, "rustc-docs");
-
         if !builder.config.compiler_docs {
-            return distdir(builder).join(format!("{}-{}.tar.gz", name, host.triple));
+            return None;
         }
-
         builder.default_doc(None);
 
-        let image = tmpdir(builder).join(format!("{}-{}-image", name, host.triple));
-        let _ = fs::remove_dir_all(&image);
-
-        let dst = image.join("share/doc/rust/html/rustc");
-        t!(fs::create_dir_all(&dst));
-        let src = builder.compiler_doc_out(host);
-        builder.cp_r(&src, &dst);
-
-        let mut cmd = rust_installer(builder);
-        cmd.arg("generate")
-            .arg("--product-name=Rustc-Documentation")
-            .arg("--rel-manifest-dir=rustlib")
-            .arg("--success-message=Rustc-documentation-is-installed.")
-            .arg("--image-dir")
-            .arg(&image)
-            .arg("--work-dir")
-            .arg(&tmpdir(builder))
-            .arg("--output-dir")
-            .arg(&distdir(builder))
-            .arg(format!("--package-name={}-{}", name, host.triple))
-            .arg("--component-name=rustc-docs")
-            .arg("--legacy-manifest-dirs=rustlib,cargo")
-            .arg("--bulk-dirs=share/doc/rust/html/rustc");
-
-        builder.info(&format!("Dist compiler docs ({})", host));
-        let _time = timeit(builder);
-        builder.run(&mut cmd);
-        builder.remove_dir(&image);
-
-        distdir(builder).join(format!("{}-{}.tar.gz", name, host.triple))
+        let mut tarball = Tarball::new(builder, "rustc-docs", &host.triple);
+        tarball.set_product_name("Rustc Documentation");
+        tarball.add_dir(&builder.compiler_doc_out(host), "share/doc/rust/html/rustc");
+        Some(tarball.generate())
     }
 }
 
@@ -345,41 +284,20 @@ fn make_run(run: RunConfig<'_>) {
     /// without any extra installed software (e.g., we bundle gcc, libraries, etc).
     fn run(self, builder: &Builder<'_>) -> Option<PathBuf> {
         let host = self.host;
-
         if !host.contains("pc-windows-gnu") {
             return None;
         }
 
-        builder.info(&format!("Dist mingw ({})", host));
-        let _time = timeit(builder);
-        let name = pkgname(builder, "rust-mingw");
-        let image = tmpdir(builder).join(format!("{}-{}-image", name, host.triple));
-        let _ = fs::remove_dir_all(&image);
-        t!(fs::create_dir_all(&image));
+        let mut tarball = Tarball::new(builder, "rust-mingw", &host.triple);
+        tarball.set_product_name("Rust MinGW");
 
         // The first argument is a "temporary directory" which is just
         // thrown away (this contains the runtime DLLs included in the rustc package
         // above) and the second argument is where to place all the MinGW components
         // (which is what we want).
-        make_win_dist(&tmpdir(builder), &image, host, &builder);
-
-        let mut cmd = rust_installer(builder);
-        cmd.arg("generate")
-            .arg("--product-name=Rust-MinGW")
-            .arg("--rel-manifest-dir=rustlib")
-            .arg("--success-message=Rust-MinGW-is-installed.")
-            .arg("--image-dir")
-            .arg(&image)
-            .arg("--work-dir")
-            .arg(&tmpdir(builder))
-            .arg("--output-dir")
-            .arg(&distdir(builder))
-            .arg(format!("--package-name={}-{}", name, host.triple))
-            .arg("--component-name=rust-mingw")
-            .arg("--legacy-manifest-dirs=rustlib,cargo");
-        builder.run(&mut cmd);
-        t!(fs::remove_dir_all(&image));
-        Some(distdir(builder).join(format!("{}-{}.tar.gz", name, host.triple)))
+        make_win_dist(&tmpdir(builder), tarball.image_dir(), host, &builder);
+
+        Some(tarball.generate())
     }
 }
 
@@ -407,30 +325,10 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
         let compiler = self.compiler;
         let host = self.compiler.host;
 
-        let name = pkgname(builder, "rustc");
-        let image = tmpdir(builder).join(format!("{}-{}-image", name, host.triple));
-        let _ = fs::remove_dir_all(&image);
-        let overlay = tmpdir(builder).join(format!("{}-{}-overlay", name, host.triple));
-        let _ = fs::remove_dir_all(&overlay);
+        let tarball = Tarball::new(builder, "rustc", &host.triple);
 
         // Prepare the rustc "image", what will actually end up getting installed
-        prepare_image(builder, compiler, &image);
-
-        // Prepare the overlay which is part of the tarball but won't actually be
-        // installed
-        let cp = |file: &str| {
-            builder.install(&builder.src.join(file), &overlay, 0o644);
-        };
-        cp("COPYRIGHT");
-        cp("LICENSE-APACHE");
-        cp("LICENSE-MIT");
-        cp("README.md");
-        // tiny morsel of metadata is used by rust-packaging
-        let version = builder.rust_version();
-        builder.create(&overlay.join("version"), &version);
-        if let Some(sha) = builder.rust_sha() {
-            builder.create(&overlay.join("git-commit-hash"), &sha);
-        }
+        prepare_image(builder, compiler, tarball.image_dir());
 
         // On MinGW we've got a few runtime DLL dependencies that we need to
         // include. The first argument to this script is where to put these DLLs
@@ -443,38 +341,11 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
         // install will *also* include the rust-mingw package, which also needs
         // licenses, so to be safe we just include it here in all MinGW packages.
         if host.contains("pc-windows-gnu") {
-            make_win_dist(&image, &tmpdir(builder), host, builder);
-
-            let dst = image.join("share/doc");
-            t!(fs::create_dir_all(&dst));
-            builder.cp_r(&builder.src.join("src/etc/third-party"), &dst);
+            make_win_dist(tarball.image_dir(), &tmpdir(builder), host, builder);
+            tarball.add_dir(builder.src.join("src/etc/third-party"), "share/doc");
         }
 
-        // Finally, wrap everything up in a nice tarball!
-        let mut cmd = rust_installer(builder);
-        cmd.arg("generate")
-            .arg("--product-name=Rust")
-            .arg("--rel-manifest-dir=rustlib")
-            .arg("--success-message=Rust-is-ready-to-roll.")
-            .arg("--image-dir")
-            .arg(&image)
-            .arg("--work-dir")
-            .arg(&tmpdir(builder))
-            .arg("--output-dir")
-            .arg(&distdir(builder))
-            .arg("--non-installed-overlay")
-            .arg(&overlay)
-            .arg(format!("--package-name={}-{}", name, host.triple))
-            .arg("--component-name=rustc")
-            .arg("--legacy-manifest-dirs=rustlib,cargo");
-
-        builder.info(&format!("Dist rustc stage{} ({})", compiler.stage, host.triple));
-        let _time = timeit(builder);
-        builder.run(&mut cmd);
-        builder.remove_dir(&image);
-        builder.remove_dir(&overlay);
-
-        return distdir(builder).join(format!("{}-{}.tar.gz", name, host.triple));
+        return tarball.generate();
 
         fn prepare_image(builder: &Builder<'_>, compiler: Compiler, image: &Path) {
             let host = compiler.host;
@@ -684,7 +555,7 @@ pub struct Std {
 }
 
 impl Step for Std {
-    type Output = PathBuf;
+    type Output = Option<PathBuf>;
     const DEFAULT: bool = true;
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
@@ -702,46 +573,24 @@ fn make_run(run: RunConfig<'_>) {
         });
     }
 
-    fn run(self, builder: &Builder<'_>) -> PathBuf {
+    fn run(self, builder: &Builder<'_>) -> Option<PathBuf> {
         let compiler = self.compiler;
         let target = self.target;
 
-        let name = pkgname(builder, "rust-std");
-        let archive = distdir(builder).join(format!("{}-{}.tar.gz", name, target.triple));
         if skip_host_target_lib(builder, compiler) {
-            return archive;
+            return None;
         }
 
         builder.ensure(compile::Std { compiler, target });
 
-        let image = tmpdir(builder).join(format!("{}-{}-image", name, target.triple));
-        let _ = fs::remove_dir_all(&image);
+        let mut tarball = Tarball::new(builder, "rust-std", &target.triple);
+        tarball.include_target_in_component_name(true);
 
         let compiler_to_use = builder.compiler_for(compiler.stage, compiler.host, target);
         let stamp = compile::libstd_stamp(builder, compiler_to_use, target);
-        copy_target_libs(builder, target, &image, &stamp);
-
-        let mut cmd = rust_installer(builder);
-        cmd.arg("generate")
-            .arg("--product-name=Rust")
-            .arg("--rel-manifest-dir=rustlib")
-            .arg("--success-message=std-is-standing-at-the-ready.")
-            .arg("--image-dir")
-            .arg(&image)
-            .arg("--work-dir")
-            .arg(&tmpdir(builder))
-            .arg("--output-dir")
-            .arg(&distdir(builder))
-            .arg(format!("--package-name={}-{}", name, target.triple))
-            .arg(format!("--component-name=rust-std-{}", target.triple))
-            .arg("--legacy-manifest-dirs=rustlib,cargo");
-
-        builder
-            .info(&format!("Dist std stage{} ({} -> {})", compiler.stage, &compiler.host, target));
-        let _time = timeit(builder);
-        builder.run(&mut cmd);
-        builder.remove_dir(&image);
-        archive
+        copy_target_libs(builder, target, &tarball.image_dir(), &stamp);
+
+        Some(tarball.generate())
     }
 }
 
@@ -752,7 +601,7 @@ pub struct RustcDev {
 }
 
 impl Step for RustcDev {
-    type Output = PathBuf;
+    type Output = Option<PathBuf>;
     const DEFAULT: bool = true;
     const ONLY_HOSTS: bool = true;
 
@@ -771,60 +620,36 @@ fn make_run(run: RunConfig<'_>) {
         });
     }
 
-    fn run(self, builder: &Builder<'_>) -> PathBuf {
+    fn run(self, builder: &Builder<'_>) -> Option<PathBuf> {
         let compiler = self.compiler;
         let target = self.target;
-
-        let name = pkgname(builder, "rustc-dev");
-        let archive = distdir(builder).join(format!("{}-{}.tar.gz", name, target.triple));
         if skip_host_target_lib(builder, compiler) {
-            return archive;
+            return None;
         }
 
         builder.ensure(compile::Rustc { compiler, target });
 
-        let image = tmpdir(builder).join(format!("{}-{}-image", name, target.triple));
-        let _ = fs::remove_dir_all(&image);
+        let tarball = Tarball::new(builder, "rustc-dev", &target.triple);
 
         let compiler_to_use = builder.compiler_for(compiler.stage, compiler.host, target);
         let stamp = compile::librustc_stamp(builder, compiler_to_use, target);
-        copy_target_libs(builder, target, &image, &stamp);
-
-        // Copy compiler sources.
-        let dst_src = image.join("lib/rustlib/rustc-src/rust");
-        t!(fs::create_dir_all(&dst_src));
+        copy_target_libs(builder, target, tarball.image_dir(), &stamp);
 
-        let src_files = ["Cargo.lock"];
+        let src_files = &["Cargo.lock"];
         // This is the reduced set of paths which will become the rustc-dev component
         // (essentially the compiler crates and all of their path dependencies).
-        copy_src_dirs(builder, &builder.src, &["compiler"], &[], &dst_src);
-        for file in src_files.iter() {
-            builder.copy(&builder.src.join(file), &dst_src.join(file));
+        copy_src_dirs(
+            builder,
+            &builder.src,
+            &["compiler"],
+            &[],
+            &tarball.image_dir().join("lib/rustlib/rustc-src/rust"),
+        );
+        for file in src_files {
+            tarball.add_file(builder.src.join(file), "lib/rustlib/rustc-src/rust", 0o644);
         }
 
-        let mut cmd = rust_installer(builder);
-        cmd.arg("generate")
-            .arg("--product-name=Rust")
-            .arg("--rel-manifest-dir=rustlib")
-            .arg("--success-message=Rust-is-ready-to-develop.")
-            .arg("--image-dir")
-            .arg(&image)
-            .arg("--work-dir")
-            .arg(&tmpdir(builder))
-            .arg("--output-dir")
-            .arg(&distdir(builder))
-            .arg(format!("--package-name={}-{}", name, target.triple))
-            .arg(format!("--component-name=rustc-dev-{}", target.triple))
-            .arg("--legacy-manifest-dirs=rustlib,cargo");
-
-        builder.info(&format!(
-            "Dist rustc-dev stage{} ({} -> {})",
-            compiler.stage, &compiler.host, target
-        ));
-        let _time = timeit(builder);
-        builder.run(&mut cmd);
-        builder.remove_dir(&image);
-        archive
+        Some(tarball.generate())
     }
 }
 
@@ -835,7 +660,7 @@ pub struct Analysis {
 }
 
 impl Step for Analysis {
-    type Output = PathBuf;
+    type Output = Option<PathBuf>;
     const DEFAULT: bool = true;
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
@@ -858,52 +683,26 @@ fn make_run(run: RunConfig<'_>) {
     }
 
     /// Creates a tarball of save-analysis metadata, if available.
-    fn run(self, builder: &Builder<'_>) -> PathBuf {
+    fn run(self, builder: &Builder<'_>) -> Option<PathBuf> {
         let compiler = self.compiler;
         let target = self.target;
         assert!(builder.config.extended);
-        let name = pkgname(builder, "rust-analysis");
-
         if compiler.host != builder.config.build {
-            return distdir(builder).join(format!("{}-{}.tar.gz", name, target.triple));
+            return None;
         }
 
         builder.ensure(compile::Std { compiler, target });
-
-        let image = tmpdir(builder).join(format!("{}-{}-image", name, target.triple));
-
         let src = builder
             .stage_out(compiler, Mode::Std)
             .join(target.triple)
             .join(builder.cargo_dir())
-            .join("deps");
+            .join("deps")
+            .join("save-analysis");
 
-        let image_src = src.join("save-analysis");
-        let dst = image.join("lib/rustlib").join(target.triple).join("analysis");
-        t!(fs::create_dir_all(&dst));
-        builder.info(&format!("image_src: {:?}, dst: {:?}", image_src, dst));
-        builder.cp_r(&image_src, &dst);
-
-        let mut cmd = rust_installer(builder);
-        cmd.arg("generate")
-            .arg("--product-name=Rust")
-            .arg("--rel-manifest-dir=rustlib")
-            .arg("--success-message=save-analysis-saved.")
-            .arg("--image-dir")
-            .arg(&image)
-            .arg("--work-dir")
-            .arg(&tmpdir(builder))
-            .arg("--output-dir")
-            .arg(&distdir(builder))
-            .arg(format!("--package-name={}-{}", name, target.triple))
-            .arg(format!("--component-name=rust-analysis-{}", target.triple))
-            .arg("--legacy-manifest-dirs=rustlib,cargo");
-
-        builder.info("Dist analysis");
-        let _time = timeit(builder);
-        builder.run(&mut cmd);
-        builder.remove_dir(&image);
-        distdir(builder).join(format!("{}-{}.tar.gz", name, target.triple))
+        let mut tarball = Tarball::new(builder, "rust-analysis", &target.triple);
+        tarball.include_target_in_component_name(true);
+        tarball.add_dir(src, format!("lib/rustlib/{}/analysis", target.triple));
+        Some(tarball.generate())
     }
 }
 
@@ -1011,9 +810,7 @@ fn make_run(run: RunConfig<'_>) {
 
     /// Creates the `rust-src` installer component
     fn run(self, builder: &Builder<'_>) -> PathBuf {
-        let name = pkgname(builder, "rust-src");
-        let image = tmpdir(builder).join(format!("{}-image", name));
-        let _ = fs::remove_dir_all(&image);
+        let tarball = Tarball::new_targetless(builder, "rust-src");
 
         // A lot of tools expect the rust-src component to be entirely in this directory, so if you
         // change that (e.g. by adding another directory `lib/rustlib/src/foo` or
@@ -1022,8 +819,7 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
         //
         // NOTE: if you update the paths here, you also should update the "virtual" path
         // translation code in `imported_source_files` in `src/librustc_metadata/rmeta/decoder.rs`
-        let dst_src = image.join("lib/rustlib/src/rust");
-        t!(fs::create_dir_all(&dst_src));
+        let dst_src = tarball.image_dir().join("lib/rustlib/src/rust");
 
         let src_files = ["Cargo.lock"];
         // This is the reduced set of paths which will become the rust-src component
@@ -1043,28 +839,7 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
             builder.copy(&builder.src.join(file), &dst_src.join(file));
         }
 
-        // Create source tarball in rust-installer format
-        let mut cmd = rust_installer(builder);
-        cmd.arg("generate")
-            .arg("--product-name=Rust")
-            .arg("--rel-manifest-dir=rustlib")
-            .arg("--success-message=Awesome-Source.")
-            .arg("--image-dir")
-            .arg(&image)
-            .arg("--work-dir")
-            .arg(&tmpdir(builder))
-            .arg("--output-dir")
-            .arg(&distdir(builder))
-            .arg(format!("--package-name={}", name))
-            .arg("--component-name=rust-src")
-            .arg("--legacy-manifest-dirs=rustlib,cargo");
-
-        builder.info("Dist src");
-        let _time = timeit(builder);
-        builder.run(&mut cmd);
-
-        builder.remove_dir(&image);
-        distdir(builder).join(&format!("{}.tar.gz", name))
+        tarball.generate()
     }
 }
 
@@ -1088,11 +863,8 @@ fn make_run(run: RunConfig<'_>) {
 
     /// Creates the plain source tarball
     fn run(self, builder: &Builder<'_>) -> PathBuf {
-        // Make sure that the root folder of tarball has the correct name
-        let plain_name = format!("{}-src", pkgname(builder, "rustc"));
-        let plain_dst_src = tmpdir(builder).join(&plain_name);
-        let _ = fs::remove_dir_all(&plain_dst_src);
-        t!(fs::create_dir_all(&plain_dst_src));
+        let tarball = Tarball::new(builder, "rustc", "src");
+        let plain_dst_src = tarball.image_dir();
 
         // This is the set of root paths which will become part of the source package
         let src_files = [
@@ -1135,28 +907,7 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
             builder.run(&mut cmd);
         }
 
-        // Create plain source tarball
-        let plain_name = format!("rustc-{}-src", builder.rust_package_vers());
-        let mut tarball = distdir(builder).join(&format!("{}.tar.gz", plain_name));
-        tarball.set_extension(""); // strip .gz
-        tarball.set_extension(""); // strip .tar
-        if let Some(dir) = tarball.parent() {
-            builder.create_dir(&dir);
-        }
-        builder.info("running installer");
-        let mut cmd = rust_installer(builder);
-        cmd.arg("tarball")
-            .arg("--input")
-            .arg(&plain_name)
-            .arg("--output")
-            .arg(&tarball)
-            .arg("--work-dir=.")
-            .current_dir(tmpdir(builder));
-
-        builder.info("Create plain source tarball");
-        let _time = timeit(builder);
-        builder.run(&mut cmd);
-        distdir(builder).join(&format!("{}.tar.gz", plain_name))
+        tarball.bare()
     }
 }
 
@@ -1212,72 +963,28 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
         let compiler = self.compiler;
         let target = self.target;
 
+        let cargo = builder.ensure(tool::Cargo { compiler, target });
         let src = builder.src.join("src/tools/cargo");
         let etc = src.join("src/etc");
-        let release_num = builder.release_num("cargo");
-        let name = pkgname(builder, "cargo");
-        let version = builder.cargo_info.version(builder, &release_num);
-
-        let tmp = tmpdir(builder);
-        let image = tmp.join("cargo-image");
-        drop(fs::remove_dir_all(&image));
-        builder.create_dir(&image);
 
         // Prepare the image directory
-        builder.create_dir(&image.join("share/zsh/site-functions"));
-        builder.create_dir(&image.join("etc/bash_completion.d"));
-        let cargo = builder.ensure(tool::Cargo { compiler, target });
-        builder.install(&cargo, &image.join("bin"), 0o755);
+        let mut tarball = Tarball::new(builder, "cargo", &target.triple);
+        tarball.set_overlay(OverlayKind::Cargo);
+
+        tarball.add_file(&cargo, "bin", 0o755);
+        tarball.add_file(etc.join("_cargo"), "share/zsh/site-functions", 0o644);
+        tarball.add_renamed_file(etc.join("cargo.bashcomp.sh"), "etc/bash_completion.d", "cargo");
+        tarball.add_dir(etc.join("man"), "share/man/man1");
+        tarball.add_legal_and_readme_to("share/doc/cargo");
+
         for dirent in fs::read_dir(cargo.parent().unwrap()).expect("read_dir") {
             let dirent = dirent.expect("read dir entry");
             if dirent.file_name().to_str().expect("utf8").starts_with("cargo-credential-") {
-                builder.install(&dirent.path(), &image.join("libexec"), 0o755);
+                tarball.add_file(&dirent.path(), "libexec", 0o755);
             }
         }
-        for man in t!(etc.join("man").read_dir()) {
-            let man = t!(man);
-            builder.install(&man.path(), &image.join("share/man/man1"), 0o644);
-        }
-        builder.install(&etc.join("_cargo"), &image.join("share/zsh/site-functions"), 0o644);
-        builder.copy(&etc.join("cargo.bashcomp.sh"), &image.join("etc/bash_completion.d/cargo"));
-        let doc = image.join("share/doc/cargo");
-        builder.install(&src.join("README.md"), &doc, 0o644);
-        builder.install(&src.join("LICENSE-MIT"), &doc, 0o644);
-        builder.install(&src.join("LICENSE-APACHE"), &doc, 0o644);
-        builder.install(&src.join("LICENSE-THIRD-PARTY"), &doc, 0o644);
-
-        // Prepare the overlay
-        let overlay = tmp.join("cargo-overlay");
-        drop(fs::remove_dir_all(&overlay));
-        builder.create_dir(&overlay);
-        builder.install(&src.join("README.md"), &overlay, 0o644);
-        builder.install(&src.join("LICENSE-MIT"), &overlay, 0o644);
-        builder.install(&src.join("LICENSE-APACHE"), &overlay, 0o644);
-        builder.install(&src.join("LICENSE-THIRD-PARTY"), &overlay, 0o644);
-        builder.create(&overlay.join("version"), &version);
-
-        // Generate the installer tarball
-        let mut cmd = rust_installer(builder);
-        cmd.arg("generate")
-            .arg("--product-name=Rust")
-            .arg("--rel-manifest-dir=rustlib")
-            .arg("--success-message=Rust-is-ready-to-roll.")
-            .arg("--image-dir")
-            .arg(&image)
-            .arg("--work-dir")
-            .arg(&tmpdir(builder))
-            .arg("--output-dir")
-            .arg(&distdir(builder))
-            .arg("--non-installed-overlay")
-            .arg(&overlay)
-            .arg(format!("--package-name={}-{}", name, target.triple))
-            .arg("--component-name=cargo")
-            .arg("--legacy-manifest-dirs=rustlib,cargo");
-
-        builder.info(&format!("Dist cargo stage{} ({})", compiler.stage, target));
-        let _time = timeit(builder);
-        builder.run(&mut cmd);
-        distdir(builder).join(format!("{}-{}.tar.gz", name, target.triple))
+
+        tarball.generate()
     }
 }
 
@@ -1311,19 +1018,6 @@ fn run(self, builder: &Builder<'_>) -> Option<PathBuf> {
         let target = self.target;
         assert!(builder.config.extended);
 
-        let src = builder.src.join("src/tools/rls");
-        let release_num = builder.release_num("rls");
-        let name = pkgname(builder, "rls");
-        let version = builder.rls_info.version(builder, &release_num);
-
-        let tmp = tmpdir(builder);
-        let image = tmp.join("rls-image");
-        drop(fs::remove_dir_all(&image));
-        t!(fs::create_dir_all(&image));
-
-        // Prepare the image directory
-        // We expect RLS to build, because we've exited this step above if tool
-        // state for RLS isn't testing.
         let rls = builder
             .ensure(tool::Rls { compiler, target, extra_features: Vec::new() })
             .or_else(|| {
@@ -1331,43 +1025,12 @@ fn run(self, builder: &Builder<'_>) -> Option<PathBuf> {
                 None
             })?;
 
-        builder.install(&rls, &image.join("bin"), 0o755);
-        let doc = image.join("share/doc/rls");
-        builder.install(&src.join("README.md"), &doc, 0o644);
-        builder.install(&src.join("LICENSE-MIT"), &doc, 0o644);
-        builder.install(&src.join("LICENSE-APACHE"), &doc, 0o644);
-
-        // Prepare the overlay
-        let overlay = tmp.join("rls-overlay");
-        drop(fs::remove_dir_all(&overlay));
-        t!(fs::create_dir_all(&overlay));
-        builder.install(&src.join("README.md"), &overlay, 0o644);
-        builder.install(&src.join("LICENSE-MIT"), &overlay, 0o644);
-        builder.install(&src.join("LICENSE-APACHE"), &overlay, 0o644);
-        builder.create(&overlay.join("version"), &version);
-
-        // Generate the installer tarball
-        let mut cmd = rust_installer(builder);
-        cmd.arg("generate")
-            .arg("--product-name=Rust")
-            .arg("--rel-manifest-dir=rustlib")
-            .arg("--success-message=RLS-ready-to-serve.")
-            .arg("--image-dir")
-            .arg(&image)
-            .arg("--work-dir")
-            .arg(&tmpdir(builder))
-            .arg("--output-dir")
-            .arg(&distdir(builder))
-            .arg("--non-installed-overlay")
-            .arg(&overlay)
-            .arg(format!("--package-name={}-{}", name, target.triple))
-            .arg("--legacy-manifest-dirs=rustlib,cargo")
-            .arg("--component-name=rls-preview");
-
-        builder.info(&format!("Dist RLS stage{} ({})", compiler.stage, target.triple));
-        let _time = timeit(builder);
-        builder.run(&mut cmd);
-        Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target.triple)))
+        let mut tarball = Tarball::new(builder, "rls", &target.triple);
+        tarball.set_overlay(OverlayKind::RLS);
+        tarball.is_preview(true);
+        tarball.add_file(rls, "bin", 0o755);
+        tarball.add_legal_and_readme_to("share/doc/rls");
+        Some(tarball.generate())
     }
 }
 
@@ -1407,60 +1070,16 @@ fn run(self, builder: &Builder<'_>) -> Option<PathBuf> {
             return None;
         }
 
-        let src = builder.src.join("src/tools/rust-analyzer");
-        let release_num = builder.release_num("rust-analyzer/crates/rust-analyzer");
-        let name = pkgname(builder, "rust-analyzer");
-        let version = builder.rust_analyzer_info.version(builder, &release_num);
-
-        let tmp = tmpdir(builder);
-        let image = tmp.join("rust-analyzer-image");
-        drop(fs::remove_dir_all(&image));
-        builder.create_dir(&image);
-
-        // Prepare the image directory
-        // We expect rust-analyer to always build, as it doesn't depend on rustc internals
-        // and doesn't have associated toolstate.
         let rust_analyzer = builder
             .ensure(tool::RustAnalyzer { compiler, target, extra_features: Vec::new() })
             .expect("rust-analyzer always builds");
 
-        builder.install(&rust_analyzer, &image.join("bin"), 0o755);
-        let doc = image.join("share/doc/rust-analyzer");
-        builder.install(&src.join("README.md"), &doc, 0o644);
-        builder.install(&src.join("LICENSE-APACHE"), &doc, 0o644);
-        builder.install(&src.join("LICENSE-MIT"), &doc, 0o644);
-
-        // Prepare the overlay
-        let overlay = tmp.join("rust-analyzer-overlay");
-        drop(fs::remove_dir_all(&overlay));
-        t!(fs::create_dir_all(&overlay));
-        builder.install(&src.join("README.md"), &overlay, 0o644);
-        builder.install(&src.join("LICENSE-APACHE"), &doc, 0o644);
-        builder.install(&src.join("LICENSE-MIT"), &doc, 0o644);
-        builder.create(&overlay.join("version"), &version);
-
-        // Generate the installer tarball
-        let mut cmd = rust_installer(builder);
-        cmd.arg("generate")
-            .arg("--product-name=Rust")
-            .arg("--rel-manifest-dir=rustlib")
-            .arg("--success-message=rust-analyzer-ready-to-serve.")
-            .arg("--image-dir")
-            .arg(&image)
-            .arg("--work-dir")
-            .arg(&tmpdir(builder))
-            .arg("--output-dir")
-            .arg(&distdir(builder))
-            .arg("--non-installed-overlay")
-            .arg(&overlay)
-            .arg(format!("--package-name={}-{}", name, target.triple))
-            .arg("--legacy-manifest-dirs=rustlib,cargo")
-            .arg("--component-name=rust-analyzer-preview");
-
-        builder.info(&format!("Dist rust-analyzer stage{} ({})", compiler.stage, target));
-        let _time = timeit(builder);
-        builder.run(&mut cmd);
-        Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target.triple)))
+        let mut tarball = Tarball::new(builder, "rust-analyzer", &target.triple);
+        tarball.set_overlay(OverlayKind::RustAnalyzer);
+        tarball.is_preview(true);
+        tarball.add_file(rust_analyzer, "bin", 0o755);
+        tarball.add_legal_and_readme_to("share/doc/rust-analyzer");
+        Some(tarball.generate())
     }
 }
 
@@ -1494,16 +1113,6 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
         let target = self.target;
         assert!(builder.config.extended);
 
-        let src = builder.src.join("src/tools/clippy");
-        let release_num = builder.release_num("clippy");
-        let name = pkgname(builder, "clippy");
-        let version = builder.clippy_info.version(builder, &release_num);
-
-        let tmp = tmpdir(builder);
-        let image = tmp.join("clippy-image");
-        drop(fs::remove_dir_all(&image));
-        builder.create_dir(&image);
-
         // Prepare the image directory
         // We expect clippy to build, because we've exited this step above if tool
         // state for clippy isn't testing.
@@ -1514,44 +1123,13 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
             .ensure(tool::CargoClippy { compiler, target, extra_features: Vec::new() })
             .expect("clippy expected to build - essential tool");
 
-        builder.install(&clippy, &image.join("bin"), 0o755);
-        builder.install(&cargoclippy, &image.join("bin"), 0o755);
-        let doc = image.join("share/doc/clippy");
-        builder.install(&src.join("README.md"), &doc, 0o644);
-        builder.install(&src.join("LICENSE-APACHE"), &doc, 0o644);
-        builder.install(&src.join("LICENSE-MIT"), &doc, 0o644);
-
-        // Prepare the overlay
-        let overlay = tmp.join("clippy-overlay");
-        drop(fs::remove_dir_all(&overlay));
-        t!(fs::create_dir_all(&overlay));
-        builder.install(&src.join("README.md"), &overlay, 0o644);
-        builder.install(&src.join("LICENSE-APACHE"), &doc, 0o644);
-        builder.install(&src.join("LICENSE-MIT"), &doc, 0o644);
-        builder.create(&overlay.join("version"), &version);
-
-        // Generate the installer tarball
-        let mut cmd = rust_installer(builder);
-        cmd.arg("generate")
-            .arg("--product-name=Rust")
-            .arg("--rel-manifest-dir=rustlib")
-            .arg("--success-message=clippy-ready-to-serve.")
-            .arg("--image-dir")
-            .arg(&image)
-            .arg("--work-dir")
-            .arg(&tmpdir(builder))
-            .arg("--output-dir")
-            .arg(&distdir(builder))
-            .arg("--non-installed-overlay")
-            .arg(&overlay)
-            .arg(format!("--package-name={}-{}", name, target.triple))
-            .arg("--legacy-manifest-dirs=rustlib,cargo")
-            .arg("--component-name=clippy-preview");
-
-        builder.info(&format!("Dist clippy stage{} ({})", compiler.stage, target));
-        let _time = timeit(builder);
-        builder.run(&mut cmd);
-        distdir(builder).join(format!("{}-{}.tar.gz", name, target.triple))
+        let mut tarball = Tarball::new(builder, "clippy", &target.triple);
+        tarball.set_overlay(OverlayKind::Clippy);
+        tarball.is_preview(true);
+        tarball.add_file(clippy, "bin", 0o755);
+        tarball.add_file(cargoclippy, "bin", 0o755);
+        tarball.add_legal_and_readme_to("share/doc/clippy");
+        tarball.generate()
     }
 }
 
@@ -1585,19 +1163,6 @@ fn run(self, builder: &Builder<'_>) -> Option<PathBuf> {
         let target = self.target;
         assert!(builder.config.extended);
 
-        let src = builder.src.join("src/tools/miri");
-        let release_num = builder.release_num("miri");
-        let name = pkgname(builder, "miri");
-        let version = builder.miri_info.version(builder, &release_num);
-
-        let tmp = tmpdir(builder);
-        let image = tmp.join("miri-image");
-        drop(fs::remove_dir_all(&image));
-        builder.create_dir(&image);
-
-        // Prepare the image directory
-        // We expect miri to build, because we've exited this step above if tool
-        // state for miri isn't testing.
         let miri = builder
             .ensure(tool::Miri { compiler, target, extra_features: Vec::new() })
             .or_else(|| {
@@ -1611,44 +1176,13 @@ fn run(self, builder: &Builder<'_>) -> Option<PathBuf> {
                 None
             })?;
 
-        builder.install(&miri, &image.join("bin"), 0o755);
-        builder.install(&cargomiri, &image.join("bin"), 0o755);
-        let doc = image.join("share/doc/miri");
-        builder.install(&src.join("README.md"), &doc, 0o644);
-        builder.install(&src.join("LICENSE-APACHE"), &doc, 0o644);
-        builder.install(&src.join("LICENSE-MIT"), &doc, 0o644);
-
-        // Prepare the overlay
-        let overlay = tmp.join("miri-overlay");
-        drop(fs::remove_dir_all(&overlay));
-        t!(fs::create_dir_all(&overlay));
-        builder.install(&src.join("README.md"), &overlay, 0o644);
-        builder.install(&src.join("LICENSE-APACHE"), &doc, 0o644);
-        builder.install(&src.join("LICENSE-MIT"), &doc, 0o644);
-        builder.create(&overlay.join("version"), &version);
-
-        // Generate the installer tarball
-        let mut cmd = rust_installer(builder);
-        cmd.arg("generate")
-            .arg("--product-name=Rust")
-            .arg("--rel-manifest-dir=rustlib")
-            .arg("--success-message=miri-ready-to-serve.")
-            .arg("--image-dir")
-            .arg(&image)
-            .arg("--work-dir")
-            .arg(&tmpdir(builder))
-            .arg("--output-dir")
-            .arg(&distdir(builder))
-            .arg("--non-installed-overlay")
-            .arg(&overlay)
-            .arg(format!("--package-name={}-{}", name, target.triple))
-            .arg("--legacy-manifest-dirs=rustlib,cargo")
-            .arg("--component-name=miri-preview");
-
-        builder.info(&format!("Dist miri stage{} ({})", compiler.stage, target));
-        let _time = timeit(builder);
-        builder.run(&mut cmd);
-        Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target.triple)))
+        let mut tarball = Tarball::new(builder, "miri", &target.triple);
+        tarball.set_overlay(OverlayKind::Miri);
+        tarball.is_preview(true);
+        tarball.add_file(miri, "bin", 0o755);
+        tarball.add_file(cargomiri, "bin", 0o755);
+        tarball.add_legal_and_readme_to("share/doc/miri");
+        Some(tarball.generate())
     }
 }
 
@@ -1681,17 +1215,6 @@ fn run(self, builder: &Builder<'_>) -> Option<PathBuf> {
         let compiler = self.compiler;
         let target = self.target;
 
-        let src = builder.src.join("src/tools/rustfmt");
-        let release_num = builder.release_num("rustfmt");
-        let name = pkgname(builder, "rustfmt");
-        let version = builder.rustfmt_info.version(builder, &release_num);
-
-        let tmp = tmpdir(builder);
-        let image = tmp.join("rustfmt-image");
-        drop(fs::remove_dir_all(&image));
-        builder.create_dir(&image);
-
-        // Prepare the image directory
         let rustfmt = builder
             .ensure(tool::Rustfmt { compiler, target, extra_features: Vec::new() })
             .or_else(|| {
@@ -1705,44 +1228,13 @@ fn run(self, builder: &Builder<'_>) -> Option<PathBuf> {
                 None
             })?;
 
-        builder.install(&rustfmt, &image.join("bin"), 0o755);
-        builder.install(&cargofmt, &image.join("bin"), 0o755);
-        let doc = image.join("share/doc/rustfmt");
-        builder.install(&src.join("README.md"), &doc, 0o644);
-        builder.install(&src.join("LICENSE-MIT"), &doc, 0o644);
-        builder.install(&src.join("LICENSE-APACHE"), &doc, 0o644);
-
-        // Prepare the overlay
-        let overlay = tmp.join("rustfmt-overlay");
-        drop(fs::remove_dir_all(&overlay));
-        builder.create_dir(&overlay);
-        builder.install(&src.join("README.md"), &overlay, 0o644);
-        builder.install(&src.join("LICENSE-MIT"), &overlay, 0o644);
-        builder.install(&src.join("LICENSE-APACHE"), &overlay, 0o644);
-        builder.create(&overlay.join("version"), &version);
-
-        // Generate the installer tarball
-        let mut cmd = rust_installer(builder);
-        cmd.arg("generate")
-            .arg("--product-name=Rust")
-            .arg("--rel-manifest-dir=rustlib")
-            .arg("--success-message=rustfmt-ready-to-fmt.")
-            .arg("--image-dir")
-            .arg(&image)
-            .arg("--work-dir")
-            .arg(&tmpdir(builder))
-            .arg("--output-dir")
-            .arg(&distdir(builder))
-            .arg("--non-installed-overlay")
-            .arg(&overlay)
-            .arg(format!("--package-name={}-{}", name, target.triple))
-            .arg("--legacy-manifest-dirs=rustlib,cargo")
-            .arg("--component-name=rustfmt-preview");
-
-        builder.info(&format!("Dist Rustfmt stage{} ({})", compiler.stage, target));
-        let _time = timeit(builder);
-        builder.run(&mut cmd);
-        Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target.triple)))
+        let mut tarball = Tarball::new(builder, "rustfmt", &target.triple);
+        tarball.set_overlay(OverlayKind::Rustfmt);
+        tarball.is_preview(true);
+        tarball.add_file(rustfmt, "bin", 0o755);
+        tarball.add_file(cargofmt, "bin", 0o755);
+        tarball.add_legal_and_readme_to("share/doc/rustfmt");
+        Some(tarball.generate())
     }
 }
 
@@ -1791,24 +1283,14 @@ fn run(self, builder: &Builder<'_>) {
         let analysis_installer = builder.ensure(Analysis { compiler, target });
 
         let docs_installer = builder.ensure(Docs { host: target });
-        let std_installer =
-            builder.ensure(Std { compiler: builder.compiler(stage, target), target });
+        let std_installer = builder.ensure(Std { compiler, target });
 
-        let tmp = tmpdir(builder);
-        let overlay = tmp.join("extended-overlay");
         let etc = builder.src.join("src/etc/installer");
-        let work = tmp.join("work");
-
-        let _ = fs::remove_dir_all(&overlay);
-        builder.install(&builder.src.join("COPYRIGHT"), &overlay, 0o644);
-        builder.install(&builder.src.join("LICENSE-APACHE"), &overlay, 0o644);
-        builder.install(&builder.src.join("LICENSE-MIT"), &overlay, 0o644);
-        let version = builder.rust_version();
-        builder.create(&overlay.join("version"), &version);
-        if let Some(sha) = builder.rust_sha() {
-            builder.create(&overlay.join("git-commit-hash"), &sha);
+
+        // Avoid producing tarballs during a dry run.
+        if builder.config.dry_run {
+            return;
         }
-        builder.install(&etc.join("README.md"), &overlay, 0o644);
 
         // When rust-std package split from rustc, we needed to ensure that during
         // upgrades rustc was upgraded before rust-std. To avoid rustc clobbering
@@ -1823,39 +1305,22 @@ fn run(self, builder: &Builder<'_>) {
         tarballs.extend(miri_installer.clone());
         tarballs.extend(rustfmt_installer.clone());
         tarballs.extend(llvm_tools_installer);
-        tarballs.push(analysis_installer);
-        tarballs.push(std_installer);
-        if builder.config.docs {
+        if let Some(analysis_installer) = analysis_installer {
+            tarballs.push(analysis_installer);
+        }
+        tarballs.push(std_installer.expect("missing std"));
+        if let Some(docs_installer) = docs_installer {
             tarballs.push(docs_installer);
         }
         if target.contains("pc-windows-gnu") {
             tarballs.push(mingw_installer.unwrap());
         }
-        let mut input_tarballs = tarballs[0].as_os_str().to_owned();
-        for tarball in &tarballs[1..] {
-            input_tarballs.push(",");
-            input_tarballs.push(tarball);
-        }
 
-        builder.info("building combined installer");
-        let mut cmd = rust_installer(builder);
-        cmd.arg("combine")
-            .arg("--product-name=Rust")
-            .arg("--rel-manifest-dir=rustlib")
-            .arg("--success-message=Rust-is-ready-to-roll.")
-            .arg("--work-dir")
-            .arg(&work)
-            .arg("--output-dir")
-            .arg(&distdir(builder))
-            .arg(format!("--package-name={}-{}", pkgname(builder, "rust"), target.triple))
-            .arg("--legacy-manifest-dirs=rustlib,cargo")
-            .arg("--input-tarballs")
-            .arg(input_tarballs)
-            .arg("--non-installed-overlay")
-            .arg(&overlay);
-        let time = timeit(&builder);
-        builder.run(&mut cmd);
-        drop(time);
+        let mut tarball = Tarball::new(builder, "rust", &target.triple);
+        let work = tarball.persist_work_dir();
+        tarball.combine(&tarballs);
+
+        let tmp = tmpdir(builder).join("combined-tarball");
 
         let mut license = String::new();
         license += &builder.read(&builder.src.join("COPYRIGHT"));
@@ -2428,58 +1893,25 @@ fn run(self, builder: &Builder<'_>) -> Option<PathBuf> {
             }
         }
 
-        builder.info(&format!("Dist LlvmTools ({})", target));
-        let _time = timeit(builder);
-        let src = builder.src.join("src/llvm-project/llvm");
-        let name = pkgname(builder, "llvm-tools");
-
-        let tmp = tmpdir(builder);
-        let image = tmp.join("llvm-tools-image");
-        drop(fs::remove_dir_all(&image));
+        let mut tarball = Tarball::new(builder, "llvm-tools", &target.triple);
+        tarball.set_overlay(OverlayKind::LLVM);
+        tarball.is_preview(true);
 
         // Prepare the image directory
         let src_bindir = builder.llvm_out(target).join("bin");
-        let dst_bindir = image.join("lib/rustlib").join(&*target.triple).join("bin");
-        t!(fs::create_dir_all(&dst_bindir));
+        let dst_bindir = format!("lib/rustlib/{}/bin", target.triple);
         for tool in LLVM_TOOLS {
             let exe = src_bindir.join(exe(tool, target));
-            builder.install(&exe, &dst_bindir, 0o755);
+            tarball.add_file(&exe, &dst_bindir, 0o755);
         }
 
         // Copy libLLVM.so to the target lib dir as well, so the RPATH like
         // `$ORIGIN/../lib` can find it. It may also be used as a dependency
         // of `rustc-dev` to support the inherited `-lLLVM` when using the
         // compiler libraries.
-        maybe_install_llvm_target(builder, target, &image);
-
-        // Prepare the overlay
-        let overlay = tmp.join("llvm-tools-overlay");
-        drop(fs::remove_dir_all(&overlay));
-        builder.create_dir(&overlay);
-        builder.install(&src.join("README.txt"), &overlay, 0o644);
-        builder.install(&src.join("LICENSE.TXT"), &overlay, 0o644);
-        builder.create(&overlay.join("version"), &builder.llvm_tools_vers());
-
-        // Generate the installer tarball
-        let mut cmd = rust_installer(builder);
-        cmd.arg("generate")
-            .arg("--product-name=Rust")
-            .arg("--rel-manifest-dir=rustlib")
-            .arg("--success-message=llvm-tools-installed.")
-            .arg("--image-dir")
-            .arg(&image)
-            .arg("--work-dir")
-            .arg(&tmpdir(builder))
-            .arg("--output-dir")
-            .arg(&distdir(builder))
-            .arg("--non-installed-overlay")
-            .arg(&overlay)
-            .arg(format!("--package-name={}-{}", name, target.triple))
-            .arg("--legacy-manifest-dirs=rustlib,cargo")
-            .arg("--component-name=llvm-tools-preview");
-
-        builder.run(&mut cmd);
-        Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target.triple)))
+        maybe_install_llvm_target(builder, target, tarball.image_dir());
+
+        Some(tarball.generate())
     }
 }
 
@@ -2515,70 +1947,35 @@ fn run(self, builder: &Builder<'_>) -> Option<PathBuf> {
             }
         }
 
-        builder.info(&format!("Dist RustDev ({})", target));
-        let _time = timeit(builder);
-        let src = builder.src.join("src/llvm-project/llvm");
-        let name = pkgname(builder, "rust-dev");
-
-        let tmp = tmpdir(builder);
-        let image = tmp.join("rust-dev-image");
-        drop(fs::remove_dir_all(&image));
-
-        // Prepare the image directory
-        let dst_bindir = image.join("bin");
-        t!(fs::create_dir_all(&dst_bindir));
+        let mut tarball = Tarball::new(builder, "rust-dev", &target.triple);
+        tarball.set_overlay(OverlayKind::LLVM);
 
         let src_bindir = builder.llvm_out(target).join("bin");
-        let install_bin =
-            |name| builder.install(&src_bindir.join(exe(name, target)), &dst_bindir, 0o755);
-        install_bin("llvm-config");
-        install_bin("llvm-ar");
-        install_bin("llvm-objdump");
-        install_bin("llvm-profdata");
-        install_bin("llvm-bcanalyzer");
-        install_bin("llvm-cov");
-        install_bin("llvm-dwp");
-        builder.install(&builder.llvm_filecheck(target), &dst_bindir, 0o755);
+        for bin in &[
+            "llvm-config",
+            "llvm-ar",
+            "llvm-objdump",
+            "llvm-profdata",
+            "llvm-bcanalyzer",
+            "llvm-cov",
+            "llvm-dwp",
+        ] {
+            tarball.add_file(src_bindir.join(exe(bin, target)), "bin", 0o755);
+        }
+        tarball.add_file(&builder.llvm_filecheck(target), "bin", 0o755);
 
         // Copy the include directory as well; needed mostly to build
         // librustc_llvm properly (e.g., llvm-config.h is in here). But also
         // just broadly useful to be able to link against the bundled LLVM.
-        builder.cp_r(&builder.llvm_out(target).join("include"), &image.join("include"));
+        tarball.add_dir(&builder.llvm_out(target).join("include"), "include");
 
         // Copy libLLVM.so to the target lib dir as well, so the RPATH like
         // `$ORIGIN/../lib` can find it. It may also be used as a dependency
         // of `rustc-dev` to support the inherited `-lLLVM` when using the
         // compiler libraries.
-        maybe_install_llvm(builder, target, &image.join("lib"));
-
-        // Prepare the overlay
-        let overlay = tmp.join("rust-dev-overlay");
-        drop(fs::remove_dir_all(&overlay));
-        builder.create_dir(&overlay);
-        builder.install(&src.join("README.txt"), &overlay, 0o644);
-        builder.install(&src.join("LICENSE.TXT"), &overlay, 0o644);
-        builder.create(&overlay.join("version"), &builder.rust_version());
-
-        // Generate the installer tarball
-        let mut cmd = rust_installer(builder);
-        cmd.arg("generate")
-            .arg("--product-name=Rust")
-            .arg("--rel-manifest-dir=rustlib")
-            .arg("--success-message=rust-dev-installed.")
-            .arg("--image-dir")
-            .arg(&image)
-            .arg("--work-dir")
-            .arg(&tmpdir(builder))
-            .arg("--output-dir")
-            .arg(&distdir(builder))
-            .arg("--non-installed-overlay")
-            .arg(&overlay)
-            .arg(format!("--package-name={}-{}", name, target.triple))
-            .arg("--legacy-manifest-dirs=rustlib,cargo")
-            .arg("--component-name=rust-dev");
-
-        builder.run(&mut cmd);
-        Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target.triple)))
+        maybe_install_llvm(builder, target, &tarball.image_dir().join("lib"));
+
+        Some(tarball.generate())
     }
 }
 
@@ -2607,44 +2004,40 @@ fn make_run(run: RunConfig<'_>) {
     fn run(self, builder: &Builder<'_>) -> PathBuf {
         let build_manifest = builder.tool_exe(Tool::BuildManifest);
 
-        let name = pkgname(builder, "build-manifest");
-        let tmp = tmpdir(builder);
-
-        // Prepare the image.
-        let image = tmp.join("build-manifest-image");
-        let image_bin = image.join("bin");
-        let _ = fs::remove_dir_all(&image);
-        t!(fs::create_dir_all(&image_bin));
-        builder.install(&build_manifest, &image_bin, 0o755);
-
-        // Prepare the overlay.
-        let overlay = tmp.join("build-manifest-overlay");
-        let _ = fs::remove_dir_all(&overlay);
-        builder.create_dir(&overlay);
-        builder.create(&overlay.join("version"), &builder.rust_version());
-        for file in &["COPYRIGHT", "LICENSE-APACHE", "LICENSE-MIT", "README.md"] {
-            builder.install(&builder.src.join(file), &overlay, 0o644);
-        }
+        let tarball = Tarball::new(builder, "build-manifest", &self.target.triple);
+        tarball.add_file(&build_manifest, "bin", 0o755);
+        tarball.generate()
+    }
+}
+
+/// Tarball containing artifacts necessary to reproduce the build of rustc.
+///
+/// Currently this is the PGO profile data.
+///
+/// Should not be considered stable by end users.
+#[derive(Clone, Debug, Eq, Hash, PartialEq)]
+pub struct ReproducibleArtifacts {
+    pub target: TargetSelection,
+}
+
+impl Step for ReproducibleArtifacts {
+    type Output = Option<PathBuf>;
+    const DEFAULT: bool = true;
+    const ONLY_HOSTS: bool = true;
+
+    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
+        run.path("reproducible")
+    }
+
+    fn make_run(run: RunConfig<'_>) {
+        run.builder.ensure(ReproducibleArtifacts { target: run.target });
+    }
+
+    fn run(self, builder: &Builder<'_>) -> Self::Output {
+        let path = builder.config.rust_profile_use.as_ref()?;
 
-        // Create the final tarball.
-        let mut cmd = rust_installer(builder);
-        cmd.arg("generate")
-            .arg("--product-name=Rust")
-            .arg("--rel-manifest-dir=rustlib")
-            .arg("--success-message=build-manifest installed.")
-            .arg("--image-dir")
-            .arg(&image)
-            .arg("--work-dir")
-            .arg(&tmpdir(builder))
-            .arg("--output-dir")
-            .arg(&distdir(builder))
-            .arg("--non-installed-overlay")
-            .arg(&overlay)
-            .arg(format!("--package-name={}-{}", name, self.target.triple))
-            .arg("--legacy-manifest-dirs=rustlib,cargo")
-            .arg("--component-name=build-manifest");
-
-        builder.run(&mut cmd);
-        distdir(builder).join(format!("{}-{}.tar.gz", name, self.target.triple))
+        let tarball = Tarball::new(builder, "reproducible-artifacts", &self.target.triple);
+        tarball.add_file(path, ".", 0o644);
+        Some(tarball.generate())
     }
 }
index 8cacc2512eff130ad030423180ba7f7acc46a062..8c849846676f0e386103c2b604e161b02ed6a4c2 100644 (file)
@@ -500,18 +500,17 @@ fn run(self, builder: &Builder<'_>) {
         let target = self.target;
         builder.info(&format!("Documenting stage{} compiler ({})", stage, target));
 
-        // This is the intended out directory for compiler documentation.
-        let out = builder.compiler_doc_out(target);
-        t!(fs::create_dir_all(&out));
-
-        let compiler = builder.compiler(stage, builder.config.build);
-
         if !builder.config.compiler_docs {
             builder.info("\tskipping - compiler/librustdoc docs disabled");
             return;
         }
 
+        // This is the intended out directory for compiler documentation.
+        let out = builder.compiler_doc_out(target);
+        t!(fs::create_dir_all(&out));
+
         // Build rustc.
+        let compiler = builder.compiler(stage, builder.config.build);
         builder.ensure(compile::Rustc { compiler, target });
 
         // This uses a shared directory so that librustdoc documentation gets
@@ -521,16 +520,17 @@ fn run(self, builder: &Builder<'_>) {
         // merging the search index, or generating local (relative) links.
         let out_dir = builder.stage_out(compiler, Mode::Rustc).join(target.triple).join("doc");
         t!(symlink_dir_force(&builder.config, &out, &out_dir));
+        // Cargo puts proc macros in `target/doc` even if you pass `--target`
+        // explicitly (https://github.com/rust-lang/cargo/issues/7677).
+        let proc_macro_out_dir = builder.stage_out(compiler, Mode::Rustc).join("doc");
+        t!(symlink_dir_force(&builder.config, &out, &proc_macro_out_dir));
 
         // Build cargo command.
         let mut cargo = builder.cargo(compiler, Mode::Rustc, SourceType::InTree, target, "doc");
         cargo.rustdocflag("--document-private-items");
         cargo.rustdocflag("--enable-index-page");
         cargo.rustdocflag("-Zunstable-options");
-        // cfg(not(bootstrap)), can be removed on the next beta bump
-        if stage != 0 {
-            cargo.rustdocflag("-Znormalize-docs");
-        }
+        cargo.rustdocflag("-Znormalize-docs");
         compile::rustc_cargo(builder, &mut cargo, target);
 
         // Only include compiler crates, no dependencies of those, such as `libc`.
@@ -628,6 +628,8 @@ fn run(self, builder: &Builder<'_>) {
         cargo.arg("-p").arg("rustdoc");
 
         cargo.rustdocflag("--document-private-items");
+        cargo.rustdocflag("--enable-index-page");
+        cargo.rustdocflag("-Zunstable-options");
         builder.run(&mut cargo.into());
     }
 }
index 5a8096674c6dae4e8b1d3dbf760b71e6e3fc3660..d6a45f1c17076f48ffb01412126f24c63583e967 100644 (file)
@@ -68,6 +68,9 @@ pub struct Flags {
     pub deny_warnings: Option<bool>,
 
     pub llvm_skip_rebuild: Option<bool>,
+
+    pub rust_profile_use: Option<String>,
+    pub rust_profile_generate: Option<String>,
 }
 
 pub enum Subcommand {
@@ -219,6 +222,8 @@ pub fn parse(args: &[String]) -> Flags {
              VALUE overrides the skip-rebuild option in config.toml.",
             "VALUE",
         );
+        opts.optopt("", "rust-profile-generate", "rustc error format", "FORMAT");
+        opts.optopt("", "rust-profile-use", "rustc error format", "FORMAT");
 
         // We can't use getopt to parse the options until we have completed specifying which
         // options are valid, but under the current implementation, some options are conditional on
@@ -674,6 +679,8 @@ pub fn parse(args: &[String]) -> Flags {
             color: matches
                 .opt_get_default("color", Color::Auto)
                 .expect("`color` should be `always`, `never`, or `auto`"),
+            rust_profile_use: matches.opt_str("rust-profile-use"),
+            rust_profile_generate: matches.opt_str("rust-profile-generate"),
         }
     }
 }
index ece9bdc7a6499f43d4ff3ab88931744e79c312e8..a47ddfbcc1f180c13deeb18bef9c449efd1d5dad 100644 (file)
 mod run;
 mod sanity;
 mod setup;
+mod tarball;
 mod test;
 mod tool;
 mod toolstate;
@@ -1068,10 +1069,6 @@ fn rust_package_vers(&self) -> String {
         self.package_vers(&self.version)
     }
 
-    fn llvm_tools_vers(&self) -> String {
-        self.rust_version()
-    }
-
     fn llvm_link_tools_dynamically(&self, target: TargetSelection) -> bool {
         target.contains("linux-gnu") || target.contains("apple-darwin")
     }
index 1564cfb06199c7e77292e3b951c20441d4b20387..fd39944e176fe991405a2a01f9da9c9745e0fb85 100644 (file)
@@ -66,7 +66,6 @@ check-stage2-T-x86_64-unknown-linux-musl-H-x86_64-unknown-linux-gnu:
 
 TESTS_IN_2 := \
        src/test/ui \
-       src/test/compile-fail \
        src/tools/linkchecker
 
 ci-subset-1:
@@ -75,8 +74,7 @@ ci-subset-2:
        $(Q)$(BOOTSTRAP) test --stage 2 $(TESTS_IN_2)
 
 TESTS_IN_MINGW_2 := \
-       src/test/ui \
-       src/test/compile-fail
+       src/test/ui
 
 ci-mingw-subset-1:
        $(Q)$(BOOTSTRAP) test --stage 2 $(TESTS_IN_MINGW_2:%=--exclude %)
diff --git a/src/bootstrap/tarball.rs b/src/bootstrap/tarball.rs
new file mode 100644 (file)
index 0000000..137370f
--- /dev/null
@@ -0,0 +1,318 @@
+use std::{
+    path::{Path, PathBuf},
+    process::Command,
+};
+
+use build_helper::t;
+
+use crate::builder::Builder;
+
+#[derive(Copy, Clone)]
+pub(crate) enum OverlayKind {
+    Rust,
+    LLVM,
+    Cargo,
+    Clippy,
+    Miri,
+    Rustfmt,
+    RLS,
+    RustAnalyzer,
+}
+
+impl OverlayKind {
+    fn legal_and_readme(&self) -> &[&str] {
+        match self {
+            OverlayKind::Rust => &["COPYRIGHT", "LICENSE-APACHE", "LICENSE-MIT", "README.md"],
+            OverlayKind::LLVM => {
+                &["src/llvm-project/llvm/LICENSE.TXT", "src/llvm-project/llvm/README.txt"]
+            }
+            OverlayKind::Cargo => &[
+                "src/tools/cargo/README.md",
+                "src/tools/cargo/LICENSE-MIT",
+                "src/tools/cargo/LICENSE-APACHE",
+                "src/tools/cargo/LICENSE-THIRD-PARTY",
+            ],
+            OverlayKind::Clippy => &[
+                "src/tools/clippy/README.md",
+                "src/tools/clippy/LICENSE-APACHE",
+                "src/tools/clippy/LICENSE-MIT",
+            ],
+            OverlayKind::Miri => &[
+                "src/tools/miri/README.md",
+                "src/tools/miri/LICENSE-APACHE",
+                "src/tools/miri/LICENSE-MIT",
+            ],
+            OverlayKind::Rustfmt => &[
+                "src/tools/rustfmt/README.md",
+                "src/tools/rustfmt/LICENSE-APACHE",
+                "src/tools/rustfmt/LICENSE-MIT",
+            ],
+            OverlayKind::RLS => &[
+                "src/tools/rls/README.md",
+                "src/tools/rls/LICENSE-APACHE",
+                "src/tools/rls/LICENSE-MIT",
+            ],
+            OverlayKind::RustAnalyzer => &[
+                "src/tools/rust-analyzer/README.md",
+                "src/tools/rust-analyzer/LICENSE-APACHE",
+                "src/tools/rust-analyzer/LICENSE-MIT",
+            ],
+        }
+    }
+
+    fn version(&self, builder: &Builder<'_>) -> String {
+        match self {
+            OverlayKind::Rust => builder.rust_version(),
+            OverlayKind::LLVM => builder.rust_version(),
+            OverlayKind::Cargo => {
+                builder.cargo_info.version(builder, &builder.release_num("cargo"))
+            }
+            OverlayKind::Clippy => {
+                builder.clippy_info.version(builder, &builder.release_num("clippy"))
+            }
+            OverlayKind::Miri => builder.miri_info.version(builder, &builder.release_num("miri")),
+            OverlayKind::Rustfmt => {
+                builder.rustfmt_info.version(builder, &builder.release_num("rustfmt"))
+            }
+            OverlayKind::RLS => builder.rls_info.version(builder, &builder.release_num("rls")),
+            OverlayKind::RustAnalyzer => builder
+                .rust_analyzer_info
+                .version(builder, &builder.release_num("rust-analyzer/crates/rust-analyzer")),
+        }
+    }
+}
+
+pub(crate) struct Tarball<'a> {
+    builder: &'a Builder<'a>,
+
+    pkgname: String,
+    component: String,
+    target: Option<String>,
+    product_name: String,
+    overlay: OverlayKind,
+
+    temp_dir: PathBuf,
+    image_dir: PathBuf,
+    overlay_dir: PathBuf,
+
+    include_target_in_component_name: bool,
+    is_preview: bool,
+    delete_temp_dir: bool,
+}
+
+impl<'a> Tarball<'a> {
+    pub(crate) fn new(builder: &'a Builder<'a>, component: &str, target: &str) -> Self {
+        Self::new_inner(builder, component, Some(target.into()))
+    }
+
+    pub(crate) fn new_targetless(builder: &'a Builder<'a>, component: &str) -> Self {
+        Self::new_inner(builder, component, None)
+    }
+
+    fn new_inner(builder: &'a Builder<'a>, component: &str, target: Option<String>) -> Self {
+        let pkgname = crate::dist::pkgname(builder, component);
+
+        let mut temp_dir = builder.out.join("tmp").join("tarball").join(component);
+        if let Some(target) = &target {
+            temp_dir = temp_dir.join(target);
+        }
+        let _ = std::fs::remove_dir_all(&temp_dir);
+
+        let image_dir = temp_dir.join("image");
+        let overlay_dir = temp_dir.join("overlay");
+
+        Self {
+            builder,
+
+            pkgname,
+            component: component.into(),
+            target,
+            product_name: "Rust".into(),
+            overlay: OverlayKind::Rust,
+
+            temp_dir,
+            image_dir,
+            overlay_dir,
+
+            include_target_in_component_name: false,
+            is_preview: false,
+            delete_temp_dir: true,
+        }
+    }
+
+    pub(crate) fn set_overlay(&mut self, overlay: OverlayKind) {
+        self.overlay = overlay;
+    }
+
+    pub(crate) fn set_product_name(&mut self, name: &str) {
+        self.product_name = name.into();
+    }
+
+    pub(crate) fn include_target_in_component_name(&mut self, include: bool) {
+        self.include_target_in_component_name = include;
+    }
+
+    pub(crate) fn is_preview(&mut self, is: bool) {
+        self.is_preview = is;
+    }
+
+    pub(crate) fn image_dir(&self) -> &Path {
+        t!(std::fs::create_dir_all(&self.image_dir));
+        &self.image_dir
+    }
+
+    pub(crate) fn add_file(&self, src: impl AsRef<Path>, destdir: impl AsRef<Path>, perms: u32) {
+        // create_dir_all fails to create `foo/bar/.`, so when the destination is "." this simply
+        // uses the base directory as the destination directory.
+        let destdir = if destdir.as_ref() == Path::new(".") {
+            self.image_dir.clone()
+        } else {
+            self.image_dir.join(destdir.as_ref())
+        };
+
+        t!(std::fs::create_dir_all(&destdir));
+        self.builder.install(src.as_ref(), &destdir, perms);
+    }
+
+    pub(crate) fn add_renamed_file(
+        &self,
+        src: impl AsRef<Path>,
+        destdir: impl AsRef<Path>,
+        new_name: &str,
+    ) {
+        let destdir = self.image_dir.join(destdir.as_ref());
+        t!(std::fs::create_dir_all(&destdir));
+        self.builder.copy(src.as_ref(), &destdir.join(new_name));
+    }
+
+    pub(crate) fn add_legal_and_readme_to(&self, destdir: impl AsRef<Path>) {
+        for file in self.overlay.legal_and_readme() {
+            self.add_file(self.builder.src.join(file), destdir.as_ref(), 0o644);
+        }
+    }
+
+    pub(crate) fn add_dir(&self, src: impl AsRef<Path>, dest: impl AsRef<Path>) {
+        let dest = self.image_dir.join(dest.as_ref());
+
+        t!(std::fs::create_dir_all(&dest));
+        self.builder.cp_r(src.as_ref(), &dest);
+    }
+
+    pub(crate) fn persist_work_dir(&mut self) -> PathBuf {
+        self.delete_temp_dir = false;
+        self.temp_dir.clone()
+    }
+
+    pub(crate) fn generate(self) -> PathBuf {
+        let mut component_name = self.component.clone();
+        if self.is_preview {
+            component_name.push_str("-preview");
+        }
+        if self.include_target_in_component_name {
+            component_name.push('-');
+            component_name.push_str(
+                &self
+                    .target
+                    .as_ref()
+                    .expect("include_target_in_component_name used in a targetless tarball"),
+            );
+        }
+
+        self.run(|this, cmd| {
+            cmd.arg("generate")
+                .arg("--image-dir")
+                .arg(&this.image_dir)
+                .arg(format!("--component-name={}", &component_name));
+            this.non_bare_args(cmd);
+        })
+    }
+
+    pub(crate) fn combine(self, tarballs: &[PathBuf]) {
+        let mut input_tarballs = tarballs[0].as_os_str().to_os_string();
+        for tarball in &tarballs[1..] {
+            input_tarballs.push(",");
+            input_tarballs.push(tarball);
+        }
+
+        self.run(|this, cmd| {
+            cmd.arg("combine").arg("--input-tarballs").arg(input_tarballs);
+            this.non_bare_args(cmd);
+        });
+    }
+
+    pub(crate) fn bare(self) -> PathBuf {
+        // Bare tarballs should have the top level directory match the package
+        // name, not "image". We rename the image directory just before passing
+        // into rust-installer.
+        let dest = self.temp_dir.join(self.package_name());
+        t!(std::fs::rename(&self.image_dir, &dest));
+
+        self.run(|this, cmd| {
+            cmd.arg("tarball")
+                .arg("--input")
+                .arg(&dest)
+                .arg("--output")
+                .arg(crate::dist::distdir(this.builder).join(this.package_name()));
+        })
+    }
+
+    fn package_name(&self) -> String {
+        if let Some(target) = &self.target {
+            format!("{}-{}", self.pkgname, target)
+        } else {
+            self.pkgname.clone()
+        }
+    }
+
+    fn non_bare_args(&self, cmd: &mut Command) {
+        cmd.arg("--rel-manifest-dir=rustlib")
+            .arg("--legacy-manifest-dirs=rustlib,cargo")
+            .arg(format!("--product-name={}", self.product_name))
+            .arg(format!("--success-message={} installed.", self.component))
+            .arg(format!("--package-name={}", self.package_name()))
+            .arg("--non-installed-overlay")
+            .arg(&self.overlay_dir)
+            .arg("--output-dir")
+            .arg(crate::dist::distdir(self.builder));
+    }
+
+    fn run(self, build_cli: impl FnOnce(&Tarball<'a>, &mut Command)) -> PathBuf {
+        t!(std::fs::create_dir_all(&self.overlay_dir));
+        self.builder.create(&self.overlay_dir.join("version"), &self.overlay.version(self.builder));
+        if let Some(sha) = self.builder.rust_sha() {
+            self.builder.create(&self.overlay_dir.join("git-commit-hash"), &sha);
+        }
+        for file in self.overlay.legal_and_readme() {
+            self.builder.install(&self.builder.src.join(file), &self.overlay_dir, 0o644);
+        }
+
+        let mut cmd = self.builder.tool_cmd(crate::tool::Tool::RustInstaller);
+
+        let package_name = self.package_name();
+        self.builder.info(&format!("Dist {}", package_name));
+        let _time = crate::util::timeit(self.builder);
+
+        build_cli(&self, &mut cmd);
+        cmd.arg("--work-dir").arg(&self.temp_dir);
+        if let Some(formats) = &self.builder.config.dist_compression_formats {
+            assert!(!formats.is_empty(), "dist.compression-formats can't be empty");
+            cmd.arg("--compression-formats").arg(formats.join(","));
+        }
+        self.builder.run(&mut cmd);
+        if self.delete_temp_dir {
+            t!(std::fs::remove_dir_all(&self.temp_dir));
+        }
+
+        // Use either the first compression format defined, or "gz" as the default.
+        let ext = self
+            .builder
+            .config
+            .dist_compression_formats
+            .as_ref()
+            .and_then(|formats| formats.get(0))
+            .map(|s| s.as_str())
+            .unwrap_or("gz");
+
+        crate::dist::distdir(self.builder).join(format!("{}.tar.{}", package_name, ext))
+    }
+}
index b99692e8ba5b8264a166ba5e071f5cd6ff04c3de..1f209f328a2bd98b272a27664a3cc71f6aec28b0 100644 (file)
@@ -869,12 +869,6 @@ fn run(self, builder: &Builder<'_>) {
     compare_mode: "nll"
 });
 
-default_test!(CompileFail {
-    path: "src/test/compile-fail",
-    mode: "compile-fail",
-    suite: "compile-fail"
-});
-
 default_test!(RunPassValgrind {
     path: "src/test/run-pass-valgrind",
     mode: "run-pass-valgrind",
@@ -1968,7 +1962,7 @@ fn run(self, builder: &Builder<'_>) {
         builder.ensure(dist::Src);
 
         let mut cmd = Command::new("tar");
-        cmd.arg("-xzf")
+        cmd.arg("-xf")
             .arg(builder.ensure(dist::PlainSourceTarball))
             .arg("--strip-components=1")
             .current_dir(&dir);
@@ -1992,10 +1986,7 @@ fn run(self, builder: &Builder<'_>) {
         t!(fs::create_dir_all(&dir));
 
         let mut cmd = Command::new("tar");
-        cmd.arg("-xzf")
-            .arg(builder.ensure(dist::Src))
-            .arg("--strip-components=1")
-            .current_dir(&dir);
+        cmd.arg("-xf").arg(builder.ensure(dist::Src)).arg("--strip-components=1").current_dir(&dir);
         builder.run(&mut cmd);
 
         let toml = dir.join("rust-src/lib/rustlib/src/rust/library/std/Cargo.toml");
index 14700aeea05afa86b1612abd3c4588bb3e14a85e..d1b4bbf7fffef374431494c36411b9e102763543 100644 (file)
@@ -85,6 +85,8 @@ ENV CC=clang CXX=clang++
 COPY scripts/sccache.sh /scripts/
 RUN sh /scripts/sccache.sh
 
+ENV PGO_HOST=x86_64-unknown-linux-gnu
+
 ENV HOSTS=x86_64-unknown-linux-gnu
 
 ENV RUST_CONFIGURE_ARGS \
@@ -98,9 +100,10 @@ ENV RUST_CONFIGURE_ARGS \
       --set llvm.thin-lto=true \
       --set llvm.ninja=false \
       --set rust.jemalloc
-ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS \
-        --include-default-paths \
-        src/tools/build-manifest
+ENV SCRIPT ../src/ci/pgo.sh python2.7 ../x.py dist \
+    --host $HOSTS --target $HOSTS \
+    --include-default-paths \
+    src/tools/build-manifest
 ENV CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_LINKER=clang
 
 # This is the only builder which will create source tarballs
index 8653aecc12c547bb70ce636ffeee783cfb4774dd..147de5f801588450a761d691f55240ecc241e046 100644 (file)
@@ -44,7 +44,6 @@ ENV WASM_TARGETS=wasm32-unknown-unknown
 ENV WASM_SCRIPT python3 /checkout/x.py --stage 2 test --host='' --target $WASM_TARGETS \
   src/test/run-make \
   src/test/ui \
-  src/test/compile-fail \
   src/test/mir-opt \
   src/test/codegen-units \
   library/core
diff --git a/src/ci/pgo.sh b/src/ci/pgo.sh
new file mode 100755 (executable)
index 0000000..13b8ca9
--- /dev/null
@@ -0,0 +1,47 @@
+#!/bin/bash
+
+set -euxo pipefail
+
+rm -rf /tmp/rustc-pgo
+
+python2.7 ../x.py build --target=$PGO_HOST --host=$PGO_HOST \
+    --stage 2 library/std --rust-profile-generate=/tmp/rustc-pgo
+
+./build/$PGO_HOST/stage2/bin/rustc --edition=2018 \
+    --crate-type=lib ../library/core/src/lib.rs
+
+# Download and build a single-file stress test benchmark on perf.rust-lang.org.
+function pgo_perf_benchmark {
+    local PERF=e095f5021bf01cf3800f50b3a9f14a9683eb3e4e
+    local github_prefix=https://raw.githubusercontent.com/rust-lang/rustc-perf/$PERF
+    local name=$1
+    curl -o /tmp/$name.rs $github_prefix/collector/benchmarks/$name/src/lib.rs
+    ./build/$PGO_HOST/stage2/bin/rustc --edition=2018 --crate-type=lib /tmp/$name.rs
+}
+
+pgo_perf_benchmark externs
+pgo_perf_benchmark ctfe-stress-4
+
+cp -pri ../src/tools/cargo /tmp/cargo
+
+# Build cargo (with some flags)
+function pgo_cargo {
+    RUSTC=./build/$PGO_HOST/stage2/bin/rustc \
+        ./build/$PGO_HOST/stage0/bin/cargo $@ \
+        --manifest-path /tmp/cargo/Cargo.toml
+}
+
+# Build a couple different variants of Cargo
+CARGO_INCREMENTAL=1 pgo_cargo check
+echo 'pub fn barbarbar() {}' >> /tmp/cargo/src/cargo/lib.rs
+CARGO_INCREMENTAL=1 pgo_cargo check
+touch /tmp/cargo/src/cargo/lib.rs
+CARGO_INCREMENTAL=1 pgo_cargo check
+pgo_cargo build --release
+
+# Merge the profile data we gathered
+./build/$PGO_HOST/llvm/bin/llvm-profdata \
+    merge -o /tmp/rustc-pgo.profdata /tmp/rustc-pgo
+
+# This produces the actual final set of artifacts.
+$@ --rust-profile-use=/tmp/rustc-pgo.profdata
index 181a7fcb732661cffec9e8c9cf3233470ce922ac..1958b6ee41d7fb9374ed619e8a1680e97652fece 100755 (executable)
@@ -53,6 +53,11 @@ RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-locked-deps"
 RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-cargo-native-static"
 RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set rust.codegen-units-std=1"
 
+# Only produce xz tarballs on CI. gz tarballs will be generated by the release
+# process by recompressing the existing xz ones. This decreases the storage
+# space required for CI artifacts.
+RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --dist-compression-formats=xz"
+
 if [ "$DIST_SRC" = "" ]; then
   RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --disable-dist-src"
 fi
index a190438d77d28041f24da4f6592e287fab073a61..5bb44f8b5b0aa105c8b22602e9b18800484afa21 160000 (submodule)
@@ -1 +1 @@
-Subproject commit a190438d77d28041f24da4f6592e287fab073a61
+Subproject commit 5bb44f8b5b0aa105c8b22602e9b18800484afa21
index d8383b65f7948c2ca19191b3b4bd709b403aaf45..a5a48441d411f61556b57d762b03d6874afe575d 160000 (submodule)
@@ -1 +1 @@
-Subproject commit d8383b65f7948c2ca19191b3b4bd709b403aaf45
+Subproject commit a5a48441d411f61556b57d762b03d6874afe575d
index a8afdca5d0715b2257b6f8b9a032fd4dd7dae855..b278478b766178491a8b6f67afa4bcd6b64d977a 160000 (submodule)
@@ -1 +1 @@
-Subproject commit a8afdca5d0715b2257b6f8b9a032fd4dd7dae855
+Subproject commit b278478b766178491a8b6f67afa4bcd6b64d977a
index 236c734a2cb323541b3394f98682cb981b9ec086..1cce0737d6a7d3ceafb139b4a206861fb1dcb2ab 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 236c734a2cb323541b3394f98682cb981b9ec086
+Subproject commit 1cce0737d6a7d3ceafb139b4a206861fb1dcb2ab
index 8adc05c5137206ddefc284b601d47d8b85ab0dcb..21d127c39c904a39215d1a25240a64c69e542810 100644 (file)
@@ -3,3 +3,6 @@ authors = ["The Rust Project Developers"]
 multilingual = false
 src = "src"
 title = "The rustc book"
+
+[output.html]
+git-repository-url = "https://github.com/rust-lang/rust/tree/master/src/doc/rustc"
index ba30c107667edbab1b3bdcb47d3b24b7bc26e184..c2e7ff589066b65b4f98771fd3928fd5d309d51c 100644 (file)
@@ -2,3 +2,6 @@
 authors = ["The Rust Project Developers"]
 src = "src"
 title = "The rustdoc book"
+
+[output.html]
+git-repository-url = "https://github.com/rust-lang/rust/tree/master/src/doc/rustdoc"
index 31e002810ce4b9f46a2c7186101da02c162da79b..80f7851debfbd7a163d1e2e8f6bb667e1b499514 100644 (file)
@@ -237,6 +237,26 @@ for a target triple that's different than your host triple.
 
 All of the usual caveats of cross-compiling code apply.
 
+## `--default-theme`: set the default theme
+
+Using this flag looks like this:
+
+```bash
+$ rustdoc src/lib.rs --default-theme=ayu
+```
+
+Sets the default theme (for users whose browser has not remembered a
+previous theme selection from the on-page theme picker).
+
+The supplied value should be the lowercase version of the theme name.
+The set of available themes can be seen in the theme picker in the
+generated output.
+
+Note that the set of available themes - and their appearance - is not
+necessarily stable from one rustdoc version to the next.  If the
+requested theme does not exist, the builtin default (currently
+`light`) is used instead.
+
 ## `--markdown-css`: include more CSS files when rendering markdown
 
 Using this flag looks like this:
index 1f6dced180b96dab02bb71ba53116477da6667fe..32dc1e02bb3dbb9bcc6251b49a6926bfc6f79d08 100644 (file)
@@ -10,7 +10,7 @@ CSS, and JavaScript.
 Let's give it a try! Create a new project with Cargo:
 
 ```bash
-$ cargo new docs
+$ cargo new docs --lib
 $ cd docs
 ```
 
index 4aef4eeab55323f6c802d4fb48ef21bbea31222a..236ccb9f905368b0ed9eb1b2cf9e2c4d537a5dc8 100644 (file)
@@ -31,7 +31,7 @@ parameters (e.g. pointers), globals, etc. `#[ffi_pure]` functions are not
 referentially-transparent, and are therefore more relaxed than `#[ffi_const]`
 functions.
 
-However, accesing global memory through volatile or atomic reads can violate the
+However, accessing global memory through volatile or atomic reads can violate the
 requirement that two consecutive function calls shall return the same value.
 
 A `pure` function that returns unit has no effect on the abstract machine's
index a0ba47e1dbe313d1fd7683c4d73766d0dcce0b6a..d38f5add7474dd3f1480bfb0ef2af08302da4d7c 100755 (executable)
@@ -1,7 +1,7 @@
 #!/usr/bin/env python
 
 """
-This script creates a pile of compile-fail tests check that all the
+This script creates a pile of UI tests check that all the
 derives have spans that point to the fields, rather than the
 #[derive(...)] line.
 
index 874550da8b0c97b196d1371af91879ca54c39b74..030892a432b31893193f126a3a006a8d5651a79a 100644 (file)
@@ -4,17 +4,21 @@
     <DisplayString>{data_ptr,[length]s8}</DisplayString>
     <StringView>data_ptr,[length]s8</StringView>
     <Expand>
-      <Item Name="[size]" ExcludeView="simple">length</Item>
-      <ArrayItems>
-        <Size>length</Size>
-        <ValuePointer>data_ptr</ValuePointer>
-      </ArrayItems>
+      <Item Name="[len]" ExcludeView="simple">length</Item>
+      <Synthetic Name="[chars]">
+        <Expand>
+          <ArrayItems>
+            <Size>length</Size>
+            <ValuePointer>data_ptr</ValuePointer>
+          </ArrayItems>
+        </Expand>
+      </Synthetic>
     </Expand>
   </Type>
   <Type Name="slice&lt;*&gt;">
-    <DisplayString>{{ length={length} }}</DisplayString>
+    <DisplayString>{{ len={length} }}</DisplayString>
     <Expand>
-      <Item Name="[size]" ExcludeView="simple">length</Item>
+      <Item Name="[len]" ExcludeView="simple">length</Item>
       <ArrayItems>
         <Size>length</Size>
         <ValuePointer>data_ptr</ValuePointer>
index de30b58526a138eef01dd532d0bdb66b0dbd3a8d..cfaafc5734bcec3149eef42e38e81f0f17068152 100644 (file)
@@ -1,9 +1,9 @@
 <?xml version="1.0" encoding="utf-8"?>
 <AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
   <Type Name="alloc::vec::Vec&lt;*&gt;">
-    <DisplayString>{{ size={len} }}</DisplayString>
+    <DisplayString>{{ len={len} }}</DisplayString>
     <Expand>
-      <Item Name="[size]" ExcludeView="simple">len</Item>
+      <Item Name="[len]" ExcludeView="simple">len</Item>
       <Item Name="[capacity]" ExcludeView="simple">buf.cap</Item>
       <ArrayItems>
         <Size>len</Size>
@@ -12,9 +12,9 @@
     </Expand>
   </Type>
   <Type Name="alloc::collections::vec_deque::VecDeque&lt;*&gt;">
-    <DisplayString>{{ size={tail &lt;= head ? head - tail : buf.cap - tail + head} }}</DisplayString>
+    <DisplayString>{{ len={tail &lt;= head ? head - tail : buf.cap - tail + head} }}</DisplayString>
     <Expand>
-      <Item Name="[size]" ExcludeView="simple">tail &lt;= head ? head - tail : buf.cap - tail + head</Item>
+      <Item Name="[len]" ExcludeView="simple">tail &lt;= head ? head - tail : buf.cap - tail + head</Item>
       <Item Name="[capacity]" ExcludeView="simple">buf.cap</Item>
       <CustomListItems>
         <Variable Name="i" InitialValue="tail" />
@@ -31,7 +31,7 @@
     </Expand>
   </Type>
   <Type Name="alloc::collections::linked_list::LinkedList&lt;*&gt;">
-    <DisplayString>{{ size={len} }}</DisplayString>
+    <DisplayString>{{ len={len} }}</DisplayString>
     <Expand>
       <LinkedListItems>
         <Size>len</Size>
     </Expand>
   </Type>
   <Type Name="alloc::string::String">
-    <DisplayString>{*(char**)this,[vec.len]s8}</DisplayString>
-    <StringView>*(char**)this,[vec.len]s8</StringView>
+    <DisplayString>{(char*)vec.buf.ptr.pointer,[vec.len]s8}</DisplayString>
+    <StringView>(char*)vec.buf.ptr.pointer,[vec.len]s8</StringView>
     <Expand>
-      <Item Name="[size]" ExcludeView="simple">vec.len</Item>
+      <Item Name="[len]" ExcludeView="simple">vec.len</Item>
       <Item Name="[capacity]" ExcludeView="simple">vec.buf.cap</Item>
-      <ArrayItems>
-        <Size>vec.len</Size>
-        <ValuePointer>*(char**)this</ValuePointer>
-      </ArrayItems>
+      <Synthetic Name="[chars]">
+        <Expand>
+          <ArrayItems>
+            <Size>vec.len</Size>
+            <ValuePointer>(char*)vec.buf.ptr.pointer</ValuePointer>
+          </ArrayItems>
+        </Expand>
+      </Synthetic>
+    </Expand>
+  </Type>
+  <Type Name="alloc::rc::Rc&lt;*&gt;">
+    <DisplayString>{ptr.pointer->value}</DisplayString>
+    <Expand>
+      <ExpandedItem>ptr.pointer->value</ExpandedItem>
+    </Expand>
+  </Type>
+  <Type Name="alloc::sync::Arc&lt;*&gt;">
+    <DisplayString>{ptr.pointer->data}</DisplayString>
+    <Expand>
+      <ExpandedItem>ptr.pointer->data</ExpandedItem>
+    </Expand>
+  </Type>
+  <Type Name="alloc::sync::Weak&lt;*&gt;">
+    <DisplayString>{ptr.pointer->data}</DisplayString>
+    <Expand>
+      <ExpandedItem>ptr.pointer->data</ExpandedItem>
     </Expand>
   </Type>
 </AutoVisualizer>
index 0e703b3b9502644e30dd527895736e874ba006bb..984a8bfb13c7c4b470f43d49f552f21d8a65dc89 100644 (file)
@@ -6,34 +6,28 @@
       <Item Name="[ptr]">pointer</Item>
     </Expand>
   </Type>
+
   <Type Name="core::ptr::Shared&lt;*&gt;">
     <DisplayString>{{ Shared {pointer} }}</DisplayString>
     <Expand>
       <Item Name="[ptr]">pointer</Item>
     </Expand>
   </Type>
+
   <Type Name="core::option::Option&lt;*&gt;">
-    <DisplayString Condition="RUST$ENUM$DISR == 0x0">{{ None }}</DisplayString>
-    <DisplayString Condition="RUST$ENUM$DISR == 0x1">{{ Some {__0} }}</DisplayString>
+    <DisplayString Condition="RUST$ENUM$DISR == 0x0">None</DisplayString>
+    <DisplayString Condition="RUST$ENUM$DISR == 0x1">Some({__0})</DisplayString>
     <Expand>
-      <Item Name="[size]" ExcludeView="simple">(ULONG)(RUST$ENUM$DISR != 0)</Item>
-      <Item Name="[value]" ExcludeView="simple">__0</Item>
-      <ArrayItems>
-        <Size>(ULONG)(RUST$ENUM$DISR != 0)</Size>
-        <ValuePointer>&amp;__0</ValuePointer>
-      </ArrayItems>
+      <Item Name="[value]" ExcludeView="simple" Condition="RUST$ENUM$DISR == 1">__0</Item>
     </Expand>
   </Type>
+
   <Type Name="core::option::Option&lt;*&gt;" Priority="MediumLow">
-    <DisplayString Condition="*(PVOID *)this == nullptr">{{ None }}</DisplayString>
-    <DisplayString>{{ Some {($T1 *)this} }}</DisplayString>
+    <DisplayString Condition="*(void**)this == nullptr">None</DisplayString>
+    <DisplayString>Some({($T1 *)this})</DisplayString>
     <Expand>
-      <Item Name="[size]" ExcludeView="simple">(ULONG)(*(PVOID *)this != nullptr)</Item>
-      <Item Name="[value]" ExcludeView="simple" Condition="*(PVOID *)this != nullptr">($T1 *)this</Item>
-      <ArrayItems>
-        <Size>(ULONG)(*(PVOID *)this != nullptr)</Size>
-        <ValuePointer>($T1 *)this</ValuePointer>
-      </ArrayItems>
+      <Item Name="Some" ExcludeView="simple" Condition="*(void**)this != nullptr">($T1 *)this</Item>
     </Expand>
   </Type>
+
 </AutoVisualizer>
\ No newline at end of file
index 9550c25f2fcfe5da1b78cc5b2ab743f3f1ab105f..7e5ee7b13daf1b6733b52d96ed75cf10d832c84b 100644 (file)
@@ -26,9 +26,9 @@
   -->
 
   <Type Name="std::collections::hash::map::HashMap&lt;*,*,*&gt;">
-    <DisplayString>{{ size={base.table.items} }}</DisplayString>
+    <DisplayString>{{ len={base.table.items} }}</DisplayString>
     <Expand>
-      <Item Name="[size]">base.table.items</Item>
+      <Item Name="[len]">base.table.items</Item>
       <Item Name="[capacity]">base.table.items + base.table.growth_left</Item>
       <Item Name="[state]">base.hash_builder</Item>
 
@@ -50,9 +50,9 @@
   </Type>
 
   <Type Name="std::collections::hash::set::HashSet&lt;*,*&gt;">
-    <DisplayString>{{ size={base.map.table.items} }}</DisplayString>
+    <DisplayString>{{ len={base.map.table.items} }}</DisplayString>
     <Expand>
-      <Item Name="[size]">base.map.table.items</Item>
+      <Item Name="[len]">base.map.table.items</Item>
       <Item Name="[capacity]">base.map.table.items + base.map.table.growth_left</Item>
       <Item Name="[state]">base.map.hash_builder</Item>
 
index 40c59ed1e0b755b11a57e34cbef047f5eeafa49f..2a8b6a321f1c6c7841af3bea2684fecf6307892e 100644 (file)
@@ -123,10 +123,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
                     attrs: Default::default(),
                     visibility: Inherited,
                     def_id: self.cx.next_def_id(param_env_def_id.krate),
-                    stability: None,
-                    const_stability: None,
-                    deprecation: None,
-                    kind: ImplItem(Impl {
+                    kind: box ImplItem(Impl {
                         unsafety: hir::Unsafety::Normal,
                         generics: new_generics,
                         provided_trait_methods: Default::default(),
@@ -600,7 +597,7 @@ fn param_env_to_generics(
                                             ref mut bindings, ..
                                         } => {
                                             bindings.push(TypeBinding {
-                                                name: left_name.clone(),
+                                                name: left_name,
                                                 kind: TypeBindingKind::Equality { ty: rhs },
                                             });
                                         }
@@ -668,7 +665,7 @@ fn param_env_to_generics(
                 GenericParamDefKind::Type { ref mut default, ref mut bounds, .. } => {
                     // We never want something like `impl<T=Foo>`.
                     default.take();
-                    let generic_ty = Type::Generic(param.name.clone());
+                    let generic_ty = Type::Generic(param.name);
                     if !has_sized.contains(&generic_ty) {
                         bounds.insert(0, GenericBound::maybe_sized(self.cx));
                     }
index 22496065afd7be5717b432c1b60a47c17b14ed4a..ba3eb007e384ddf0d52db01945750af0a2452c06 100644 (file)
@@ -112,10 +112,7 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> {
                     attrs: Default::default(),
                     visibility: Inherited,
                     def_id: self.cx.next_def_id(impl_def_id.krate),
-                    stability: None,
-                    const_stability: None,
-                    deprecation: None,
-                    kind: ImplItem(Impl {
+                    kind: box ImplItem(Impl {
                         unsafety: hir::Unsafety::Normal,
                         generics: (
                             self.cx.tcx.generics_of(impl_def_id),
index 783be6c8243d3cd6933603c56f583f6a85117fce..c168c56d30d0d18fe0fee1dce8fccffcb5440cf8 100644 (file)
@@ -482,10 +482,7 @@ fn fill_in(
                         source: clean::Span::dummy(),
                         def_id: DefId::local(CRATE_DEF_INDEX),
                         visibility: clean::Public,
-                        stability: None,
-                        const_stability: None,
-                        deprecation: None,
-                        kind: clean::ImportItem(clean::Import::new_simple(
+                        kind: box clean::ImportItem(clean::Import::new_simple(
                             item.ident.name,
                             clean::ImportSource {
                                 path: clean::Path {
index 9a15a4bb9174702aec49253ff53b4e81728ee0c1..8b80f098baa64012ea7f7540773f21d268df5b05 100644 (file)
@@ -218,11 +218,6 @@ fn clean(&self, cx: &DocContext<'_>) -> ExternalCrate {
 
 impl Clean<Item> for doctree::Module<'_> {
     fn clean(&self, cx: &DocContext<'_>) -> Item {
-        // maintain a stack of mod ids, for doc comment path resolution
-        // but we also need to resolve the module's own docs based on whether its docs were written
-        // inside or outside the module, so check for that
-        let attrs = self.attrs.clean(cx);
-
         let mut items: Vec<Item> = vec![];
         items.extend(self.imports.iter().flat_map(|x| x.clean(cx)));
         items.extend(self.foreigns.iter().map(|x| x.clean(cx)));
@@ -251,7 +246,7 @@ fn clean(&self, cx: &DocContext<'_>) -> Item {
             ModuleItem(Module { is_crate: self.is_crate, items }),
             cx,
         );
-        Item { attrs, source: span.clean(cx), ..what_rustc_thinks }
+        Item { source: span.clean(cx), ..what_rustc_thinks }
     }
 }
 
@@ -638,6 +633,18 @@ fn is_impl_trait(param: &hir::GenericParam<'_>) -> bool {
                 _ => false,
             }
         }
+        /// This can happen for `async fn`, e.g. `async fn f<'_>(&'_ self)`.
+        ///
+        /// See [`lifetime_to_generic_param`] in [`rustc_ast_lowering`] for more information.
+        ///
+        /// [`lifetime_to_generic_param`]: rustc_ast_lowering::LoweringContext::lifetime_to_generic_param
+        fn is_elided_lifetime(param: &hir::GenericParam<'_>) -> bool {
+            match param.kind {
+                hir::GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Elided } => true,
+                _ => false,
+            }
+        }
+
         let impl_trait_params = self
             .params
             .iter()
@@ -656,7 +663,7 @@ fn is_impl_trait(param: &hir::GenericParam<'_>) -> bool {
             .collect::<Vec<_>>();
 
         let mut params = Vec::with_capacity(self.params.len());
-        for p in self.params.iter().filter(|p| !is_impl_trait(p)) {
+        for p in self.params.iter().filter(|p| !is_impl_trait(p) && !is_elided_lifetime(p)) {
             let p = p.clean(cx);
             params.push(p);
         }
@@ -824,7 +831,7 @@ fn clean(&self, cx: &DocContext<'_>) -> Generics {
         where_predicates.retain(|pred| match *pred {
             WP::BoundPredicate { ty: Generic(ref g), ref bounds } => {
                 if bounds.iter().any(|b| b.is_sized_bound(cx)) {
-                    sized_params.insert(g.clone());
+                    sized_params.insert(*g);
                     false
                 } else {
                     true
@@ -840,7 +847,7 @@ fn clean(&self, cx: &DocContext<'_>) -> Generics {
                 && !sized_params.contains(&tp.name)
             {
                 where_predicates.push(WP::BoundPredicate {
-                    ty: Type::Generic(tp.name.clone()),
+                    ty: Type::Generic(tp.name),
                     bounds: vec![GenericBound::maybe_sized(cx)],
                 })
             }
@@ -934,7 +941,7 @@ fn clean(&self, cx: &DocContext<'_>) -> Arguments {
                 .iter()
                 .enumerate()
                 .map(|(i, ty)| {
-                    let mut name = self.1.get(i).map(|ident| ident.name).unwrap_or(kw::Invalid);
+                    let mut name = self.1.get(i).map(|ident| ident.name).unwrap_or(kw::Empty);
                     if name.is_empty() {
                         name = kw::Underscore;
                     }
@@ -993,7 +1000,7 @@ fn clean(&self, cx: &DocContext<'_>) -> FnDecl {
                     .iter()
                     .map(|t| Argument {
                         type_: t.clean(cx),
-                        name: names.next().map(|i| i.name).unwrap_or(kw::Invalid),
+                        name: names.next().map(|i| i.name).unwrap_or(kw::Empty),
                     })
                     .collect(),
             },
@@ -1437,7 +1444,16 @@ fn clean(&self, cx: &DocContext<'_>) -> Type {
             TyKind::Never => Never,
             TyKind::Ptr(ref m) => RawPointer(m.mutbl, box m.ty.clean(cx)),
             TyKind::Rptr(ref l, ref m) => {
-                let lifetime = if l.is_elided() { None } else { Some(l.clean(cx)) };
+                // There are two times a `Fresh` lifetime can be created:
+                // 1. For `&'_ x`, written by the user. This corresponds to `lower_lifetime` in `rustc_ast_lowering`.
+                // 2. For `&x` as a parameter to an `async fn`. This corresponds to `elided_ref_lifetime in `rustc_ast_lowering`.
+                //    See #59286 for more information.
+                // Ideally we would only hide the `'_` for case 2., but I don't know a way to distinguish it.
+                // Turning `fn f(&'_ self)` into `fn f(&self)` isn't the worst thing in the world, though;
+                // there's no case where it could cause the function to fail to compile.
+                let elided =
+                    l.is_elided() || matches!(l.name, LifetimeName::Param(ParamName::Fresh(_)));
+                let lifetime = if elided { None } else { Some(l.clean(cx)) };
                 BorrowedRef { lifetime, mutability: m.mutbl, type_: box m.ty.clean(cx) }
             }
             TyKind::Slice(ref ty) => Slice(box ty.clean(cx)),
@@ -1777,25 +1793,28 @@ fn clean(&self, cx: &DocContext<'_>) -> Visibility {
             hir::VisibilityKind::Inherited => Visibility::Inherited,
             hir::VisibilityKind::Crate(_) => {
                 let krate = DefId::local(CRATE_DEF_INDEX);
-                Visibility::Restricted(krate, cx.tcx.def_path(krate))
+                Visibility::Restricted(krate)
             }
             hir::VisibilityKind::Restricted { ref path, .. } => {
                 let path = path.clean(cx);
                 let did = register_res(cx, path.res);
-                Visibility::Restricted(did, cx.tcx.def_path(did))
+                Visibility::Restricted(did)
             }
         }
     }
 }
 
 impl Clean<Visibility> for ty::Visibility {
-    fn clean(&self, cx: &DocContext<'_>) -> Visibility {
+    fn clean(&self, _cx: &DocContext<'_>) -> Visibility {
         match *self {
             ty::Visibility::Public => Visibility::Public,
+            // NOTE: this is not quite right: `ty` uses `Invisible` to mean 'private',
+            // while rustdoc really does mean inherited. That means that for enum variants, such as
+            // `pub enum E { V }`, `V` will be marked as `Public` by `ty`, but as `Inherited` by rustdoc.
+            // This is the main reason `impl Clean for hir::Visibility` still exists; various parts of clean
+            // override `tcx.visibility` explicitly to make sure this distinction is captured.
             ty::Visibility::Invisible => Visibility::Inherited,
-            ty::Visibility::Restricted(module) => {
-                Visibility::Restricted(module, cx.tcx.def_path(module))
-            }
+            ty::Visibility::Restricted(module) => Visibility::Restricted(module),
         }
     }
 }
@@ -2141,10 +2160,7 @@ fn clean_extern_crate(
         source: krate.span.clean(cx),
         def_id: crate_def_id,
         visibility: krate.vis.clean(cx),
-        stability: None,
-        const_stability: None,
-        deprecation: None,
-        kind: ExternCrateItem(name, orig_name),
+        kind: box ExternCrateItem(name, orig_name),
     }]
 }
 
@@ -2226,10 +2242,7 @@ fn clean(&self, cx: &DocContext<'_>) -> Vec<Item> {
                         source: self.span.clean(cx),
                         def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(),
                         visibility: self.vis.clean(cx),
-                        stability: None,
-                        const_stability: None,
-                        deprecation: None,
-                        kind: ImportItem(Import::new_simple(
+                        kind: box ImportItem(Import::new_simple(
                             self.name,
                             resolve_use_source(cx, path),
                             false,
@@ -2247,10 +2260,7 @@ fn clean(&self, cx: &DocContext<'_>) -> Vec<Item> {
             source: self.span.clean(cx),
             def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(),
             visibility: self.vis.clean(cx),
-            stability: None,
-            const_stability: None,
-            deprecation: None,
-            kind: ImportItem(inner),
+            kind: box ImportItem(inner),
         }]
     }
 }
@@ -2319,14 +2329,14 @@ fn clean(&self, cx: &DocContext<'_>) -> Item {
             if matchers.len() <= 1 {
                 format!(
                     "{}macro {}{} {{\n    ...\n}}",
-                    vis.print_with_space(),
+                    vis.print_with_space(cx.tcx),
                     name,
                     matchers.iter().map(|span| span.to_src(cx)).collect::<String>(),
                 )
             } else {
                 format!(
                     "{}macro {} {{\n{}}}",
-                    vis.print_with_space(),
+                    vis.print_with_space(cx.tcx),
                     name,
                     matchers
                         .iter()
index d8dfdd0941be8fca1982828d022ac1e4601e87f7..0d33bc9afd5ecc5cf750b8352cf041f2ebe79ae7 100644 (file)
     crate name: Option<Symbol>,
     crate attrs: Attributes,
     crate visibility: Visibility,
-    crate kind: ItemKind,
+    crate kind: Box<ItemKind>,
     crate def_id: DefId,
-    crate stability: Option<Stability>,
-    crate deprecation: Option<Deprecation>,
-    crate const_stability: Option<ConstStability>,
 }
 
+// `Item` is used a lot. Make sure it doesn't unintentionally get bigger.
+#[cfg(target_arch = "x86_64")]
+rustc_data_structures::static_assert_size!(Item, 136);
+
 impl fmt::Debug for Item {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
         let def_id: &dyn fmt::Debug = if self.is_fake() { &"**FAKE**" } else { &self.def_id };
@@ -102,13 +103,23 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
             .field("kind", &self.kind)
             .field("visibility", &self.visibility)
             .field("def_id", def_id)
-            .field("stability", &self.stability)
-            .field("deprecation", &self.deprecation)
             .finish()
     }
 }
 
 impl Item {
+    crate fn stability<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Option<&'tcx Stability> {
+        if self.is_fake() { None } else { tcx.lookup_stability(self.def_id) }
+    }
+
+    crate fn const_stability<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Option<&'tcx ConstStability> {
+        if self.is_fake() { None } else { tcx.lookup_const_stability(self.def_id) }
+    }
+
+    crate fn deprecation(&self, tcx: TyCtxt<'_>) -> Option<Deprecation> {
+        if self.is_fake() { None } else { tcx.lookup_deprecation(self.def_id) }
+    }
+
     /// Finds the `doc` attribute as a NameValue and returns the corresponding
     /// value found.
     crate fn doc_value(&self) -> Option<&str> {
@@ -145,14 +156,11 @@ pub fn from_def_id_and_parts(
 
         Item {
             def_id,
-            kind,
+            kind: box kind,
             name,
             source: source.clean(cx),
             attrs: cx.tcx.get_attrs(def_id).clean(cx),
             visibility: cx.tcx.visibility(def_id).clean(cx),
-            stability: cx.tcx.lookup_stability(def_id).cloned(),
-            deprecation: cx.tcx.lookup_deprecation(def_id),
-            const_stability: cx.tcx.lookup_const_stability(def_id).cloned(),
         }
     }
 
@@ -167,7 +175,7 @@ pub fn from_def_id_and_parts(
     }
 
     crate fn is_crate(&self) -> bool {
-        match self.kind {
+        match *self.kind {
             StrippedItem(box ModuleItem(Module { is_crate: true, .. }))
             | ModuleItem(Module { is_crate: true, .. }) => true,
             _ => false,
@@ -219,14 +227,14 @@ pub fn from_def_id_and_parts(
         self.type_() == ItemType::Keyword
     }
     crate fn is_stripped(&self) -> bool {
-        match self.kind {
+        match *self.kind {
             StrippedItem(..) => true,
             ImportItem(ref i) => !i.should_be_displayed,
             _ => false,
         }
     }
     crate fn has_stripped_fields(&self) -> Option<bool> {
-        match self.kind {
+        match *self.kind {
             StructItem(ref _struct) => Some(_struct.fields_stripped),
             UnionItem(ref union) => Some(union.fields_stripped),
             VariantItem(Variant { kind: VariantKind::Struct(ref vstruct) }) => {
@@ -236,8 +244,8 @@ pub fn from_def_id_and_parts(
         }
     }
 
-    crate fn stability_class(&self) -> Option<String> {
-        self.stability.as_ref().and_then(|ref s| {
+    crate fn stability_class(&self, tcx: TyCtxt<'_>) -> Option<String> {
+        self.stability(tcx).as_ref().and_then(|ref s| {
             let mut classes = Vec::with_capacity(2);
 
             if s.level.is_unstable() {
@@ -245,7 +253,7 @@ pub fn from_def_id_and_parts(
             }
 
             // FIXME: what about non-staged API items that are deprecated?
-            if self.deprecation.is_some() {
+            if self.deprecation(tcx).is_some() {
                 classes.push("deprecated");
             }
 
@@ -253,15 +261,15 @@ pub fn from_def_id_and_parts(
         })
     }
 
-    crate fn stable_since(&self) -> Option<SymbolStr> {
-        match self.stability?.level {
+    crate fn stable_since(&self, tcx: TyCtxt<'_>) -> Option<SymbolStr> {
+        match self.stability(tcx)?.level {
             StabilityLevel::Stable { since, .. } => Some(since.as_str()),
             StabilityLevel::Unstable { .. } => None,
         }
     }
 
-    crate fn const_stable_since(&self) -> Option<SymbolStr> {
-        match self.const_stability?.level {
+    crate fn const_stable_since(&self, tcx: TyCtxt<'_>) -> Option<SymbolStr> {
+        match self.const_stability(tcx)?.level {
             StabilityLevel::Stable { since, .. } => Some(since.as_str()),
             StabilityLevel::Unstable { .. } => None,
         }
@@ -277,7 +285,7 @@ pub fn from_def_id_and_parts(
     }
 
     crate fn is_default(&self) -> bool {
-        match self.kind {
+        match *self.kind {
             ItemKind::MethodItem(_, Some(defaultness)) => {
                 defaultness.has_value() && !defaultness.is_final()
             }
@@ -627,7 +635,7 @@ impl Attributes {
         let clean_attr = |(attr, parent_module): (&ast::Attribute, _)| {
             if let Some(value) = attr.doc_str() {
                 trace!("got doc_str={:?}", value);
-                let value = beautify_doc_string(value);
+                let value = beautify_doc_string(value).to_string();
                 let kind = if attr.is_doc_comment() {
                     DocFragmentKind::SugaredDoc
                 } else {
@@ -1579,11 +1587,11 @@ fn from(prim_ty: hir::PrimTy) -> PrimitiveType {
     }
 }
 
-#[derive(Clone, Debug)]
+#[derive(Copy, Clone, Debug)]
 crate enum Visibility {
     Public,
     Inherited,
-    Restricted(DefId, rustc_hir::definitions::DefPath),
+    Restricted(DefId),
 }
 
 impl Visibility {
index 4d525d62c52cc3d36b8c8a2415b2900d289d6c33..a6c090c6576ef4f200973b3076d3b626112a353f 100644 (file)
@@ -8,7 +8,6 @@
 };
 use crate::core::DocContext;
 
-use itertools::Itertools;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
@@ -43,7 +42,7 @@
     let mut module = module.clean(cx);
     let mut masked_crates = FxHashSet::default();
 
-    match module.kind {
+    match *module.kind {
         ItemKind::ModuleItem(ref module) => {
             for it in &module.items {
                 // `compiler_builtins` should be masked too, but we can't apply
@@ -61,7 +60,7 @@
 
     let ExternalCrate { name, src, primitives, keywords, .. } = LOCAL_CRATE.clean(cx);
     {
-        let m = match module.kind {
+        let m = match *module.kind {
             ItemKind::ModuleItem(ref mut m) => m,
             _ => unreachable!(),
         };
@@ -74,7 +73,7 @@
             )
         }));
         m.items.extend(keywords.into_iter().map(|(def_id, kw)| {
-            Item::from_def_id_and_parts(def_id, Some(kw.clone()), ItemKind::KeywordItem(kw), cx)
+            Item::from_def_id_and_parts(def_id, Some(kw), ItemKind::KeywordItem(kw), cx)
         }));
     }
 
@@ -307,7 +306,7 @@ pub(super) fn external_path(
         .segments
         .iter()
         .map(|s| PathSegment {
-            name: s.name.clone(),
+            name: s.name,
             args: GenericArgs::AngleBracketed { args: vec![], bindings: vec![] },
         })
         .collect();
@@ -338,7 +337,7 @@ pub(super) fn external_path(
     let tcx = cx.tcx;
 
     for item in items {
-        let target = match item.kind {
+        let target = match *item.kind {
             ItemKind::TypedefItem(ref t, true) => &t.type_,
             _ => continue,
         };
@@ -558,10 +557,13 @@ fn print_const_with_custom_print_scalar(cx: &DocContext<'_>, ct: &'tcx ty::Const
     ty: Ty<'tcx>,
     param_env_def_id: DefId,
 ) -> impl Iterator<Item = Item> {
-    AutoTraitFinder::new(cx)
-        .get_auto_trait_impls(ty, param_env_def_id)
-        .into_iter()
-        .chain(BlanketImplFinder::new(cx).get_blanket_impls(ty, param_env_def_id))
+    let auto_impls = cx.sess().time("get_auto_trait_impls", || {
+        AutoTraitFinder::new(cx).get_auto_trait_impls(ty, param_env_def_id)
+    });
+    let blanket_impls = cx.sess().time("get_blanket_impls", || {
+        BlanketImplFinder::new(cx).get_blanket_impls(ty, param_env_def_id)
+    });
+    auto_impls.into_iter().chain(blanket_impls)
 }
 
 crate fn register_res(cx: &DocContext<'_>, res: Res) -> DefId {
index 37fe13c32ce745dfee79c88fb44610377b5bb538..02dd42ce0c14df4691250a86f74180be66dd6ae5 100644 (file)
@@ -247,9 +247,10 @@ fn run_test(
     edition: Edition,
     outdir: DirState,
     path: PathBuf,
+    test_id: &str,
 ) -> Result<(), TestFailure> {
     let (test, line_offset, supports_color) =
-        make_test(test, Some(cratename), as_test_harness, opts, edition);
+        make_test(test, Some(cratename), as_test_harness, opts, edition, Some(test_id));
 
     let output_file = outdir.path().join("rust_out");
 
@@ -387,6 +388,7 @@ fn drop(&mut self) {
     dont_insert_main: bool,
     opts: &TestOptions,
     edition: Edition,
+    test_id: Option<&str>,
 ) -> (String, usize, bool) {
     let (crate_attrs, everything_else, crates) = partition_source(s);
     let everything_else = everything_else.trim();
@@ -542,16 +544,41 @@ fn drop(&mut self) {
         prog.push_str(everything_else);
     } else {
         let returns_result = everything_else.trim_end().ends_with("(())");
+        // Give each doctest main function a unique name.
+        // This is for example needed for the tooling around `-Z instrument-coverage`.
+        let inner_fn_name = if let Some(test_id) = test_id {
+            format!("_doctest_main_{}", test_id)
+        } else {
+            "_inner".into()
+        };
+        let inner_attr = if test_id.is_some() { "#[allow(non_snake_case)] " } else { "" };
         let (main_pre, main_post) = if returns_result {
             (
-                "fn main() { fn _inner() -> Result<(), impl core::fmt::Debug> {",
-                "}\n_inner().unwrap() }",
+                format!(
+                    "fn main() {{ {}fn {}() -> Result<(), impl core::fmt::Debug> {{\n",
+                    inner_attr, inner_fn_name
+                ),
+                format!("\n}} {}().unwrap() }}", inner_fn_name),
+            )
+        } else if test_id.is_some() {
+            (
+                format!("fn main() {{ {}fn {}() {{\n", inner_attr, inner_fn_name),
+                format!("\n}} {}() }}", inner_fn_name),
             )
         } else {
-            ("fn main() {\n", "\n}")
+            ("fn main() {\n".into(), "\n}".into())
         };
-        prog.extend([main_pre, everything_else, main_post].iter().cloned());
+        // Note on newlines: We insert a line/newline *before*, and *after*
+        // the doctest and adjust the `line_offset` accordingly.
+        // In the case of `-Z instrument-coverage`, this means that the generated
+        // inner `main` function spans from the doctest opening codeblock to the
+        // closing one. For example
+        // /// ``` <- start of the inner main
+        // /// <- code under doctest
+        // /// ``` <- end of the inner main
         line_offset += 1;
+
+        prog.extend([&main_pre, everything_else, &main_post].iter().cloned());
     }
 
     debug!("final doctest:\n{}", prog);
@@ -749,28 +776,24 @@ fn add_test(&mut self, test: String, config: LangString, line: usize) {
             _ => PathBuf::from(r"doctest.rs"),
         };
 
+        // For example `module/file.rs` would become `module_file_rs`
+        let file = filename
+            .to_string()
+            .chars()
+            .map(|c| if c.is_ascii_alphanumeric() { c } else { '_' })
+            .collect::<String>();
+        let test_id = format!(
+            "{file}_{line}_{number}",
+            file = file,
+            line = line,
+            number = {
+                // Increases the current test number, if this file already
+                // exists or it creates a new entry with a test number of 0.
+                self.visited_tests.entry((file.clone(), line)).and_modify(|v| *v += 1).or_insert(0)
+            },
+        );
         let outdir = if let Some(mut path) = options.persist_doctests.clone() {
-            // For example `module/file.rs` would become `module_file_rs`
-            let folder_name = filename
-                .to_string()
-                .chars()
-                .map(|c| if c == '\\' || c == '/' || c == '.' { '_' } else { c })
-                .collect::<String>();
-
-            path.push(format!(
-                "{krate}_{file}_{line}_{number}",
-                krate = cratename,
-                file = folder_name,
-                line = line,
-                number = {
-                    // Increases the current test number, if this file already
-                    // exists or it creates a new entry with a test number of 0.
-                    self.visited_tests
-                        .entry((folder_name.clone(), line))
-                        .and_modify(|v| *v += 1)
-                        .or_insert(0)
-                },
-            ));
+            path.push(&test_id);
 
             std::fs::create_dir_all(&path)
                 .expect("Couldn't create directory for doctest executables");
@@ -817,6 +840,7 @@ fn add_test(&mut self, test: String, config: LangString, line: usize) {
                     edition,
                     outdir,
                     path,
+                    &test_id,
                 );
 
                 if let Err(err) = res {
index a024e9c72a43e01969a2523dfca486cc115a7b67..465b2b1d69b34551d0b0945176c89afd36e924bc 100644 (file)
@@ -11,7 +11,7 @@ fn main() {
 assert_eq!(2+2, 4);
 }"
     .to_string();
-    let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION);
+    let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION, None);
     assert_eq!((output, len), (expected, 2));
 }
 
@@ -26,7 +26,7 @@ fn main() {
 assert_eq!(2+2, 4);
 }"
     .to_string();
-    let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION);
+    let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION, None);
     assert_eq!((output, len), (expected, 2));
 }
 
@@ -44,7 +44,7 @@ fn main() {
 assert_eq!(2+2, 4);
 }"
     .to_string();
-    let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION);
+    let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION, None);
     assert_eq!((output, len), (expected, 3));
 }
 
@@ -61,7 +61,7 @@ fn main() {
 assert_eq!(2+2, 4);
 }"
     .to_string();
-    let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION);
+    let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION, None);
     assert_eq!((output, len), (expected, 2));
 }
 
@@ -79,7 +79,7 @@ fn main() {
 assert_eq!(2+2, 4);
 }"
     .to_string();
-    let (output, len, _) = make_test(input, Some("std"), false, &opts, DEFAULT_EDITION);
+    let (output, len, _) = make_test(input, Some("std"), false, &opts, DEFAULT_EDITION, None);
     assert_eq!((output, len), (expected, 2));
 }
 
@@ -98,7 +98,7 @@ fn main() {
 assert_eq!(2+2, 4);
 }"
     .to_string();
-    let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION);
+    let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION, None);
     assert_eq!((output, len), (expected, 2));
 }
 
@@ -115,7 +115,7 @@ fn main() {
 assert_eq!(2+2, 4);
 }"
     .to_string();
-    let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION);
+    let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION, None);
     assert_eq!((output, len), (expected, 2));
 }
 
@@ -134,7 +134,7 @@ fn main() {
 assert_eq!(2+2, 4);
 }"
     .to_string();
-    let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION);
+    let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION, None);
     assert_eq!((output, len), (expected, 3));
 
     // Adding more will also bump the returned line offset.
@@ -147,7 +147,7 @@ fn main() {
 assert_eq!(2+2, 4);
 }"
     .to_string();
-    let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION);
+    let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION, None);
     assert_eq!((output, len), (expected, 4));
 }
 
@@ -164,7 +164,7 @@ fn main() {
 assert_eq!(2+2, 4);
 }"
     .to_string();
-    let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION);
+    let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION, None);
     assert_eq!((output, len), (expected, 2));
 }
 
@@ -180,7 +180,7 @@ fn main() {
     assert_eq!(2+2, 4);
 }"
     .to_string();
-    let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION);
+    let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION, None);
     assert_eq!((output, len), (expected, 1));
 }
 
@@ -196,7 +196,7 @@ fn main() {
 assert_eq!(2+2, 4);
 }"
     .to_string();
-    let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION);
+    let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION, None);
     assert_eq!((output, len), (expected, 2));
 }
 
@@ -210,7 +210,7 @@ fn make_test_dont_insert_main() {
 //Ceci n'est pas une `fn main`
 assert_eq!(2+2, 4);"
         .to_string();
-    let (output, len, _) = make_test(input, None, true, &opts, DEFAULT_EDITION);
+    let (output, len, _) = make_test(input, None, true, &opts, DEFAULT_EDITION, None);
     assert_eq!((output, len), (expected, 1));
 }
 
@@ -224,7 +224,7 @@ fn make_test_display_warnings() {
 assert_eq!(2+2, 4);
 }"
     .to_string();
-    let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION);
+    let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION, None);
     assert_eq!((output, len), (expected, 1));
 }
 
@@ -242,7 +242,7 @@ fn main() {
 }"
     .to_string();
 
-    let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION);
+    let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION, None);
     assert_eq!((output, len), (expected, 2));
 
     let input = "extern crate hella_qwop;
@@ -256,7 +256,7 @@ fn main() {
 }"
     .to_string();
 
-    let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION);
+    let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION, None);
     assert_eq!((output, len), (expected, 3));
 }
 
@@ -274,6 +274,41 @@ fn main() {}
 }"
     .to_string();
 
-    let (output, len, _) = make_test(input, Some("my_crate"), false, &opts, DEFAULT_EDITION);
+    let (output, len, _) = make_test(input, Some("my_crate"), false, &opts, DEFAULT_EDITION, None);
     assert_eq!((output, len), (expected, 1));
 }
+
+#[test]
+fn make_test_returns_result() {
+    // creates an inner function and unwraps it
+    let opts = TestOptions::default();
+    let input = "use std::io;
+let mut input = String::new();
+io::stdin().read_line(&mut input)?;
+Ok::<(), io:Error>(())";
+    let expected = "#![allow(unused)]
+fn main() { fn _inner() -> Result<(), impl core::fmt::Debug> {
+use std::io;
+let mut input = String::new();
+io::stdin().read_line(&mut input)?;
+Ok::<(), io:Error>(())
+} _inner().unwrap() }"
+        .to_string();
+    let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION, None);
+    assert_eq!((output, len), (expected, 2));
+}
+
+#[test]
+fn make_test_named_wrapper() {
+    // creates an inner function with a specific name
+    let opts = TestOptions::default();
+    let input = "assert_eq!(2+2, 4);";
+    let expected = "#![allow(unused)]
+fn main() { #[allow(non_snake_case)] fn _doctest_main__some_unique_name() {
+assert_eq!(2+2, 4);
+} _doctest_main__some_unique_name() }"
+        .to_string();
+    let (output, len, _) =
+        make_test(input, None, false, &opts, DEFAULT_EDITION, Some("_some_unique_name"));
+    assert_eq!((output, len), (expected, 2));
+}
index ee9a6981857998546af36a594fa4c259cb5f437f..bc9f1cf8806ab47a10b3cc03492b222870e220c9 100644 (file)
@@ -9,7 +9,6 @@
 
 crate struct Module<'hir> {
     crate name: Option<Symbol>,
-    crate attrs: &'hir [ast::Attribute],
     crate where_outer: Span,
     crate where_inner: Span,
     crate imports: Vec<Import<'hir>>,
 }
 
 impl Module<'hir> {
-    crate fn new(name: Option<Symbol>, attrs: &'hir [ast::Attribute]) -> Module<'hir> {
+    crate fn new(name: Option<Symbol>) -> Module<'hir> {
         Module {
             name,
             id: hir::CRATE_HIR_ID,
             where_outer: rustc_span::DUMMY_SP,
             where_inner: rustc_span::DUMMY_SP,
-            attrs,
             imports: Vec::new(),
             mods: Vec::new(),
             items: Vec::new(),
index 285fabdc3723040d86124f21c78f7e00d13d2ade..c39cc3ca39771841e8ff6e32a782dfd70b7a2a69 100644 (file)
@@ -3,12 +3,12 @@
 crate struct StripItem(pub Item);
 
 impl StripItem {
-    crate fn strip(self) -> Option<Item> {
+    crate fn strip(self) -> Item {
         match self.0 {
-            Item { kind: StrippedItem(..), .. } => Some(self.0),
+            Item { kind: box StrippedItem(..), .. } => self.0,
             mut i => {
-                i.kind = StrippedItem(box i.kind);
-                Some(i)
+                i.kind = box StrippedItem(i.kind);
+                i
             }
         }
     }
@@ -72,9 +72,9 @@ fn fold_inner_recur(&mut self, kind: ItemKind) -> ItemKind {
 
     /// don't override!
     fn fold_item_recur(&mut self, mut item: Item) -> Item {
-        item.kind = match item.kind {
+        item.kind = box match *item.kind {
             StrippedItem(box i) => StrippedItem(box self.fold_inner_recur(i)),
-            _ => self.fold_inner_recur(item.kind),
+            _ => self.fold_inner_recur(*item.kind),
         };
         item
     }
index 77a3e9fa9549b4780de2dcc898c0fadd18579a34..899d61d8e43dfe191da3a3dd0600a237f2fc5e6c 100644 (file)
@@ -219,7 +219,7 @@ fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
 
         // If this is a stripped module,
         // we don't want it or its children in the search index.
-        let orig_stripped_mod = match item.kind {
+        let orig_stripped_mod = match *item.kind {
             clean::StrippedItem(box clean::ModuleItem(..)) => {
                 mem::replace(&mut self.stripped_mod, true)
             }
@@ -228,7 +228,7 @@ fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
 
         // If the impl is from a masked crate or references something from a
         // masked crate then remove it completely.
-        if let clean::ImplItem(ref i) = item.kind {
+        if let clean::ImplItem(ref i) = *item.kind {
             if self.masked_crates.contains(&item.def_id.krate)
                 || i.trait_.def_id().map_or(false, |d| self.masked_crates.contains(&d.krate))
                 || i.for_.def_id().map_or(false, |d| self.masked_crates.contains(&d.krate))
@@ -239,12 +239,12 @@ fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
 
         // Propagate a trait method's documentation to all implementors of the
         // trait.
-        if let clean::TraitItem(ref t) = item.kind {
+        if let clean::TraitItem(ref t) = *item.kind {
             self.traits.entry(item.def_id).or_insert_with(|| t.clone());
         }
 
         // Collect all the implementors of traits.
-        if let clean::ImplItem(ref i) = item.kind {
+        if let clean::ImplItem(ref i) = *item.kind {
             if let Some(did) = i.trait_.def_id() {
                 if i.blanket_impl.is_none() {
                     self.implementors
@@ -257,7 +257,7 @@ fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
 
         // Index this method for searching later on.
         if let Some(ref s) = item.name {
-            let (parent, is_inherent_impl_item) = match item.kind {
+            let (parent, is_inherent_impl_item) = match *item.kind {
                 clean::StrippedItem(..) => ((None, None), false),
                 clean::AssocConstItem(..) | clean::TypedefItem(_, true)
                     if self.parent_is_trait_impl =>
@@ -348,7 +348,7 @@ fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
             _ => false,
         };
 
-        match item.kind {
+        match *item.kind {
             clean::StructItem(..)
             | clean::EnumItem(..)
             | clean::TypedefItem(..)
@@ -387,7 +387,7 @@ fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
 
         // Maintain the parent stack
         let orig_parent_is_trait_impl = self.parent_is_trait_impl;
-        let parent_pushed = match item.kind {
+        let parent_pushed = match *item.kind {
             clean::TraitItem(..)
             | clean::EnumItem(..)
             | clean::ForeignTypeItem
@@ -425,38 +425,33 @@ fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
         // Once we've recursively found all the generics, hoard off all the
         // implementations elsewhere.
         let item = self.fold_item_recur(item);
-        let ret = if let clean::Item { kind: clean::ImplItem(_), .. } = item {
+        let ret = if let clean::Item { kind: box clean::ImplItem(ref i), .. } = item {
             // Figure out the id of this impl. This may map to a
             // primitive rather than always to a struct/enum.
             // Note: matching twice to restrict the lifetime of the `i` borrow.
             let mut dids = FxHashSet::default();
-            if let clean::Item { kind: clean::ImplItem(ref i), .. } = item {
-                match i.for_ {
-                    clean::ResolvedPath { did, .. }
-                    | clean::BorrowedRef { type_: box clean::ResolvedPath { did, .. }, .. } => {
-                        dids.insert(did);
-                    }
-                    ref t => {
-                        let did = t
-                            .primitive_type()
-                            .and_then(|t| self.primitive_locations.get(&t).cloned());
+            match i.for_ {
+                clean::ResolvedPath { did, .. }
+                | clean::BorrowedRef { type_: box clean::ResolvedPath { did, .. }, .. } => {
+                    dids.insert(did);
+                }
+                ref t => {
+                    let did =
+                        t.primitive_type().and_then(|t| self.primitive_locations.get(&t).cloned());
 
-                        if let Some(did) = did {
-                            dids.insert(did);
-                        }
+                    if let Some(did) = did {
+                        dids.insert(did);
                     }
                 }
+            }
 
-                if let Some(generics) = i.trait_.as_ref().and_then(|t| t.generics()) {
-                    for bound in generics {
-                        if let Some(did) = bound.def_id() {
-                            dids.insert(did);
-                        }
+            if let Some(generics) = i.trait_.as_ref().and_then(|t| t.generics()) {
+                for bound in generics {
+                    if let Some(did) = bound.def_id() {
+                        dids.insert(did);
                     }
                 }
-            } else {
-                unreachable!()
-            };
+            }
             let impl_item = Impl { impl_item: item };
             if impl_item.trait_did().map_or(true, |d| self.traits.contains_key(&d)) {
                 for did in dids {
index af512e3746092683c5a9616c5f1a64f2a9602ae8..ad51adf2fe3f5aa2d2d404f58fdec59ecf4cdba2 100644 (file)
@@ -60,7 +60,7 @@ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
 
 impl<'a> From<&'a clean::Item> for ItemType {
     fn from(item: &'a clean::Item) -> ItemType {
-        let kind = match item.kind {
+        let kind = match *item.kind {
             clean::StrippedItem(box ref item) => item,
             ref kind => kind,
         };
index 55fd4948f45272299f10c22cdd959ab13c0576fe..58b9f5fbf0f6ca842e4e7c9ea2f438a7bc06988e 100644 (file)
@@ -32,7 +32,7 @@
 
 impl Impl {
     crate fn inner_impl(&self) -> &clean::Impl {
-        match self.impl_item.kind {
+        match *self.impl_item.kind {
             clean::ImplItem(ref impl_) => impl_,
             _ => panic!("non-impl item found in impl"),
         }
index fbbd3c1ccf5140530fd73a8975dae619219e8bb8..e84a9853d9b7c0fd11ebd69a84920fdc5ff9bd14 100644 (file)
@@ -89,7 +89,7 @@ fn mod_item_in(
             }
 
             cx.mod_item_in(&item, &name, &cache)?;
-            let module = match item.kind {
+            let module = match *item.kind {
                 clean::StrippedItem(box clean::ModuleItem(m)) | clean::ModuleItem(m) => m,
                 _ => unreachable!(),
             };
index f80346aa50b4f5de0476a55e65dfc3aef8383846..7b0b219570b983586b9ae4b58108c310a14ab15b 100644 (file)
@@ -11,6 +11,7 @@
 
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir as hir;
+use rustc_middle::ty::TyCtxt;
 use rustc_span::def_id::{DefId, CRATE_DEF_INDEX};
 use rustc_target::spec::abi::Abi;
 
@@ -1084,18 +1085,18 @@ impl Function<'_> {
 }
 
 impl clean::Visibility {
-    crate fn print_with_space(&self) -> impl fmt::Display + '_ {
+    crate fn print_with_space<'tcx>(self, tcx: TyCtxt<'tcx>) -> impl fmt::Display + 'tcx {
         use rustc_span::symbol::kw;
 
-        display_fn(move |f| match *self {
+        display_fn(move |f| match self {
             clean::Public => f.write_str("pub "),
             clean::Inherited => Ok(()),
-            // If this is `pub(crate)`, `path` will be empty.
-            clean::Visibility::Restricted(did, _) if did.index == CRATE_DEF_INDEX => {
+            clean::Visibility::Restricted(did) if did.index == CRATE_DEF_INDEX => {
                 write!(f, "pub(crate) ")
             }
-            clean::Visibility::Restricted(did, ref path) => {
+            clean::Visibility::Restricted(did) => {
                 f.write_str("pub(")?;
+                let path = tcx.def_path(did);
                 debug!("path={:?}", path);
                 let first_name =
                     path.data[0].data.get_opt_name().expect("modules are always named");
index 1cbfbf50dd745dafd90905e0630ac6d6d39ede55..d21998bb8cfe5d358016a7b6e930ee0ed6a60aaf 100644 (file)
@@ -11,7 +11,8 @@
 use std::iter::Peekable;
 
 use rustc_lexer::{LiteralKind, TokenKind};
-use rustc_span::symbol::Ident;
+use rustc_span::edition::Edition;
+use rustc_span::symbol::Symbol;
 use rustc_span::with_default_session_globals;
 
 /// Highlights `src`, returning the HTML output.
     src: String,
     class: Option<&str>,
     playground_button: Option<&str>,
-    tooltip: Option<(&str, &str)>,
+    tooltip: Option<(Option<Edition>, &str)>,
+    edition: Edition,
 ) -> String {
     debug!("highlighting: ================\n{}\n==============", src);
     let mut out = String::with_capacity(src.len());
-    if let Some((tooltip, class)) = tooltip {
+    if let Some((edition_info, class)) = tooltip {
         write!(
             out,
-            "<div class='information'><div class='tooltip {}'>ⓘ<span \
-                  class='tooltiptext'>{}</span></div></div>",
-            class, tooltip
+            "<div class='information'><div class='tooltip {}'{}>ⓘ</div></div>",
+            class,
+            if let Some(edition_info) = edition_info {
+                format!(" data-edition=\"{}\"", edition_info)
+            } else {
+                String::new()
+            },
         )
         .unwrap();
     }
 
     write_header(&mut out, class);
-    write_code(&mut out, &src);
+    write_code(&mut out, &src, edition);
     write_footer(&mut out, playground_button);
 
     out
@@ -45,10 +51,10 @@ fn write_header(out: &mut String, class: Option<&str>) {
         .unwrap()
 }
 
-fn write_code(out: &mut String, src: &str) {
+fn write_code(out: &mut String, src: &str, edition: Edition) {
     // This replace allows to fix how the code source with DOS backline characters is displayed.
     let src = src.replace("\r\n", "\n");
-    Classifier::new(&src).highlight(&mut |highlight| {
+    Classifier::new(&src, edition).highlight(&mut |highlight| {
         match highlight {
             Highlight::Token { text, class } => string(out, Escape(text), class),
             Highlight::EnterSpan { class } => enter_span(out, class),
@@ -139,12 +145,19 @@ struct Classifier<'a> {
     in_attribute: bool,
     in_macro: bool,
     in_macro_nonterminal: bool,
+    edition: Edition,
 }
 
 impl<'a> Classifier<'a> {
-    fn new(src: &str) -> Classifier<'_> {
+    fn new(src: &str, edition: Edition) -> Classifier<'_> {
         let tokens = TokenIter { src }.peekable();
-        Classifier { tokens, in_attribute: false, in_macro: false, in_macro_nonterminal: false }
+        Classifier {
+            tokens,
+            in_attribute: false,
+            in_macro: false,
+            in_macro_nonterminal: false,
+            edition,
+        }
     }
 
     /// Exhausts the `Classifier` writing the output into `sink`.
@@ -296,7 +309,7 @@ fn advance(&mut self, token: TokenKind, text: &'a str, sink: &mut dyn FnMut(High
                 "Option" | "Result" => Class::PreludeTy,
                 "Some" | "None" | "Ok" | "Err" => Class::PreludeVal,
                 // Keywords are also included in the identifier set.
-                _ if Ident::from_str(text).is_reserved() => Class::KeyWord,
+                _ if Symbol::intern(text).is_reserved(|| self.edition) => Class::KeyWord,
                 _ if self.in_macro_nonterminal => {
                     self.in_macro_nonterminal = false;
                     Class::MacroNonTerminal
index f57f52d6f087554ae57537cb98be73daa4f67663..f97c8a7ab71484cf62235cc92b64aa2f514adb92 100644 (file)
@@ -1,5 +1,6 @@
 use super::write_code;
 use expect_test::expect_file;
+use rustc_span::edition::Edition;
 
 const STYLE: &str = r#"
 <style>
@@ -18,7 +19,7 @@ fn test_html_highlighting() {
     let src = include_str!("fixtures/sample.rs");
     let html = {
         let mut out = String::new();
-        write_code(&mut out, src);
+        write_code(&mut out, src, Edition::Edition2018);
         format!("{}<pre><code>{}</code></pre>\n", STYLE, out)
     };
     expect_file!["fixtures/sample.html"].assert_eq(&html);
@@ -30,6 +31,6 @@ fn test_dos_backline() {
     println!(\"foo\");\r\n\
 }\r\n";
     let mut html = String::new();
-    write_code(&mut html, src);
+    write_code(&mut html, src, Edition::Edition2018);
     expect_file!["fixtures/dos_line.html"].assert_eq(&html);
 }
index 6261e843d239d645aaa6dc5805394fa839540506..20cf48915c3c8dfa9081aaf4af9c7bbf6ecc9fe0 100644 (file)
@@ -248,7 +248,7 @@ fn next(&mut self) -> Option<Self::Item> {
                 .join("\n");
             let krate = krate.as_ref().map(|s| &**s);
             let (test, _, _) =
-                doctest::make_test(&test, krate, false, &Default::default(), edition);
+                doctest::make_test(&test, krate, false, &Default::default(), edition, None);
             let channel = if test.contains("#![feature(") { "&amp;version=nightly" } else { "" };
 
             let edition_string = format!("&amp;edition={}", edition);
@@ -284,60 +284,28 @@ fn dont_escape(c: u8) -> bool {
         });
 
         let tooltip = if ignore != Ignore::None {
-            Some(("This example is not tested".to_owned(), "ignore"))
+            Some((None, "ignore"))
         } else if compile_fail {
-            Some(("This example deliberately fails to compile".to_owned(), "compile_fail"))
+            Some((None, "compile_fail"))
         } else if should_panic {
-            Some(("This example panics".to_owned(), "should_panic"))
+            Some((None, "should_panic"))
         } else if explicit_edition {
-            Some((format!("This code runs with edition {}", edition), "edition"))
+            Some((Some(edition), "edition"))
         } else {
             None
         };
 
-        if let Some((s1, s2)) = tooltip {
-            s.push_str(&highlight::render_with_highlighting(
-                text,
-                Some(&format!(
-                    "rust-example-rendered{}",
-                    if ignore != Ignore::None {
-                        " ignore"
-                    } else if compile_fail {
-                        " compile_fail"
-                    } else if should_panic {
-                        " should_panic"
-                    } else if explicit_edition {
-                        " edition "
-                    } else {
-                        ""
-                    }
-                )),
-                playground_button.as_deref(),
-                Some((s1.as_str(), s2)),
-            ));
-            Some(Event::Html(s.into()))
-        } else {
-            s.push_str(&highlight::render_with_highlighting(
-                text,
-                Some(&format!(
-                    "rust-example-rendered{}",
-                    if ignore != Ignore::None {
-                        " ignore"
-                    } else if compile_fail {
-                        " compile_fail"
-                    } else if should_panic {
-                        " should_panic"
-                    } else if explicit_edition {
-                        " edition "
-                    } else {
-                        ""
-                    }
-                )),
-                playground_button.as_deref(),
-                None,
-            ));
-            Some(Event::Html(s.into()))
-        }
+        s.push_str(&highlight::render_with_highlighting(
+            text,
+            Some(&format!(
+                "rust-example-rendered{}",
+                if let Some((_, class)) = tooltip { format!(" {}", class) } else { String::new() }
+            )),
+            playground_button.as_deref(),
+            tooltip,
+            edition,
+        ));
+        Some(Event::Html(s.into()))
     }
 }
 
@@ -450,7 +418,7 @@ fn next(&mut self) -> Option<Self::Item> {
 struct HeadingLinks<'a, 'b, 'ids, I> {
     inner: I,
     toc: Option<&'b mut TocBuilder>,
-    buf: VecDeque<(Event<'a>, Range<usize>)>,
+    buf: VecDeque<Event<'a>>,
     id_map: &'ids mut IdMap,
 }
 
@@ -460,10 +428,8 @@ fn new(iter: I, toc: Option<&'b mut TocBuilder>, ids: &'ids mut IdMap) -> Self {
     }
 }
 
-impl<'a, 'b, 'ids, I: Iterator<Item = (Event<'a>, Range<usize>)>> Iterator
-    for HeadingLinks<'a, 'b, 'ids, I>
-{
-    type Item = (Event<'a>, Range<usize>);
+impl<'a, 'b, 'ids, I: Iterator<Item = Event<'a>>> Iterator for HeadingLinks<'a, 'b, 'ids, I> {
+    type Item = Event<'a>;
 
     fn next(&mut self) -> Option<Self::Item> {
         if let Some(e) = self.buf.pop_front() {
@@ -471,29 +437,31 @@ fn next(&mut self) -> Option<Self::Item> {
         }
 
         let event = self.inner.next();
-        if let Some((Event::Start(Tag::Heading(level)), _)) = event {
+        if let Some(Event::Start(Tag::Heading(level))) = event {
             let mut id = String::new();
             for event in &mut self.inner {
-                match &event.0 {
+                match &event {
                     Event::End(Tag::Heading(..)) => break,
-                    Event::Start(Tag::Link(_, _, _)) | Event::End(Tag::Link(..)) => {}
                     Event::Text(text) | Event::Code(text) => {
                         id.extend(text.chars().filter_map(slugify));
-                        self.buf.push_back(event);
                     }
-                    _ => self.buf.push_back(event),
+                    _ => {}
+                }
+                match event {
+                    Event::Start(Tag::Link(_, _, _)) | Event::End(Tag::Link(..)) => {}
+                    event => self.buf.push_back(event),
                 }
             }
             let id = self.id_map.derive(id);
 
             if let Some(ref mut builder) = self.toc {
                 let mut html_header = String::new();
-                html::push_html(&mut html_header, self.buf.iter().map(|(ev, _)| ev.clone()));
+                html::push_html(&mut html_header, self.buf.iter().cloned());
                 let sec = builder.push(level as u32, html_header, id.clone());
-                self.buf.push_front((Event::Html(format!("{} ", sec).into()), 0..0));
+                self.buf.push_front(Event::Html(format!("{} ", sec).into()));
             }
 
-            self.buf.push_back((Event::Html(format!("</a></h{}>", level).into()), 0..0));
+            self.buf.push_back(Event::Html(format!("</a></h{}>", level).into()));
 
             let start_tags = format!(
                 "<h{level} id=\"{id}\" class=\"section-header\">\
@@ -501,7 +469,7 @@ fn next(&mut self) -> Option<Self::Item> {
                 id = id,
                 level = level
             );
-            return Some((Event::Html(start_tags.into()), 0..0));
+            return Some(Event::Html(start_tags.into()));
         }
         event
     }
@@ -592,23 +560,23 @@ fn get_entry(&mut self, key: &str) -> &mut (Vec<Event<'a>>, u16) {
     }
 }
 
-impl<'a, I: Iterator<Item = (Event<'a>, Range<usize>)>> Iterator for Footnotes<'a, I> {
-    type Item = (Event<'a>, Range<usize>);
+impl<'a, I: Iterator<Item = Event<'a>>> Iterator for Footnotes<'a, I> {
+    type Item = Event<'a>;
 
     fn next(&mut self) -> Option<Self::Item> {
         loop {
             match self.inner.next() {
-                Some((Event::FootnoteReference(ref reference), range)) => {
+                Some(Event::FootnoteReference(ref reference)) => {
                     let entry = self.get_entry(&reference);
                     let reference = format!(
                         "<sup id=\"fnref{0}\"><a href=\"#fn{0}\">{0}</a></sup>",
                         (*entry).1
                     );
-                    return Some((Event::Html(reference.into()), range));
+                    return Some(Event::Html(reference.into()));
                 }
-                Some((Event::Start(Tag::FootnoteDefinition(def)), _)) => {
+                Some(Event::Start(Tag::FootnoteDefinition(def))) => {
                     let mut content = Vec::new();
-                    for (event, _) in &mut self.inner {
+                    for event in &mut self.inner {
                         if let Event::End(Tag::FootnoteDefinition(..)) = event {
                             break;
                         }
@@ -639,7 +607,7 @@ fn next(&mut self) -> Option<Self::Item> {
                             ret.push_str("</li>");
                         }
                         ret.push_str("</ol></div>");
-                        return Some((Event::Html(ret.into()), 0..0));
+                        return Some(Event::Html(ret.into()));
                     } else {
                         return None;
                     }
@@ -949,14 +917,13 @@ pub fn into_string(self) -> String {
         };
 
         let p = Parser::new_with_broken_link_callback(md, opts(), Some(&mut replacer));
-        let p = p.into_offset_iter();
 
         let mut s = String::with_capacity(md.len() * 3 / 2);
 
         let p = HeadingLinks::new(p, None, &mut ids);
-        let p = Footnotes::new(p);
-        let p = LinkReplacer::new(p.map(|(ev, _)| ev), links);
+        let p = LinkReplacer::new(p, links);
         let p = CodeBlocks::new(p, codes, edition, playground);
+        let p = Footnotes::new(p);
         html::push_html(&mut s, p);
 
         s
@@ -967,7 +934,7 @@ impl MarkdownWithToc<'_> {
     crate fn into_string(self) -> String {
         let MarkdownWithToc(md, mut ids, codes, edition, playground) = self;
 
-        let p = Parser::new_ext(md, opts()).into_offset_iter();
+        let p = Parser::new_ext(md, opts());
 
         let mut s = String::with_capacity(md.len() * 3 / 2);
 
@@ -975,8 +942,8 @@ impl MarkdownWithToc<'_> {
 
         {
             let p = HeadingLinks::new(p, Some(&mut toc), &mut ids);
+            let p = CodeBlocks::new(p, codes, edition, playground);
             let p = Footnotes::new(p);
-            let p = CodeBlocks::new(p.map(|(ev, _)| ev), codes, edition, playground);
             html::push_html(&mut s, p);
         }
 
@@ -992,19 +959,19 @@ impl MarkdownHtml<'_> {
         if md.is_empty() {
             return String::new();
         }
-        let p = Parser::new_ext(md, opts()).into_offset_iter();
+        let p = Parser::new_ext(md, opts());
 
         // Treat inline HTML as plain text.
-        let p = p.map(|event| match event.0 {
-            Event::Html(text) => (Event::Text(text), event.1),
+        let p = p.map(|event| match event {
+            Event::Html(text) => Event::Text(text),
             _ => event,
         });
 
         let mut s = String::with_capacity(md.len() * 3 / 2);
 
         let p = HeadingLinks::new(p, None, &mut ids);
+        let p = CodeBlocks::new(p, codes, edition, playground);
         let p = Footnotes::new(p);
-        let p = CodeBlocks::new(p.map(|(ev, _)| ev), codes, edition, playground);
         html::push_html(&mut s, p);
 
         s
@@ -1059,7 +1026,7 @@ fn markdown_summary_with_limit(md: &str, length_limit: usize) -> (String, bool)
     fn push(s: &mut String, text_length: &mut usize, text: &str) {
         s.push_str(text);
         *text_length += text.len();
-    };
+    }
 
     'outer: for event in Parser::new_ext(md, summary_opts()) {
         match &event {
@@ -1157,45 +1124,50 @@ fn push(s: &mut String, text_length: &mut usize, text: &str) {
     s
 }
 
-crate fn markdown_links(md: &str) -> Vec<(String, Range<usize>)> {
+crate fn markdown_links(md: &str) -> Vec<(String, Option<Range<usize>>)> {
     if md.is_empty() {
         return vec![];
     }
 
     let mut links = vec![];
-    // Used to avoid mutable borrow issues in the `push` closure
-    // Probably it would be more efficient to use a `RefCell` but it doesn't seem worth the churn.
     let mut shortcut_links = vec![];
 
-    let span_for_link = |link: &str, span: Range<usize>| {
-        // Pulldown includes the `[]` as well as the URL. Only highlight the relevant span.
-        // NOTE: uses `rfind` in case the title and url are the same: `[Ok][Ok]`
-        match md[span.clone()].rfind(link) {
-            Some(start) => {
-                let start = span.start + start;
-                start..start + link.len()
+    {
+        let locate = |s: &str| unsafe {
+            let s_start = s.as_ptr();
+            let s_end = s_start.add(s.len());
+            let md_start = md.as_ptr();
+            let md_end = md_start.add(md.len());
+            if md_start <= s_start && s_end <= md_end {
+                let start = s_start.offset_from(md_start) as usize;
+                let end = s_end.offset_from(md_start) as usize;
+                Some(start..end)
+            } else {
+                None
+            }
+        };
+
+        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(&mut push));
+
+        // There's no need to thread an IdMap through to here because
+        // the IDs generated aren't going to be emitted anywhere.
+        let mut ids = IdMap::new();
+        let iter = Footnotes::new(HeadingLinks::new(p, None, &mut ids));
+
+        for ev in iter {
+            if let Event::Start(Tag::Link(_, dest, _)) = ev {
+                debug!("found link: {}", dest);
+                links.push(match dest {
+                    CowStr::Borrowed(s) => (s.to_owned(), locate(s)),
+                    s @ (CowStr::Boxed(..) | CowStr::Inlined(..)) => (s.into_string(), None),
+                });
             }
-            // This can happen for things other than intra-doc links, like `#1` expanded to `https://github.com/rust-lang/rust/issues/1`.
-            None => span,
-        }
-    };
-    let mut push = |link: BrokenLink<'_>| {
-        let span = span_for_link(link.reference, link.span);
-        shortcut_links.push((link.reference.to_owned(), span));
-        None
-    };
-    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.
-    let mut ids = IdMap::new();
-    let iter = Footnotes::new(HeadingLinks::new(p.into_offset_iter(), None, &mut ids));
-
-    for ev in iter {
-        if let Event::Start(Tag::Link(_, dest, _)) = ev.0 {
-            debug!("found link: {}", dest);
-            let span = span_for_link(&dest, ev.1);
-            links.push((dest.into_string(), span));
         }
     }
 
index 25fe31aab59467b6bf561eff3b674e79c6b7db3b..c408e576639d9f3f0648efad5f3bb74612683964 100644 (file)
@@ -165,7 +165,7 @@ struct CrateData<'a> {
 }
 
 crate fn get_index_search_type(item: &clean::Item) -> Option<IndexItemFunctionType> {
-    let (all_types, ret_types) = match item.kind {
+    let (all_types, ret_types) = match *item.kind {
         clean::FunctionItem(ref f) => (&f.all_types, &f.ret_types),
         clean::MethodItem(ref m, _) => (&m.all_types, &m.ret_types),
         clean::TyMethodItem(ref m) => (&m.all_types, &m.ret_types),
index c21570d9716efc27c84360f3ff15051222868c26..a83a3600383eee5b5690ef94527f7825613343ef 100644 (file)
     playground: Option<markdown::Playground>,
 }
 
-impl Context<'_> {
+impl<'tcx> Context<'tcx> {
     fn path(&self, filename: &str) -> PathBuf {
         // We use splitn vs Path::extension here because we might get a filename
         // like `style.min.css` and we want to process that into
@@ -176,6 +176,10 @@ fn path(&self, filename: &str) -> PathBuf {
         self.dst.join(&filename)
     }
 
+    fn tcx(&self) -> TyCtxt<'tcx> {
+        self.shared.tcx
+    }
+
     fn sess(&self) -> &Session {
         &self.shared.tcx.sess
     }
@@ -534,7 +538,7 @@ fn after_run(&mut self, diag: &rustc_errors::Handler) -> Result<(), Error> {
     fn after_krate(&mut self, krate: &clean::Crate, cache: &Cache) -> Result<(), Error> {
         let final_file = self.dst.join(&*krate.name.as_str()).join("all.html");
         let settings_file = self.dst.join("settings.html");
-        let crate_name = krate.name.clone();
+        let crate_name = krate.name;
 
         let mut root_path = self.dst.to_str().expect("invalid path").to_owned();
         if !root_path.ends_with('/') {
@@ -629,7 +633,7 @@ fn mod_item_in(
 
         // Render sidebar-items.js used throughout this module.
         if !self.render_redirect_pages {
-            let module = match item.kind {
+            let module = match *item.kind {
                 clean::StrippedItem(box clean::ModuleItem(ref m)) | clean::ModuleItem(ref m) => m,
                 _ => unreachable!(),
             };
@@ -1708,8 +1712,8 @@ fn print_item(cx: &Context<'_>, item: &clean::Item, buf: &mut Buffer, cache: &Ca
     write!(buf, "<h1 class=\"fqn\"><span class=\"out-of-band\">");
     render_stability_since_raw(
         buf,
-        item.stable_since().as_deref(),
-        item.const_stable_since().as_deref(),
+        item.stable_since(cx.tcx()).as_deref(),
+        item.const_stable_since(cx.tcx()).as_deref(),
         None,
         None,
     );
@@ -1735,7 +1739,7 @@ fn print_item(cx: &Context<'_>, item: &clean::Item, buf: &mut Buffer, cache: &Ca
 
     write!(buf, "</span>"); // out-of-band
     write!(buf, "<span class=\"in-band\">");
-    let name = match item.kind {
+    let name = match *item.kind {
         clean::ModuleItem(ref m) => {
             if m.is_crate {
                 "Crate "
@@ -1784,7 +1788,7 @@ fn print_item(cx: &Context<'_>, item: &clean::Item, buf: &mut Buffer, cache: &Ca
 
     write!(buf, "</span></h1>"); // in-band
 
-    match item.kind {
+    match *item.kind {
         clean::ModuleItem(ref m) => item_module(buf, cx, item, &m.items),
         clean::FunctionItem(ref f) | clean::ForeignFunctionItem(ref f) => {
             item_function(buf, cx, item, f)
@@ -2061,14 +2065,20 @@ fn reorder(ty: ItemType) -> u8 {
         }
     }
 
-    fn cmp(i1: &clean::Item, i2: &clean::Item, idx1: usize, idx2: usize) -> Ordering {
+    fn cmp(
+        i1: &clean::Item,
+        i2: &clean::Item,
+        idx1: usize,
+        idx2: usize,
+        tcx: TyCtxt<'_>,
+    ) -> Ordering {
         let ty1 = i1.type_();
         let ty2 = i2.type_();
         if ty1 != ty2 {
             return (reorder(ty1), idx1).cmp(&(reorder(ty2), idx2));
         }
-        let s1 = i1.stability.as_ref().map(|s| s.level);
-        let s2 = i2.stability.as_ref().map(|s| s.level);
+        let s1 = i1.stability(tcx).as_ref().map(|s| s.level);
+        let s2 = i2.stability(tcx).as_ref().map(|s| s.level);
         if let (Some(a), Some(b)) = (s1, s2) {
             match (a.is_stable(), b.is_stable()) {
                 (true, true) | (false, false) => {}
@@ -2076,13 +2086,13 @@ fn cmp(i1: &clean::Item, i2: &clean::Item, idx1: usize, idx2: usize) -> Ordering
                 (true, false) => return Ordering::Greater,
             }
         }
-        let lhs = i1.name.unwrap_or(kw::Invalid).as_str();
-        let rhs = i2.name.unwrap_or(kw::Invalid).as_str();
+        let lhs = i1.name.unwrap_or(kw::Empty).as_str();
+        let rhs = i2.name.unwrap_or(kw::Empty).as_str();
         compare_names(&lhs, &rhs)
     }
 
     if cx.shared.sort_modules_alphabetically {
-        indices.sort_by(|&i1, &i2| cmp(&items[i1], &items[i2], i1, i2));
+        indices.sort_by(|&i1, &i2| cmp(&items[i1], &items[i2], i1, i2, cx.tcx()));
     }
     // This call is to remove re-export duplicates in cases such as:
     //
@@ -2139,7 +2149,7 @@ fn cmp(i1: &clean::Item, i2: &clean::Item, idx1: usize, idx2: usize) -> Ordering
             );
         }
 
-        match myitem.kind {
+        match *myitem.kind {
             clean::ExternCrateItem(ref name, ref src) => {
                 use crate::html::format::anchor;
 
@@ -2147,14 +2157,14 @@ fn cmp(i1: &clean::Item, i2: &clean::Item, idx1: usize, idx2: usize) -> Ordering
                     Some(ref src) => write!(
                         w,
                         "<tr><td><code>{}extern crate {} as {};",
-                        myitem.visibility.print_with_space(),
+                        myitem.visibility.print_with_space(cx.tcx()),
                         anchor(myitem.def_id, &*src.as_str()),
                         name
                     ),
                     None => write!(
                         w,
                         "<tr><td><code>{}extern crate {};",
-                        myitem.visibility.print_with_space(),
+                        myitem.visibility.print_with_space(cx.tcx()),
                         anchor(myitem.def_id, &*name.as_str())
                     ),
                 }
@@ -2165,7 +2175,7 @@ fn cmp(i1: &clean::Item, i2: &clean::Item, idx1: usize, idx2: usize) -> Ordering
                 write!(
                     w,
                     "<tr><td><code>{}{}</code></td></tr>",
-                    myitem.visibility.print_with_space(),
+                    myitem.visibility.print_with_space(cx.tcx()),
                     import.print()
                 );
             }
@@ -2175,7 +2185,7 @@ fn cmp(i1: &clean::Item, i2: &clean::Item, idx1: usize, idx2: usize) -> Ordering
                     continue;
                 }
 
-                let unsafety_flag = match myitem.kind {
+                let unsafety_flag = match *myitem.kind {
                     clean::FunctionItem(ref func) | clean::ForeignFunctionItem(ref func)
                         if func.header.unsafety == hir::Unsafety::Unsafe =>
                     {
@@ -2184,7 +2194,7 @@ fn cmp(i1: &clean::Item, i2: &clean::Item, idx1: usize, idx2: usize) -> Ordering
                     _ => "",
                 };
 
-                let stab = myitem.stability_class();
+                let stab = myitem.stability_class(cx.tcx());
                 let add = if stab.is_some() { " " } else { "" };
 
                 let doc_value = myitem.doc_value().unwrap_or("");
@@ -2196,7 +2206,7 @@ fn cmp(i1: &clean::Item, i2: &clean::Item, idx1: usize, idx2: usize) -> Ordering
                          <td class=\"docblock-short\">{stab_tags}{docs}</td>\
                      </tr>",
                     name = *myitem.name.as_ref().unwrap(),
-                    stab_tags = extra_info_tags(myitem, item),
+                    stab_tags = extra_info_tags(myitem, item, cx.tcx()),
                     docs = MarkdownSummaryLine(doc_value, &myitem.links()).into_string(),
                     class = myitem.type_(),
                     add = add,
@@ -2220,7 +2230,7 @@ fn cmp(i1: &clean::Item, i2: &clean::Item, idx1: usize, idx2: usize) -> Ordering
 
 /// Render the stability, deprecation and portability tags that are displayed in the item's summary
 /// at the module level.
-fn extra_info_tags(item: &clean::Item, parent: &clean::Item) -> String {
+fn extra_info_tags(item: &clean::Item, parent: &clean::Item, tcx: TyCtxt<'_>) -> String {
     let mut tags = String::new();
 
     fn tag_html(class: &str, title: &str, contents: &str) -> String {
@@ -2228,7 +2238,7 @@ fn tag_html(class: &str, title: &str, contents: &str) -> String {
     }
 
     // The trailing space after each tag is to space it properly against the rest of the docs.
-    if let Some(depr) = &item.deprecation {
+    if let Some(depr) = &item.deprecation(tcx) {
         let mut message = "Deprecated";
         if !stability::deprecation_in_effect(
             depr.is_since_rustc_version,
@@ -2241,7 +2251,10 @@ fn tag_html(class: &str, title: &str, contents: &str) -> String {
 
     // The "rustc_private" crates are permanently unstable so it makes no sense
     // to render "unstable" everywhere.
-    if item.stability.as_ref().map(|s| s.level.is_unstable() && s.feature != sym::rustc_private)
+    if item
+        .stability(tcx)
+        .as_ref()
+        .map(|s| s.level.is_unstable() && s.feature != sym::rustc_private)
         == Some(true)
     {
         tags += &tag_html("unstable", "", "Experimental");
@@ -2287,7 +2300,7 @@ fn short_item_info(
     let error_codes = cx.shared.codes;
 
     if let Some(Deprecation { note, since, is_since_rustc_version, suggestion: _ }) =
-        item.deprecation
+        item.deprecation(cx.tcx())
     {
         // We display deprecation messages for #[deprecated] and #[rustc_deprecated]
         // but only display the future-deprecation messages for #[rustc_deprecated].
@@ -2327,7 +2340,7 @@ fn short_item_info(
     // Render unstable items. But don't render "rustc_private" crates (internal compiler crates).
     // Those crates are permanently unstable so it makes no sense to render "unstable" everywhere.
     if let Some((StabilityLevel::Unstable { reason, issue, .. }, feature)) = item
-        .stability
+        .stability(cx.tcx())
         .as_ref()
         .filter(|stab| stab.feature != sym::rustc_private)
         .map(|stab| (stab.level, stab.feature))
@@ -2379,7 +2392,7 @@ fn item_constant(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, c: &clean::
     write!(
         w,
         "{vis}const {name}: {typ}",
-        vis = it.visibility.print_with_space(),
+        vis = it.visibility.print_with_space(cx.tcx()),
         name = it.name.as_ref().unwrap(),
         typ = c.type_.print(),
     );
@@ -2413,7 +2426,7 @@ fn item_static(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::St
     write!(
         w,
         "{vis}static {mutability}{name}: {typ}</pre>",
-        vis = it.visibility.print_with_space(),
+        vis = it.visibility.print_with_space(cx.tcx()),
         mutability = s.mutability.print_with_space(),
         name = it.name.as_ref().unwrap(),
         typ = s.type_.print()
@@ -2424,7 +2437,7 @@ fn item_static(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::St
 fn item_function(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, f: &clean::Function) {
     let header_len = format!(
         "{}{}{}{}{:#}fn {}{:#}",
-        it.visibility.print_with_space(),
+        it.visibility.print_with_space(cx.tcx()),
         f.header.constness.print_with_space(),
         f.header.asyncness.print_with_space(),
         f.header.unsafety.print_with_space(),
@@ -2439,7 +2452,7 @@ fn item_function(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, f: &clean::
         w,
         "{vis}{constness}{asyncness}{unsafety}{abi}fn \
          {name}{generics}{decl}{spotlight}{where_clause}</pre>",
-        vis = it.visibility.print_with_space(),
+        vis = it.visibility.print_with_space(cx.tcx()),
         constness = f.header.constness.print_with_space(),
         asyncness = f.header.asyncness.print_with_space(),
         unsafety = f.header.unsafety.print_with_space(),
@@ -2480,8 +2493,8 @@ fn render_implementor(
         parent,
         AssocItemLink::Anchor(None),
         RenderMode::Normal,
-        implementor.impl_item.stable_since().as_deref(),
-        implementor.impl_item.const_stable_since().as_deref(),
+        implementor.impl_item.stable_since(cx.tcx()).as_deref(),
+        implementor.impl_item.const_stable_since(cx.tcx()).as_deref(),
         false,
         Some(use_absolute),
         false,
@@ -2511,8 +2524,8 @@ fn render_impls(
                 containing_item,
                 assoc_link,
                 RenderMode::Normal,
-                containing_item.stable_since().as_deref(),
-                containing_item.const_stable_since().as_deref(),
+                containing_item.stable_since(cx.tcx()).as_deref(),
+                containing_item.const_stable_since(cx.tcx()).as_deref(),
                 true,
                 None,
                 false,
@@ -2565,7 +2578,7 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra
         write!(
             w,
             "{}{}{}trait {}{}{}",
-            it.visibility.print_with_space(),
+            it.visibility.print_with_space(cx.tcx()),
             t.unsafety.print_with_space(),
             if t.is_auto { "auto " } else { "" },
             it.name.as_ref().unwrap(),
@@ -2585,21 +2598,21 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra
             // FIXME: we should be using a derived_id for the Anchors here
             write!(w, "{{\n");
             for t in &types {
-                render_assoc_item(w, t, AssocItemLink::Anchor(None), ItemType::Trait);
+                render_assoc_item(w, t, AssocItemLink::Anchor(None), ItemType::Trait, cx);
                 write!(w, ";\n");
             }
             if !types.is_empty() && !consts.is_empty() {
                 w.write_str("\n");
             }
             for t in &consts {
-                render_assoc_item(w, t, AssocItemLink::Anchor(None), ItemType::Trait);
+                render_assoc_item(w, t, AssocItemLink::Anchor(None), ItemType::Trait, cx);
                 write!(w, ";\n");
             }
             if !consts.is_empty() && !required.is_empty() {
                 w.write_str("\n");
             }
             for (pos, m) in required.iter().enumerate() {
-                render_assoc_item(w, m, AssocItemLink::Anchor(None), ItemType::Trait);
+                render_assoc_item(w, m, AssocItemLink::Anchor(None), ItemType::Trait, cx);
                 write!(w, ";\n");
 
                 if pos < required.len() - 1 {
@@ -2610,8 +2623,8 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra
                 w.write_str("\n");
             }
             for (pos, m) in provided.iter().enumerate() {
-                render_assoc_item(w, m, AssocItemLink::Anchor(None), ItemType::Trait);
-                match m.kind {
+                render_assoc_item(w, m, AssocItemLink::Anchor(None), ItemType::Trait, cx);
+                match *m.kind {
                     clean::MethodItem(ref inner, _)
                         if !inner.generics.where_predicates.is_empty() =>
                     {
@@ -2659,9 +2672,9 @@ fn trait_item(
         let item_type = m.type_();
         let id = cx.derive_id(format!("{}.{}", item_type, name));
         write!(w, "<h3 id=\"{id}\" class=\"method\"><code>", id = id,);
-        render_assoc_item(w, m, AssocItemLink::Anchor(Some(&id)), ItemType::Impl);
+        render_assoc_item(w, m, AssocItemLink::Anchor(Some(&id)), ItemType::Impl, cx);
         write!(w, "</code>");
-        render_stability_since(w, m, t);
+        render_stability_since(w, m, t, cx.tcx());
         write_srclink(cx, m, w, cache);
         write!(w, "</h3>");
         document(w, cx, m, Some(t));
@@ -2768,8 +2781,8 @@ fn trait_item(
                     it,
                     assoc_link,
                     RenderMode::Normal,
-                    implementor.impl_item.stable_since().as_deref(),
-                    implementor.impl_item.const_stable_since().as_deref(),
+                    implementor.impl_item.stable_since(cx.tcx()).as_deref(),
+                    implementor.impl_item.const_stable_since(cx.tcx()).as_deref(),
                     false,
                     None,
                     true,
@@ -2877,12 +2890,13 @@ fn assoc_const(
     _default: Option<&String>,
     link: AssocItemLink<'_>,
     extra: &str,
+    cx: &Context<'_>,
 ) {
     write!(
         w,
         "{}{}const <a href=\"{}\" class=\"constant\"><b>{}</b></a>: {}",
         extra,
-        it.visibility.print_with_space(),
+        it.visibility.print_with_space(cx.tcx()),
         naive_assoc_href(it, link),
         it.name.as_ref().unwrap(),
         ty.print()
@@ -2950,13 +2964,18 @@ fn render_stability_since_raw(
     }
 }
 
-fn render_stability_since(w: &mut Buffer, item: &clean::Item, containing_item: &clean::Item) {
+fn render_stability_since(
+    w: &mut Buffer,
+    item: &clean::Item,
+    containing_item: &clean::Item,
+    tcx: TyCtxt<'_>,
+) {
     render_stability_since_raw(
         w,
-        item.stable_since().as_deref(),
-        item.const_stable_since().as_deref(),
-        containing_item.stable_since().as_deref(),
-        containing_item.const_stable_since().as_deref(),
+        item.stable_since(tcx).as_deref(),
+        item.const_stable_since(tcx).as_deref(),
+        containing_item.stable_since(tcx).as_deref(),
+        containing_item.const_stable_since(tcx).as_deref(),
     )
 }
 
@@ -2965,6 +2984,7 @@ fn render_assoc_item(
     item: &clean::Item,
     link: AssocItemLink<'_>,
     parent: ItemType,
+    cx: &Context<'_>,
 ) {
     fn method(
         w: &mut Buffer,
@@ -2974,6 +2994,7 @@ fn method(
         d: &clean::FnDecl,
         link: AssocItemLink<'_>,
         parent: ItemType,
+        cx: &Context<'_>,
     ) {
         let name = meth.name.as_ref().unwrap();
         let anchor = format!("#{}.{}", meth.type_(), name);
@@ -2994,7 +3015,7 @@ fn method(
         };
         let mut header_len = format!(
             "{}{}{}{}{}{:#}fn {}{:#}",
-            meth.visibility.print_with_space(),
+            meth.visibility.print_with_space(cx.tcx()),
             header.constness.print_with_space(),
             header.asyncness.print_with_space(),
             header.unsafety.print_with_space(),
@@ -3016,7 +3037,7 @@ fn method(
             "{}{}{}{}{}{}{}fn <a href=\"{href}\" class=\"fnname\">{name}</a>\
              {generics}{decl}{spotlight}{where_clause}",
             if parent == ItemType::Trait { "    " } else { "" },
-            meth.visibility.print_with_space(),
+            meth.visibility.print_with_space(cx.tcx()),
             header.constness.print_with_space(),
             header.asyncness.print_with_space(),
             header.unsafety.print_with_space(),
@@ -3030,11 +3051,13 @@ fn method(
             where_clause = WhereClause { gens: g, indent, end_newline }
         )
     }
-    match item.kind {
+    match *item.kind {
         clean::StrippedItem(..) => {}
-        clean::TyMethodItem(ref m) => method(w, item, m.header, &m.generics, &m.decl, link, parent),
+        clean::TyMethodItem(ref m) => {
+            method(w, item, m.header, &m.generics, &m.decl, link, parent, cx)
+        }
         clean::MethodItem(ref m, _) => {
-            method(w, item, m.header, &m.generics, &m.decl, link, parent)
+            method(w, item, m.header, &m.generics, &m.decl, link, parent, cx)
         }
         clean::AssocConstItem(ref ty, ref default) => assoc_const(
             w,
@@ -3043,6 +3066,7 @@ fn method(
             default.as_ref(),
             link,
             if parent == ItemType::Trait { "    " } else { "" },
+            cx,
         ),
         clean::AssocTypeItem(ref bounds, ref default) => assoc_type(
             w,
@@ -3066,7 +3090,7 @@ fn item_struct(
     wrap_into_docblock(w, |w| {
         write!(w, "<pre class=\"rust struct\">");
         render_attributes(w, it, true);
-        render_struct(w, it, Some(&s.generics), s.struct_type, &s.fields, "", true);
+        render_struct(w, it, Some(&s.generics), s.struct_type, &s.fields, "", true, cx);
         write!(w, "</pre>")
     });
 
@@ -3074,7 +3098,7 @@ fn item_struct(
     let mut fields = s
         .fields
         .iter()
-        .filter_map(|f| match f.kind {
+        .filter_map(|f| match *f.kind {
             clean::StructFieldItem(ref ty) => Some((f, ty)),
             _ => None,
         })
@@ -3116,7 +3140,7 @@ fn item_union(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::Uni
     wrap_into_docblock(w, |w| {
         write!(w, "<pre class=\"rust union\">");
         render_attributes(w, it, true);
-        render_union(w, it, Some(&s.generics), &s.fields, "", true);
+        render_union(w, it, Some(&s.generics), &s.fields, "", true, cx);
         write!(w, "</pre>")
     });
 
@@ -3124,7 +3148,7 @@ fn item_union(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::Uni
     let mut fields = s
         .fields
         .iter()
-        .filter_map(|f| match f.kind {
+        .filter_map(|f| match *f.kind {
             clean::StructFieldItem(ref ty) => Some((f, ty)),
             _ => None,
         })
@@ -3149,7 +3173,7 @@ fn item_union(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::Uni
                 shortty = ItemType::StructField,
                 ty = ty.print()
             );
-            if let Some(stability_class) = field.stability_class() {
+            if let Some(stability_class) = field.stability_class(cx.tcx()) {
                 write!(w, "<span class=\"stab {stab}\"></span>", stab = stability_class);
             }
             document(w, cx, field, Some(it));
@@ -3165,7 +3189,7 @@ fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum
         write!(
             w,
             "{}enum {}{}{}",
-            it.visibility.print_with_space(),
+            it.visibility.print_with_space(cx.tcx()),
             it.name.as_ref().unwrap(),
             e.generics.print(),
             WhereClause { gens: &e.generics, indent: 0, end_newline: true }
@@ -3177,7 +3201,7 @@ fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum
             for v in &e.variants {
                 write!(w, "    ");
                 let name = v.name.as_ref().unwrap();
-                match v.kind {
+                match *v.kind {
                     clean::VariantItem(ref var) => match var.kind {
                         clean::VariantKind::CLike => write!(w, "{}", name),
                         clean::VariantKind::Tuple(ref tys) => {
@@ -3191,7 +3215,7 @@ fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum
                             write!(w, ")");
                         }
                         clean::VariantKind::Struct(ref s) => {
-                            render_struct(w, v, None, s.struct_type, &s.fields, "    ", false);
+                            render_struct(w, v, None, s.struct_type, &s.fields, "    ", false, cx);
                         }
                     },
                     _ => unreachable!(),
@@ -3227,7 +3251,7 @@ fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum
                 id = id,
                 name = variant.name.as_ref().unwrap()
             );
-            if let clean::VariantItem(ref var) = variant.kind {
+            if let clean::VariantItem(ref var) = *variant.kind {
                 if let clean::VariantKind::Tuple(ref tys) = var.kind {
                     write!(w, "(");
                     for (i, ty) in tys.iter().enumerate() {
@@ -3244,7 +3268,8 @@ fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum
             document_non_exhaustive(w, variant);
 
             use crate::clean::{Variant, VariantKind};
-            if let clean::VariantItem(Variant { kind: VariantKind::Struct(ref s) }) = variant.kind {
+            if let clean::VariantItem(Variant { kind: VariantKind::Struct(ref s) }) = *variant.kind
+            {
                 let variant_id = cx.derive_id(format!(
                     "{}.{}.fields",
                     ItemType::Variant,
@@ -3258,7 +3283,7 @@ fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum
                 );
                 for field in &s.fields {
                     use crate::clean::StructFieldItem;
-                    if let StructFieldItem(ref ty) = field.kind {
+                    if let StructFieldItem(ref ty) = *field.kind {
                         let id = cx.derive_id(format!(
                             "variant.{}.field.{}",
                             variant.name.as_ref().unwrap(),
@@ -3279,7 +3304,7 @@ fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum
                 }
                 write!(w, "</div></div>");
             }
-            render_stability_since(w, variant, it);
+            render_stability_since(w, variant, it, cx.tcx());
         }
     }
     render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All, cache)
@@ -3335,11 +3360,12 @@ fn render_struct(
     fields: &[clean::Item],
     tab: &str,
     structhead: bool,
+    cx: &Context<'_>,
 ) {
     write!(
         w,
         "{}{}{}",
-        it.visibility.print_with_space(),
+        it.visibility.print_with_space(cx.tcx()),
         if structhead { "struct " } else { "" },
         it.name.as_ref().unwrap()
     );
@@ -3354,12 +3380,12 @@ fn render_struct(
             let mut has_visible_fields = false;
             write!(w, " {{");
             for field in fields {
-                if let clean::StructFieldItem(ref ty) = field.kind {
+                if let clean::StructFieldItem(ref ty) = *field.kind {
                     write!(
                         w,
                         "\n{}    {}{}: {},",
                         tab,
-                        field.visibility.print_with_space(),
+                        field.visibility.print_with_space(cx.tcx()),
                         field.name.as_ref().unwrap(),
                         ty.print()
                     );
@@ -3385,10 +3411,10 @@ fn render_struct(
                 if i > 0 {
                     write!(w, ", ");
                 }
-                match field.kind {
+                match *field.kind {
                     clean::StrippedItem(box clean::StructFieldItem(..)) => write!(w, "_"),
                     clean::StructFieldItem(ref ty) => {
-                        write!(w, "{}{}", field.visibility.print_with_space(), ty.print())
+                        write!(w, "{}{}", field.visibility.print_with_space(cx.tcx()), ty.print())
                     }
                     _ => unreachable!(),
                 }
@@ -3416,11 +3442,12 @@ fn render_union(
     fields: &[clean::Item],
     tab: &str,
     structhead: bool,
+    cx: &Context<'_>,
 ) {
     write!(
         w,
         "{}{}{}",
-        it.visibility.print_with_space(),
+        it.visibility.print_with_space(cx.tcx()),
         if structhead { "union " } else { "" },
         it.name.as_ref().unwrap()
     );
@@ -3431,11 +3458,11 @@ fn render_union(
 
     write!(w, " {{\n{}", tab);
     for field in fields {
-        if let clean::StructFieldItem(ref ty) = field.kind {
+        if let clean::StructFieldItem(ref ty) = *field.kind {
             write!(
                 w,
                 "    {}{}: {},\n{}",
-                field.visibility.print_with_space(),
+                field.visibility.print_with_space(cx.tcx()),
                 field.name.as_ref().unwrap(),
                 ty.print(),
                 tab
@@ -3456,7 +3483,7 @@ enum AssocItemLink<'a> {
 }
 
 impl<'a> AssocItemLink<'a> {
-    fn anchor(&self, id: &'a String) -> Self {
+    fn anchor(&self, id: &'a str) -> Self {
         match *self {
             AssocItemLink::Anchor(_) => AssocItemLink::Anchor(Some(&id)),
             ref other => *other,
@@ -3510,8 +3537,8 @@ fn render_assoc_items(
                 containing_item,
                 AssocItemLink::Anchor(None),
                 render_mode,
-                containing_item.stable_since().as_deref(),
-                containing_item.const_stable_since().as_deref(),
+                containing_item.stable_since(cx.tcx()).as_deref(),
+                containing_item.const_stable_since(cx.tcx()).as_deref(),
                 true,
                 None,
                 false,
@@ -3593,7 +3620,7 @@ fn render_deref_methods(
         .inner_impl()
         .items
         .iter()
-        .find_map(|item| match item.kind {
+        .find_map(|item| match *item.kind {
             clean::TypedefItem(ref t, true) => Some(match *t {
                 clean::Typedef { item_type: Some(ref type_), .. } => (type_, &t.type_),
                 _ => (&t.type_, &t.type_),
@@ -3615,7 +3642,7 @@ fn render_deref_methods(
 }
 
 fn should_render_item(item: &clean::Item, deref_mut_: bool) -> bool {
-    let self_type_opt = match item.kind {
+    let self_type_opt = match *item.kind {
         clean::MethodItem(ref method, _) => method.decl.self_type(),
         clean::TyMethodItem(ref method) => method.decl.self_type(),
         _ => None,
@@ -3666,7 +3693,7 @@ fn spotlight_decl(decl: &clean::FnDecl) -> String {
                     ));
                     let t_did = impl_.trait_.def_id().unwrap();
                     for it in &impl_.items {
-                        if let clean::TypedefItem(ref tydef, _) = it.kind {
+                        if let clean::TypedefItem(ref tydef, _) = *it.kind {
                             out.push_str("<span class=\"where fmt-newline\">    ");
                             assoc_type(
                                 &mut out,
@@ -3738,7 +3765,7 @@ fn render_impl(
             fmt_impl_for_trait_page(&i.inner_impl(), w, use_absolute);
             if show_def_docs {
                 for it in &i.inner_impl().items {
-                    if let clean::TypedefItem(ref tydef, _) = it.kind {
+                    if let clean::TypedefItem(ref tydef, _) = *it.kind {
                         write!(w, "<span class=\"where fmt-newline\">  ");
                         assoc_type(w, it, &[], Some(&tydef.type_), AssocItemLink::Anchor(None), "");
                         write!(w, ";</span>");
@@ -3758,8 +3785,8 @@ fn render_impl(
         write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
         render_stability_since_raw(
             w,
-            i.impl_item.stable_since().as_deref(),
-            i.impl_item.const_stable_since().as_deref(),
+            i.impl_item.stable_since(cx.tcx()).as_deref(),
+            i.impl_item.const_stable_since(cx.tcx()).as_deref(),
             outer_version,
             outer_const_version,
         );
@@ -3820,19 +3847,19 @@ fn doc_impl_item(
             } else {
                 (true, " hidden")
             };
-        match item.kind {
+        match *item.kind {
             clean::MethodItem(..) | clean::TyMethodItem(_) => {
                 // Only render when the method is not static or we allow static methods
                 if render_method_item {
                     let id = cx.derive_id(format!("{}.{}", item_type, name));
                     write!(w, "<h4 id=\"{}\" class=\"{}{}\">", id, item_type, extra_class);
                     write!(w, "<code>");
-                    render_assoc_item(w, item, link.anchor(&id), ItemType::Impl);
+                    render_assoc_item(w, item, link.anchor(&id), ItemType::Impl, cx);
                     write!(w, "</code>");
                     render_stability_since_raw(
                         w,
-                        item.stable_since().as_deref(),
-                        item.const_stable_since().as_deref(),
+                        item.stable_since(cx.tcx()).as_deref(),
+                        item.const_stable_since(cx.tcx()).as_deref(),
                         outer_version,
                         outer_const_version,
                     );
@@ -3849,12 +3876,12 @@ fn doc_impl_item(
             clean::AssocConstItem(ref ty, ref default) => {
                 let id = cx.derive_id(format!("{}.{}", item_type, name));
                 write!(w, "<h4 id=\"{}\" class=\"{}{}\"><code>", id, item_type, extra_class);
-                assoc_const(w, item, ty, default.as_ref(), link.anchor(&id), "");
+                assoc_const(w, item, ty, default.as_ref(), link.anchor(&id), "", cx);
                 write!(w, "</code>");
                 render_stability_since_raw(
                     w,
-                    item.stable_since().as_deref(),
-                    item.const_stable_since().as_deref(),
+                    item.stable_since(cx.tcx()).as_deref(),
+                    item.const_stable_since(cx.tcx()).as_deref(),
                     outer_version,
                     outer_const_version,
                 );
@@ -3940,7 +3967,7 @@ fn render_default_items(
         cache: &Cache,
     ) {
         for trait_item in &t.items {
-            let n = trait_item.name.clone();
+            let n = trait_item.name;
             if i.items.iter().any(|m| m.name == n) {
                 continue;
             }
@@ -4074,7 +4101,7 @@ fn item_foreign_type(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, cache:
     write!(
         w,
         "    {}type {};\n}}</pre>",
-        it.visibility.print_with_space(),
+        it.visibility.print_with_space(cx.tcx()),
         it.name.as_ref().unwrap(),
     );
 
@@ -4097,7 +4124,7 @@ fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buffer, cache:
         write!(
             buffer,
             "<p class=\"location\">{}{}</p>",
-            match it.kind {
+            match *it.kind {
                 clean::StructItem(..) => "Struct ",
                 clean::TraitItem(..) => "Trait ",
                 clean::PrimitiveItem(..) => "Primitive Type ",
@@ -4137,7 +4164,7 @@ fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buffer, cache:
             it.name.as_ref().expect("crates always have a name")
         );
     }
-    match it.kind {
+    match *it.kind {
         clean::StructItem(ref s) => sidebar_struct(buffer, it, s),
         clean::TraitItem(ref t) => sidebar_trait(buffer, it, t),
         clean::PrimitiveItem(_) => sidebar_primitive(buffer, it),
@@ -4180,7 +4207,7 @@ fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buffer, cache:
                 ty: \"{ty}\", \
                 relpath: \"{path}\"\
             }};</script>",
-        name = it.name.unwrap_or(kw::Invalid),
+        name = it.name.unwrap_or(kw::Empty),
         ty = it.type_(),
         path = relpath
     );
@@ -4277,7 +4304,7 @@ fn sidebar_assoc_items(it: &clean::Item) -> String {
                 .find(|i| i.inner_impl().trait_.def_id() == c.deref_trait_did)
             {
                 if let Some((target, real_target)) =
-                    impl_.inner_impl().items.iter().find_map(|item| match item.kind {
+                    impl_.inner_impl().items.iter().find_map(|item| match *item.kind {
                         clean::TypedefItem(ref t, true) => Some(match *t {
                             clean::Typedef { item_type: Some(ref type_), .. } => (type_, &t.type_),
                             _ => (&t.type_, &t.type_),
@@ -4416,7 +4443,7 @@ fn get_id_for_impl_on_foreign_type(for_: &clean::Type, trait_: &clean::Type) ->
 }
 
 fn extract_for_impl_name(item: &clean::Item) -> Option<(String, String)> {
-    match item.kind {
+    match *item.kind {
         clean::ItemKind::ImplItem(ref i) => {
             if let Some(ref trait_) = i.trait_ {
                 Some((
@@ -4567,7 +4594,7 @@ fn sidebar_typedef(buf: &mut Buffer, it: &clean::Item) {
 fn get_struct_fields_name(fields: &[clean::Item]) -> String {
     let mut fields = fields
         .iter()
-        .filter(|f| if let clean::StructFieldItem(..) = f.kind { true } else { false })
+        .filter(|f| matches!(*f.kind, clean::StructFieldItem(..)))
         .filter_map(|f| match f.name {
             Some(ref name) => {
                 Some(format!("<a href=\"#structfield.{name}\">{name}</a>", name = name))
@@ -4721,6 +4748,7 @@ fn item_macro(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Mac
             Some("macro"),
             None,
             None,
+            it.source.span().edition(),
         ))
     });
     document(w, cx, it, None)
index 87934c8a0e50ea82df2165d2a5675bf15c6c3405..ac07aeb8bc8b71d5b9c0b0a12b90d9cc40669854 100644 (file)
@@ -8,6 +8,7 @@
 use crate::html::render::{SharedContext, BASIC_KEYWORDS};
 use rustc_hir::def_id::LOCAL_CRATE;
 use rustc_session::Session;
+use rustc_span::edition::Edition;
 use rustc_span::source_map::FileName;
 use std::ffi::OsStr;
 use std::fs;
@@ -132,7 +133,7 @@ fn emit_source(&mut self, filename: &FileName) -> Result<(), Error> {
             &self.scx.layout,
             &page,
             "",
-            |buf: &mut _| print_src(buf, contents),
+            |buf: &mut _| print_src(buf, contents, self.scx.edition),
             &self.scx.style_files,
         );
         self.scx.fs.write(&cur, v.as_bytes())?;
@@ -170,7 +171,7 @@ fn emit_source(&mut self, filename: &FileName) -> Result<(), Error> {
 
 /// Wrapper struct to render the source code of a file. This will do things like
 /// adding line numbers to the left-hand side.
-fn print_src(buf: &mut Buffer, s: String) {
+fn print_src(buf: &mut Buffer, s: String, edition: Edition) {
     let lines = s.lines().count();
     let mut cols = 0;
     let mut tmp = lines;
@@ -183,5 +184,5 @@ fn print_src(buf: &mut Buffer, s: String) {
         write!(buf, "<span id=\"{0}\">{0:1$}</span>\n", i, cols);
     }
     write!(buf, "</pre>");
-    write!(buf, "{}", highlight::render_with_highlighting(s, None, None, None));
+    write!(buf, "{}", highlight::render_with_highlighting(s, None, None, None, edition));
 }
index 42e4fa051527169212c2094e346cfcb8c4cfc482..62b08e519bf5ced361751f68f4cdf31040ae4b67 100644 (file)
@@ -122,7 +122,9 @@ h3.impl, h3.method, h3.type {
 h1, h2, h3, h4,
 .sidebar, a.source, .search-input, .content table td:first-child > a,
 .collapse-toggle, div.item-list .out-of-band,
-#source-sidebar, #sidebar-toggle {
+#source-sidebar, #sidebar-toggle,
+/* This selector is for the items listed in the "all items" page. */
+#main > ul.docblock > li > a {
        font-family: "Fira Sans", sans-serif;
 }
 
@@ -1079,20 +1081,29 @@ h3 > .collapse-toggle, h4 > .collapse-toggle {
        cursor: pointer;
 }
 
-.tooltip .tooltiptext {
-       width: 120px;
+.tooltip::after {
        display: none;
        text-align: center;
        padding: 5px 3px 3px 3px;
        border-radius: 6px;
        margin-left: 5px;
-       top: -5px;
-       left: 105%;
-       z-index: 10;
        font-size: 16px;
 }
 
-.tooltip .tooltiptext::after {
+.tooltip.ignore::after {
+       content: "This example is not tested";
+}
+.tooltip.compile_fail::after {
+       content: "This example deliberately fails to compile";
+}
+.tooltip.should_panic::after {
+       content: "This example panics";
+}
+.tooltip.edition::after {
+       content: "This code runs with edition " attr(data-edition);
+}
+
+.tooltip::before {
        content: " ";
        position: absolute;
        top: 50%;
@@ -1100,9 +1111,10 @@ h3 > .collapse-toggle, h4 > .collapse-toggle {
        margin-top: -5px;
        border-width: 5px;
        border-style: solid;
+       display: none;
 }
 
-.tooltip:hover .tooltiptext {
+.tooltip:hover::before, .tooltip:hover::after {
        display: inline;
 }
 
index 76bbe4f6201939103af39b4124a3195f881cb4f9..fd8153519afaf1757da297c079de51d0d53bdef0 100644 (file)
@@ -388,13 +388,13 @@ pre.ignore:hover, .information:hover + pre.ignore {
        color: #39AFD7;
 }
 
-.tooltip .tooltiptext {
+.tooltip::after {
        background-color: #314559;
        color: #c5c5c5;
        border: 1px solid #5c6773;
 }
 
-.tooltip .tooltiptext::after {
+.tooltip::before {
        border-color: transparent #314559 transparent transparent;
 }
 
index 86ce99284eba8e3c9ece3e536639106c3e5d220c..8c7794479a70a35fc3c08a287aaa355c960fe5f0 100644 (file)
@@ -337,13 +337,13 @@ pre.ignore:hover, .information:hover + pre.ignore {
        color: #0089ff;
 }
 
-.tooltip .tooltiptext {
+.tooltip::after {
        background-color: #000;
        color: #fff;
        border-color: #000;
 }
 
-.tooltip .tooltiptext::after {
+.tooltip::before {
        border-color: transparent black transparent transparent;
 }
 
index 997e1f00f859e3e1e85e350866b2a096018a1b11..814043b35ae61fe9082249df41b78da4def241b4 100644 (file)
@@ -329,12 +329,12 @@ pre.ignore:hover, .information:hover + pre.ignore {
        color: #0089ff;
 }
 
-.tooltip .tooltiptext {
+.tooltip::after {
        background-color: #000;
        color: #fff;
 }
 
-.tooltip .tooltiptext::after {
+.tooltip::before {
        border-color: transparent black transparent transparent;
 }
 
index 496cc3d8560a16d8d49571f36bfc960c027eddd9..e347f7f84116073f81af4a471a5e8f4ae1801c8b 100644 (file)
 impl JsonRenderer<'_> {
     pub(super) fn convert_item(&self, item: clean::Item) -> Option<Item> {
         let item_type = ItemType::from(&item);
-        let clean::Item {
-            source,
-            name,
-            attrs,
-            kind,
-            visibility,
-            def_id,
-            stability: _,
-            const_stability: _,
-            deprecation,
-        } = item;
-        match kind {
+        let deprecation = item.deprecation(self.tcx);
+        let clean::Item { source, name, attrs, kind, visibility, def_id } = item;
+        match *kind {
             clean::StrippedItem(_) => None,
-            _ => Some(Item {
+            kind => Some(Item {
                 id: def_id.into(),
                 crate_id: def_id.krate.as_u32(),
                 name: name.map(|sym| sym.to_string()),
                 source: self.convert_span(source),
-                visibility: visibility.into(),
+                visibility: self.convert_visibility(visibility),
                 docs: attrs.collapsed_doc_value().unwrap_or_default(),
                 links: attrs
                     .links
@@ -75,31 +66,29 @@ fn convert_span(&self, span: clean::Span) -> Option<Span> {
             _ => None,
         }
     }
-}
-
-impl From<rustc_attr::Deprecation> for Deprecation {
-    fn from(deprecation: rustc_attr::Deprecation) -> Self {
-        #[rustfmt::skip]
-        let rustc_attr::Deprecation { since, note, is_since_rustc_version: _, suggestion: _ } = deprecation;
-        Deprecation { since: since.map(|s| s.to_string()), note: note.map(|s| s.to_string()) }
-    }
-}
 
-impl From<clean::Visibility> for Visibility {
-    fn from(v: clean::Visibility) -> Self {
+    fn convert_visibility(&self, v: clean::Visibility) -> Visibility {
         use clean::Visibility::*;
         match v {
             Public => Visibility::Public,
             Inherited => Visibility::Default,
-            Restricted(did, _) if did.index == CRATE_DEF_INDEX => Visibility::Crate,
-            Restricted(did, path) => Visibility::Restricted {
+            Restricted(did) if did.index == CRATE_DEF_INDEX => Visibility::Crate,
+            Restricted(did) => Visibility::Restricted {
                 parent: did.into(),
-                path: path.to_string_no_crate_verbose(),
+                path: self.tcx.def_path(did).to_string_no_crate_verbose(),
             },
         }
     }
 }
 
+impl From<rustc_attr::Deprecation> for Deprecation {
+    fn from(deprecation: rustc_attr::Deprecation) -> Self {
+        #[rustfmt::skip]
+        let rustc_attr::Deprecation { since, note, is_since_rustc_version: _, suggestion: _ } = deprecation;
+        Deprecation { since: since.map(|s| s.to_string()), note: note.map(|s| s.to_string()) }
+    }
+}
+
 impl From<clean::GenericArgs> for GenericArgs {
     fn from(args: clean::GenericArgs) -> Self {
         use clean::GenericArgs::*;
index dc2bc14e7ceb9074a73b54b6ecf9c42bf72509e8..df7ab9b7361a01af8b5992e59c817c2a65bfad92 100644 (file)
@@ -178,9 +178,9 @@ fn mod_item_in(
         cache: &Cache,
     ) -> Result<(), Error> {
         use clean::types::ItemKind::*;
-        if let ModuleItem(m) = &item.kind {
+        if let ModuleItem(m) = &*item.kind {
             for item in &m.items {
-                match &item.kind {
+                match &*item.kind {
                     // These don't have names so they don't get added to the output by default
                     ImportItem(_) => self.item(item.clone(), cache).unwrap(),
                     ExternCrateItem(_, _) => self.item(item.clone(), cache).unwrap(),
index 72f1b817d5d87ee7adc1ea33664a24795c7b5f0d..7ed64c5813fcd8f00203a10d6ad7afa47d0470cf 100644 (file)
@@ -17,6 +17,7 @@
 #![feature(type_ascription)]
 #![feature(split_inclusive)]
 #![feature(str_split_once)]
+#![feature(iter_intersperse)]
 #![recursion_limit = "256"]
 
 #[macro_use]
@@ -263,13 +264,13 @@ fn opts() -> Vec<RustcOptGroup> {
                 "sort modules by where they appear in the program, rather than alphabetically",
             )
         }),
-        unstable("default-theme", |o| {
+        stable("default-theme", |o| {
             o.optopt(
                 "",
                 "default-theme",
                 "Set the default theme. THEME should be the theme name, generally lowercase. \
                  If an unknown default theme is specified, the builtin default is used. \
-                 The set of themes, and the rustdoc built-in default is not stable.",
+                 The set of themes, and the rustdoc built-in default, are not stable.",
                 "THEME",
             )
         }),
index 52f6a97089bdef225f9879b86e3b659b55f081e6..0a00323a3179ff2b589157c56ed1dad715d1b5de 100644 (file)
@@ -5,7 +5,7 @@
 use crate::passes::doc_test_lints::{should_have_doc_example, Tests};
 use crate::passes::Pass;
 use rustc_lint::builtin::MISSING_DOCS;
-use rustc_middle::lint::LintSource;
+use rustc_middle::lint::LintLevelSource;
 use rustc_session::lint;
 use rustc_span::symbol::sym;
 use rustc_span::FileName;
@@ -187,7 +187,7 @@ fn print_table_record(
 
 impl<'a, 'b> fold::DocFolder for CoverageCalculator<'a, 'b> {
     fn fold_item(&mut self, i: clean::Item) -> Option<clean::Item> {
-        match i.kind {
+        match *i.kind {
             _ if !i.def_id.is_local() => {
                 // non-local items are skipped because they can be out of the users control,
                 // especially in the case of trait impls, which rustdoc eagerly inlines
@@ -254,7 +254,7 @@ fn fold_item(&mut self, i: clean::Item) -> Option<clean::Item> {
                 // `missing_docs` is allow-by-default, so don't treat this as ignoring the item
                 // unless the user had an explicit `allow`
                 let should_have_docs =
-                    level != lint::Level::Allow || matches!(source, LintSource::Default);
+                    level != lint::Level::Allow || matches!(source, LintLevelSource::Default);
                 debug!("counting {:?} {:?} in {}", i.type_(), i.name, filename);
                 self.items.entry(filename).or_default().count_item(
                     has_docs,
index a8adfe08b2561168c42f00904cc7a5f5ba75b371..63cb02af3bcbb323f5d321b162138dd4377502b7 100644 (file)
 use rustc_hir::def::{
     DefKind,
     Namespace::{self, *},
-    PerNS, Res,
+    PerNS,
 };
 use rustc_hir::def_id::{CrateNum, DefId};
-use rustc_middle::ty;
+use rustc_middle::{bug, ty};
 use rustc_resolve::ParentScope;
 use rustc_session::lint::{
     builtin::{BROKEN_INTRA_DOC_LINKS, PRIVATE_INTRA_DOC_LINKS},
     Lint,
 };
 use rustc_span::hygiene::MacroKind;
-use rustc_span::symbol::sym;
 use rustc_span::symbol::Ident;
 use rustc_span::symbol::Symbol;
 use rustc_span::DUMMY_SP;
@@ -28,6 +27,7 @@
 
 use std::borrow::Cow;
 use std::cell::Cell;
+use std::convert::{TryFrom, TryInto};
 use std::mem;
 use std::ops::Range;
 
@@ -61,6 +61,71 @@ fn from(err: ResolutionFailure<'a>) -> Self {
     }
 }
 
+#[derive(Copy, Clone, Debug, Hash)]
+enum Res {
+    Def(DefKind, DefId),
+    Primitive(PrimitiveType),
+}
+
+type ResolveRes = rustc_hir::def::Res<rustc_ast::NodeId>;
+
+impl Res {
+    fn descr(self) -> &'static str {
+        match self {
+            Res::Def(kind, id) => ResolveRes::Def(kind, id).descr(),
+            Res::Primitive(_) => "builtin type",
+        }
+    }
+
+    fn article(self) -> &'static str {
+        match self {
+            Res::Def(kind, id) => ResolveRes::Def(kind, id).article(),
+            Res::Primitive(_) => "a",
+        }
+    }
+
+    fn name(self, tcx: ty::TyCtxt<'_>) -> String {
+        match self {
+            Res::Def(_, id) => tcx.item_name(id).to_string(),
+            Res::Primitive(prim) => prim.as_str().to_string(),
+        }
+    }
+
+    fn def_id(self) -> DefId {
+        self.opt_def_id().expect("called def_id() on a primitive")
+    }
+
+    fn opt_def_id(self) -> Option<DefId> {
+        match self {
+            Res::Def(_, id) => Some(id),
+            Res::Primitive(_) => None,
+        }
+    }
+
+    fn as_hir_res(self) -> Option<rustc_hir::def::Res> {
+        match self {
+            Res::Def(kind, id) => Some(rustc_hir::def::Res::Def(kind, id)),
+            // FIXME: maybe this should handle the subset of PrimitiveType that fits into hir::PrimTy?
+            Res::Primitive(_) => None,
+        }
+    }
+}
+
+impl TryFrom<ResolveRes> for Res {
+    type Error = ();
+
+    fn try_from(res: ResolveRes) -> Result<Self, ()> {
+        use rustc_hir::def::Res::*;
+        match res {
+            Def(kind, id) => Ok(Res::Def(kind, id)),
+            PrimTy(prim) => Ok(Res::Primitive(PrimitiveType::from_hir(prim))),
+            // e.g. `#[derive]`
+            NonMacroAttr(..) | Err => Result::Err(()),
+            other => bug!("unrecognized res {:?}", other),
+        }
+    }
+}
+
 #[derive(Debug)]
 /// A link failed to resolve.
 enum ResolutionFailure<'a> {
@@ -180,7 +245,7 @@ struct DiagnosticInfo<'a> {
     item: &'a Item,
     dox: &'a str,
     ori_link: &'a str,
-    link_range: Range<usize>,
+    link_range: Option<Range<usize>>,
 }
 
 #[derive(Clone, Debug, Hash)]
@@ -253,12 +318,9 @@ fn variant_field(
             .enter_resolver(|resolver| {
                 resolver.resolve_str_path_error(DUMMY_SP, &path, TypeNS, module_id)
             })
-            .map(|(_, res)| res)
-            .unwrap_or(Res::Err);
-        if let Res::Err = ty_res {
-            return Err(no_res().into());
-        }
-        let ty_res = ty_res.map_id(|_| panic!("unexpected node_id"));
+            .and_then(|(_, res)| res.try_into())
+            .map_err(|()| no_res())?;
+
         match ty_res {
             Res::Def(DefKind::Enum, did) => {
                 if cx
@@ -309,7 +371,7 @@ fn variant_field(
     /// lifetimes on `&'path` will work.
     fn resolve_primitive_associated_item(
         &self,
-        prim_ty: hir::PrimTy,
+        prim_ty: PrimitiveType,
         ns: Namespace,
         module_id: DefId,
         item_name: Symbol,
@@ -317,7 +379,7 @@ fn resolve_primitive_associated_item(
     ) -> Result<(Res, Option<String>), ErrorKind<'path>> {
         let cx = self.cx;
 
-        PrimitiveType::from_hir(prim_ty)
+        prim_ty
             .impls(cx.tcx)
             .into_iter()
             .find_map(|&impl_| {
@@ -336,21 +398,21 @@ fn resolve_primitive_associated_item(
                     })
                     .map(|out| {
                         (
-                            Res::PrimTy(prim_ty),
-                            Some(format!("{}#{}.{}", prim_ty.name(), out, item_str)),
+                            Res::Primitive(prim_ty),
+                            Some(format!("{}#{}.{}", prim_ty.as_str(), out, item_str)),
                         )
                     })
             })
             .ok_or_else(|| {
                 debug!(
                     "returning primitive error for {}::{} in {} namespace",
-                    prim_ty.name(),
+                    prim_ty.as_str(),
                     item_name,
                     ns.descr()
                 );
                 ResolutionFailure::NotResolved {
                     module_id,
-                    partial_res: Some(Res::PrimTy(prim_ty)),
+                    partial_res: Some(Res::Primitive(prim_ty)),
                     unresolved: item_str.into(),
                 }
                 .into()
@@ -377,19 +439,18 @@ fn resolve_macro(
                 false,
             ) {
                 if let SyntaxExtensionKind::LegacyBang { .. } = ext.kind {
-                    return Ok(res.map_id(|_| panic!("unexpected id")));
+                    return Ok(res.try_into().unwrap());
                 }
             }
-            if let Some(res) = resolver.all_macros().get(&Symbol::intern(path_str)) {
-                return Ok(res.map_id(|_| panic!("unexpected id")));
+            if let Some(&res) = resolver.all_macros().get(&Symbol::intern(path_str)) {
+                return Ok(res.try_into().unwrap());
             }
             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"));
+                if let Ok(res) = res.try_into() {
                     return Ok(res);
                 }
             }
@@ -408,14 +469,16 @@ fn resolve_macro(
     /// Associated items will never be resolved by this function.
     fn resolve_path(&self, path_str: &str, ns: Namespace, module_id: DefId) -> Option<Res> {
         let result = self.cx.enter_resolver(|resolver| {
-            resolver.resolve_str_path_error(DUMMY_SP, &path_str, ns, module_id)
+            resolver
+                .resolve_str_path_error(DUMMY_SP, &path_str, ns, module_id)
+                .and_then(|(_, res)| res.try_into())
         });
         debug!("{} resolved to {:?} in namespace {:?}", path_str, result, ns);
-        match result.map(|(_, res)| res) {
-            // resolver doesn't know about true and false so we'll have to resolve them
+        match result {
+            // resolver doesn't know about true, false, and types that aren't paths (e.g. `()`)
             // manually as bool
-            Ok(Res::Err) | Err(()) => is_bool_value(path_str, ns).map(|(_, res)| res),
-            Ok(res) => Some(res.map_id(|_| panic!("unexpected node_id"))),
+            Err(()) => resolve_primitive(path_str, ns),
+            Ok(res) => Some(res),
         }
     }
 
@@ -444,13 +507,13 @@ fn resolve<'path>(
                     return handle_variant(cx, res, extra_fragment);
                 }
                 // Not a trait item; just return what we found.
-                Res::PrimTy(ty) => {
+                Res::Primitive(ty) => {
                     if extra_fragment.is_some() {
                         return Err(ErrorKind::AnchorFailure(
                             AnchorFailure::RustdocAnchorConflict(res),
                         ));
                     }
-                    return Ok((res, Some(ty.name_str().to_owned())));
+                    return Ok((res, Some(ty.as_str().to_owned())));
                 }
                 Res::Def(DefKind::Mod, _) => {
                     return Ok((res, extra_fragment.clone()));
@@ -483,7 +546,6 @@ fn resolve<'path>(
 
         // FIXME: are these both necessary?
         let ty_res = if let Some(ty_res) = resolve_primitive(&path_root, TypeNS)
-            .map(|(_, res)| res)
             .or_else(|| self.resolve_path(&path_root, TypeNS, module_id))
         {
             ty_res
@@ -502,7 +564,7 @@ fn resolve<'path>(
         };
 
         let res = match ty_res {
-            Res::PrimTy(prim) => Some(
+            Res::Primitive(prim) => Some(
                 self.resolve_primitive_associated_item(prim, ns, module_id, item_name, item_str),
             ),
             Res::Def(
@@ -920,7 +982,7 @@ fn resolve_link(
         parent_node: Option<DefId>,
         krate: CrateNum,
         ori_link: String,
-        link_range: Range<usize>,
+        link_range: Option<Range<usize>>,
     ) -> Option<ItemLink> {
         trace!("considering link '{}'", ori_link);
 
@@ -958,7 +1020,7 @@ fn resolve_link(
             (link.trim(), None)
         };
 
-        if path_str.contains(|ch: char| !(ch.is_alphanumeric() || ":_<>, !".contains(ch))) {
+        if path_str.contains(|ch: char| !(ch.is_alphanumeric() || ":_<>, !*&;".contains(ch))) {
             return None;
         }
 
@@ -1046,9 +1108,8 @@ fn resolve_link(
         // Sanity check to make sure we don't have any angle brackets after stripping generics.
         assert!(!path_str.contains(['<', '>'].as_slice()));
 
-        // The link is not an intra-doc link if it still contains commas or spaces after
-        // stripping generics.
-        if path_str.contains([',', ' '].as_slice()) {
+        // The link is not an intra-doc link if it still contains spaces after stripping generics.
+        if path_str.contains(' ') {
             return None;
         }
 
@@ -1068,9 +1129,9 @@ fn resolve_link(
         if matches!(
             disambiguator,
             None | Some(Disambiguator::Namespace(Namespace::TypeNS) | Disambiguator::Primitive)
-        ) && !matches!(res, Res::PrimTy(_))
+        ) && !matches!(res, Res::Primitive(_))
         {
-            if let Some((path, prim)) = resolve_primitive(path_str, TypeNS) {
+            if let Some(prim) = resolve_primitive(path_str, TypeNS) {
                 // `prim@char`
                 if matches!(disambiguator, Some(Disambiguator::Primitive)) {
                     if fragment.is_some() {
@@ -1085,7 +1146,7 @@ fn resolve_link(
                         return None;
                     }
                     res = prim;
-                    fragment = Some(path.as_str().to_string());
+                    fragment = Some(prim.name(self.cx.tcx));
                 } else {
                     // `[char]` when a `char` module is in scope
                     let candidates = vec![res, prim];
@@ -1111,8 +1172,8 @@ fn resolve_link(
             };
             report_diagnostic(cx, BROKEN_INTRA_DOC_LINKS, &msg, &item, dox, &link_range, callback);
         };
-        if let Res::PrimTy(..) = res {
-            match disambiguator {
+        match res {
+            Res::Primitive(_) => match disambiguator {
                 Some(Disambiguator::Primitive | Disambiguator::Namespace(_)) | None => {
                     Some(ItemLink { link: ori_link, link_text, did: None, fragment })
                 }
@@ -1120,12 +1181,11 @@ fn resolve_link(
                     report_mismatch(other, Disambiguator::Primitive);
                     None
                 }
-            }
-        } else {
-            debug!("intra-doc link to {} resolved to {:?}", path_str, res);
+            },
+            Res::Def(kind, id) => {
+                debug!("intra-doc link to {} resolved to {:?}", path_str, res);
 
-            // Disallow e.g. linking to enums with `struct@`
-            if let Res::Def(kind, _) = res {
+                // Disallow e.g. linking to enums with `struct@`
                 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)))
@@ -1144,27 +1204,26 @@ fn resolve_link(
                         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;
+                // item can be non-local e.g. when using #[doc(primitive = "pointer")]
+                if let Some((src_id, dst_id)) = 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);
+                    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);
+                    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);
+                    }
                 }
+                let id = clean::register_res(cx, rustc_hir::def::Res::Def(kind, id));
+                Some(ItemLink { link: ori_link, link_text, did: Some(id), fragment })
             }
-            let id = clean::register_res(cx, res);
-            Some(ItemLink { link: ori_link, link_text, did: Some(id), fragment })
         }
     }
 
@@ -1175,7 +1234,7 @@ fn resolve_with_disambiguator_cached(
     ) -> Option<(Res, Option<String>)> {
         // Try to look up both the result and the corresponding side channel value
         if let Some(ref cached) = self.visited_links.get(&key) {
-            self.kind_side_channel.set(cached.side_channel.clone());
+            self.kind_side_channel.set(cached.side_channel);
             return Some(cached.res.clone());
         }
 
@@ -1296,16 +1355,18 @@ fn resolve_with_disambiguator(
                     .and_then(|(res, fragment)| {
                         // Constructors are picked up in the type namespace.
                         match res {
-                            Res::Def(DefKind::Ctor(..), _) | Res::SelfCtor(..) => {
+                            Res::Def(DefKind::Ctor(..), _) => {
                                 Err(ResolutionFailure::WrongNamespace(res, TypeNS))
                             }
-                            _ => match (fragment, extra_fragment.clone()) {
-                                (Some(fragment), Some(_)) => {
-                                    // Shouldn't happen but who knows?
-                                    Ok((res, Some(fragment)))
+                            _ => {
+                                match (fragment, extra_fragment.clone()) {
+                                    (Some(fragment), Some(_)) => {
+                                        // Shouldn't happen but who knows?
+                                        Ok((res, Some(fragment)))
+                                    }
+                                    (fragment, None) | (None, fragment) => Ok((res, fragment)),
                                 }
-                                (fragment, None) | (None, fragment) => Ok((res, fragment)),
-                            },
+                            }
                         }
                     }),
                 };
@@ -1414,8 +1475,11 @@ fn from_str(link: &str) -> Result<(Self, &str), ()> {
                 ("!", DefKind::Macro(MacroKind::Bang)),
             ];
             for &(suffix, kind) in &suffixes {
-                if link.ends_with(suffix) {
-                    return Ok((Kind(kind), link.trim_end_matches(suffix)));
+                if let Some(link) = link.strip_suffix(suffix) {
+                    // Avoid turning `!` or `()` into an empty string
+                    if !link.is_empty() {
+                        return Ok((Kind(kind), link));
+                    }
                 }
             }
             Err(())
@@ -1445,12 +1509,10 @@ fn from_str(link: &str) -> Result<(Self, &str), ()> {
         }
     }
 
-    /// WARNING: panics on `Res::Err`
     fn from_res(res: Res) -> Self {
         match res {
             Res::Def(kind, _) => Disambiguator::Kind(kind),
-            Res::PrimTy(_) => Disambiguator::Primitive,
-            _ => Disambiguator::Namespace(res.ns().expect("can't call `from_res` on Res::err")),
+            Res::Primitive(_) => Disambiguator::Primitive,
         }
     }
 
@@ -1566,7 +1628,7 @@ fn report_diagnostic(
     msg: &str,
     item: &Item,
     dox: &str,
-    link_range: &Range<usize>,
+    link_range: &Option<Range<usize>>,
     decorate: impl FnOnce(&mut DiagnosticBuilder<'_>, Option<rustc_span::Span>),
 ) {
     let hir_id = match cx.as_local_hir_id(item.def_id) {
@@ -1584,26 +1646,31 @@ fn report_diagnostic(
     cx.tcx.struct_span_lint_hir(lint, hir_id, sp, |lint| {
         let mut diag = lint.build(msg);
 
-        let span = super::source_span_for_markdown_range(cx, dox, link_range, attrs);
-        if let Some(sp) = span {
-            diag.set_span(sp);
-        } else {
-            // blah blah blah\nblah\nblah [blah] blah blah\nblah blah
-            //                       ^     ~~~~
-            //                       |     link_range
-            //                       last_new_line_offset
-            let last_new_line_offset = dox[..link_range.start].rfind('\n').map_or(0, |n| n + 1);
-            let line = dox[last_new_line_offset..].lines().next().unwrap_or("");
-
-            // Print the line containing the `link_range` and manually mark it with '^'s.
-            diag.note(&format!(
-                "the link appears in this line:\n\n{line}\n\
-                    {indicator: <before$}{indicator:^<found$}",
-                line = line,
-                indicator = "",
-                before = link_range.start - last_new_line_offset,
-                found = link_range.len(),
-            ));
+        let span = link_range
+            .as_ref()
+            .and_then(|range| super::source_span_for_markdown_range(cx, dox, range, attrs));
+
+        if let Some(link_range) = link_range {
+            if let Some(sp) = span {
+                diag.set_span(sp);
+            } else {
+                // blah blah blah\nblah\nblah [blah] blah blah\nblah blah
+                //                       ^     ~~~~
+                //                       |     link_range
+                //                       last_new_line_offset
+                let last_new_line_offset = dox[..link_range.start].rfind('\n').map_or(0, |n| n + 1);
+                let line = dox[last_new_line_offset..].lines().next().unwrap_or("");
+
+                // Print the line containing the `link_range` and manually mark it with '^'s.
+                diag.note(&format!(
+                    "the link appears in this line:\n\n{line}\n\
+                     {indicator: <before$}{indicator:^<found$}",
+                    line = line,
+                    indicator = "",
+                    before = link_range.start - last_new_line_offset,
+                    found = link_range.len(),
+                ));
+            }
         }
 
         decorate(&mut diag, span);
@@ -1623,9 +1690,10 @@ fn resolution_failure(
     path_str: &str,
     disambiguator: Option<Disambiguator>,
     dox: &str,
-    link_range: Range<usize>,
+    link_range: Option<Range<usize>>,
     kinds: SmallVec<[ResolutionFailure<'_>; 3]>,
 ) {
+    let tcx = collector.cx.tcx;
     report_diagnostic(
         collector.cx,
         BROKEN_INTRA_DOC_LINKS,
@@ -1634,16 +1702,9 @@ fn resolution_failure(
         dox,
         &link_range,
         |diag, sp| {
-            let item = |res: Res| {
-                format!(
-                    "the {} `{}`",
-                    res.descr(),
-                    collector.cx.tcx.item_name(res.def_id()).to_string()
-                )
-            };
+            let item = |res: Res| format!("the {} `{}`", res.descr(), res.name(tcx),);
             let assoc_item_not_allowed = |res: Res| {
-                let def_id = res.def_id();
-                let name = collector.cx.tcx.item_name(def_id);
+                let name = res.name(tcx);
                 format!(
                     "`{}` is {} {}, not a module or type, and cannot have associated items",
                     name,
@@ -1709,7 +1770,7 @@ fn split(path: &str) -> Option<(&str, &str)> {
                     if let Some(module) = last_found_module {
                         let note = if partial_res.is_some() {
                             // Part of the link resolved; e.g. `std::io::nonexistent`
-                            let module_name = collector.cx.tcx.item_name(module);
+                            let module_name = tcx.item_name(module);
                             format!("no item named `{}` in module `{}`", unresolved, module_name)
                         } else {
                             // None of the link resolved; e.g. `Notimported`
@@ -1733,14 +1794,10 @@ fn split(path: &str) -> Option<(&str, &str)> {
 
                     // Otherwise, it must be an associated item or variant
                     let res = partial_res.expect("None case was handled by `last_found_module`");
-                    let diagnostic_name;
-                    let (kind, name) = match res {
-                        Res::Def(kind, def_id) => {
-                            diagnostic_name = collector.cx.tcx.item_name(def_id).as_str();
-                            (Some(kind), &*diagnostic_name)
-                        }
-                        Res::PrimTy(ty) => (None, ty.name_str()),
-                        _ => unreachable!("only ADTs and primitives are in scope at module level"),
+                    let name = res.name(tcx);
+                    let kind = match res {
+                        Res::Def(kind, _) => Some(kind),
+                        Res::Primitive(_) => None,
                     };
                     let path_description = if let Some(kind) = kind {
                         match kind {
@@ -1857,7 +1914,7 @@ fn anchor_failure(
     item: &Item,
     path_str: &str,
     dox: &str,
-    link_range: Range<usize>,
+    link_range: Option<Range<usize>>,
     failure: AnchorFailure,
 ) {
     let msg = match failure {
@@ -1882,7 +1939,7 @@ fn ambiguity_error(
     item: &Item,
     path_str: &str,
     dox: &str,
-    link_range: Range<usize>,
+    link_range: Option<Range<usize>>,
     candidates: Vec<Res>,
 ) {
     let mut msg = format!("`{}` is ", path_str);
@@ -1931,12 +1988,13 @@ fn suggest_disambiguator(
     path_str: &str,
     dox: &str,
     sp: Option<rustc_span::Span>,
-    link_range: &Range<usize>,
+    link_range: &Option<Range<usize>>,
 ) {
     let suggestion = disambiguator.suggestion();
     let help = format!("to link to the {}, {}", disambiguator.descr(), suggestion.descr());
 
     if let Some(sp) = sp {
+        let link_range = link_range.as_ref().expect("must have a link range if we have a span");
         let msg = if dox.bytes().nth(link_range.start) == Some(b'`') {
             format!("`{}`", suggestion.as_help(path_str))
         } else {
@@ -1955,7 +2013,7 @@ fn privacy_error(
     item: &Item,
     path_str: &str,
     dox: &str,
-    link_range: Range<usize>,
+    link_range: Option<Range<usize>>,
 ) {
     let sym;
     let item_name = match item.name {
@@ -1997,53 +2055,49 @@ fn handle_variant(
         .parent(res.def_id())
         .map(|parent| {
             let parent_def = Res::Def(DefKind::Enum, parent);
-            let variant = cx.tcx.expect_variant_res(res);
+            let variant = cx.tcx.expect_variant_res(res.as_hir_res().unwrap());
             (parent_def, Some(format!("variant.{}", variant.ident.name)))
         })
         .ok_or_else(|| ResolutionFailure::NoParentItem.into())
 }
 
-// FIXME: At this point, this is basically a copy of the PrimitiveTypeTable
-const PRIMITIVES: &[(Symbol, Res)] = &[
-    (sym::u8, Res::PrimTy(hir::PrimTy::Uint(rustc_ast::UintTy::U8))),
-    (sym::u16, Res::PrimTy(hir::PrimTy::Uint(rustc_ast::UintTy::U16))),
-    (sym::u32, Res::PrimTy(hir::PrimTy::Uint(rustc_ast::UintTy::U32))),
-    (sym::u64, Res::PrimTy(hir::PrimTy::Uint(rustc_ast::UintTy::U64))),
-    (sym::u128, Res::PrimTy(hir::PrimTy::Uint(rustc_ast::UintTy::U128))),
-    (sym::usize, Res::PrimTy(hir::PrimTy::Uint(rustc_ast::UintTy::Usize))),
-    (sym::i8, Res::PrimTy(hir::PrimTy::Int(rustc_ast::IntTy::I8))),
-    (sym::i16, Res::PrimTy(hir::PrimTy::Int(rustc_ast::IntTy::I16))),
-    (sym::i32, Res::PrimTy(hir::PrimTy::Int(rustc_ast::IntTy::I32))),
-    (sym::i64, Res::PrimTy(hir::PrimTy::Int(rustc_ast::IntTy::I64))),
-    (sym::i128, Res::PrimTy(hir::PrimTy::Int(rustc_ast::IntTy::I128))),
-    (sym::isize, Res::PrimTy(hir::PrimTy::Int(rustc_ast::IntTy::Isize))),
-    (sym::f32, Res::PrimTy(hir::PrimTy::Float(rustc_ast::FloatTy::F32))),
-    (sym::f64, Res::PrimTy(hir::PrimTy::Float(rustc_ast::FloatTy::F64))),
-    (sym::str, Res::PrimTy(hir::PrimTy::Str)),
-    (sym::bool, Res::PrimTy(hir::PrimTy::Bool)),
-    (sym::char, Res::PrimTy(hir::PrimTy::Char)),
-];
-
 /// Resolve a primitive type or value.
-fn resolve_primitive(path_str: &str, ns: Namespace) -> Option<(Symbol, Res)> {
-    is_bool_value(path_str, ns).or_else(|| {
-        if ns == TypeNS {
-            // FIXME: this should be replaced by a lookup in PrimitiveTypeTable
-            let maybe_primitive = Symbol::intern(path_str);
-            PRIMITIVES.iter().find(|x| x.0 == maybe_primitive).copied()
-        } else {
-            None
-        }
-    })
-}
-
-/// Resolve a primitive value.
-fn is_bool_value(path_str: &str, ns: Namespace) -> Option<(Symbol, Res)> {
-    if ns == TypeNS && (path_str == "true" || path_str == "false") {
-        Some((sym::bool, Res::PrimTy(hir::PrimTy::Bool)))
-    } else {
-        None
+fn resolve_primitive(path_str: &str, ns: Namespace) -> Option<Res> {
+    if ns != TypeNS {
+        return None;
     }
+    use PrimitiveType::*;
+    let prim = match path_str {
+        "isize" => Isize,
+        "i8" => I8,
+        "i16" => I16,
+        "i32" => I32,
+        "i64" => I64,
+        "i128" => I128,
+        "usize" => Usize,
+        "u8" => U8,
+        "u16" => U16,
+        "u32" => U32,
+        "u64" => U64,
+        "u128" => U128,
+        "f32" => F32,
+        "f64" => F64,
+        "char" => Char,
+        "bool" | "true" | "false" => Bool,
+        "str" => Str,
+        // See #80181 for why these don't have symbols associated.
+        "slice" => Slice,
+        "array" => Array,
+        "tuple" => Tuple,
+        "unit" => Unit,
+        "pointer" | "*" | "*const" | "*mut" => RawPointer,
+        "reference" | "&" | "&mut" => Reference,
+        "fn" => Fn,
+        "never" | "!" => Never,
+        _ => return None,
+    };
+    debug!("resolved primitives {:?}", prim);
+    Some(Res::Primitive(prim))
 }
 
 fn strip_generics_from_path(path_str: &str) -> Result<String, ResolutionFailure<'static>> {
index 1e9bc67de04b833bccf478cae1419f8726016ea7..9b0ae09cb3fd57c9f660faf22a5f6514ebc2b7f2 100644 (file)
 
 crate fn collect_trait_impls(krate: Crate, cx: &DocContext<'_>) -> Crate {
     let mut synth = SyntheticImplCollector::new(cx);
-    let mut krate = synth.fold_crate(krate);
+    let mut krate = cx.sess().time("collect_synthetic_impls", || synth.fold_crate(krate));
 
     let prims: FxHashSet<PrimitiveType> = krate.primitives.iter().map(|p| p.1).collect();
 
     let crate_items = {
         let mut coll = ItemCollector::new();
-        krate = coll.fold_crate(krate);
+        krate = cx.sess().time("collect_items_for_trait_impls", || coll.fold_crate(krate));
         coll.items
     };
 
     // Also try to inline primitive impls from other crates.
     for &def_id in PrimitiveType::all_impls(cx.tcx).values().flatten() {
         if !def_id.is_local() {
-            inline::build_impl(cx, None, def_id, None, &mut new_items);
+            cx.sess().time("build_primitive_trait_impl", || {
+                inline::build_impl(cx, None, def_id, None, &mut new_items);
 
-            // FIXME(eddyb) is this `doc(hidden)` check needed?
-            if !cx.tcx.get_attrs(def_id).lists(sym::doc).has_word(sym::hidden) {
-                let self_ty = cx.tcx.type_of(def_id);
-                let impls = get_auto_trait_and_blanket_impls(cx, self_ty, def_id);
-                let mut renderinfo = cx.renderinfo.borrow_mut();
+                // FIXME(eddyb) is this `doc(hidden)` check needed?
+                if !cx.tcx.get_attrs(def_id).lists(sym::doc).has_word(sym::hidden) {
+                    let self_ty = cx.tcx.type_of(def_id);
+                    let impls = get_auto_trait_and_blanket_impls(cx, self_ty, def_id);
+                    let mut renderinfo = cx.renderinfo.borrow_mut();
 
-                new_items.extend(impls.filter(|i| renderinfo.inlined.insert(i.def_id)));
-            }
+                    new_items.extend(impls.filter(|i| renderinfo.inlined.insert(i.def_id)));
+                }
+            })
         }
     }
 
 
     // scan through included items ahead of time to splice in Deref targets to the "valid" sets
     for it in &new_items {
-        if let ImplItem(Impl { ref for_, ref trait_, ref items, .. }) = it.kind {
+        if let ImplItem(Impl { ref for_, ref trait_, ref items, .. }) = *it.kind {
             if cleaner.keep_item(for_) && trait_.def_id() == cx.tcx.lang_items().deref_trait() {
                 let target = items
                     .iter()
-                    .find_map(|item| match item.kind {
+                    .find_map(|item| match *item.kind {
                         TypedefItem(ref t, true) => Some(&t.type_),
                         _ => None,
                     })
@@ -76,7 +78,7 @@
     }
 
     new_items.retain(|it| {
-        if let ImplItem(Impl { ref for_, ref trait_, ref blanket_impl, .. }) = it.kind {
+        if let ImplItem(Impl { ref for_, ref trait_, ref blanket_impl, .. }) = *it.kind {
             cleaner.keep_item(for_)
                 || trait_.as_ref().map_or(false, |t| cleaner.keep_item(t))
                 || blanket_impl.is_some()
     }
 
     if let Some(ref mut it) = krate.module {
-        if let ModuleItem(Module { ref mut items, .. }) = it.kind {
+        if let ModuleItem(Module { ref mut items, .. }) = *it.kind {
             items.extend(synth.impls);
             items.extend(new_items);
         } else {
@@ -151,11 +153,13 @@ fn fold_item(&mut self, i: Item) -> Option<Item> {
         if i.is_struct() || i.is_enum() || i.is_union() {
             // FIXME(eddyb) is this `doc(hidden)` check needed?
             if !self.cx.tcx.get_attrs(i.def_id).lists(sym::doc).has_word(sym::hidden) {
-                self.impls.extend(get_auto_trait_and_blanket_impls(
-                    self.cx,
-                    self.cx.tcx.type_of(i.def_id),
-                    i.def_id,
-                ));
+                self.cx.sess().time("get_auto_trait_and_blanket_synthetic_impls", || {
+                    self.impls.extend(get_auto_trait_and_blanket_impls(
+                        self.cx,
+                        self.cx.tcx.type_of(i.def_id),
+                        i.def_id,
+                    ));
+                });
             }
         }
 
index 1c1141e7c81226b0a042b302decb005162e6ac99..a513c2abc87477bc331de8a2ffa49cc46a7d2cd2 100644 (file)
@@ -9,7 +9,7 @@
 use crate::core::DocContext;
 use crate::fold::DocFolder;
 use crate::html::markdown::{find_testable_code, ErrorCodes, Ignore, LangString};
-use rustc_middle::lint::LintSource;
+use rustc_middle::lint::LintLevelSource;
 use rustc_session::lint;
 
 crate const CHECK_PRIVATE_ITEMS_DOC_TESTS: Pass = Pass {
@@ -59,7 +59,7 @@ fn add_test(&mut self, _: String, config: LangString, _: usize) {
 
 crate fn should_have_doc_example(cx: &DocContext<'_>, item: &clean::Item) -> bool {
     if matches!(
-        item.kind,
+        *item.kind,
         clean::StructFieldItem(_)
             | clean::VariantItem(_)
             | clean::AssocConstItem(_, _)
@@ -77,7 +77,7 @@ fn add_test(&mut self, _: String, config: LangString, _: usize) {
     let hir_id = cx.tcx.hir().local_def_id_to_hir_id(item.def_id.expect_local());
     let (level, source) =
         cx.tcx.lint_level_at_node(lint::builtin::MISSING_DOC_CODE_EXAMPLES, hir_id);
-    level != lint::Level::Allow || matches!(source, LintSource::Default)
+    level != lint::Level::Allow || matches!(source, LintLevelSource::Default)
 }
 
 crate fn look_for_tests<'tcx>(cx: &DocContext<'tcx>, dox: &str, item: &Item) {
index 6b59eb8cf288a8246ad06462d92e1c9e93fc41d2..01e3d0acaa8555689e7caafc59b5a290659ecc94 100644 (file)
@@ -41,7 +41,7 @@ fn fold_item(&mut self, i: Item) -> Option<Item> {
         if i.attrs.lists(sym::doc).has_word(sym::hidden) {
             debug!("strip_hidden: stripping {:?} {:?}", i.type_(), i.name);
             // use a dedicated hidden item for given item type if any
-            match i.kind {
+            match *i.kind {
                 clean::StructFieldItem(..) | clean::ModuleItem(..) => {
                     // We need to recurse into stripped modules to
                     // strip things like impl methods but when doing so
@@ -49,7 +49,7 @@ fn fold_item(&mut self, i: Item) -> Option<Item> {
                     let old = mem::replace(&mut self.update_retained, false);
                     let ret = StripItem(self.fold_item_recur(i)).strip();
                     self.update_retained = old;
-                    return ret;
+                    return Some(ret);
                 }
                 _ => return None,
             }
index 444fd593ec9c9856bef17f84fca3cfe3fdbb4f7d..a1924422f0e5ee27e70d6f895d3afa8db090fa92 100644 (file)
@@ -13,7 +13,7 @@
 
 impl<'a> DocFolder for Stripper<'a> {
     fn fold_item(&mut self, i: Item) -> Option<Item> {
-        match i.kind {
+        match *i.kind {
             clean::StrippedItem(..) => {
                 // We need to recurse into stripped modules to strip things
                 // like impl methods but when doing so we must not add any
@@ -51,7 +51,7 @@ fn fold_item(&mut self, i: Item) -> Option<Item> {
 
             clean::StructFieldItem(..) => {
                 if !i.visibility.is_public() {
-                    return StripItem(i).strip();
+                    return Some(StripItem(i).strip());
                 }
             }
 
@@ -61,7 +61,7 @@ fn fold_item(&mut self, i: Item) -> Option<Item> {
                     let old = mem::replace(&mut self.update_retained, false);
                     let ret = StripItem(self.fold_item_recur(i)).strip();
                     self.update_retained = old;
-                    return ret;
+                    return Some(ret);
                 }
             }
 
@@ -86,7 +86,7 @@ fn fold_item(&mut self, i: Item) -> Option<Item> {
             clean::KeywordItem(..) => {}
         }
 
-        let fastreturn = match i.kind {
+        let fastreturn = match *i.kind {
             // nothing left to do for traits (don't want to filter their
             // methods out, visibility controlled by the trait)
             clean::TraitItem(..) => true,
@@ -121,7 +121,7 @@ fn fold_item(&mut self, i: Item) -> Option<Item> {
 
 impl<'a> DocFolder for ImplStripper<'a> {
     fn fold_item(&mut self, i: Item) -> Option<Item> {
-        if let clean::ImplItem(ref imp) = i.kind {
+        if let clean::ImplItem(ref imp) = *i.kind {
             // emptied none trait impls can be stripped
             if imp.trait_.is_none() && imp.items.is_empty() {
                 return None;
@@ -160,7 +160,7 @@ fn fold_item(&mut self, i: Item) -> Option<Item> {
 
 impl DocFolder for ImportStripper {
     fn fold_item(&mut self, i: Item) -> Option<Item> {
-        match i.kind {
+        match *i.kind {
             clean::ExternCrateItem(..) | clean::ImportItem(..) if !i.visibility.is_public() => None,
             _ => Some(self.fold_item_recur(i)),
         }
index f9cb1d586b10266b53601e6842c46d2de4d3ba1c..3c0aeaad43e5da5322b73755d323c5ae1e5d9e48 100644 (file)
@@ -1,7 +1,6 @@
 //! The Rust AST Visitor. Extracts useful information and massages it into a form
 //! usable for `clean`.
 
-use rustc_ast as ast;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
@@ -64,7 +63,6 @@ fn store_path(&mut self, did: DefId) {
     crate fn visit(mut self, krate: &'tcx hir::Crate<'_>) -> Module<'tcx> {
         let mut module = self.visit_mod_contents(
             krate.item.span,
-            krate.item.attrs,
             &Spanned { span: rustc_span::DUMMY_SP, node: hir::VisibilityKind::Public },
             hir::CRATE_HIR_ID,
             &krate.item.module,
@@ -82,13 +80,12 @@ fn store_path(&mut self, did: DefId) {
     fn visit_mod_contents(
         &mut self,
         span: Span,
-        attrs: &'tcx [ast::Attribute],
         vis: &'tcx hir::Visibility<'_>,
         id: hir::HirId,
         m: &'tcx hir::Mod<'tcx>,
         name: Option<Symbol>,
     ) -> Module<'tcx> {
-        let mut om = Module::new(name, attrs);
+        let mut om = Module::new(name);
         om.where_outer = span;
         om.where_inner = m.inner;
         om.id = id;
@@ -292,7 +289,6 @@ fn visit_item(
             hir::ItemKind::Mod(ref m) => {
                 om.mods.push(self.visit_mod_contents(
                     item.span,
-                    &item.attrs,
                     &item.vis,
                     item.hir_id,
                     m,
index 6e05b66c3fe4acdc1babb334a2e1bb350e11038b..e853b9b4e4191a9984c9bc5f9b7f83f4f94422ba 100644 (file)
@@ -12,7 +12,7 @@
 # stable release's version number. `date` is the date where the release we're
 # bootstrapping off was released.
 
-date: 2020-11-18
+date: 2020-12-30
 rustc: beta
 
 # We use a nightly rustfmt to format the source because it solves some
diff --git a/src/test/codegen/slice-ref-equality.rs b/src/test/codegen/slice-ref-equality.rs
new file mode 100644 (file)
index 0000000..acc7879
--- /dev/null
@@ -0,0 +1,16 @@
+// compile-flags: -C opt-level=3
+
+#![crate_type = "lib"]
+
+// #71602: check that slice equality just generates a single bcmp
+
+// CHECK-LABEL: @is_zero_slice
+#[no_mangle]
+pub fn is_zero_slice(data: &[u8; 4]) -> bool {
+    // CHECK: start:
+    // CHECK-NEXT: %{{.+}} = getelementptr {{.+}}
+    // CHECK-NEXT: %[[BCMP:.+]] = tail call i32 @{{bcmp|memcmp}}({{.+}})
+    // CHECK-NEXT: %[[EQ:.+]] = icmp eq i32 %[[BCMP]], 0
+    // CHECK-NEXT: ret i1 %[[EQ]]
+    *data == [0; 4]
+}
diff --git a/src/test/compile-fail/asm-src-loc-codegen-units.rs b/src/test/compile-fail/asm-src-loc-codegen-units.rs
deleted file mode 100644 (file)
index 5b8690c..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-// compile-flags: -C codegen-units=2
-// ignore-emscripten
-
-#![feature(llvm_asm)]
-
-fn main() {
-    unsafe {
-        llvm_asm!("nowayisthisavalidinstruction"); //~ ERROR instruction
-    }
-}
diff --git a/src/test/compile-fail/asm-src-loc.rs b/src/test/compile-fail/asm-src-loc.rs
deleted file mode 100644 (file)
index 7c87f37..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-// ignore-emscripten
-
-#![feature(llvm_asm)]
-
-fn main() {
-    unsafe {
-        llvm_asm!("nowayisthisavalidinstruction"); //~ ERROR instruction
-    }
-}
diff --git a/src/test/compile-fail/auxiliary/crateresolve1-1.rs b/src/test/compile-fail/auxiliary/crateresolve1-1.rs
deleted file mode 100644 (file)
index a00a19e..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-// compile-flags:-C extra-filename=-1
-#![crate_name = "crateresolve1"]
-#![crate_type = "lib"]
-
-pub fn f() -> isize { 10 }
diff --git a/src/test/compile-fail/auxiliary/crateresolve1-2.rs b/src/test/compile-fail/auxiliary/crateresolve1-2.rs
deleted file mode 100644 (file)
index 71cc0a1..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-// compile-flags:-C extra-filename=-2
-#![crate_name = "crateresolve1"]
-#![crate_type = "lib"]
-
-pub fn f() -> isize { 20 }
diff --git a/src/test/compile-fail/auxiliary/crateresolve1-3.rs b/src/test/compile-fail/auxiliary/crateresolve1-3.rs
deleted file mode 100644 (file)
index 921687d..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-// compile-flags:-C extra-filename=-3
-#![crate_name = "crateresolve1"]
-#![crate_type = "lib"]
-
-pub fn f() -> isize { 30 }
diff --git a/src/test/compile-fail/auxiliary/depends.rs b/src/test/compile-fail/auxiliary/depends.rs
deleted file mode 100644 (file)
index e9bc2f4..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-// no-prefer-dynamic
-
-#![feature(panic_runtime)]
-#![crate_type = "rlib"]
-#![panic_runtime]
-#![no_std]
-
-extern crate needs_panic_runtime;
diff --git a/src/test/compile-fail/auxiliary/needs-panic-runtime.rs b/src/test/compile-fail/auxiliary/needs-panic-runtime.rs
deleted file mode 100644 (file)
index 3f030c1..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-// no-prefer-dynamic
-
-#![feature(needs_panic_runtime)]
-#![crate_type = "rlib"]
-#![needs_panic_runtime]
-#![no_std]
diff --git a/src/test/compile-fail/auxiliary/panic-runtime-lang-items.rs b/src/test/compile-fail/auxiliary/panic-runtime-lang-items.rs
deleted file mode 100644 (file)
index b9ef2f3..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-// no-prefer-dynamic
-
-#![crate_type = "rlib"]
-
-#![no_std]
-#![feature(lang_items)]
-
-use core::panic::PanicInfo;
-
-#[lang = "panic_impl"]
-fn panic_impl(info: &PanicInfo) -> ! { loop {} }
-#[lang = "eh_personality"]
-fn eh_personality() {}
-#[lang = "eh_catch_typeinfo"]
-static EH_CATCH_TYPEINFO: u8 = 0;
diff --git a/src/test/compile-fail/auxiliary/panic-runtime-unwind.rs b/src/test/compile-fail/auxiliary/panic-runtime-unwind.rs
deleted file mode 100644 (file)
index 97452a3..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-// compile-flags:-C panic=unwind
-// no-prefer-dynamic
-
-#![feature(panic_runtime)]
-#![crate_type = "rlib"]
-
-#![no_std]
-#![panic_runtime]
-
-#[no_mangle]
-pub extern fn __rust_maybe_catch_panic() {}
-
-#[no_mangle]
-pub extern fn __rust_start_panic() {}
-
-#[no_mangle]
-pub extern fn rust_eh_personality() {}
diff --git a/src/test/compile-fail/auxiliary/panic-runtime-unwind2.rs b/src/test/compile-fail/auxiliary/panic-runtime-unwind2.rs
deleted file mode 100644 (file)
index 97452a3..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-// compile-flags:-C panic=unwind
-// no-prefer-dynamic
-
-#![feature(panic_runtime)]
-#![crate_type = "rlib"]
-
-#![no_std]
-#![panic_runtime]
-
-#[no_mangle]
-pub extern fn __rust_maybe_catch_panic() {}
-
-#[no_mangle]
-pub extern fn __rust_start_panic() {}
-
-#[no_mangle]
-pub extern fn rust_eh_personality() {}
diff --git a/src/test/compile-fail/auxiliary/some-panic-impl.rs b/src/test/compile-fail/auxiliary/some-panic-impl.rs
deleted file mode 100644 (file)
index 0348b3a..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-// no-prefer-dynamic
-
-#![crate_type = "rlib"]
-#![no_std]
-
-use core::panic::PanicInfo;
-
-#[panic_handler]
-fn panic(info: &PanicInfo) -> ! {
-    loop {}
-}
diff --git a/src/test/compile-fail/auxiliary/wants-panic-runtime-unwind.rs b/src/test/compile-fail/auxiliary/wants-panic-runtime-unwind.rs
deleted file mode 100644 (file)
index d5f0102..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-// no-prefer-dynamic
-
-#![crate_type = "rlib"]
-#![no_std]
-
-extern crate panic_runtime_unwind;
diff --git a/src/test/compile-fail/auxiliary/weak-lang-items.rs b/src/test/compile-fail/auxiliary/weak-lang-items.rs
deleted file mode 100644 (file)
index 7a698cf..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-// no-prefer-dynamic
-
-// This aux-file will require the eh_personality function to be codegen'd, but
-// it hasn't been defined just yet. Make sure we don't explode.
-
-#![no_std]
-#![crate_type = "rlib"]
-
-struct A;
-
-impl core::ops::Drop for A {
-    fn drop(&mut self) {}
-}
-
-pub fn foo() {
-    let _a = A;
-    panic!("wut");
-}
-
-mod std {
-    pub use core::{option, fmt};
-}
diff --git a/src/test/compile-fail/coerce-unsafe-closure-to-unsafe-fn-ptr.rs b/src/test/compile-fail/coerce-unsafe-closure-to-unsafe-fn-ptr.rs
deleted file mode 100644 (file)
index 3677769..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-fn main() {
-    let _: unsafe fn() = || { ::std::pin::Pin::new_unchecked(&0_u8); };
-    //~^ ERROR E0133
-    let _: unsafe fn() = || unsafe { ::std::pin::Pin::new_unchecked(&0_u8); }; // OK
-}
diff --git a/src/test/compile-fail/coerce-unsafe-to-closure.rs b/src/test/compile-fail/coerce-unsafe-to-closure.rs
deleted file mode 100644 (file)
index 78bdd36..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-fn main() {
-    let x: Option<&[u8]> = Some("foo").map(std::mem::transmute);
-    //~^ ERROR E0277
-}
diff --git a/src/test/compile-fail/consts/const-fn-error.rs b/src/test/compile-fail/consts/const-fn-error.rs
deleted file mode 100644 (file)
index 68a4d41..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-#![feature(const_fn)]
-
-const X : usize = 2;
-
-const fn f(x: usize) -> usize {
-    let mut sum = 0;
-    for i in 0..x {
-        //~^ ERROR mutable references
-        //~| ERROR calls in constant functions
-        //~| ERROR calls in constant functions
-        //~| ERROR E0080
-        //~| ERROR E0744
-        sum += i;
-    }
-    sum
-}
-
-#[allow(unused_variables)]
-fn main() {
-    let a : [i32; f(X)];
-}
diff --git a/src/test/compile-fail/consts/issue-55878.rs b/src/test/compile-fail/consts/issue-55878.rs
deleted file mode 100644 (file)
index fee664c..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-// normalize-stderr-64bit "18446744073709551615" -> "SIZE"
-// normalize-stderr-32bit "4294967295" -> "SIZE"
-
-// error-pattern: are too big for the current architecture
-fn main() {
-    println!("Size: {}", std::mem::size_of::<[u8; u64::MAX as usize]>());
-}
diff --git a/src/test/compile-fail/crateresolve1.rs b/src/test/compile-fail/crateresolve1.rs
deleted file mode 100644 (file)
index 453c8d9..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-// aux-build:crateresolve1-1.rs
-// aux-build:crateresolve1-2.rs
-// aux-build:crateresolve1-3.rs
-// error-pattern:multiple matching crates for `crateresolve1`
-
-extern crate crateresolve1;
-
-fn main() {
-}
diff --git a/src/test/compile-fail/empty-extern-arg.rs b/src/test/compile-fail/empty-extern-arg.rs
deleted file mode 100644 (file)
index d3cb5aa..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-// compile-flags: --extern std=
-// error-pattern: extern location for std does not exist
-
-fn main() {}
diff --git a/src/test/compile-fail/invalid-link-args.rs b/src/test/compile-fail/invalid-link-args.rs
deleted file mode 100644 (file)
index 1e68b4f..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-// ignore-msvc due to linker-flavor=ld
-// error-pattern:aFdEfSeVEEE
-// compile-flags: -C linker-flavor=ld
-
-/* Make sure invalid link_args are printed to stderr. */
-
-#![feature(link_args)]
-
-#[link_args = "aFdEfSeVEEE"]
-extern {}
-
-fn main() { }
diff --git a/src/test/compile-fail/issue-10755.rs b/src/test/compile-fail/issue-10755.rs
deleted file mode 100644 (file)
index 3c6fcdd..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-// compile-flags: -C linker=llllll -C linker-flavor=ld
-// error-pattern: linker `llllll` not found
-
-fn main() {
-}
diff --git a/src/test/compile-fail/issue-23595-1.rs b/src/test/compile-fail/issue-23595-1.rs
deleted file mode 100644 (file)
index 483c205..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-#![feature(associated_type_defaults)]
-
-use std::ops::Index;
-
-trait Hierarchy {
-    type Value;
-    type ChildKey;
-    type Children = dyn Index<Self::ChildKey, Output=dyn Hierarchy>;
-    //~^ ERROR: the value of the associated types
-
-    fn data(&self) -> Option<(Self::Value, Self::Children)>;
-}
-
-fn main() {}
diff --git a/src/test/compile-fail/issue-27675-unchecked-bounds.rs b/src/test/compile-fail/issue-27675-unchecked-bounds.rs
deleted file mode 100644 (file)
index 1cfc230..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-/// The compiler previously did not properly check the bound of `From` when it was used from type
-/// of the dyn trait object (use in `copy_any` below). Since the associated type is under user
-/// control in this usage, the compiler could be tricked to believe any type implemented any trait.
-/// This would ICE, except for pure marker traits like `Copy`. It did not require providing an
-/// instance of the dyn trait type, only name said type.
-trait Setup {
-    type From: Copy;
-}
-
-fn copy<U: Setup + ?Sized>(from: &U::From) -> U::From {
-    *from
-}
-
-pub fn copy_any<T>(t: &T) -> T {
-    copy::<dyn Setup<From=T>>(t)
-    //~^ ERROR the trait bound `T: Copy` is not satisfied
-}
-
-fn main() {}
diff --git a/src/test/compile-fail/issue-43733-2.rs b/src/test/compile-fail/issue-43733-2.rs
deleted file mode 100644 (file)
index 61dd3a9..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-#![feature(cfg_target_thread_local, thread_local_internals)]
-
-// On platforms *without* `#[thread_local]`, use
-// a custom non-`Sync` type to fake the same error.
-#[cfg(not(target_thread_local))]
-struct Key<T> {
-    _data: std::cell::UnsafeCell<Option<T>>,
-    _flag: std::cell::Cell<()>,
-}
-
-#[cfg(not(target_thread_local))]
-impl<T> Key<T> {
-    const fn new() -> Self {
-        Key {
-            _data: std::cell::UnsafeCell::new(None),
-            _flag: std::cell::Cell::new(()),
-        }
-    }
-}
-
-#[cfg(target_thread_local)]
-use std::thread::__FastLocalKeyInner as Key;
-
-static __KEY: Key<()> = Key::new();
-//~^ ERROR `UnsafeCell<Option<()>>` cannot be shared between threads
-//~| ERROR cannot be shared between threads safely [E0277]
-
-fn main() {}
diff --git a/src/test/compile-fail/issue-44415.rs b/src/test/compile-fail/issue-44415.rs
deleted file mode 100644 (file)
index 71e7646..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-#![feature(core_intrinsics)]
-
-use std::intrinsics;
-
-struct Foo {
-    bytes: [u8; unsafe { intrinsics::size_of::<Foo>() }],
-    //~^ ERROR cycle detected when simplifying constant for the type system
-    x: usize,
-}
-
-fn main() {}
diff --git a/src/test/compile-fail/issue-46209-private-enum-variant-reexport.rs b/src/test/compile-fail/issue-46209-private-enum-variant-reexport.rs
deleted file mode 100644 (file)
index d54c993..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-#![feature(crate_visibility_modifier)]
-
-mod rank {
-    pub use self::Professor::*;
-    //~^ ERROR enum is private and its variants cannot be re-exported
-    pub use self::Lieutenant::{JuniorGrade, Full};
-    //~^ ERROR variant `JuniorGrade` is private and cannot be re-exported
-    //~| ERROR variant `Full` is private and cannot be re-exported
-    pub use self::PettyOfficer::*;
-    //~^ ERROR enum is private and its variants cannot be re-exported
-    pub use self::Crewman::*;
-    //~^ ERROR enum is private and its variants cannot be re-exported
-
-    enum Professor {
-        Adjunct,
-        Assistant,
-        Associate,
-        Full
-    }
-
-    enum Lieutenant {
-        JuniorGrade,
-        Full,
-    }
-
-    pub(in rank) enum PettyOfficer {
-        SecondClass,
-        FirstClass,
-        Chief,
-        MasterChief
-    }
-
-    crate enum Crewman {
-        Recruit,
-        Apprentice,
-        Full
-    }
-
-}
-
-fn main() {}
diff --git a/src/test/compile-fail/issue-52443.rs b/src/test/compile-fail/issue-52443.rs
deleted file mode 100644 (file)
index 4519833..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-fn main() {
-    [(); & { loop { continue } } ]; //~ ERROR mismatched types
-
-    [(); loop { break }]; //~ ERROR mismatched types
-
-    [(); {while true {break}; 0}];
-    //~^ WARN denote infinite loops with
-
-    [(); { for _ in 0usize.. {}; 0}];
-    //~^ ERROR `for` is not allowed in a `const`
-    //~| ERROR calls in constants are limited to constant functions
-    //~| ERROR mutable references are not allowed in constants
-    //~| ERROR calls in constants are limited to constant functions
-}
diff --git a/src/test/compile-fail/meta-expected-error-wrong-rev.rs b/src/test/compile-fail/meta-expected-error-wrong-rev.rs
deleted file mode 100644 (file)
index 7e49434..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-// ignore-compare-mode-nll
-
-// revisions: a
-// should-fail
-
-// This is a "meta-test" of the compilertest framework itself.  In
-// particular, it includes the right error message, but the message
-// targets the wrong revision, so we expect the execution to fail.
-// See also `meta-expected-error-correct-rev.rs`.
-
-#[cfg(a)]
-fn foo() {
-    let x: u32 = 22_usize; //[b]~ ERROR mismatched types
-}
-
-fn main() { }
diff --git a/src/test/compile-fail/must_use-in-stdlib-traits.rs b/src/test/compile-fail/must_use-in-stdlib-traits.rs
deleted file mode 100644 (file)
index 70dddf6..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-#![deny(unused_must_use)]
-#![feature(arbitrary_self_types)]
-
-use std::iter::Iterator;
-use std::future::Future;
-
-use std::task::{Context, Poll};
-use std::pin::Pin;
-use std::unimplemented;
-
-struct MyFuture;
-
-impl Future for MyFuture {
-   type Output = u32;
-
-   fn poll(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<u32> {
-      Poll::Pending
-   }
-}
-
-fn iterator() -> impl Iterator {
-   std::iter::empty::<u32>()
-}
-
-fn future() -> impl Future {
-   MyFuture
-}
-
-fn square_fn_once() -> impl FnOnce(u32) -> u32 {
-   |x| x * x
-}
-
-fn square_fn_mut() -> impl FnMut(u32) -> u32 {
-   |x| x * x
-}
-
-fn square_fn() -> impl Fn(u32) -> u32 {
-   |x| x * x
-}
-
-fn main() {
-   iterator(); //~ ERROR unused implementer of `Iterator` that must be used
-   future(); //~ ERROR unused implementer of `Future` that must be used
-   square_fn_once(); //~ ERROR unused implementer of `FnOnce` that must be used
-   square_fn_mut(); //~ ERROR unused implementer of `FnMut` that must be used
-   square_fn(); //~ ERROR unused implementer of `Fn` that must be used
-}
diff --git a/src/test/compile-fail/not-utf8.bin b/src/test/compile-fail/not-utf8.bin
deleted file mode 100644 (file)
index 4148e5b..0000000
Binary files a/src/test/compile-fail/not-utf8.bin and /dev/null differ
diff --git a/src/test/compile-fail/not-utf8.rs b/src/test/compile-fail/not-utf8.rs
deleted file mode 100644 (file)
index 1cb1fdc..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-// error-pattern: did not contain valid UTF-8
-
-fn foo() {
-    include!("not-utf8.bin")
-}
diff --git a/src/test/compile-fail/panic-handler-missing.rs b/src/test/compile-fail/panic-handler-missing.rs
deleted file mode 100644 (file)
index 1c380c9..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-// error-pattern: `#[panic_handler]` function required, but not found
-
-#![feature(lang_items)]
-#![no_main]
-#![no_std]
-
-#[lang = "eh_personality"]
-fn eh() {}
diff --git a/src/test/compile-fail/panic-handler-twice.rs b/src/test/compile-fail/panic-handler-twice.rs
deleted file mode 100644 (file)
index 0c5359b..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-// aux-build:some-panic-impl.rs
-
-#![feature(lang_items)]
-#![no_std]
-#![no_main]
-
-extern crate some_panic_impl;
-
-use core::panic::PanicInfo;
-
-#[panic_handler]
-fn panic(info: &PanicInfo) -> ! {
-    //~^ ERROR found duplicate lang item `panic_impl`
-    loop {}
-}
-
-#[lang = "eh_personality"]
-fn eh() {}
diff --git a/src/test/compile-fail/runtime-depend-on-needs-runtime.rs b/src/test/compile-fail/runtime-depend-on-needs-runtime.rs
deleted file mode 100644 (file)
index 866c5b2..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-// aux-build:needs-panic-runtime.rs
-// aux-build:depends.rs
-// error-pattern:cannot depend on a crate that needs a panic runtime
-
-extern crate depends;
-
-fn main() {}
diff --git a/src/test/compile-fail/runtime-depend-on-needs-runtime.stderr b/src/test/compile-fail/runtime-depend-on-needs-runtime.stderr
deleted file mode 100644 (file)
index 27e27dd..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-error: the crate `depends` cannot depend on a crate that needs a panic runtime, but it depends on `needs_panic_runtime`
-
-error: aborting due to previous error
-
diff --git a/src/test/compile-fail/specialization/issue-50452.rs b/src/test/compile-fail/specialization/issue-50452.rs
deleted file mode 100644 (file)
index 958f0eb..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-// compile-fail
-#![feature(specialization)]
-//~^ WARN the feature `specialization` is incomplete
-
-pub trait Foo {
-    fn foo();
-}
-
-impl Foo for i32 {}
-impl Foo for i64 {
-    fn foo() {}
-    //~^ERROR `foo` specializes an item from a parent `impl`
-}
-impl<T> Foo for T {
-    fn foo() {}
-}
-
-fn main() {
-    i32::foo();
-    i64::foo();
-    u8::foo();
-}
diff --git a/src/test/compile-fail/two-panic-runtimes.rs b/src/test/compile-fail/two-panic-runtimes.rs
deleted file mode 100644 (file)
index 671d445..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-// error-pattern:cannot link together two panic runtimes: panic_runtime_unwind and panic_runtime_unwind2
-// ignore-tidy-linelength
-// aux-build:panic-runtime-unwind.rs
-// aux-build:panic-runtime-unwind2.rs
-// aux-build:panic-runtime-lang-items.rs
-
-#![no_std]
-#![no_main]
-
-extern crate panic_runtime_unwind;
-extern crate panic_runtime_unwind2;
-extern crate panic_runtime_lang_items;
-
-fn main() {}
diff --git a/src/test/compile-fail/unwind-tables-panic-required.rs b/src/test/compile-fail/unwind-tables-panic-required.rs
deleted file mode 100644 (file)
index 314d9e7..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-// Tests that the compiler errors if the user tries to turn off unwind tables
-// when they are required.
-//
-// compile-flags: -C panic=unwind -C force-unwind-tables=no
-// ignore-tidy-linelength
-//
-// error-pattern: panic=unwind requires unwind tables, they cannot be disabled with `-C force-unwind-tables=no`.
-
-pub fn main() {
-}
diff --git a/src/test/compile-fail/unwind-tables-target-required.rs b/src/test/compile-fail/unwind-tables-target-required.rs
deleted file mode 100644 (file)
index 14c1789..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-// Tests that the compiler errors if the user tries to turn off unwind tables
-// when they are required.
-//
-// only-x86_64-windows-msvc
-// compile-flags: -C force-unwind-tables=no
-// ignore-tidy-linelength
-//
-// error-pattern: target requires unwind tables, they cannot be disabled with `-C force-unwind-tables=no`.
-
-pub fn main() {
-}
diff --git a/src/test/compile-fail/want-abort-got-unwind.rs b/src/test/compile-fail/want-abort-got-unwind.rs
deleted file mode 100644 (file)
index 30782e1..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-// error-pattern:is not compiled with this crate's panic strategy `abort`
-// aux-build:panic-runtime-unwind.rs
-// compile-flags:-C panic=abort
-
-extern crate panic_runtime_unwind;
-
-fn main() {}
diff --git a/src/test/compile-fail/want-abort-got-unwind2.rs b/src/test/compile-fail/want-abort-got-unwind2.rs
deleted file mode 100644 (file)
index 35d8d46..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-// error-pattern:is not compiled with this crate's panic strategy `abort`
-// aux-build:panic-runtime-unwind.rs
-// aux-build:wants-panic-runtime-unwind.rs
-// compile-flags:-C panic=abort
-
-extern crate wants_panic_runtime_unwind;
-
-fn main() {}
diff --git a/src/test/compile-fail/weak-lang-item.rs b/src/test/compile-fail/weak-lang-item.rs
deleted file mode 100644 (file)
index 3fa3822..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-// aux-build:weak-lang-items.rs
-// error-pattern: `#[panic_handler]` function required, but not found
-// error-pattern: language item required, but not found: `eh_personality`
-// ignore-emscripten compiled with panic=abort, personality not required
-
-#![no_std]
-
-extern crate core;
-extern crate weak_lang_items;
-
-fn main() {}
index 9f59936a92d1006ff217ff4f47707c611ecc2ca4..7115aec1041af49774955f1a9733de8572c90d92 100644 (file)
@@ -10,8 +10,8 @@
 // cdb-command: g
 
 // cdb-command: dx hash_set,d
-// cdb-check:hash_set,d [...] : { size=15 } [Type: [...]::HashSet<u64, [...]>]
-// cdb-check:    [size]           : 15 [Type: [...]]
+// cdb-check:hash_set,d [...] : { len=15 } [Type: [...]::HashSet<u64, [...]>]
+// cdb-check:    [len]            : 15 [Type: [...]]
 // cdb-check:    [capacity]       : [...]
 // cdb-check:    [[...]] [...]    : 0 [Type: u64]
 // cdb-command: dx hash_set,d
@@ -44,8 +44,8 @@
 // cdb-check:    [[...]] [...]    : 14 [Type: u64]
 
 // cdb-command: dx hash_map,d
-// cdb-check:hash_map,d [...] : { size=15 } [Type: [...]::HashMap<u64, u64, [...]>]
-// cdb-check:    [size]           : 15 [Type: [...]]
+// cdb-check:hash_map,d [...] : { len=15 } [Type: [...]::HashMap<u64, u64, [...]>]
+// cdb-check:    [len]            : 15 [Type: [...]]
 // cdb-check:    [capacity]       : [...]
 // cdb-check:    ["0x0"]          : 0 [Type: unsigned __int64]
 // cdb-command: dx hash_map,d
index 6632488171dad9fbab3218dfb65c62307b2e8f26..1a99f8412504a4580b249d4dacc278937a76dc75 100644 (file)
@@ -74,8 +74,8 @@
 // NOTE: While slices have a .natvis entry that works in VS & VS Code, it fails in CDB 10.0.18362.1
 
 // cdb-command: dx vec,d
-// cdb-check:vec,d [...] : { size=4 } [Type: [...]::Vec<u64, alloc::alloc::Global>]
-// cdb-check:    [size]           : 4 [Type: [...]]
+// cdb-check:vec,d [...] : { len=4 } [Type: [...]::Vec<u64, alloc::alloc::Global>]
+// cdb-check:    [len]            : 4 [Type: [...]]
 // cdb-check:    [capacity]       : [...] [Type: [...]]
 // cdb-check:    [0]              : 4 [Type: unsigned __int64]
 // cdb-check:    [1]              : 5 [Type: unsigned __int64]
 // cdb-command: dx string
 // cdb-check:string           : "IAMA string!" [Type: [...]::String]
 // cdb-check:    [<Raw View>]     [Type: [...]::String]
-// cdb-check:    [size]           : 0xc [Type: [...]]
+// cdb-check:    [len]            : 0xc [Type: [...]]
 // cdb-check:    [capacity]       : 0xc [Type: [...]]
+
+// cdb-command: dx -r2 string
 // cdb-check:    [0]              : 73 'I' [Type: char]
 // cdb-check:    [1]              : 65 'A' [Type: char]
 // cdb-check:    [2]              : 77 'M' [Type: char]
 // NOTE: OsString doesn't have a .natvis entry yet.
 
 // cdb-command: dx some
-// cdb-check:some             : { Some 8 } [Type: [...]::Option<i16>]
+// cdb-check:some             : Some(8) [Type: [...]::Option<i16>]
 // cdb-command: dx none
-// cdb-check:none             : { None } [Type: [...]::Option<i64>]
+// cdb-check:none             : None [Type: [...]::Option<i64>]
 // cdb-command: dx some_string
-// cdb-check:some_string      : { Some "IAMA optional string!" } [[...]::Option<[...]::String>]
+// cdb-check:some_string      : Some("IAMA optional string!") [[...]::Option<[...]::String>]
 
 #![allow(unused_variables)]
 use std::ffi::OsString;
index f01676b6da8639368817e5f2417b6abaff7e997e..3397ef95856a5a0ad4fa47d41d120d2aec7d2274 100644 (file)
@@ -14,9 +14,6 @@
 -         _2 = CheckedAdd(const 1_u32, const 1_u32); // scope 0 at $DIR/checked_add.rs:5:18: 5:23
 -         assert(!move (_2.1: bool), "attempt to compute `{} + {}`, which would overflow", const 1_u32, const 1_u32) -> bb1; // scope 0 at $DIR/checked_add.rs:5:18: 5:23
 +         _2 = const (2_u32, false);       // scope 0 at $DIR/checked_add.rs:5:18: 5:23
-+                                          // ty::Const
-+                                          // + ty: (u32, bool)
-+                                          // + val: Value(ByRef { alloc: Allocation { bytes: [2, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [31], len: Size { raw: 8 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } })
 +                                          // mir::Constant
 +                                          // + span: $DIR/checked_add.rs:5:18: 5:23
 +                                          // + literal: Const { ty: (u32, bool), val: Value(ByRef { alloc: Allocation { bytes: [2, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [31], len: Size { raw: 8 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) }
index 8c7b35887c915474a9c621757dc99bef798d7114..9ddb34e58e5a685f58153146c348e64ba9975bf3 100644 (file)
@@ -18,9 +18,6 @@
 -         assert(!move (_3.1: bool), "attempt to compute `{} + {}`, which would overflow", move _2, const 1_u8) -> bb1; // scope 0 at $DIR/indirect.rs:5:13: 5:29
 +         _2 = const 2_u8;                 // scope 0 at $DIR/indirect.rs:5:13: 5:25
 +         _3 = const (3_u8, false);        // scope 0 at $DIR/indirect.rs:5:13: 5:29
-+                                          // ty::Const
-+                                          // + ty: (u8, bool)
-+                                          // + val: Value(ByRef { alloc: Allocation { bytes: [3, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [3], len: Size { raw: 2 } }, size: Size { raw: 2 }, align: Align { pow2: 0 }, mutability: Not, extra: () }, offset: Size { raw: 0 } })
 +                                          // mir::Constant
 +                                          // + span: $DIR/indirect.rs:5:13: 5:29
 +                                          // + literal: Const { ty: (u8, bool), val: Value(ByRef { alloc: Allocation { bytes: [3, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [3], len: Size { raw: 2 } }, size: Size { raw: 2 }, align: Align { pow2: 0 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) }
index 492938fc206bd69e165d756831738df916ae333e..da35bf18c7116e48974ab7d26cf1bacaa9f09375 100644 (file)
@@ -15,9 +15,6 @@
           (_3.1: u8) = const 2_u8;         // scope 0 at $DIR/issue-67019.rs:11:11: 11:17
 -         (_2.0: (u8, u8)) = move _3;      // scope 0 at $DIR/issue-67019.rs:11:10: 11:19
 +         (_2.0: (u8, u8)) = const (1_u8, 2_u8); // scope 0 at $DIR/issue-67019.rs:11:10: 11:19
-+                                          // ty::Const
-+                                          // + ty: (u8, u8)
-+                                          // + val: Value(ByRef { alloc: Allocation { bytes: [1, 2], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [3], len: Size { raw: 2 } }, size: Size { raw: 2 }, align: Align { pow2: 0 }, mutability: Not, extra: () }, offset: Size { raw: 0 } })
 +                                          // mir::Constant
 +                                          // + span: $DIR/issue-67019.rs:11:10: 11:19
 +                                          // + literal: Const { ty: (u8, u8), val: Value(ByRef { alloc: Allocation { bytes: [1, 2], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [3], len: Size { raw: 2 } }, size: Size { raw: 2 }, align: Align { pow2: 0 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) }
index 204c1acecf548a99e2a9206fcdc7025fe069c63d..12b02e90345d9ff0266b24fd7c9320198988b6ed 100644 (file)
@@ -20,9 +20,6 @@
           StorageLive(_2);                 // scope 1 at $DIR/mutable_variable_aggregate.rs:7:9: 7:10
 -         _2 = _1;                         // scope 1 at $DIR/mutable_variable_aggregate.rs:7:13: 7:14
 +         _2 = const (42_i32, 99_i32);     // scope 1 at $DIR/mutable_variable_aggregate.rs:7:13: 7:14
-+                                          // ty::Const
-+                                          // + ty: (i32, i32)
-+                                          // + val: Value(ByRef { alloc: Allocation { bytes: [42, 0, 0, 0, 99, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [255], len: Size { raw: 8 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } })
 +                                          // mir::Constant
 +                                          // + span: $DIR/mutable_variable_aggregate.rs:7:13: 7:14
 +                                          // + literal: Const { ty: (i32, i32), val: Value(ByRef { alloc: Allocation { bytes: [42, 0, 0, 0, 99, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [255], len: Size { raw: 8 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) }
index 53ffc01ccaf2571676a0ffa7ae5f81b05a37fcbe..a10bac4f3ea3b04bcb0e8ac2bf553f8a8d0a04ca 100644 (file)
@@ -27,9 +27,6 @@
 -         _2 = CheckedAdd(const 2_i32, const 2_i32); // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18
 -         assert(!move (_2.1: bool), "attempt to compute `{} + {}`, which would overflow", const 2_i32, const 2_i32) -> bb1; // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18
 +         _2 = const (4_i32, false);       // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18
-+                                          // ty::Const
-+                                          // + ty: (i32, bool)
-+                                          // + val: Value(ByRef { alloc: Allocation { bytes: [4, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [31], len: Size { raw: 8 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } })
 +                                          // mir::Constant
 +                                          // + span: $DIR/optimizes_into_variable.rs:12:13: 12:18
 +                                          // + literal: Const { ty: (i32, bool), val: Value(ByRef { alloc: Allocation { bytes: [4, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [31], len: Size { raw: 8 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) }
index 53ffc01ccaf2571676a0ffa7ae5f81b05a37fcbe..a10bac4f3ea3b04bcb0e8ac2bf553f8a8d0a04ca 100644 (file)
@@ -27,9 +27,6 @@
 -         _2 = CheckedAdd(const 2_i32, const 2_i32); // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18
 -         assert(!move (_2.1: bool), "attempt to compute `{} + {}`, which would overflow", const 2_i32, const 2_i32) -> bb1; // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18
 +         _2 = const (4_i32, false);       // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18
-+                                          // ty::Const
-+                                          // + ty: (i32, bool)
-+                                          // + val: Value(ByRef { alloc: Allocation { bytes: [4, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [31], len: Size { raw: 8 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } })
 +                                          // mir::Constant
 +                                          // + span: $DIR/optimizes_into_variable.rs:12:13: 12:18
 +                                          // + literal: Const { ty: (i32, bool), val: Value(ByRef { alloc: Allocation { bytes: [4, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [31], len: Size { raw: 8 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) }
index fc8a5437232cf55539f46ee02b282234d13c66fe..f0e9916e6300e3c6834cc9938b20cc9a7b54e032 100644 (file)
@@ -9,9 +9,6 @@
 -         _1 = CheckedAdd(const 2_u32, const 2_u32); // scope 0 at $DIR/return_place.rs:6:5: 6:10
 -         assert(!move (_1.1: bool), "attempt to compute `{} + {}`, which would overflow", const 2_u32, const 2_u32) -> bb1; // scope 0 at $DIR/return_place.rs:6:5: 6:10
 +         _1 = const (4_u32, false);       // scope 0 at $DIR/return_place.rs:6:5: 6:10
-+                                          // ty::Const
-+                                          // + ty: (u32, bool)
-+                                          // + val: Value(ByRef { alloc: Allocation { bytes: [4, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [31], len: Size { raw: 8 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } })
 +                                          // mir::Constant
 +                                          // + span: $DIR/return_place.rs:6:5: 6:10
 +                                          // + literal: Const { ty: (u32, bool), val: Value(ByRef { alloc: Allocation { bytes: [4, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [31], len: Size { raw: 8 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) }
index 2de1ab19b7c3de491497c3d2a1394edb0de6305b..da4b135d4c6d6ab2df6a6e77a1501251afdb18bc 100644 (file)
@@ -18,9 +18,6 @@
           StorageLive(_3);                 // scope 1 at $DIR/tuple_literal_propagation.rs:5:13: 5:14
 -         _3 = _1;                         // scope 1 at $DIR/tuple_literal_propagation.rs:5:13: 5:14
 +         _3 = const (1_u32, 2_u32);       // scope 1 at $DIR/tuple_literal_propagation.rs:5:13: 5:14
-+                                          // ty::Const
-+                                          // + ty: (u32, u32)
-+                                          // + val: Value(ByRef { alloc: Allocation { bytes: [1, 0, 0, 0, 2, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [255], len: Size { raw: 8 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } })
 +                                          // mir::Constant
 +                                          // + span: $DIR/tuple_literal_propagation.rs:5:13: 5:14
 +                                          // + literal: Const { ty: (u32, u32), val: Value(ByRef { alloc: Allocation { bytes: [1, 0, 0, 0, 2, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [255], len: Size { raw: 8 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) }
index e9cc72f2138891640f29e3553a92db65be8b9e8e..096bba64c0bb882522373957cc04aa07f3df9440 100644 (file)
@@ -4,27 +4,21 @@
   fn forget(_1: T) -> () {
       debug t => _1;                       // in scope 0 at $DIR/lower_intrinsics.rs:18:18: 18:19
       let mut _0: ();                      // return place in scope 0 at $DIR/lower_intrinsics.rs:18:24: 18:24
-      let _2: ();                          // in scope 0 at $DIR/lower_intrinsics.rs:19:14: 19:41
-      let mut _3: T;                       // in scope 0 at $DIR/lower_intrinsics.rs:19:39: 19:40
-      scope 1 {
-      }
+      let mut _2: T;                       // in scope 0 at $DIR/lower_intrinsics.rs:19:30: 19:31
   
       bb0: {
-          StorageLive(_2);                 // scope 0 at $DIR/lower_intrinsics.rs:19:5: 19:43
-          StorageLive(_3);                 // scope 1 at $DIR/lower_intrinsics.rs:19:39: 19:40
-          _3 = move _1;                    // scope 1 at $DIR/lower_intrinsics.rs:19:39: 19:40
--         _2 = std::intrinsics::forget::<T>(move _3) -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:19:14: 19:41
+          StorageLive(_2);                 // scope 0 at $DIR/lower_intrinsics.rs:19:30: 19:31
+          _2 = move _1;                    // scope 0 at $DIR/lower_intrinsics.rs:19:30: 19:31
+-         _0 = std::intrinsics::forget::<T>(move _2) -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:19:5: 19:32
 -                                          // mir::Constant
--                                          // + span: $DIR/lower_intrinsics.rs:19:14: 19:38
--                                          // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(T) {std::intrinsics::forget::<T>}, val: Value(Scalar(<ZST>)) }
-+         _2 = const ();                   // scope 1 at $DIR/lower_intrinsics.rs:19:14: 19:41
-+         goto -> bb1;                     // scope 1 at $DIR/lower_intrinsics.rs:19:14: 19:41
+-                                          // + span: $DIR/lower_intrinsics.rs:19:5: 19:29
+-                                          // + literal: Const { ty: extern "rust-intrinsic" fn(T) {std::intrinsics::forget::<T>}, val: Value(Scalar(<ZST>)) }
++         _0 = const ();                   // scope 0 at $DIR/lower_intrinsics.rs:19:5: 19:32
++         goto -> bb1;                     // scope 0 at $DIR/lower_intrinsics.rs:19:5: 19:32
       }
   
       bb1: {
-          StorageDead(_3);                 // scope 1 at $DIR/lower_intrinsics.rs:19:40: 19:41
-          StorageDead(_2);                 // scope 0 at $DIR/lower_intrinsics.rs:19:43: 19:44
-          _0 = const ();                   // scope 0 at $DIR/lower_intrinsics.rs:18:24: 20:2
+          StorageDead(_2);                 // scope 0 at $DIR/lower_intrinsics.rs:19:31: 19:32
           goto -> bb2;                     // scope 0 at $DIR/lower_intrinsics.rs:20:1: 20:2
       }
   
index 8d28354a5f14eb90e452c6f9a2d48dd437abbdfd..d9891465dabb743fc4afd282f76549e7b2205f4c 100644 (file)
@@ -16,7 +16,7 @@ pub fn size_of<T>() -> usize {
 
 // EMIT_MIR lower_intrinsics.forget.LowerIntrinsics.diff
 pub fn forget<T>(t: T) {
-    unsafe { core::intrinsics::forget(t) };
+    core::intrinsics::forget(t)
 }
 
 // EMIT_MIR lower_intrinsics.unreachable.LowerIntrinsics.diff
index 3064e92f90007c1d1327e3f1c86b133c4d328475..34f8ca870cd230eb20eb6341b2ed533133babfb1 100644 (file)
@@ -42,9 +42,6 @@
                                            // mir::Constant
                                            // + span: $DIR/simplify-locals-removes-unused-consts.rs:14:5: 14:12
                                            // + literal: Const { ty: fn(((), ())) {use_zst}, val: Value(Scalar(<ZST>)) }
-                                           // ty::Const
-                                           // + ty: ((), ())
-                                           // + val: Value(Scalar(<ZST>))
                                            // mir::Constant
                                            // + span: $DIR/simplify-locals-removes-unused-consts.rs:14:5: 14:22
                                            // + literal: Const { ty: ((), ()), val: Value(Scalar(<ZST>)) }
index 5c24f909130c0745645bd6c1df2ec8f292cb07eb..c4700b317efa03b7286bf2ecf4a78e2838228f2f 100644 (file)
@@ -98,7 +98,7 @@ endif
        # Run it in order to generate some profiling data,
        # with `LLVM_PROFILE_FILE=<profdata_file>` environment variable set to
        # output the coverage stats for this run.
-       LLVM_PROFILE_FILE="$(TMPDIR)"/$@.profraw \
+       LLVM_PROFILE_FILE="$(TMPDIR)"/$@-%p.profraw \
                        $(call RUN,$@) || \
                        ( \
                                status=$$?; \
@@ -108,9 +108,16 @@ endif
                                ) \
                        )
 
+       # Run it through rustdoc as well to cover doctests
+       LLVM_PROFILE_FILE="$(TMPDIR)"/$@-%p.profraw \
+                       $(RUSTDOC) --crate-name workaround_for_79771 --test $(SOURCEDIR)/$@.rs \
+                       $$( grep -q '^\/\/ require-rust-edition-2018' $(SOURCEDIR)/$@.rs && echo "--edition=2018" ) \
+                       -L "$(TMPDIR)" -Zinstrument-coverage \
+                       -Z unstable-options --persist-doctests=$(TMPDIR)/rustdoc-$@
+
        # Postprocess the profiling data so it can be used by the llvm-cov tool
        "$(LLVM_BIN_DIR)"/llvm-profdata merge --sparse \
-                       "$(TMPDIR)"/$@.profraw \
+                       "$(TMPDIR)"/$@-*.profraw \
                        -o "$(TMPDIR)"/$@.profdata
 
        # Generate a coverage report using `llvm-cov show`.
@@ -121,8 +128,15 @@ endif
                        --show-line-counts-or-regions \
                        --instr-profile="$(TMPDIR)"/$@.profdata \
                        $(call BIN,"$(TMPDIR)"/$@) \
-               > "$(TMPDIR)"/actual_show_coverage.$@.txt \
-               2> "$(TMPDIR)"/show_coverage_stderr.$@.txt || \
+                       $$( \
+                               for file in $(TMPDIR)/rustdoc-$@/*/rust_out; \
+                               do \
+                               [[ -x $$file ]] && printf "%s %s " -object $$file; \
+                               done \
+                       ) \
+               2> "$(TMPDIR)"/show_coverage_stderr.$@.txt \
+               | "$(PYTHON)" $(BASEDIR)/normalize_paths.py \
+               > "$(TMPDIR)"/actual_show_coverage.$@.txt || \
        ( status=$$? ; \
                >&2 cat "$(TMPDIR)"/show_coverage_stderr.$@.txt ; \
                exit $$status \
diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.doctest.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.doctest.txt
new file mode 100644 (file)
index 0000000..e1731c7
--- /dev/null
@@ -0,0 +1,79 @@
+../coverage/doctest.rs:
+    1|       |//! This test ensures that code from doctests is properly re-mapped.
+    2|       |//! See <https://github.com/rust-lang/rust/issues/79417> for more info.
+    3|       |//!
+    4|       |//! Just some random code:
+    5|      1|//! ```
+    6|      1|//! if true {
+    7|       |//!     // this is executed!
+    8|      1|//!     assert_eq!(1, 1);
+    9|       |//! } else {
+   10|       |//!     // this is not!
+   11|       |//!     assert_eq!(1, 2);
+   12|       |//! }
+   13|      1|//! ```
+   14|       |//!
+   15|       |//! doctest testing external code:
+   16|       |//! ```
+   17|      1|//! extern crate doctest_crate;
+   18|      1|//! doctest_crate::fn_run_in_doctests(1);
+   19|      1|//! ```
+   20|       |//!
+   21|       |//! doctest returning a result:
+   22|      1|//! ```
+   23|      1|//! #[derive(Debug)]
+   24|      1|//! struct SomeError;
+   25|      1|//! let mut res = Err(SomeError);
+   26|      1|//! if res.is_ok() {
+   27|      0|//!   res?;
+   28|      1|//! } else {
+   29|      1|//!   res = Ok(0);
+   30|      1|//! }
+   31|       |//! // need to be explicit because rustdoc cant infer the return type
+   32|      1|//! Ok::<(), SomeError>(())
+   33|      1|//! ```
+   34|       |//!
+   35|       |//! doctest with custom main:
+   36|       |//! ```
+   37|       |//! #[derive(Debug)]
+   38|       |//! struct SomeError;
+   39|       |//!
+   40|       |//! extern crate doctest_crate;
+   41|       |//!
+   42|      1|//! fn doctest_main() -> Result<(), SomeError> {
+   43|      1|//!     doctest_crate::fn_run_in_doctests(2);
+   44|      1|//!     Ok(())
+   45|      1|//! }
+   46|       |//!
+   47|       |//! // this `main` is not shown as covered, as it clashes with all the other
+   48|       |//! // `main` functions that were automatically generated for doctests
+   49|       |//! fn main() -> Result<(), SomeError> {
+   50|       |//!     doctest_main()
+   51|       |//! }
+   52|       |//! ```
+   53|       |
+   54|       |/// doctest attached to fn testing external code:
+   55|       |/// ```
+   56|      1|/// extern crate doctest_crate;
+   57|      1|/// doctest_crate::fn_run_in_doctests(3);
+   58|      1|/// ```
+   59|       |///
+   60|      1|fn main() {
+   61|      1|    if true {
+   62|      1|        assert_eq!(1, 1);
+   63|       |    } else {
+   64|       |        assert_eq!(1, 2);
+   65|       |    }
+   66|      1|}
+
+../coverage/lib/doctest_crate.rs:
+    1|       |/// A function run only from within doctests
+    2|      3|pub fn fn_run_in_doctests(conditional: usize) {
+    3|      3|    match conditional {
+    4|      1|        1 => assert_eq!(1, 1), // this is run,
+    5|      1|        2 => assert_eq!(1, 1), // this,
+    6|      1|        3 => assert_eq!(1, 1), // and this too
+    7|      0|        _ => assert_eq!(1, 2), // however this is not
+    8|       |    }
+    9|      3|}
+
index e14e733fff6d4cbe55f76924985cb802434c4a49..4c03e950af029de06d229074b246fca1d69326f6 100644 (file)
    18|      2|    println!("used_only_from_bin_crate_generic_function with {:?}", arg);
    19|      2|}
   ------------------
-  | used_crate::used_only_from_bin_crate_generic_function::<&str>:
+  | used_crate::used_only_from_bin_crate_generic_function::<&alloc::vec::Vec<i32>>:
   |   17|      1|pub fn used_only_from_bin_crate_generic_function<T: Debug>(arg: T) {
   |   18|      1|    println!("used_only_from_bin_crate_generic_function with {:?}", arg);
   |   19|      1|}
   ------------------
-  | used_crate::used_only_from_bin_crate_generic_function::<&alloc::vec::Vec<i32>>:
+  | used_crate::used_only_from_bin_crate_generic_function::<&str>:
   |   17|      1|pub fn used_only_from_bin_crate_generic_function<T: Debug>(arg: T) {
   |   18|      1|    println!("used_only_from_bin_crate_generic_function with {:?}", arg);
   |   19|      1|}
diff --git a/src/test/run-make-fulldeps/coverage-reports/normalize_paths.py b/src/test/run-make-fulldeps/coverage-reports/normalize_paths.py
new file mode 100755 (executable)
index 0000000..e5777ad
--- /dev/null
@@ -0,0 +1,12 @@
+#!/usr/bin/env python
+
+from __future__ import print_function
+
+import sys
+
+# Normalize file paths in output
+for line in sys.stdin:
+    if line.startswith("..") and line.rstrip().endswith(".rs:"):
+        print(line.replace("\\", "/"), end='')
+    else:
+        print(line, end='')
diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.doctest/doctest.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.doctest/doctest.main.-------.InstrumentCoverage.0.html
new file mode 100644 (file)
index 0000000..8d07455
--- /dev/null
@@ -0,0 +1,127 @@
+<!DOCTYPE html>
+<!--
+
+Preview this file as rendered HTML from the github source at:
+https://htmlpreview.github.io/?https://github.com/rust-lang/rust/blob/master/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.doctest/doctest.main.-------.InstrumentCoverage.0.html
+
+For revisions in Pull Requests (PR):
+  * Replace "rust-lang" with the github PR author
+  * Replace "master" with the PR branch name
+
+-->
+<html>
+<head>
+<title>doctest.main - Coverage Spans</title>
+<style>
+    .line {
+        counter-increment: line;
+    }
+    .line:before {
+        content: counter(line) ": ";
+        font-family: Menlo, Monaco, monospace;
+        font-style: italic;
+        width: 3.8em;
+        display: inline-block;
+        text-align: right;
+        filter: opacity(50%);
+        -webkit-user-select: none;
+    }
+    .code {
+        color: #dddddd;
+        background-color: #222222;
+        font-family: Menlo, Monaco, monospace;
+        line-height: 1.4em;
+        border-bottom: 2px solid #222222;
+        white-space: pre;
+        display: inline-block;
+    }
+    .odd {
+        background-color: #55bbff;
+        color: #223311;
+    }
+    .even {
+        background-color: #ee7756;
+        color: #551133;
+    }
+    .code {
+        --index: calc(var(--layer) - 1);
+        padding-top: calc(var(--index) * 0.15em);
+        filter:
+            hue-rotate(calc(var(--index) * 25deg))
+            saturate(calc(100% - (var(--index) * 2%)))
+            brightness(calc(100% - (var(--index) * 1.5%)));
+    }
+    .annotation {
+        color: #4444ff;
+        font-family: monospace;
+        font-style: italic;
+        display: none;
+        -webkit-user-select: none;
+    }
+    body:active .annotation {
+        /* requires holding mouse down anywhere on the page */
+        display: inline-block;
+    }
+    span:hover .annotation {
+        /* requires hover over a span ONLY on its first line */
+        display: inline-block;
+    }
+</style>
+</head>
+<body>
+<div class="code" style="counter-reset: line 59"><span class="line"><span><span class="code even" style="--layer: 1"><span class="annotation">@0⦊</span>fn main() <span class="annotation">⦉@0</span></span></span><span class="code" style="--layer: 0">{</span></span>
+<span class="line"><span class="code" style="--layer: 0">    if </span><span><span class="code even" style="--layer: 1" title="61:8-61:12: @0[1]: _1 = const true
+61:8-61:12: @0[2]: FakeRead(ForMatchedPlace, _1)"><span class="annotation">@0⦊</span>true<span class="annotation">⦉@0</span></span></span><span class="code" style="--layer: 0"> {</span></span>
+<span class="line"><span class="code" style="--layer: 0">        </span><span><span class="code odd" style="--layer: 1" title="62:9-62:26: @5[0]: _2 = const ()"><span class="annotation">@5⦊</span></span></span><span class="code even" style="--layer: 2" title="62:9-62:26: @6[5]: _75 = const main::promoted[3]
+62:9-62:26: @6[6]: _18 = &amp;(*_75)
+62:9-62:26: @6[7]: _17 = &amp;(*_18)
+62:9-62:26: @6[8]: _16 = move _17 as &amp;[&amp;str] (Pointer(Unsize))
+62:9-62:26: @6[17]: _26 = &amp;(*_8)
+62:9-62:26: @6[18]: _25 = &amp;_26
+62:9-62:26: @6[21]: _28 = &amp;(*_9)
+62:9-62:26: @6[22]: _27 = &amp;_28
+62:9-62:26: @6[23]: _24 = (move _25, move _27)
+62:9-62:26: @6[26]: FakeRead(ForMatchedPlace, _24)
+62:9-62:26: @6[28]: _29 = (_24.0: &amp;&amp;i32)
+62:9-62:26: @6[30]: _30 = (_24.1: &amp;&amp;i32)
+62:9-62:26: @6[33]: _32 = &amp;(*_29)
+62:9-62:26: @6[35]: _33 = &lt;&amp;i32 as Debug&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r &amp;i32, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+62:9-62:26: @6.Call: _31 = ArgumentV1::new::&lt;&amp;i32&gt;(move _32, move _33) -&gt; [return: bb7, unwind: bb17]
+62:9-62:26: @7[4]: _35 = &amp;(*_30)
+62:9-62:26: @7[6]: _36 = &lt;&amp;i32 as Debug&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r &amp;i32, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+62:9-62:26: @7.Call: _34 = ArgumentV1::new::&lt;&amp;i32&gt;(move _35, move _36) -&gt; [return: bb8, unwind: bb17]
+62:9-62:26: @8[2]: _23 = [move _31, move _34]
+62:9-62:26: @8[7]: _22 = &amp;_23
+62:9-62:26: @8[8]: _21 = &amp;(*_22)
+62:9-62:26: @8[9]: _20 = move _21 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+62:9-62:26: @8.Call: _15 = Arguments::new_v1(move _16, move _20) -&gt; [return: bb9, unwind: bb17]
+62:9-62:26: @9.Call: core::panicking::panic_fmt(move _15) -&gt; bb17"><span class="annotation">@4,6,7,8,9⦊</span>assert_eq!(1, 1);<span class="annotation">⦉@4,6,7,8,9</span></span><span><span class="code odd" style="--layer: 1" title="62:9-62:26: @5[0]: _2 = const ()"><span class="annotation">⦉@5</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    } else {</span></span>
+<span class="line"><span class="code" style="--layer: 0">        </span><span><span class="code even" style="--layer: 1" title="64:9-64:26: @11[0]: _37 = const ()"><span class="annotation">@11⦊</span></span></span><span class="code even" style="--layer: 2" title="64:9-64:26: @12[5]: _72 = const main::promoted[0]
+64:9-64:26: @12[6]: _53 = &amp;(*_72)
+64:9-64:26: @12[7]: _52 = &amp;(*_53)
+64:9-64:26: @12[8]: _51 = move _52 as &amp;[&amp;str] (Pointer(Unsize))
+64:9-64:26: @12[17]: _61 = &amp;(*_43)
+64:9-64:26: @12[18]: _60 = &amp;_61
+64:9-64:26: @12[21]: _63 = &amp;(*_44)
+64:9-64:26: @12[22]: _62 = &amp;_63
+64:9-64:26: @12[23]: _59 = (move _60, move _62)
+64:9-64:26: @12[26]: FakeRead(ForMatchedPlace, _59)
+64:9-64:26: @12[28]: _64 = (_59.0: &amp;&amp;i32)
+64:9-64:26: @12[30]: _65 = (_59.1: &amp;&amp;i32)
+64:9-64:26: @12[33]: _67 = &amp;(*_64)
+64:9-64:26: @12[35]: _68 = &lt;&amp;i32 as Debug&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r &amp;i32, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+64:9-64:26: @12.Call: _66 = ArgumentV1::new::&lt;&amp;i32&gt;(move _67, move _68) -&gt; [return: bb13, unwind: bb17]
+64:9-64:26: @13[4]: _70 = &amp;(*_65)
+64:9-64:26: @13[6]: _71 = &lt;&amp;i32 as Debug&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r &amp;i32, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+64:9-64:26: @13.Call: _69 = ArgumentV1::new::&lt;&amp;i32&gt;(move _70, move _71) -&gt; [return: bb14, unwind: bb17]
+64:9-64:26: @14[2]: _58 = [move _66, move _69]
+64:9-64:26: @14[7]: _57 = &amp;_58
+64:9-64:26: @14[8]: _56 = &amp;(*_57)
+64:9-64:26: @14[9]: _55 = move _56 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+64:9-64:26: @14.Call: _50 = Arguments::new_v1(move _51, move _55) -&gt; [return: bb15, unwind: bb17]
+64:9-64:26: @15.Call: core::panicking::panic_fmt(move _50) -&gt; bb17"><span class="annotation">@10,12,13,14,15⦊</span>assert_eq!(1, 2);<span class="annotation">⦉@10,12,13,14,15</span></span><span><span class="code even" style="--layer: 1" title="64:9-64:26: @11[0]: _37 = const ()"><span class="annotation">⦉@11</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    }</span></span>
+<span class="line"><span class="code" style="--layer: 0">}</span><span><span class="code odd" style="--layer: 1" title="66:2-66:2: @16.Return: return"><span class="annotation">@16⦊</span>‸<span class="annotation">⦉@16</span></span></span></span></div>
+</body>
+</html>
diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.doctest_crate/doctest_crate.fn_run_in_doctests.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.doctest_crate/doctest_crate.fn_run_in_doctests.-------.InstrumentCoverage.0.html
new file mode 100644 (file)
index 0000000..ae119d9
--- /dev/null
@@ -0,0 +1,173 @@
+<!DOCTYPE html>
+<!--
+
+Preview this file as rendered HTML from the github source at:
+https://htmlpreview.github.io/?https://github.com/rust-lang/rust/blob/master/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.doctest_crate/doctest_crate.fn_run_in_doctests.-------.InstrumentCoverage.0.html
+
+For revisions in Pull Requests (PR):
+  * Replace "rust-lang" with the github PR author
+  * Replace "master" with the PR branch name
+
+-->
+<html>
+<head>
+<title>doctest_crate.fn_run_in_doctests - Coverage Spans</title>
+<style>
+    .line {
+        counter-increment: line;
+    }
+    .line:before {
+        content: counter(line) ": ";
+        font-family: Menlo, Monaco, monospace;
+        font-style: italic;
+        width: 3.8em;
+        display: inline-block;
+        text-align: right;
+        filter: opacity(50%);
+        -webkit-user-select: none;
+    }
+    .code {
+        color: #dddddd;
+        background-color: #222222;
+        font-family: Menlo, Monaco, monospace;
+        line-height: 1.4em;
+        border-bottom: 2px solid #222222;
+        white-space: pre;
+        display: inline-block;
+    }
+    .odd {
+        background-color: #55bbff;
+        color: #223311;
+    }
+    .even {
+        background-color: #ee7756;
+        color: #551133;
+    }
+    .code {
+        --index: calc(var(--layer) - 1);
+        padding-top: calc(var(--index) * 0.15em);
+        filter:
+            hue-rotate(calc(var(--index) * 25deg))
+            saturate(calc(100% - (var(--index) * 2%)))
+            brightness(calc(100% - (var(--index) * 1.5%)));
+    }
+    .annotation {
+        color: #4444ff;
+        font-family: monospace;
+        font-style: italic;
+        display: none;
+        -webkit-user-select: none;
+    }
+    body:active .annotation {
+        /* requires holding mouse down anywhere on the page */
+        display: inline-block;
+    }
+    span:hover .annotation {
+        /* requires hover over a span ONLY on its first line */
+        display: inline-block;
+    }
+</style>
+</head>
+<body>
+<div class="code" style="counter-reset: line 1"><span class="line"><span><span class="code even" style="--layer: 1"><span class="annotation">@0⦊</span>pub fn fn_run_in_doctests(conditional: usize) <span class="annotation">⦉@0</span></span></span><span class="code" style="--layer: 0">{</span></span>
+<span class="line"><span class="code" style="--layer: 0">    match </span><span><span class="code even" style="--layer: 1" title="3:11-3:22: @0[0]: FakeRead(ForMatchedPlace, _1)"><span class="annotation">@0⦊</span>conditional<span class="annotation">⦉@0</span></span></span><span class="code" style="--layer: 0"> {</span></span>
+<span class="line"><span class="code" style="--layer: 0">        1 =&gt; </span><span><span class="code odd" style="--layer: 1" title="4:14-4:30: @7[0]: _0 = const ()"><span class="annotation">@7⦊</span></span></span><span class="code even" style="--layer: 2" title="4:14-4:30: @8[5]: _138 = const fn_run_in_doctests::promoted[0]
+4:14-4:30: @8[6]: _17 = &amp;(*_138)
+4:14-4:30: @8[7]: _16 = &amp;(*_17)
+4:14-4:30: @8[8]: _15 = move _16 as &amp;[&amp;str] (Pointer(Unsize))
+4:14-4:30: @8[17]: _25 = &amp;(*_7)
+4:14-4:30: @8[18]: _24 = &amp;_25
+4:14-4:30: @8[21]: _27 = &amp;(*_8)
+4:14-4:30: @8[22]: _26 = &amp;_27
+4:14-4:30: @8[23]: _23 = (move _24, move _26)
+4:14-4:30: @8[26]: FakeRead(ForMatchedPlace, _23)
+4:14-4:30: @8[28]: _28 = (_23.0: &amp;&amp;i32)
+4:14-4:30: @8[30]: _29 = (_23.1: &amp;&amp;i32)
+4:14-4:30: @8[33]: _31 = &amp;(*_28)
+4:14-4:30: @8[35]: _32 = &lt;&amp;i32 as Debug&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r &amp;i32, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+4:14-4:30: @8.Call: _30 = ArgumentV1::new::&lt;&amp;i32&gt;(move _31, move _32) -&gt; [return: bb9, unwind: bb33]
+4:14-4:30: @9[4]: _34 = &amp;(*_29)
+4:14-4:30: @9[6]: _35 = &lt;&amp;i32 as Debug&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r &amp;i32, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+4:14-4:30: @9.Call: _33 = ArgumentV1::new::&lt;&amp;i32&gt;(move _34, move _35) -&gt; [return: bb10, unwind: bb33]
+4:14-4:30: @10[2]: _22 = [move _30, move _33]
+4:14-4:30: @10[7]: _21 = &amp;_22
+4:14-4:30: @10[8]: _20 = &amp;(*_21)
+4:14-4:30: @10[9]: _19 = move _20 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+4:14-4:30: @10.Call: _14 = Arguments::new_v1(move _15, move _19) -&gt; [return: bb11, unwind: bb33]
+4:14-4:30: @11.Call: core::panicking::panic_fmt(move _14) -&gt; bb33"><span class="annotation">@6,8,9,10,11⦊</span>assert_eq!(1, 1)<span class="annotation">⦉@6,8,9,10,11</span></span><span><span class="code odd" style="--layer: 1" title="4:14-4:30: @7[0]: _0 = const ()"><span class="annotation">⦉@7</span></span></span><span class="code" style="--layer: 0">, // this is run,</span></span>
+<span class="line"><span class="code" style="--layer: 0">        2 =&gt; </span><span><span class="code even" style="--layer: 1" title="5:14-5:30: @14[0]: _0 = const ()"><span class="annotation">@14⦊</span></span></span><span class="code even" style="--layer: 2" title="5:14-5:30: @15[5]: _141 = const fn_run_in_doctests::promoted[3]
+5:14-5:30: @15[6]: _51 = &amp;(*_141)
+5:14-5:30: @15[7]: _50 = &amp;(*_51)
+5:14-5:30: @15[8]: _49 = move _50 as &amp;[&amp;str] (Pointer(Unsize))
+5:14-5:30: @15[17]: _59 = &amp;(*_41)
+5:14-5:30: @15[18]: _58 = &amp;_59
+5:14-5:30: @15[21]: _61 = &amp;(*_42)
+5:14-5:30: @15[22]: _60 = &amp;_61
+5:14-5:30: @15[23]: _57 = (move _58, move _60)
+5:14-5:30: @15[26]: FakeRead(ForMatchedPlace, _57)
+5:14-5:30: @15[28]: _62 = (_57.0: &amp;&amp;i32)
+5:14-5:30: @15[30]: _63 = (_57.1: &amp;&amp;i32)
+5:14-5:30: @15[33]: _65 = &amp;(*_62)
+5:14-5:30: @15[35]: _66 = &lt;&amp;i32 as Debug&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r &amp;i32, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+5:14-5:30: @15.Call: _64 = ArgumentV1::new::&lt;&amp;i32&gt;(move _65, move _66) -&gt; [return: bb16, unwind: bb33]
+5:14-5:30: @16[4]: _68 = &amp;(*_63)
+5:14-5:30: @16[6]: _69 = &lt;&amp;i32 as Debug&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r &amp;i32, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+5:14-5:30: @16.Call: _67 = ArgumentV1::new::&lt;&amp;i32&gt;(move _68, move _69) -&gt; [return: bb17, unwind: bb33]
+5:14-5:30: @17[2]: _56 = [move _64, move _67]
+5:14-5:30: @17[7]: _55 = &amp;_56
+5:14-5:30: @17[8]: _54 = &amp;(*_55)
+5:14-5:30: @17[9]: _53 = move _54 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+5:14-5:30: @17.Call: _48 = Arguments::new_v1(move _49, move _53) -&gt; [return: bb18, unwind: bb33]
+5:14-5:30: @18.Call: core::panicking::panic_fmt(move _48) -&gt; bb33"><span class="annotation">@13,15,16,17,18⦊</span>assert_eq!(1, 1)<span class="annotation">⦉@13,15,16,17,18</span></span><span><span class="code even" style="--layer: 1" title="5:14-5:30: @14[0]: _0 = const ()"><span class="annotation">⦉@14</span></span></span><span class="code" style="--layer: 0">, // this,</span></span>
+<span class="line"><span class="code" style="--layer: 0">        3 =&gt; </span><span><span class="code odd" style="--layer: 1" title="6:14-6:30: @21[0]: _0 = const ()"><span class="annotation">@21⦊</span></span></span><span class="code even" style="--layer: 2" title="6:14-6:30: @22[5]: _144 = const fn_run_in_doctests::promoted[6]
+6:14-6:30: @22[6]: _85 = &amp;(*_144)
+6:14-6:30: @22[7]: _84 = &amp;(*_85)
+6:14-6:30: @22[8]: _83 = move _84 as &amp;[&amp;str] (Pointer(Unsize))
+6:14-6:30: @22[17]: _93 = &amp;(*_75)
+6:14-6:30: @22[18]: _92 = &amp;_93
+6:14-6:30: @22[21]: _95 = &amp;(*_76)
+6:14-6:30: @22[22]: _94 = &amp;_95
+6:14-6:30: @22[23]: _91 = (move _92, move _94)
+6:14-6:30: @22[26]: FakeRead(ForMatchedPlace, _91)
+6:14-6:30: @22[28]: _96 = (_91.0: &amp;&amp;i32)
+6:14-6:30: @22[30]: _97 = (_91.1: &amp;&amp;i32)
+6:14-6:30: @22[33]: _99 = &amp;(*_96)
+6:14-6:30: @22[35]: _100 = &lt;&amp;i32 as Debug&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r &amp;i32, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+6:14-6:30: @22.Call: _98 = ArgumentV1::new::&lt;&amp;i32&gt;(move _99, move _100) -&gt; [return: bb23, unwind: bb33]
+6:14-6:30: @23[4]: _102 = &amp;(*_97)
+6:14-6:30: @23[6]: _103 = &lt;&amp;i32 as Debug&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r &amp;i32, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+6:14-6:30: @23.Call: _101 = ArgumentV1::new::&lt;&amp;i32&gt;(move _102, move _103) -&gt; [return: bb24, unwind: bb33]
+6:14-6:30: @24[2]: _90 = [move _98, move _101]
+6:14-6:30: @24[7]: _89 = &amp;_90
+6:14-6:30: @24[8]: _88 = &amp;(*_89)
+6:14-6:30: @24[9]: _87 = move _88 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+6:14-6:30: @24.Call: _82 = Arguments::new_v1(move _83, move _87) -&gt; [return: bb25, unwind: bb33]
+6:14-6:30: @25.Call: core::panicking::panic_fmt(move _82) -&gt; bb33"><span class="annotation">@20,22,23,24,25⦊</span>assert_eq!(1, 1)<span class="annotation">⦉@20,22,23,24,25</span></span><span><span class="code odd" style="--layer: 1" title="6:14-6:30: @21[0]: _0 = const ()"><span class="annotation">⦉@21</span></span></span><span class="code" style="--layer: 0">, // and this too</span></span>
+<span class="line"><span class="code" style="--layer: 0">        _ =&gt; </span><span><span class="code even" style="--layer: 1" title="7:14-7:30: @27[0]: _0 = const ()"><span class="annotation">@27⦊</span></span></span><span class="code even" style="--layer: 2" title="7:14-7:30: @28[5]: _147 = const fn_run_in_doctests::promoted[9]
+7:14-7:30: @28[6]: _119 = &amp;(*_147)
+7:14-7:30: @28[7]: _118 = &amp;(*_119)
+7:14-7:30: @28[8]: _117 = move _118 as &amp;[&amp;str] (Pointer(Unsize))
+7:14-7:30: @28[17]: _127 = &amp;(*_109)
+7:14-7:30: @28[18]: _126 = &amp;_127
+7:14-7:30: @28[21]: _129 = &amp;(*_110)
+7:14-7:30: @28[22]: _128 = &amp;_129
+7:14-7:30: @28[23]: _125 = (move _126, move _128)
+7:14-7:30: @28[26]: FakeRead(ForMatchedPlace, _125)
+7:14-7:30: @28[28]: _130 = (_125.0: &amp;&amp;i32)
+7:14-7:30: @28[30]: _131 = (_125.1: &amp;&amp;i32)
+7:14-7:30: @28[33]: _133 = &amp;(*_130)
+7:14-7:30: @28[35]: _134 = &lt;&amp;i32 as Debug&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r &amp;i32, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+7:14-7:30: @28.Call: _132 = ArgumentV1::new::&lt;&amp;i32&gt;(move _133, move _134) -&gt; [return: bb29, unwind: bb33]
+7:14-7:30: @29[4]: _136 = &amp;(*_131)
+7:14-7:30: @29[6]: _137 = &lt;&amp;i32 as Debug&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r &amp;i32, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+7:14-7:30: @29.Call: _135 = ArgumentV1::new::&lt;&amp;i32&gt;(move _136, move _137) -&gt; [return: bb30, unwind: bb33]
+7:14-7:30: @30[2]: _124 = [move _132, move _135]
+7:14-7:30: @30[7]: _123 = &amp;_124
+7:14-7:30: @30[8]: _122 = &amp;(*_123)
+7:14-7:30: @30[9]: _121 = move _122 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+7:14-7:30: @30.Call: _116 = Arguments::new_v1(move _117, move _121) -&gt; [return: bb31, unwind: bb33]
+7:14-7:30: @31.Call: core::panicking::panic_fmt(move _116) -&gt; bb33"><span class="annotation">@26,28,29,30,31⦊</span>assert_eq!(1, 2)<span class="annotation">⦉@26,28,29,30,31</span></span><span><span class="code even" style="--layer: 1" title="7:14-7:30: @27[0]: _0 = const ()"><span class="annotation">⦉@27</span></span></span><span class="code" style="--layer: 0">, // however this is not</span></span>
+<span class="line"><span class="code" style="--layer: 0">    }</span></span>
+<span class="line"><span class="code" style="--layer: 0">}</span><span><span class="code odd" style="--layer: 1" title="9:2-9:2: @32.Return: return"><span class="annotation">@32⦊</span>‸<span class="annotation">⦉@32</span></span></span></span></div>
+</body>
+</html>
index abf8df8fdc9e621132970f7cbde7608ac1d42916..d1824d189e38248b8d51973a80a103bae265bcbc 100644 (file)
@@ -1,3 +1,3 @@
-# Directory "instrument-coverage" supports the tests at prefix ../instrument-coverage-*
+# Directory "coverage" supports the tests at prefix ../coverage-*
 
-# Use ./x.py [options] test src/test/run-make-fulldeps/instrument-coverage to run all related tests.
+# Use ./x.py [options] test src/test/run-make-fulldeps/coverage to run all related tests.
index 7dc485cd94d66dc03f96cb76ce32fb7bbf328c17..4d340d4b1dadddb324f3b349ea0acb37207a68b2 100644 (file)
@@ -1,7 +1,7 @@
-# Common Makefile include for Rust `run-make-fulldeps/instrument-coverage-* tests. Include this
+# Common Makefile include for Rust `run-make-fulldeps/coverage-* tests. Include this
 # file with the line:
 #
-# -include ../instrument-coverage/coverage_tools.mk
+# -include ../coverage/coverage_tools.mk
 
 -include ../tools.mk
 
diff --git a/src/test/run-make-fulldeps/coverage/doctest.rs b/src/test/run-make-fulldeps/coverage/doctest.rs
new file mode 100644 (file)
index 0000000..e41d669
--- /dev/null
@@ -0,0 +1,66 @@
+//! This test ensures that code from doctests is properly re-mapped.
+//! See <https://github.com/rust-lang/rust/issues/79417> for more info.
+//!
+//! Just some random code:
+//! ```
+//! if true {
+//!     // this is executed!
+//!     assert_eq!(1, 1);
+//! } else {
+//!     // this is not!
+//!     assert_eq!(1, 2);
+//! }
+//! ```
+//!
+//! doctest testing external code:
+//! ```
+//! extern crate doctest_crate;
+//! doctest_crate::fn_run_in_doctests(1);
+//! ```
+//!
+//! doctest returning a result:
+//! ```
+//! #[derive(Debug)]
+//! struct SomeError;
+//! let mut res = Err(SomeError);
+//! if res.is_ok() {
+//!   res?;
+//! } else {
+//!   res = Ok(0);
+//! }
+//! // need to be explicit because rustdoc cant infer the return type
+//! Ok::<(), SomeError>(())
+//! ```
+//!
+//! doctest with custom main:
+//! ```
+//! #[derive(Debug)]
+//! struct SomeError;
+//!
+//! extern crate doctest_crate;
+//!
+//! fn doctest_main() -> Result<(), SomeError> {
+//!     doctest_crate::fn_run_in_doctests(2);
+//!     Ok(())
+//! }
+//!
+//! // this `main` is not shown as covered, as it clashes with all the other
+//! // `main` functions that were automatically generated for doctests
+//! fn main() -> Result<(), SomeError> {
+//!     doctest_main()
+//! }
+//! ```
+
+/// doctest attached to fn testing external code:
+/// ```
+/// extern crate doctest_crate;
+/// doctest_crate::fn_run_in_doctests(3);
+/// ```
+///
+fn main() {
+    if true {
+        assert_eq!(1, 1);
+    } else {
+        assert_eq!(1, 2);
+    }
+}
diff --git a/src/test/run-make-fulldeps/coverage/lib/doctest_crate.rs b/src/test/run-make-fulldeps/coverage/lib/doctest_crate.rs
new file mode 100644 (file)
index 0000000..c321014
--- /dev/null
@@ -0,0 +1,9 @@
+/// A function run only from within doctests
+pub fn fn_run_in_doctests(conditional: usize) {
+    match conditional {
+        1 => assert_eq!(1, 1), // this is run,
+        2 => assert_eq!(1, 1), // this,
+        3 => assert_eq!(1, 1), // and this too
+        _ => assert_eq!(1, 2), // however this is not
+    }
+}
index 03a797d95f98477f0fbf90ed99f5affcd94866dc..e7268311b1317edcbb7e99a26f776b14ec96f9ad 100644 (file)
@@ -1,9 +1,8 @@
 -include ../tools.mk
 
-# Modelled after compile-fail/changing-crates test, but this one puts
+# Modelled after ui/changing-crates.rs test, but this one puts
 # more than one (mismatching) candidate crate into the search path,
-# which did not appear directly expressible in compile-fail/aux-build
-# infrastructure.
+# which did not appear directly expressible in UI testing infrastructure.
 #
 # Note that we move the built libraries into target direcrtories rather than
 # use the `--out-dir` option because the `../tools.mk` file already bakes a
@@ -33,4 +32,4 @@ all:
                'crate `crateA`:' \
                'crate `crateB`:' \
                < $(LOG)
-       # the 'crate `crateA`' will match two entries.
\ No newline at end of file
+       # the 'crate `crateA`' will match two entries.
diff --git a/src/test/run-make-fulldeps/separate-link/Makefile b/src/test/run-make-fulldeps/separate-link/Makefile
new file mode 100644 (file)
index 0000000..060484e
--- /dev/null
@@ -0,0 +1,6 @@
+-include ../tools.mk
+
+all:
+       echo 'fn main(){}' | $(RUSTC) -Z no-link -
+       $(RUSTC) -Z link-only $(TMPDIR)/rust_out.rlink
+       $(call RUN,rust_out)
index 12898aa5c74b9ff7e4eb55836928bb23ada90476..71b38a9f8ca566474d5ea68f488ed29e574422c6 100644 (file)
@@ -5,7 +5,7 @@
 // causing a type mismatch.
 
 // The test is nearly the same as the one in
-// compile-fail/type-mismatch-same-crate-name.rs
+// ui/type/type-mismatch-same-crate-name.rs
 // but deals with the case where one of the crates
 // is only introduced as an indirect dependency.
 // and the type is accessed via a re-export.
index 97760cbf8fb5878ef000a36a5b2d13e1cd932081..ed62f0208aa54cbe4d848934d346b54c208c9003 100644 (file)
@@ -1,6 +1,5 @@
 // check-pass
 // edition:2018
-#![feature(min_const_generics)]
 trait ValidTrait {}
 
 /// This has docs
diff --git a/src/test/rustdoc-ui/intra-doc/non-path-primitives.rs b/src/test/rustdoc-ui/intra-doc/non-path-primitives.rs
new file mode 100644 (file)
index 0000000..114502b
--- /dev/null
@@ -0,0 +1,34 @@
+#![deny(broken_intra_doc_links)]
+// These are links that could reasonably expected to work, but don't.
+
+// `[]` isn't supported because it had too many false positives.
+//! [X]([T]::not_here)
+//! [Y](&[]::not_here)
+//! [X]([]::not_here)
+//! [Y]([T;N]::not_here)
+
+// These don't work because markdown syntax doesn't allow it.
+//! [[T]::rotate_left] //~ ERROR unresolved link to `T`
+//! [&[]::not_here]
+//![Z]([T; N]::map) //~ ERROR unresolved link to `Z`
+//! [`[T; N]::map`]
+//! [[]::map]
+//! [Z][] //~ ERROR unresolved link to `Z`
+//!
+//! [Z]: [T; N]::map //~ ERROR unresolved link to `Z`
+
+// `()` isn't supported because it had too many false positives.
+//! [()::not_here]
+//! [X]((,)::not_here)
+//! [(,)::not_here]
+
+// FIXME: Associated items on some primitives aren't working, because the impls
+// are part of the compiler instead of being part of the source code.
+//! [unit::eq] //~ ERROR unresolved
+//! [tuple::eq] //~ ERROR unresolved
+//! [fn::eq] //~ ERROR unresolved
+//! [never::eq] //~ ERROR unresolved
+
+// FIXME(#78800): This breaks because it's a blanket impl
+// (I think? Might break for other reasons too.)
+//! [reference::deref] //~ ERROR unresolved
diff --git a/src/test/rustdoc-ui/intra-doc/non-path-primitives.stderr b/src/test/rustdoc-ui/intra-doc/non-path-primitives.stderr
new file mode 100644 (file)
index 0000000..ea831e6
--- /dev/null
@@ -0,0 +1,69 @@
+error: unresolved link to `T`
+  --> $DIR/non-path-primitives.rs:11:7
+   |
+LL | //! [[T]::rotate_left]
+   |       ^ no item named `T` in scope
+   |
+note: the lint level is defined here
+  --> $DIR/non-path-primitives.rs:1:9
+   |
+LL | #![deny(broken_intra_doc_links)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^
+   = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
+
+error: unresolved link to `Z`
+  --> $DIR/non-path-primitives.rs:13:5
+   |
+LL | //![Z]([T; N]::map)
+   |     ^ no item named `Z` in scope
+   |
+   = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
+
+error: unresolved link to `Z`
+  --> $DIR/non-path-primitives.rs:16:6
+   |
+LL | //! [Z][]
+   |      ^ no item named `Z` in scope
+   |
+   = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
+
+error: unresolved link to `Z`
+  --> $DIR/non-path-primitives.rs:18:6
+   |
+LL | //! [Z]: [T; N]::map
+   |      ^ no item named `Z` in scope
+   |
+   = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
+
+error: unresolved link to `unit::eq`
+  --> $DIR/non-path-primitives.rs:27:6
+   |
+LL | //! [unit::eq]
+   |      ^^^^^^^^ the builtin type `unit` has no associated item named `eq`
+
+error: unresolved link to `tuple::eq`
+  --> $DIR/non-path-primitives.rs:28:6
+   |
+LL | //! [tuple::eq]
+   |      ^^^^^^^^^ the builtin type `tuple` has no associated item named `eq`
+
+error: unresolved link to `fn::eq`
+  --> $DIR/non-path-primitives.rs:29:6
+   |
+LL | //! [fn::eq]
+   |      ^^^^^^ the builtin type `fn` has no associated item named `eq`
+
+error: unresolved link to `never::eq`
+  --> $DIR/non-path-primitives.rs:30:6
+   |
+LL | //! [never::eq]
+   |      ^^^^^^^^^ the builtin type `never` has no associated item named `eq`
+
+error: unresolved link to `reference::deref`
+  --> $DIR/non-path-primitives.rs:34:6
+   |
+LL | //! [reference::deref]
+   |      ^^^^^^^^^^^^^^^^ the builtin type `reference` has no associated item named `deref`
+
+error: aborting due to 9 previous errors
+
diff --git a/src/test/rustdoc-ui/reference-link-has-one-warning.rs b/src/test/rustdoc-ui/reference-link-has-one-warning.rs
deleted file mode 100644 (file)
index 21cb7eb..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-// ignore-test
-// check-pass
-
-/// docs [label][with#anchor#error]
-//~^ WARNING has an issue with the link anchor
-pub struct S;
diff --git a/src/test/rustdoc-ui/reference-link-has-one-warning.stderr b/src/test/rustdoc-ui/reference-link-has-one-warning.stderr
deleted file mode 100644 (file)
index a1eeb60..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-warning: `[with#anchor#error]` has an issue with the link anchor.
-  --> $DIR/reference-link-has-one-warning.rs:3:18
-   |
-LL | /// docs [label][with#anchor#error]
-   |                  ^^^^^^^^^^^^^^^^^ only one `#` is allowed in a link
-   |
-   = note: `#[warn(broken_intra_doc_links)]` on by default
-
-warning: 1 warning emitted
-
diff --git a/src/test/rustdoc-ui/reference-links.rs b/src/test/rustdoc-ui/reference-links.rs
new file mode 100644 (file)
index 0000000..7c1a797
--- /dev/null
@@ -0,0 +1,7 @@
+// Test that errors point to the reference, not to the title text.
+#![deny(broken_intra_doc_links)]
+//! Links to [a] [link][a]
+//!
+//! [a]: std::process::Comman
+//~^ ERROR unresolved
+//~| ERROR unresolved
diff --git a/src/test/rustdoc-ui/reference-links.stderr b/src/test/rustdoc-ui/reference-links.stderr
new file mode 100644 (file)
index 0000000..6ba73fb
--- /dev/null
@@ -0,0 +1,20 @@
+error: unresolved link to `std::process::Comman`
+  --> $DIR/reference-links.rs:5:10
+   |
+LL | //! [a]: std::process::Comman
+   |          ^^^^^^^^^^^^^^^^^^^^ no item named `Comman` in module `process`
+   |
+note: the lint level is defined here
+  --> $DIR/reference-links.rs:2:9
+   |
+LL | #![deny(broken_intra_doc_links)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^
+
+error: unresolved link to `std::process::Comman`
+  --> $DIR/reference-links.rs:5:10
+   |
+LL | //! [a]: std::process::Comman
+   |          ^^^^^^^^^^^^^^^^^^^^ no item named `Comman` in module `process`
+
+error: aborting due to 2 previous errors
+
index e7a7d1831f73efbef707ef40b05e0671b4d0b30f..aa4ad261c80ff54d657c0336aa14e83ab6689d98 100644 (file)
@@ -1,6 +1,5 @@
+// ignore-tidy-linelength
 // edition:2018
-#![feature(min_const_generics)]
-
 // @has async_fn/fn.foo.html '//pre[@class="rust fn"]' 'pub async fn foo() -> Option<Foo>'
 pub async fn foo() -> Option<Foo> {
     None
@@ -48,7 +47,50 @@ pub async fn f() {}
     pub async fn mut_self(mut self, mut first: usize) {}
 }
 
+pub trait Pattern<'a> {}
+
 pub trait Trait<const N: usize> {}
 // @has async_fn/fn.const_generics.html
 // @has - '//pre[@class="rust fn"]' 'pub async fn const_generics<const N: usize>(_: impl Trait<N>)'
 pub async fn const_generics<const N: usize>(_: impl Trait<N>) {}
+
+// test that elided lifetimes are properly elided and not displayed as `'_`
+// regression test for #63037
+// @has async_fn/fn.elided.html
+// @has - '//pre[@class="rust fn"]' 'pub async fn elided(foo: &str) -> &str'
+pub async fn elided(foo: &str) -> &str {}
+// This should really be shown as written, but for implementation reasons it's difficult.
+// See `impl Clean for TyKind::Rptr`.
+// @has async_fn/fn.user_elided.html
+// @has - '//pre[@class="rust fn"]' 'pub async fn user_elided(foo: &str) -> &str'
+pub async fn user_elided(foo: &'_ str) -> &str {}
+// @has async_fn/fn.static_trait.html
+// @has - '//pre[@class="rust fn"]' 'pub async fn static_trait(foo: &str) -> Box<dyn Bar>'
+pub async fn static_trait(foo: &str) -> Box<dyn Bar> {}
+// @has async_fn/fn.lifetime_for_trait.html
+// @has - '//pre[@class="rust fn"]' "pub async fn lifetime_for_trait(foo: &str) -> Box<dyn Bar + '_>"
+pub async fn lifetime_for_trait(foo: &str) -> Box<dyn Bar + '_> {}
+// @has async_fn/fn.elided_in_input_trait.html
+// @has - '//pre[@class="rust fn"]' "pub async fn elided_in_input_trait(t: impl Pattern<'_>)"
+pub async fn elided_in_input_trait(t: impl Pattern<'_>) {}
+
+struct AsyncFdReadyGuard<'a, T> { x: &'a T }
+
+impl Foo {
+    // @has async_fn/struct.Foo.html
+    // @has - '//h4[@class="method"]' 'pub async fn complicated_lifetimes( &self, context: &impl Bar) -> impl Iterator<Item = &usize>'
+    pub async fn complicated_lifetimes(&self, context: &impl Bar) -> impl Iterator<Item = &usize> {}
+    // taken from `tokio` as an example of a method that was particularly bad before
+    // @has - '//h4[@class="method"]' "pub async fn readable<T>(&self) -> Result<AsyncFdReadyGuard<'_, T>, ()>"
+    pub async fn readable<T>(&self) -> Result<AsyncFdReadyGuard<'_, T>, ()> {}
+    // @has - '//h4[@class="method"]' "pub async fn mut_self(&mut self)"
+    pub async fn mut_self(&mut self) {}
+}
+
+// test named lifetimes, just in case
+// @has async_fn/fn.named.html
+// @has - '//pre[@class="rust fn"]' "pub async fn named<'a, 'b>(foo: &'a str) -> &'b str"
+pub async fn named<'a, 'b>(foo: &'a str) -> &'b str {}
+// @has async_fn/fn.named_trait.html
+// @has - '//pre[@class="rust fn"]' "pub async fn named_trait<'a, 'b>(foo: impl Pattern<'a>) -> impl Pattern<'b>"
+pub async fn named_trait<'a, 'b>(foo: impl Pattern<'a>) -> impl Pattern<'b> {}
index b59b21111b009740350b5f5db4a6a1d941a3a231..140c5b3a67203cd3016de0d23e3e0f30a491e6d0 100644 (file)
@@ -1,10 +1,9 @@
 #![crate_name = "foo"]
 
-// ignore-tidy-linelength
-
-// @has foo/fn.bar.html '//*[@class="tooltip compile_fail"]/span' "This example deliberately fails to compile"
-// @has foo/fn.bar.html '//*[@class="tooltip ignore"]/span' "This example is not tested"
-// @has foo/fn.bar.html '//*[@class="tooltip should_panic"]/span' "This example panics"
+// @has foo/fn.bar.html '//*[@class="tooltip compile_fail"]' "ⓘ"
+// @has foo/fn.bar.html '//*[@class="tooltip ignore"]' "ⓘ"
+// @has foo/fn.bar.html '//*[@class="tooltip should_panic"]' "ⓘ"
+// @has foo/fn.bar.html '//*[@data-edition="2018"]' "ⓘ"
 
 /// foo
 ///
@@ -20,7 +19,7 @@
 /// hoo();
 /// ```
 ///
-/// ```
+/// ```edition2018
 /// let x = 0;
 /// ```
 pub fn bar() -> usize { 2 }
index b8bd040f7a4b2feb62e241db0858e7af4209ac61..55b632a48f2e5e4687196ef13bdd6cbb71700bc4 100644 (file)
@@ -1,6 +1,4 @@
 // edition:2018
-#![feature(min_const_generics)]
-
 pub fn extern_fn<const N: usize>() -> impl Iterator<Item = [u8; N]> {
     [[0; N]; N].iter().copied()
 }
index 9c68e067c6f8ffda550c9faba2dd8d5b04c398d9..21bf216c304416816ac9ae790d0c200e2ba3c3ab 100644 (file)
@@ -1,6 +1,5 @@
 // edition:2018
 // aux-build: extern_crate.rs
-#![feature(min_const_generics)]
 #![crate_name = "foo"]
 
 extern crate extern_crate;
index 3064d0701e3006afa1c59725ef04013dc24f437b..85160dc07a7aa15e9c9222c0c0756c73220d0418 100644 (file)
@@ -1,5 +1,4 @@
 // ignore-tidy-linelength
-#![feature(min_const_generics)]
 #![crate_name = "foo"]
 
 // @has foo/type.CellIndex.html '//pre[@class="rust typedef"]' 'type CellIndex<const D: usize> = [i64; D];'
diff --git a/src/test/rustdoc/intra-doc/non-path-primitives.rs b/src/test/rustdoc/intra-doc/non-path-primitives.rs
new file mode 100644 (file)
index 0000000..ad4f6dd
--- /dev/null
@@ -0,0 +1,39 @@
+// ignore-tidy-linelength
+#![crate_name = "foo"]
+#![deny(broken_intra_doc_links)]
+
+// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.slice.html#method.rotate_left"]' 'slice::rotate_left'
+//! [slice::rotate_left]
+
+// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.array.html#method.map"]' 'array::map'
+//! [array::map]
+
+// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.pointer.html#method.is_null"]' 'pointer::is_null'
+// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.pointer.html#method.is_null"]' '*const::is_null'
+// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.pointer.html#method.is_null"]' '*mut::is_null'
+// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.pointer.html#method.is_null"]' '*::is_null'
+//! [pointer::is_null]
+//! [*const::is_null]
+//! [*mut::is_null]
+//! [*::is_null]
+
+// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.unit.html"]' 'unit'
+//! [unit]
+
+// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.tuple.html"]' 'tuple'
+//! [tuple]
+
+// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.reference.html"]' 'reference'
+// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.reference.html"]' '&'
+// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.reference.html"]' '&mut'
+//! [reference]
+//! [&]
+//! [&mut]
+
+// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.fn.html"]' 'fn'
+//! [fn]
+
+// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.never.html"]' 'never'
+// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.never.html"]' '!'
+//! [never]
+//! [!]
index fabcd727482dcba1e7683c668216e541bd908ec4..cc97971a0ddb78fa598c32651834a049e2ecf0a5 100644 (file)
@@ -1,8 +1,8 @@
 // Reject mixing cyclic structure and Drop when using TypedArena.
 //
-// (Compare against compile-fail/dropck_vec_cycle_checked.rs)
+// (Compare against dropck-vec-cycle-checked.rs)
 //
-// (Also compare against compile-fail/dropck_tarena_unsound_drop.rs,
+// (Also compare against ui-fulldeps/dropck-tarena-unsound-drop.rs,
 //  which is a reduction of this code to more directly show the reason
 //  for the error message we see here.)
 
index c5b9efee8e73040625a122c8704227bcda5f90f0..187f9a24a9075fff3ca5db4e7a1270bb38e2bb84 100644 (file)
@@ -5,7 +5,7 @@
 // methods might access borrowed data, as long as the borrowed data
 // has lifetime that strictly outlives the arena itself.
 //
-// Compare against compile-fail/dropck_tarena_unsound_drop.rs, which
+// Compare against ui-fulldeps/dropck-tarena-unsound-drop.rs, which
 // shows a similar setup, but restricts `f` so that the struct `C<'a>`
 // is force-fed a lifetime equal to that of the borrowed arena.
 
index d485893281562a24dd2701122486e8176d5452e0..c8559d247282430981f82a7cdf39552f1b59792b 100644 (file)
@@ -17,7 +17,12 @@ impl Drop for D {
     fn drop(&mut self) {
         println!("Dropping {}", self.0);
         let old = LOG.load(Ordering::SeqCst);
-        LOG.compare_and_swap(old, old << 4 | self.0 as usize, Ordering::SeqCst);
+        let _ = LOG.compare_exchange(
+            old,
+            old << 4 | self.0 as usize,
+            Ordering::SeqCst,
+            Ordering::SeqCst
+        );
     }
 }
 
index e8a5b00a55b9cf600b2789550e79f108a1928184..e75051caabcc32a69eccd57c3b66faa76c66bf51 100644 (file)
@@ -17,7 +17,12 @@ impl Drop for D {
     fn drop(&mut self) {
         println!("Dropping {}", self.0);
         let old = LOG.load(Ordering::SeqCst);
-        LOG.compare_and_swap(old, old << 4 | self.0 as usize, Ordering::SeqCst);
+        let _ = LOG.compare_exchange(
+            old,
+            old << 4 | self.0 as usize,
+            Ordering::SeqCst,
+            Ordering::SeqCst
+        );
     }
 }
 
index e64985ae3f69d5d1937459c95d474f59920974ef..c6d311148d07e4f844b78efea2b7ca922d6cf3e7 100644 (file)
@@ -2,7 +2,7 @@
 
 // Ensure that we can copy out of a fixed-size array.
 //
-// (Compare with compile-fail/move-out-of-array-1.rs)
+// (Compare with ui/moves/move-out-of-array-1.rs)
 
 #[derive(Copy, Clone)]
 struct C { _x: u8 }
index 7c1a92c79d973f297e5f690e6215f25daf90016d..0ad05b3adeb88faf45c31ec42b49a4770c0c5ce0 100644 (file)
@@ -6,7 +6,6 @@ LL | #![feature(const_generics)]
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-   = help: consider using `min_const_generics` instead, which is more stable and complete
 
 error[E0308]: mismatched types
   --> $DIR/match_arr_unknown_len.rs:6:9
index 52b892dbcdfaf8e2ceff89c433ed1841b24f5dfc..96497a53d308e4d66f36d1e4757e389e82b3e05a 100644 (file)
@@ -18,7 +18,12 @@ impl Drop for D {
     fn drop(&mut self) {
         println!("Dropping {}", self.0);
         let old = LOG.load(Ordering::SeqCst);
-        LOG.compare_and_swap(old, old << 4 | self.0 as usize, Ordering::SeqCst);
+        let _ = LOG.compare_exchange(
+            old,
+            old << 4 | self.0 as usize,
+            Ordering::SeqCst,
+            Ordering::SeqCst,
+        );
     }
 }
 
index d51821059fc1391cfbc9591ae8287ae0cd725cfc..5152d784047a52658e4568be40cbd32c801cdffb 100644 (file)
@@ -14,8 +14,7 @@ impl Foo for Def {
 
 pub fn test<A: Foo, B: Foo>() {
     let _array: [u32; <A as Foo>::Y];
-    //~^ ERROR the trait bound `A: Foo` is not satisfied [E0277]
+    //~^ ERROR generic parameters may not be used
 }
 
-fn main() {
-}
+fn main() {}
index ac40e390cfbbd50bce084ffe4a0422b1fda74bd2..d3a1cd30e2be60512ea5dd8a78efa8bfa8573216 100644 (file)
@@ -1,17 +1,11 @@
-error[E0277]: the trait bound `A: Foo` is not satisfied
-  --> $DIR/associated-const-type-parameter-arrays.rs:16:23
+error: generic parameters may not be used in const operations
+  --> $DIR/associated-const-type-parameter-arrays.rs:16:24
    |
-LL |     const Y: usize;
-   |     --------------- required by `Foo::Y`
-...
 LL |     let _array: [u32; <A as Foo>::Y];
-   |                       ^^^^^^^^^^^^^ the trait `Foo` is not implemented for `A`
+   |                        ^ cannot perform const operation using `A`
    |
-help: consider further restricting this bound
-   |
-LL | pub fn test<A: Foo + Foo, B: Foo>() {
-   |                    ^^^^^
+   = note: type parameters may not be used in const expressions
+   = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0277`.
index bec922b0721b978cae319d2b0d0962e94e79e057..242a02353a101325aaa7a0c83771aff97b7dccfb 100644 (file)
@@ -5,7 +5,7 @@ trait Adapter {
 struct Foo<A: Adapter> {
     adapter: A,
     links: [u32; A::LINKS], // Shouldn't suggest bounds already there.
-    //~^ ERROR: no associated item named `LINKS` found
+    //~^ ERROR generic parameters may not be used in const operations
 }
 
 fn main() {}
index ff1ad4c006e786e569f5e52b4d77b7d1146b7c11..0d84dca5b8099dd28252c8fc0444d06a614a32f0 100644 (file)
@@ -1,11 +1,11 @@
-error[E0599]: no associated item named `LINKS` found for type parameter `A` in the current scope
-  --> $DIR/associated-item-duplicate-bounds.rs:7:21
+error: generic parameters may not be used in const operations
+  --> $DIR/associated-item-duplicate-bounds.rs:7:18
    |
 LL |     links: [u32; A::LINKS], // Shouldn't suggest bounds already there.
-   |                     ^^^^^ associated item not found in `A`
+   |                  ^^^^^^^^ cannot perform const operation using `A`
    |
-   = help: items from traits can only be used if the type parameter is bounded by the trait
+   = note: type parameters may not be used in const expressions
+   = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0599`.
index 5f06a829600af416ff60717d0887242441525049..3b8c8c019e50b2274ea3798f3e6083b761c87592 100644 (file)
@@ -3,7 +3,7 @@
 // the trait definition if there is no default method and for every impl,
 // `Self` does implement `Get`.
 //
-// See also compile-fail tests associated-types-no-suitable-supertrait
+// See also tests associated-types-no-suitable-supertrait
 // and associated-types-no-suitable-supertrait-2, which show how small
 // variants of the code below can fail.
 
index afb2b3df716ebda7e0b2828b9518dcfcbae60a06..61ef013236e8d2bf63328221c0d45b3c9b21614c 100644 (file)
@@ -24,13 +24,13 @@ impl Tr for u32 {
 // ...but not in an impl that redefines one of the types.
 impl Tr for bool {
     type A = Box<Self::B>;
-    //~^ ERROR type mismatch resolving `<bool as Tr>::B == _`
+    //~^ ERROR overflow evaluating the requirement `<bool as Tr>::B == _`
 }
 // (the error is shown twice for some reason)
 
 impl Tr for usize {
     type B = &'static Self::A;
-    //~^ ERROR type mismatch resolving `<usize as Tr>::A == _`
+    //~^ ERROR overflow evaluating the requirement `<usize as Tr>::A == _`
 }
 
 fn main() {
index ae7150d47ca999e0921b6efc688d8109a3b96bd8..5e98520b41187a5c9261e03603184c1022ecdbcf 100644 (file)
@@ -1,15 +1,15 @@
-error[E0271]: type mismatch resolving `<bool as Tr>::B == _`
+error[E0275]: overflow evaluating the requirement `<bool as Tr>::B == _`
   --> $DIR/defaults-cyclic-fail-1.rs:26:5
    |
 LL |     type A = Box<Self::B>;
-   |     ^^^^^^^^^^^^^^^^^^^^^^ cyclic type of infinite size
+   |     ^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0271]: type mismatch resolving `<usize as Tr>::A == _`
+error[E0275]: overflow evaluating the requirement `<usize as Tr>::A == _`
   --> $DIR/defaults-cyclic-fail-1.rs:32:5
    |
 LL |     type B = &'static Self::A;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ cyclic type of infinite size
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0271`.
+For more information about this error, try `rustc --explain E0275`.
index ba4bb0d5a296bbc7fed770e052082ab0d3f4440c..e91c9f2d29a8215e785dea0147b251edcadb4e13 100644 (file)
@@ -25,13 +25,13 @@ impl Tr for u32 {
 
 impl Tr for bool {
     type A = Box<Self::B>;
-    //~^ ERROR type mismatch resolving `<bool as Tr>::B == _`
+    //~^ ERROR overflow evaluating the requirement `<bool as Tr>::B == _`
 }
 // (the error is shown twice for some reason)
 
 impl Tr for usize {
     type B = &'static Self::A;
-    //~^ ERROR type mismatch resolving `<usize as Tr>::A == _`
+    //~^ ERROR overflow evaluating the requirement `<usize as Tr>::A == _`
 }
 
 fn main() {
index 0dfbac2dec5d5d4a0576e43708b029409413b0db..c538805f858219dbccb8bdc34a4b4b5bd4d06f4e 100644 (file)
@@ -1,15 +1,15 @@
-error[E0271]: type mismatch resolving `<bool as Tr>::B == _`
+error[E0275]: overflow evaluating the requirement `<bool as Tr>::B == _`
   --> $DIR/defaults-cyclic-fail-2.rs:27:5
    |
 LL |     type A = Box<Self::B>;
-   |     ^^^^^^^^^^^^^^^^^^^^^^ cyclic type of infinite size
+   |     ^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0271]: type mismatch resolving `<usize as Tr>::A == _`
+error[E0275]: overflow evaluating the requirement `<usize as Tr>::A == _`
   --> $DIR/defaults-cyclic-fail-2.rs:33:5
    |
 LL |     type B = &'static Self::A;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ cyclic type of infinite size
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0271`.
+For more information about this error, try `rustc --explain E0275`.
index 4c43e6a182dc91d96be6f1c4674f0f3040713690..d4fa5be742ff3486dab53e8773b600c9fa3f410b 100644 (file)
@@ -4,7 +4,7 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation
 LL |     type Ty = Vec<[u8]>;
    |     ^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    | 
-  ::: $SRC_DIR/alloc/src/vec.rs:LL:COL
+  ::: $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
    |
 LL | pub struct Vec<T, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global> {
    |                - required by this bound in `Vec`
diff --git a/src/test/ui/associated-types/impl-wf-cycle-1.rs b/src/test/ui/associated-types/impl-wf-cycle-1.rs
new file mode 100644 (file)
index 0000000..ba07421
--- /dev/null
@@ -0,0 +1,29 @@
+// Regression test for #79714
+
+trait Baz {}
+impl Baz for () {}
+impl<T> Baz for (T,) {}
+
+trait Fiz {}
+impl Fiz for bool {}
+
+trait Grault {
+    type A;
+    type B;
+}
+
+impl<T: Grault> Grault for (T,)
+where
+    Self::A: Baz,
+    Self::B: Fiz,
+{
+    type A = ();
+    //~^ ERROR overflow evaluating the requirement `<(T,) as Grault>::A == _`
+    type B = bool;
+    //~^ ERROR overflow evaluating the requirement `<(T,) as Grault>::A == _`
+}
+//~^^^^^^^^^^ ERROR overflow evaluating the requirement `<(T,) as Grault>::A == _`
+
+fn main() {
+    let x: <(_,) as Grault>::A = ();
+}
diff --git a/src/test/ui/associated-types/impl-wf-cycle-1.stderr b/src/test/ui/associated-types/impl-wf-cycle-1.stderr
new file mode 100644 (file)
index 0000000..8232804
--- /dev/null
@@ -0,0 +1,39 @@
+error[E0275]: overflow evaluating the requirement `<(T,) as Grault>::A == _`
+  --> $DIR/impl-wf-cycle-1.rs:15:1
+   |
+LL | / impl<T: Grault> Grault for (T,)
+LL | | where
+LL | |     Self::A: Baz,
+LL | |     Self::B: Fiz,
+...  |
+LL | |
+LL | | }
+   | |_^
+   |
+   = note: required because of the requirements on the impl of `Grault` for `(T,)`
+   = note: 1 redundant requirements hidden
+   = note: required because of the requirements on the impl of `Grault` for `(T,)`
+
+error[E0275]: overflow evaluating the requirement `<(T,) as Grault>::A == _`
+  --> $DIR/impl-wf-cycle-1.rs:20:5
+   |
+LL |     type A = ();
+   |     ^^^^^^^^^^^^
+   |
+   = note: required because of the requirements on the impl of `Grault` for `(T,)`
+   = note: 1 redundant requirements hidden
+   = note: required because of the requirements on the impl of `Grault` for `(T,)`
+
+error[E0275]: overflow evaluating the requirement `<(T,) as Grault>::A == _`
+  --> $DIR/impl-wf-cycle-1.rs:22:5
+   |
+LL |     type B = bool;
+   |     ^^^^^^^^^^^^^^
+   |
+   = note: required because of the requirements on the impl of `Grault` for `(T,)`
+   = note: 1 redundant requirements hidden
+   = note: required because of the requirements on the impl of `Grault` for `(T,)`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0275`.
diff --git a/src/test/ui/associated-types/impl-wf-cycle-2.rs b/src/test/ui/associated-types/impl-wf-cycle-2.rs
new file mode 100644 (file)
index 0000000..6fccc54
--- /dev/null
@@ -0,0 +1,16 @@
+// Regression test for #79714
+
+trait Grault {
+    type A;
+}
+
+impl<T: Grault> Grault for (T,)
+where
+    Self::A: Copy,
+{
+    type A = ();
+    //~^ ERROR overflow evaluating the requirement `<(T,) as Grault>::A == _`
+}
+//~^^^^^^^ ERROR overflow evaluating the requirement `<(T,) as Grault>::A == _`
+
+fn main() {}
diff --git a/src/test/ui/associated-types/impl-wf-cycle-2.stderr b/src/test/ui/associated-types/impl-wf-cycle-2.stderr
new file mode 100644 (file)
index 0000000..5cd18a3
--- /dev/null
@@ -0,0 +1,25 @@
+error[E0275]: overflow evaluating the requirement `<(T,) as Grault>::A == _`
+  --> $DIR/impl-wf-cycle-2.rs:7:1
+   |
+LL | / impl<T: Grault> Grault for (T,)
+LL | | where
+LL | |     Self::A: Copy,
+LL | | {
+LL | |     type A = ();
+LL | |
+LL | | }
+   | |_^
+   |
+   = note: required because of the requirements on the impl of `Grault` for `(T,)`
+
+error[E0275]: overflow evaluating the requirement `<(T,) as Grault>::A == _`
+  --> $DIR/impl-wf-cycle-2.rs:11:5
+   |
+LL |     type A = ();
+   |     ^^^^^^^^^^^^
+   |
+   = note: required because of the requirements on the impl of `Grault` for `(T,)`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0275`.
diff --git a/src/test/ui/associated-types/issue-23595-1.rs b/src/test/ui/associated-types/issue-23595-1.rs
new file mode 100644 (file)
index 0000000..483c205
--- /dev/null
@@ -0,0 +1,14 @@
+#![feature(associated_type_defaults)]
+
+use std::ops::Index;
+
+trait Hierarchy {
+    type Value;
+    type ChildKey;
+    type Children = dyn Index<Self::ChildKey, Output=dyn Hierarchy>;
+    //~^ ERROR: the value of the associated types
+
+    fn data(&self) -> Option<(Self::Value, Self::Children)>;
+}
+
+fn main() {}
diff --git a/src/test/ui/associated-types/issue-23595-1.stderr b/src/test/ui/associated-types/issue-23595-1.stderr
new file mode 100644 (file)
index 0000000..bb45568
--- /dev/null
@@ -0,0 +1,16 @@
+error[E0191]: the value of the associated types `ChildKey` (from trait `Hierarchy`), `Children` (from trait `Hierarchy`), `Value` (from trait `Hierarchy`) must be specified
+  --> $DIR/issue-23595-1.rs:8:58
+   |
+LL |     type Value;
+   |     ----------- `Value` defined here
+LL |     type ChildKey;
+   |     -------------- `ChildKey` defined here
+LL |     type Children = dyn Index<Self::ChildKey, Output=dyn Hierarchy>;
+   |     -----------------------------------------------------^^^^^^^^^--
+   |     |                                                    |
+   |     |                                                    help: specify the associated types: `Hierarchy<Value = Type, ChildKey = Type, Children = Type>`
+   |     `Children` defined here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0191`.
diff --git a/src/test/ui/associated-types/issue-27675-unchecked-bounds.rs b/src/test/ui/associated-types/issue-27675-unchecked-bounds.rs
new file mode 100644 (file)
index 0000000..1cfc230
--- /dev/null
@@ -0,0 +1,19 @@
+/// The compiler previously did not properly check the bound of `From` when it was used from type
+/// of the dyn trait object (use in `copy_any` below). Since the associated type is under user
+/// control in this usage, the compiler could be tricked to believe any type implemented any trait.
+/// This would ICE, except for pure marker traits like `Copy`. It did not require providing an
+/// instance of the dyn trait type, only name said type.
+trait Setup {
+    type From: Copy;
+}
+
+fn copy<U: Setup + ?Sized>(from: &U::From) -> U::From {
+    *from
+}
+
+pub fn copy_any<T>(t: &T) -> T {
+    copy::<dyn Setup<From=T>>(t)
+    //~^ ERROR the trait bound `T: Copy` is not satisfied
+}
+
+fn main() {}
diff --git a/src/test/ui/associated-types/issue-27675-unchecked-bounds.stderr b/src/test/ui/associated-types/issue-27675-unchecked-bounds.stderr
new file mode 100644 (file)
index 0000000..02396bd
--- /dev/null
@@ -0,0 +1,17 @@
+error[E0277]: the trait bound `T: Copy` is not satisfied
+  --> $DIR/issue-27675-unchecked-bounds.rs:15:31
+   |
+LL | fn copy<U: Setup + ?Sized>(from: &U::From) -> U::From {
+   |            ----- required by this bound in `copy`
+...
+LL |     copy::<dyn Setup<From=T>>(t)
+   |                               ^ the trait `Copy` is not implemented for `T`
+   |
+help: consider restricting type parameter `T`
+   |
+LL | pub fn copy_any<T: Copy>(t: &T) -> T {
+   |                  ^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
index ff0260523db3b6665fdf283bd39c2e1b347ff646..a9208ade74068f3789206a5bc947a3f5aaf1f246 100644 (file)
@@ -1,11 +1,11 @@
 error[E0573]: expected type, found built-in attribute `feature`
-  --> $DIR/issue-78654.rs:10:15
+  --> $DIR/issue-78654.rs:9:15
    |
 LL | impl<const H: feature> Foo {
    |               ^^^^^^^ not a type
 
 error[E0207]: the const parameter `H` is not constrained by the impl trait, self type, or predicates
-  --> $DIR/issue-78654.rs:10:12
+  --> $DIR/issue-78654.rs:9:12
    |
 LL | impl<const H: feature> Foo {
    |            ^ unconstrained const parameter
index ff0260523db3b6665fdf283bd39c2e1b347ff646..a9208ade74068f3789206a5bc947a3f5aaf1f246 100644 (file)
@@ -1,11 +1,11 @@
 error[E0573]: expected type, found built-in attribute `feature`
-  --> $DIR/issue-78654.rs:10:15
+  --> $DIR/issue-78654.rs:9:15
    |
 LL | impl<const H: feature> Foo {
    |               ^^^^^^^ not a type
 
 error[E0207]: the const parameter `H` is not constrained by the impl trait, self type, or predicates
-  --> $DIR/issue-78654.rs:10:12
+  --> $DIR/issue-78654.rs:9:12
    |
 LL | impl<const H: feature> Foo {
    |            ^ unconstrained const parameter
index b57ed35f8e369c69b2cfe491bf8ad5801c26fe70..37ebb4ecac8b8db31211c58411b9fd5febe1129b 100644 (file)
@@ -3,7 +3,6 @@
 
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 struct Foo;
 
index 60a5bb9f7866694c691577de408f469102de7e41..260d78b543a4ca53a791f8b8f90c1d40ecd2289d 100644 (file)
@@ -15,7 +15,7 @@ error[E0277]: the size for values of type `dyn Trait` cannot be known at compila
 LL |     let x: Vec<dyn Trait + Sized> = Vec::new();
    |            ^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    | 
-  ::: $SRC_DIR/alloc/src/vec.rs:LL:COL
+  ::: $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
    |
 LL | pub struct Vec<T, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global> {
    |                - required by this bound in `Vec`
diff --git a/src/test/ui/binding/const-param.full.stderr b/src/test/ui/binding/const-param.full.stderr
new file mode 100644 (file)
index 0000000..0200c6d
--- /dev/null
@@ -0,0 +1,9 @@
+error[E0158]: const parameters cannot be referenced in patterns
+  --> $DIR/const-param.rs:8:9
+   |
+LL |         N => {}
+   |         ^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0158`.
diff --git a/src/test/ui/binding/const-param.min.stderr b/src/test/ui/binding/const-param.min.stderr
new file mode 100644 (file)
index 0000000..0200c6d
--- /dev/null
@@ -0,0 +1,9 @@
+error[E0158]: const parameters cannot be referenced in patterns
+  --> $DIR/const-param.rs:8:9
+   |
+LL |         N => {}
+   |         ^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0158`.
index 3c7f4d071f6945bec39a26998f92b697b0843c08..4aec801cb1552df3eec4b18eae7ba7954bca843d 100644 (file)
@@ -1,6 +1,7 @@
 // Identifier pattern referring to a const generic parameter is an error (issue #68853).
-
-#![feature(const_generics)] //~ WARN the feature `const_generics` is incomplete
+// revisions: full min
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
 
 fn check<const N: usize>() {
     match 1 {
diff --git a/src/test/ui/binding/const-param.stderr b/src/test/ui/binding/const-param.stderr
deleted file mode 100644 (file)
index d3d06a2..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/const-param.rs:3:12
-   |
-LL | #![feature(const_generics)]
-   |            ^^^^^^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-   = help: consider using `min_const_generics` instead, which is more stable and complete
-
-error[E0158]: const parameters cannot be referenced in patterns
-  --> $DIR/const-param.rs:7:9
-   |
-LL |         N => {}
-   |         ^
-
-error: aborting due to previous error; 1 warning emitted
-
-For more information about this error, try `rustc --explain E0158`.
index ca1496a6c8d9b6781357a32ee267ec7e2a52e038..a4090777939029b5b725667642285ed116a04e48 100644 (file)
@@ -23,7 +23,7 @@ error[E0499]: cannot borrow `x` as mutable more than once at a time
   --> $DIR/borrowck-mut-borrow-linear-errors.rs:12:30
    |
 LL |             _ => { addr.push(&mut x); }
-   |                              ^^^^^^ mutable borrow starts here in previous iteration of loop
+   |                              ^^^^^^ `x` was mutably borrowed here in the previous iteration of the loop
 
 error: aborting due to 3 previous errors
 
index 260b9673d74baf019213d1aaf63ecbdb8540561a..b621694a548cfa3619b3e21dbc7766f924a67465 100644 (file)
@@ -15,7 +15,7 @@ LL | impl<'a, T : 'a> FuncWrapper<'a, T> {
 LL |             (self.func)(arg)
    |             ------------^^^-
    |             |           |
-   |             |           mutable borrow starts here in previous iteration of loop
+   |             |           `*arg` was mutably borrowed here in the previous iteration of the loop
    |             argument requires that `*arg` is borrowed for `'a`
 
 error[E0499]: cannot borrow `*arg` as mutable more than once at a time
@@ -27,7 +27,7 @@ LL | impl<'a, T : 'a> FuncWrapper<'a, T> {
 LL |             (self.func)(arg)
    |             ------------^^^-
    |             |           |
-   |             |           mutable borrow starts here in previous iteration of loop
+   |             |           `*arg` was mutably borrowed here in the previous iteration of the loop
    |             argument requires that `*arg` is borrowed for `'a`
 
 error[E0499]: cannot borrow `*arg` as mutable more than once at a time
@@ -39,7 +39,7 @@ LL | impl<'a, T : 'a> FuncWrapper<'a, T> {
 LL |             (self.func)(arg)
    |             ------------^^^-
    |             |           |
-   |             |           mutable borrow starts here in previous iteration of loop
+   |             |           `*arg` was mutably borrowed here in the previous iteration of the loop
    |             argument requires that `*arg` is borrowed for `'a`
 
 error: aborting due to 3 previous errors; 1 warning emitted
index 38993a50bf6b20e84b192b15731e221c56a79c4c..d4e515d12bbb5d563898fbbe6b5781ca77a574d7 100644 (file)
@@ -2,7 +2,7 @@ error[E0499]: cannot borrow `foo` as mutable more than once at a time
   --> $DIR/two-phase-across-loop.rs:17:22
    |
 LL |         strings.push(foo.get_string());
-   |                      ^^^ mutable borrow starts here in previous iteration of loop
+   |                      ^^^ `foo` was mutably borrowed here in the previous iteration of the loop
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/closures/coerce-unsafe-closure-to-unsafe-fn-ptr.rs b/src/test/ui/closures/coerce-unsafe-closure-to-unsafe-fn-ptr.rs
new file mode 100644 (file)
index 0000000..3677769
--- /dev/null
@@ -0,0 +1,5 @@
+fn main() {
+    let _: unsafe fn() = || { ::std::pin::Pin::new_unchecked(&0_u8); };
+    //~^ ERROR E0133
+    let _: unsafe fn() = || unsafe { ::std::pin::Pin::new_unchecked(&0_u8); }; // OK
+}
diff --git a/src/test/ui/closures/coerce-unsafe-closure-to-unsafe-fn-ptr.stderr b/src/test/ui/closures/coerce-unsafe-closure-to-unsafe-fn-ptr.stderr
new file mode 100644 (file)
index 0000000..a1fb1c0
--- /dev/null
@@ -0,0 +1,11 @@
+error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
+  --> $DIR/coerce-unsafe-closure-to-unsafe-fn-ptr.rs:2:31
+   |
+LL |     let _: unsafe fn() = || { ::std::pin::Pin::new_unchecked(&0_u8); };
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function
+   |
+   = note: consult the function's documentation for information on how to avoid undefined behavior
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0133`.
diff --git a/src/test/ui/closures/coerce-unsafe-to-closure.rs b/src/test/ui/closures/coerce-unsafe-to-closure.rs
new file mode 100644 (file)
index 0000000..78bdd36
--- /dev/null
@@ -0,0 +1,4 @@
+fn main() {
+    let x: Option<&[u8]> = Some("foo").map(std::mem::transmute);
+    //~^ ERROR E0277
+}
diff --git a/src/test/ui/closures/coerce-unsafe-to-closure.stderr b/src/test/ui/closures/coerce-unsafe-to-closure.stderr
new file mode 100644 (file)
index 0000000..ab035d0
--- /dev/null
@@ -0,0 +1,11 @@
+error[E0277]: expected a `FnOnce<(&str,)>` closure, found `unsafe extern "rust-intrinsic" fn(_) -> _ {transmute::<_, _>}`
+  --> $DIR/coerce-unsafe-to-closure.rs:2:44
+   |
+LL |     let x: Option<&[u8]> = Some("foo").map(std::mem::transmute);
+   |                                            ^^^^^^^^^^^^^^^^^^^ expected an `FnOnce<(&str,)>` closure, found `unsafe extern "rust-intrinsic" fn(_) -> _ {transmute::<_, _>}`
+   |
+   = help: the trait `FnOnce<(&str,)>` is not implemented for `unsafe extern "rust-intrinsic" fn(_) -> _ {transmute::<_, _>}`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
index facc0bcf5130cbec26a14771efe01117b0b36315..3bc62141927ae14358312ae03de46b01851b6202 100644 (file)
@@ -3,7 +3,6 @@
 
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 trait Trait {}
 
index b52e505070330d912bfdd4912eff2b8cf1ab0fea..e533d4f7fb834e322d9f96c93ae7dde5e2e7549a 100644 (file)
@@ -1,11 +1,11 @@
 error: lifetime parameters must be declared prior to const parameters
-  --> $DIR/argument_order.rs:12:32
+  --> $DIR/argument_order.rs:11:32
    |
 LL | struct AlsoBad<const N: usize, 'a, T, 'b, const M: usize, U> {
    |               -----------------^^-----^^-------------------- help: reorder the parameters: lifetimes, then consts and types: `<'a, 'b, const N: usize, T, const M: usize, U>`
 
 error[E0747]: lifetime provided when a type was expected
-  --> $DIR/argument_order.rs:20:23
+  --> $DIR/argument_order.rs:19:23
    |
 LL |     let _: AlsoBad<7, 'static, u32, 'static, 17, u16>;
    |                       ^^^^^^^
index 728ae69b41f19f77d770c876d268329b2b436254..f23bc6d6a2bfac79e242c405838ad92d55bfb26e 100644 (file)
@@ -1,23 +1,23 @@
 error: type parameters must be declared prior to const parameters
-  --> $DIR/argument_order.rs:6:28
+  --> $DIR/argument_order.rs:5:28
    |
 LL | struct Bad<const N: usize, T> {
    |           -----------------^- help: reorder the parameters: lifetimes, then types, then consts: `<T, const N: usize>`
 
 error: lifetime parameters must be declared prior to const parameters
-  --> $DIR/argument_order.rs:12:32
+  --> $DIR/argument_order.rs:11:32
    |
 LL | struct AlsoBad<const N: usize, 'a, T, 'b, const M: usize, U> {
    |               -----------------^^-----^^-------------------- help: reorder the parameters: lifetimes, then types, then consts: `<'a, 'b, T, U, const N: usize, const M: usize>`
 
 error: type parameters must be declared prior to const parameters
-  --> $DIR/argument_order.rs:12:36
+  --> $DIR/argument_order.rs:11:36
    |
 LL | struct AlsoBad<const N: usize, 'a, T, 'b, const M: usize, U> {
    |               ---------------------^----------------------^- help: reorder the parameters: lifetimes, then types, then consts: `<'a, 'b, T, U, const N: usize, const M: usize>`
 
 error[E0747]: lifetime provided when a type was expected
-  --> $DIR/argument_order.rs:20:23
+  --> $DIR/argument_order.rs:19:23
    |
 LL |     let _: AlsoBad<7, 'static, u32, 'static, 17, u16>;
    |                       ^^^^^^^
index 507baf5fd755eeb58e04f80e57d14087846abc74..95eaeea58184017b32002169817e37d6847c3d13 100644 (file)
@@ -1,7 +1,6 @@
 // revisions: full min
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 struct Bad<const N: usize, T> {
     //[min]~^ ERROR type parameters must be declared prior to const parameters
index cf4487b5829c1f4af7bf46635b11d4670ed20d07..0fb23e41b013fa076ed25d15909eaf5890e55bc0 100644 (file)
@@ -1,5 +1,5 @@
 error: constant expression depends on a generic parameter
-  --> $DIR/array-size-in-generic-struct-param.rs:9:38
+  --> $DIR/array-size-in-generic-struct-param.rs:8:38
    |
 LL | struct ArithArrayLen<const N: usize>([u32; 0 + N]);
    |                                      ^^^^^^^^^^^^
@@ -7,7 +7,7 @@ LL | struct ArithArrayLen<const N: usize>([u32; 0 + N]);
    = note: this may fail depending on what value the parameter takes
 
 error: constant expression depends on a generic parameter
-  --> $DIR/array-size-in-generic-struct-param.rs:20:10
+  --> $DIR/array-size-in-generic-struct-param.rs:19:10
    |
 LL |     arr: [u8; CFG.arr_size],
    |          ^^^^^^^^^^^^^^^^^^
index 73c9ea59c955bddc4f9f1c4005afc148899f0f7f..7af23103ce70f5dd62cf568d35e3c66d9d68c3e4 100644 (file)
@@ -1,5 +1,5 @@
 error: generic parameters may not be used in const operations
-  --> $DIR/array-size-in-generic-struct-param.rs:9:48
+  --> $DIR/array-size-in-generic-struct-param.rs:8:48
    |
 LL | struct ArithArrayLen<const N: usize>([u32; 0 + N]);
    |                                                ^ cannot perform const operation using `N`
@@ -8,7 +8,7 @@ LL | struct ArithArrayLen<const N: usize>([u32; 0 + N]);
    = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
-  --> $DIR/array-size-in-generic-struct-param.rs:20:15
+  --> $DIR/array-size-in-generic-struct-param.rs:19:15
    |
 LL |     arr: [u8; CFG.arr_size],
    |               ^^^ cannot perform const operation using `CFG`
@@ -17,7 +17,7 @@ LL |     arr: [u8; CFG.arr_size],
    = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error: `Config` is forbidden as the type of a const generic parameter
-  --> $DIR/array-size-in-generic-struct-param.rs:18:21
+  --> $DIR/array-size-in-generic-struct-param.rs:17:21
    |
 LL | struct B<const CFG: Config> {
    |                     ^^^^^^
index 768180d0813a93b4fb8a98c790bbe8c070fb0876..cd0a9742cd1ab20b4605ee9e936e90d677a60c52 100644 (file)
@@ -3,7 +3,6 @@
 
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 #[allow(dead_code)]
 struct ArithArrayLen<const N: usize>([u32; 0 + N]);
index 390b6cc2049e546eed3cdb4cebc9ad1ff2a62357..732a18714566ca68b450a9d86dce80059f0a3f4c 100644 (file)
@@ -2,7 +2,6 @@
 // revisions: full min
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 #![allow(dead_code)]
 
index 8ccbe5dee0e443795de5fc2a3d97f44e348b967a..6644e74f97a0b544dd83a6dd54b82345e79485da 100644 (file)
@@ -1,5 +1,5 @@
 error[E0277]: the trait bound `u16: Bar<N>` is not satisfied
-  --> $DIR/associated-type-bound-fail.rs:14:5
+  --> $DIR/associated-type-bound-fail.rs:13:5
    |
 LL |     type Assoc: Bar<N>;
    |                 ------ required by this bound in `Foo::Assoc`
index 8ccbe5dee0e443795de5fc2a3d97f44e348b967a..6644e74f97a0b544dd83a6dd54b82345e79485da 100644 (file)
@@ -1,5 +1,5 @@
 error[E0277]: the trait bound `u16: Bar<N>` is not satisfied
-  --> $DIR/associated-type-bound-fail.rs:14:5
+  --> $DIR/associated-type-bound-fail.rs:13:5
    |
 LL |     type Assoc: Bar<N>;
    |                 ------ required by this bound in `Foo::Assoc`
index 3440b1356c2424418ce914dbbf8b24f1f095d51e..83b267008057024a1ccb68024177a6cecffae933 100644 (file)
@@ -1,7 +1,6 @@
 // revisions: full min
 #![cfg_attr(full, allow(incomplete_features))]
 #![cfg_attr(full, feature(const_generics))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 trait Bar<const N: usize> {}
 
index 374a49194b1786189fd333c53eff9e55bfa9efcd..02f77396c0b6053797072977dff24ab5208c1782 100644 (file)
@@ -2,7 +2,6 @@
 // revisions: full min
 #![cfg_attr(full, allow(incomplete_features))]
 #![cfg_attr(full, feature(const_generics))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 trait Bar<const N: usize> {}
 
index 899a5a1836c338d349c78d6537146a295d0fc345..8d4cd9c0d6b7c9f40e5c6caa729fee5659590226 100644 (file)
@@ -1,6 +1,5 @@
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 pub struct Struct<const N: usize>(pub [u8; N]);
 
index 725005971e1e9aac1c6cc1211175e06332df1f66..d9baab956c9f3365222f34d11860a544b5c88f0a 100644 (file)
@@ -1,7 +1,6 @@
 // edition:2018
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 pub trait Foo<const N: usize> {}
 struct Local;
index 2e25dadf119c4b26b083e004d8f73014bf22daa3..4a6b57842217ee9ecbc1179a4dc9cfe172748d0b 100644 (file)
@@ -1,6 +1,5 @@
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 pub struct Num<const N: usize>;
 
index d13ae12c03bc2fbd599499c241e9aad7628a87bf..34255fa9f58814cbd29c09d44b57232d816adfcb 100644 (file)
@@ -3,7 +3,6 @@
 
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 pub trait Foo {
     fn foo(&self);
index 2f9afe0b46433c821dadd52b0d7d59deb90209ba..ac358b01672bf807f24dcd2d354f4c043b93ac3a 100644 (file)
@@ -3,7 +3,6 @@
 
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 use std::fmt::Debug;
 
index 931f6ade7f15c88dc78c269b1c978b78c6741b19..44aef859f2de64a8880a362e149d717ceea6f68a 100644 (file)
@@ -2,7 +2,6 @@
 // revisions: full min
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 // This test confirms that the types can be inferred correctly for this example with const
 // generics. Previously this would ICE, and more recently error.
index 1c3ddd345a53333ab27b792d42fcbf34d75087d9..7737705440eb8ae46897dcd9a7efb0c861fc9009 100644 (file)
@@ -1,5 +1,5 @@
 error: expressions must be enclosed in braces to be used as const generic arguments
-  --> $DIR/closing-args-token.rs:11:9
+  --> $DIR/closing-args-token.rs:10:9
    |
 LL |     S::<5 + 2 >> 7>;
    |         ^^^^^
@@ -10,7 +10,7 @@ LL |     S::<{ 5 + 2 } >> 7>;
    |         ^       ^
 
 error: comparison operators cannot be chained
-  --> $DIR/closing-args-token.rs:11:16
+  --> $DIR/closing-args-token.rs:10:16
    |
 LL |     S::<5 + 2 >> 7>;
    |                ^  ^
@@ -21,7 +21,7 @@ LL |     S::<5 + 2 >> 7 && 7>;
    |                    ^^^^
 
 error: comparison operators cannot be chained
-  --> $DIR/closing-args-token.rs:17:20
+  --> $DIR/closing-args-token.rs:16:20
    |
 LL |     S::<{ 5 + 2 } >> 7>;
    |                    ^  ^
@@ -32,13 +32,13 @@ LL |     S::<{ 5 + 2 } >> 7 && 7>;
    |                        ^^^^
 
 error: expected expression, found `;`
-  --> $DIR/closing-args-token.rs:22:16
+  --> $DIR/closing-args-token.rs:21:16
    |
 LL |     T::<0 >= 3>;
    |                ^ expected expression
 
 error: comparison operators cannot be chained
-  --> $DIR/closing-args-token.rs:28:12
+  --> $DIR/closing-args-token.rs:27:12
    |
 LL |     T::<x >>= 2 > 0>;
    |            ^^   ^
index 1c3ddd345a53333ab27b792d42fcbf34d75087d9..7737705440eb8ae46897dcd9a7efb0c861fc9009 100644 (file)
@@ -1,5 +1,5 @@
 error: expressions must be enclosed in braces to be used as const generic arguments
-  --> $DIR/closing-args-token.rs:11:9
+  --> $DIR/closing-args-token.rs:10:9
    |
 LL |     S::<5 + 2 >> 7>;
    |         ^^^^^
@@ -10,7 +10,7 @@ LL |     S::<{ 5 + 2 } >> 7>;
    |         ^       ^
 
 error: comparison operators cannot be chained
-  --> $DIR/closing-args-token.rs:11:16
+  --> $DIR/closing-args-token.rs:10:16
    |
 LL |     S::<5 + 2 >> 7>;
    |                ^  ^
@@ -21,7 +21,7 @@ LL |     S::<5 + 2 >> 7 && 7>;
    |                    ^^^^
 
 error: comparison operators cannot be chained
-  --> $DIR/closing-args-token.rs:17:20
+  --> $DIR/closing-args-token.rs:16:20
    |
 LL |     S::<{ 5 + 2 } >> 7>;
    |                    ^  ^
@@ -32,13 +32,13 @@ LL |     S::<{ 5 + 2 } >> 7 && 7>;
    |                        ^^^^
 
 error: expected expression, found `;`
-  --> $DIR/closing-args-token.rs:22:16
+  --> $DIR/closing-args-token.rs:21:16
    |
 LL |     T::<0 >= 3>;
    |                ^ expected expression
 
 error: comparison operators cannot be chained
-  --> $DIR/closing-args-token.rs:28:12
+  --> $DIR/closing-args-token.rs:27:12
    |
 LL |     T::<x >>= 2 > 0>;
    |            ^^   ^
index 8699637c54e94ce0f332cfd9007235ed321c5a62..a9b552ebed7a7f1df749a26dfd65c8d436b3f342 100644 (file)
@@ -2,7 +2,6 @@
 
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 struct S<const X: u32>;
 struct T<const X: bool>;
index a3c295f73c7eadc2ec6c20fe5ea254778935446f..8e20df2810399dabeeb0511abf333f99d79e01a9 100644 (file)
@@ -3,7 +3,6 @@
 
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 fn foo<const N: usize>(v: &[u8; N]) -> &[u8] {
     v
index 7771bf336016a466c36aad7dad9ea18c6adb4212..8c31c8651a2b61e87c39c39716161da381b75656 100644 (file)
@@ -4,7 +4,6 @@
 
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 struct A<const N: usize>; // ok
 
index edb403ce8fd667cb6367cc0195a8ec8ac875e7b2..3d3bd2664c8b23c83e2f7c8254b9f89f9ec1cb4a 100644 (file)
@@ -5,7 +5,6 @@
 
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 pub struct A<const N: u32>;
 
index 77b68052fc0bb226ec323407e109a7fb164628e4..ad40b48afe5edef4721b23e524dbc1db1c2e1926 100644 (file)
@@ -4,7 +4,6 @@
 
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 trait IsZeroTrait<const IS_ZERO: bool>{}
 
index 042fa9ad958b18d4bf22026d20a774c949c867d9..bfa4ba3068628eecbd95771c88da9f7424e66c57 100644 (file)
@@ -1,5 +1,5 @@
 error: generic parameters may not be used in const operations
-  --> $DIR/const-arg-in-const-arg.rs:14:23
+  --> $DIR/const-arg-in-const-arg.rs:13:23
    |
 LL |     let _: [u8; foo::<T>()];
    |                       ^ cannot perform const operation using `T`
@@ -8,7 +8,7 @@ LL |     let _: [u8; foo::<T>()];
    = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
-  --> $DIR/const-arg-in-const-arg.rs:15:23
+  --> $DIR/const-arg-in-const-arg.rs:14:23
    |
 LL |     let _: [u8; bar::<N>()];
    |                       ^ cannot perform const operation using `N`
@@ -17,7 +17,7 @@ LL |     let _: [u8; bar::<N>()];
    = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
-  --> $DIR/const-arg-in-const-arg.rs:25:23
+  --> $DIR/const-arg-in-const-arg.rs:24:23
    |
 LL |     let _ = [0; bar::<N>()];
    |                       ^ cannot perform const operation using `N`
@@ -26,7 +26,7 @@ LL |     let _ = [0; bar::<N>()];
    = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
-  --> $DIR/const-arg-in-const-arg.rs:30:24
+  --> $DIR/const-arg-in-const-arg.rs:29:24
    |
 LL |     let _: Foo<{ foo::<T>() }>;
    |                        ^ cannot perform const operation using `T`
@@ -35,7 +35,7 @@ LL |     let _: Foo<{ foo::<T>() }>;
    = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
-  --> $DIR/const-arg-in-const-arg.rs:31:24
+  --> $DIR/const-arg-in-const-arg.rs:30:24
    |
 LL |     let _: Foo<{ bar::<N>() }>;
    |                        ^ cannot perform const operation using `N`
@@ -44,7 +44,7 @@ LL |     let _: Foo<{ bar::<N>() }>;
    = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
-  --> $DIR/const-arg-in-const-arg.rs:36:27
+  --> $DIR/const-arg-in-const-arg.rs:35:27
    |
 LL |     let _ = Foo::<{ foo::<T>() }>;
    |                           ^ cannot perform const operation using `T`
@@ -53,7 +53,7 @@ LL |     let _ = Foo::<{ foo::<T>() }>;
    = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
-  --> $DIR/const-arg-in-const-arg.rs:37:27
+  --> $DIR/const-arg-in-const-arg.rs:36:27
    |
 LL |     let _ = Foo::<{ bar::<N>() }>;
    |                           ^ cannot perform const operation using `N`
@@ -62,7 +62,7 @@ LL |     let _ = Foo::<{ bar::<N>() }>;
    = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error[E0658]: a non-static lifetime is not allowed in a `const`
-  --> $DIR/const-arg-in-const-arg.rs:16:23
+  --> $DIR/const-arg-in-const-arg.rs:15:23
    |
 LL |     let _: [u8; faz::<'a>(&())];
    |                       ^^
@@ -71,7 +71,7 @@ LL |     let _: [u8; faz::<'a>(&())];
    = help: add `#![feature(const_generics)]` to the crate attributes to enable
 
 error[E0658]: a non-static lifetime is not allowed in a `const`
-  --> $DIR/const-arg-in-const-arg.rs:17:23
+  --> $DIR/const-arg-in-const-arg.rs:16:23
    |
 LL |     let _: [u8; baz::<'a>(&())];
    |                       ^^
@@ -80,7 +80,7 @@ LL |     let _: [u8; baz::<'a>(&())];
    = help: add `#![feature(const_generics)]` to the crate attributes to enable
 
 error[E0658]: a non-static lifetime is not allowed in a `const`
-  --> $DIR/const-arg-in-const-arg.rs:18:23
+  --> $DIR/const-arg-in-const-arg.rs:17:23
    |
 LL |     let _: [u8; faz::<'b>(&())];
    |                       ^^
@@ -89,7 +89,7 @@ LL |     let _: [u8; faz::<'b>(&())];
    = help: add `#![feature(const_generics)]` to the crate attributes to enable
 
 error[E0658]: a non-static lifetime is not allowed in a `const`
-  --> $DIR/const-arg-in-const-arg.rs:19:23
+  --> $DIR/const-arg-in-const-arg.rs:18:23
    |
 LL |     let _: [u8; baz::<'b>(&())];
    |                       ^^
@@ -98,7 +98,7 @@ LL |     let _: [u8; baz::<'b>(&())];
    = help: add `#![feature(const_generics)]` to the crate attributes to enable
 
 error[E0658]: a non-static lifetime is not allowed in a `const`
-  --> $DIR/const-arg-in-const-arg.rs:26:23
+  --> $DIR/const-arg-in-const-arg.rs:25:23
    |
 LL |     let _ = [0; faz::<'a>(&())];
    |                       ^^
@@ -107,7 +107,7 @@ LL |     let _ = [0; faz::<'a>(&())];
    = help: add `#![feature(const_generics)]` to the crate attributes to enable
 
 error[E0658]: a non-static lifetime is not allowed in a `const`
-  --> $DIR/const-arg-in-const-arg.rs:27:23
+  --> $DIR/const-arg-in-const-arg.rs:26:23
    |
 LL |     let _ = [0; baz::<'a>(&())];
    |                       ^^
@@ -116,7 +116,7 @@ LL |     let _ = [0; baz::<'a>(&())];
    = help: add `#![feature(const_generics)]` to the crate attributes to enable
 
 error[E0658]: a non-static lifetime is not allowed in a `const`
-  --> $DIR/const-arg-in-const-arg.rs:28:23
+  --> $DIR/const-arg-in-const-arg.rs:27:23
    |
 LL |     let _ = [0; faz::<'b>(&())];
    |                       ^^
@@ -125,7 +125,7 @@ LL |     let _ = [0; faz::<'b>(&())];
    = help: add `#![feature(const_generics)]` to the crate attributes to enable
 
 error[E0658]: a non-static lifetime is not allowed in a `const`
-  --> $DIR/const-arg-in-const-arg.rs:29:23
+  --> $DIR/const-arg-in-const-arg.rs:28:23
    |
 LL |     let _ = [0; baz::<'b>(&())];
    |                       ^^
@@ -134,7 +134,7 @@ LL |     let _ = [0; baz::<'b>(&())];
    = help: add `#![feature(const_generics)]` to the crate attributes to enable
 
 error[E0658]: a non-static lifetime is not allowed in a `const`
-  --> $DIR/const-arg-in-const-arg.rs:32:24
+  --> $DIR/const-arg-in-const-arg.rs:31:24
    |
 LL |     let _: Foo<{ faz::<'a>(&()) }>;
    |                        ^^
@@ -143,7 +143,7 @@ LL |     let _: Foo<{ faz::<'a>(&()) }>;
    = help: add `#![feature(const_generics)]` to the crate attributes to enable
 
 error[E0658]: a non-static lifetime is not allowed in a `const`
-  --> $DIR/const-arg-in-const-arg.rs:33:24
+  --> $DIR/const-arg-in-const-arg.rs:32:24
    |
 LL |     let _: Foo<{ baz::<'a>(&()) }>;
    |                        ^^
@@ -152,7 +152,7 @@ LL |     let _: Foo<{ baz::<'a>(&()) }>;
    = help: add `#![feature(const_generics)]` to the crate attributes to enable
 
 error[E0658]: a non-static lifetime is not allowed in a `const`
-  --> $DIR/const-arg-in-const-arg.rs:34:24
+  --> $DIR/const-arg-in-const-arg.rs:33:24
    |
 LL |     let _: Foo<{ faz::<'b>(&()) }>;
    |                        ^^
@@ -161,7 +161,7 @@ LL |     let _: Foo<{ faz::<'b>(&()) }>;
    = help: add `#![feature(const_generics)]` to the crate attributes to enable
 
 error[E0658]: a non-static lifetime is not allowed in a `const`
-  --> $DIR/const-arg-in-const-arg.rs:35:24
+  --> $DIR/const-arg-in-const-arg.rs:34:24
    |
 LL |     let _: Foo<{ baz::<'b>(&()) }>;
    |                        ^^
@@ -170,7 +170,7 @@ LL |     let _: Foo<{ baz::<'b>(&()) }>;
    = help: add `#![feature(const_generics)]` to the crate attributes to enable
 
 error[E0658]: a non-static lifetime is not allowed in a `const`
-  --> $DIR/const-arg-in-const-arg.rs:38:27
+  --> $DIR/const-arg-in-const-arg.rs:37:27
    |
 LL |     let _ = Foo::<{ faz::<'a>(&()) }>;
    |                           ^^
@@ -179,7 +179,7 @@ LL |     let _ = Foo::<{ faz::<'a>(&()) }>;
    = help: add `#![feature(const_generics)]` to the crate attributes to enable
 
 error[E0658]: a non-static lifetime is not allowed in a `const`
-  --> $DIR/const-arg-in-const-arg.rs:39:27
+  --> $DIR/const-arg-in-const-arg.rs:38:27
    |
 LL |     let _ = Foo::<{ baz::<'a>(&()) }>;
    |                           ^^
@@ -188,7 +188,7 @@ LL |     let _ = Foo::<{ baz::<'a>(&()) }>;
    = help: add `#![feature(const_generics)]` to the crate attributes to enable
 
 error[E0658]: a non-static lifetime is not allowed in a `const`
-  --> $DIR/const-arg-in-const-arg.rs:40:27
+  --> $DIR/const-arg-in-const-arg.rs:39:27
    |
 LL |     let _ = Foo::<{ faz::<'b>(&()) }>;
    |                           ^^
@@ -197,7 +197,7 @@ LL |     let _ = Foo::<{ faz::<'b>(&()) }>;
    = help: add `#![feature(const_generics)]` to the crate attributes to enable
 
 error[E0658]: a non-static lifetime is not allowed in a `const`
-  --> $DIR/const-arg-in-const-arg.rs:41:27
+  --> $DIR/const-arg-in-const-arg.rs:40:27
    |
 LL |     let _ = Foo::<{ baz::<'b>(&()) }>;
    |                           ^^
index 9927538ef50c6209e023d5a4e5fbbc719602ea2f..8279f4a3f61ea85743fb19ffa0c3fa1f483555c0 100644 (file)
@@ -2,7 +2,6 @@
 // FIXME(const_generics): This test currently causes an ICE because
 // we don't yet correctly deal with lifetimes, reenable this test once
 // this is fixed.
-#![cfg_attr(min, feature(min_const_generics))]
 
 const fn foo<T>() -> usize { std::mem::size_of::<T>() }
 const fn bar<const N: usize>() -> usize { N }
index 5c438efd82a0c1a46e62f1ad7eb4a5c7ce70f4c5..43ed12efb895a101f56b0337a0a18449ebeb1d86 100644 (file)
@@ -3,7 +3,6 @@
 
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 fn const_u32_identity<const X: u32>() -> u32 {
     X
index 3827002ff4bc6fa06c5a41e03fffb234fa2a3847..d0ea51ea4173a501df00bf8b51de2183bc7d2b2f 100644 (file)
@@ -1,5 +1,5 @@
 error[E0747]: constant provided when a type was expected
-  --> $DIR/const-arg-type-arg-misordered.rs:8:35
+  --> $DIR/const-arg-type-arg-misordered.rs:7:35
    |
 LL | fn foo<const N: usize>() -> Array<N, ()> {
    |                                   ^
index 2c5fc8dcc01fc98a3c2a45174d2c4e93b5d7af8a..d7b7df0eb55bceed0d029dba5cae9ab0001616b3 100644 (file)
@@ -1,5 +1,5 @@
 error[E0747]: constant provided when a type was expected
-  --> $DIR/const-arg-type-arg-misordered.rs:8:35
+  --> $DIR/const-arg-type-arg-misordered.rs:7:35
    |
 LL | fn foo<const N: usize>() -> Array<N, ()> {
    |                                   ^
index 6680f772fa3fea7705ae14b2aae9de01d0fab40b..5415791d21bb3b87b735a0604e8226bdea77211c 100644 (file)
@@ -1,7 +1,6 @@
 // revisions: full min
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 type Array<T, const N: usize> = [T; N];
 
index 4d627f05adc061dd61e6ff8d12b7548b149a8d70..5dca01f0dc078e4fcde903dd70282fb844fff17d 100644 (file)
@@ -1,5 +1,5 @@
 error[E0277]: the size for values of type `T` cannot be known at compilation time
-  --> $DIR/const-argument-if-length.rs:8:28
+  --> $DIR/const-argument-if-length.rs:7:28
    |
 LL | pub const fn is_zst<T: ?Sized>() -> usize {
    |                     - this type parameter needs to be `Sized`
@@ -12,7 +12,7 @@ LL | pub const fn size_of<T>() -> usize {
    |                      - required by this bound in `std::mem::size_of`
 
 error[E0277]: the size for values of type `T` cannot be known at compilation time
-  --> $DIR/const-argument-if-length.rs:17:12
+  --> $DIR/const-argument-if-length.rs:16:12
    |
 LL | pub struct AtLeastByte<T: ?Sized> {
    |                        - this type parameter needs to be `Sized`
index 8a1074392a5cbd09bf65f568cda92eb9a791a432..ea177c1974619c09025fd188e407d171c08cde4d 100644 (file)
@@ -1,5 +1,5 @@
 error: generic parameters may not be used in const operations
-  --> $DIR/const-argument-if-length.rs:19:24
+  --> $DIR/const-argument-if-length.rs:18:24
    |
 LL |     pad: [u8; is_zst::<T>()],
    |                        ^ cannot perform const operation using `T`
@@ -8,7 +8,7 @@ LL |     pad: [u8; is_zst::<T>()],
    = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error[E0277]: the size for values of type `T` cannot be known at compilation time
-  --> $DIR/const-argument-if-length.rs:17:12
+  --> $DIR/const-argument-if-length.rs:16:12
    |
 LL | pub struct AtLeastByte<T: ?Sized> {
    |                        - this type parameter needs to be `Sized`
index 8090738312418d57a73db7d6ab7692478029660e..67ed85f96afd7f2ddf55e6fece652fdcb60526d6 100644 (file)
@@ -2,7 +2,6 @@
 
 #![cfg_attr(full, allow(incomplete_features))]
 #![cfg_attr(full, feature(const_generics))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 pub const fn is_zst<T: ?Sized>() -> usize {
     if std::mem::size_of::<T>() == 0 {
index 0615a4c206d80745b38aac7653302939f394b08c..93c5173554f3c4a9065af26b997787c458c4e80f 100644 (file)
@@ -1,5 +1,5 @@
 error: expressions must be enclosed in braces to be used as const generic arguments
-  --> $DIR/const-expression-parameter.rs:16:20
+  --> $DIR/const-expression-parameter.rs:15:20
    |
 LL |     i32_identity::<1 + 2>();
    |                    ^^^^^
index 0615a4c206d80745b38aac7653302939f394b08c..93c5173554f3c4a9065af26b997787c458c4e80f 100644 (file)
@@ -1,5 +1,5 @@
 error: expressions must be enclosed in braces to be used as const generic arguments
-  --> $DIR/const-expression-parameter.rs:16:20
+  --> $DIR/const-expression-parameter.rs:15:20
    |
 LL |     i32_identity::<1 + 2>();
    |                    ^^^^^
index 3ef7c8b32e035afae302569b85e9bc9fcaeb8a86..cb609a5641613e30d5bc9fad9095c3a254ce4595 100644 (file)
@@ -2,7 +2,6 @@
 
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 fn i32_identity<const X: i32>() -> i32 {
     5
index add1290b1d9758a6fcb0235d686c4d1d04ab008e..5c1ee4e0d5a9eebbfe60df610111e630d2b41b29 100644 (file)
@@ -4,7 +4,6 @@
 
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 const fn const_u32_identity<const X: u32>() -> u32 {
     X
index 34edd0b4a8e870f86a8a3c55f89df476b38214d0..224fc794e327f5d4006a6373471a041606d70d5f 100644 (file)
@@ -3,7 +3,6 @@
 
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 struct Foo<T, const N: usize>([T; N]);
 
index a954c0263521695593882ff40c83ae28a8c6d611..95632f798969f96827fee0ffe756c3172352a9c8 100644 (file)
@@ -3,7 +3,6 @@
 
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 #[derive(Debug)]
 struct S<const N: usize>;
index 3982f7a7f125cc32feff0ba09995c20c3f00548f..6c2b14f2770da147c56c556222b70e88a9dc8eaa 100644 (file)
@@ -3,7 +3,6 @@
 
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 struct Foo<const A: usize, const B: usize>;
 
index c2acaabbd8832cecba0b8bfbf43cc02404bef244..09a4f66de39c52348c32cdae49cf01f58d7deccd 100644 (file)
@@ -1,5 +1,5 @@
 error: lifetime parameters must be declared prior to const parameters
-  --> $DIR/const-param-before-other-params.rs:6:21
+  --> $DIR/const-param-before-other-params.rs:5:21
    |
 LL | fn bar<const X: (), 'a>(_: &'a ()) {
    |       --------------^^- help: reorder the parameters: lifetimes, then consts and types: `<'a, const X: ()>`
index 354c6d0615f1b5947db9ce8c41be1cb3050224b5..1e49588f1b4e926a2cee586060cecdd4847e067c 100644 (file)
@@ -1,17 +1,17 @@
 error: lifetime parameters must be declared prior to const parameters
-  --> $DIR/const-param-before-other-params.rs:6:21
+  --> $DIR/const-param-before-other-params.rs:5:21
    |
 LL | fn bar<const X: (), 'a>(_: &'a ()) {
    |       --------------^^- help: reorder the parameters: lifetimes, then types, then consts: `<'a, const X: ()>`
 
 error: type parameters must be declared prior to const parameters
-  --> $DIR/const-param-before-other-params.rs:11:21
+  --> $DIR/const-param-before-other-params.rs:10:21
    |
 LL | fn foo<const X: (), T>(_: &T) {}
    |       --------------^- help: reorder the parameters: lifetimes, then types, then consts: `<T, const X: ()>`
 
 error: `()` is forbidden as the type of a const generic parameter
-  --> $DIR/const-param-before-other-params.rs:6:17
+  --> $DIR/const-param-before-other-params.rs:5:17
    |
 LL | fn bar<const X: (), 'a>(_: &'a ()) {
    |                 ^^
@@ -20,7 +20,7 @@ LL | fn bar<const X: (), 'a>(_: &'a ()) {
    = help: more complex types are supported with `#[feature(const_generics)]`
 
 error: `()` is forbidden as the type of a const generic parameter
-  --> $DIR/const-param-before-other-params.rs:11:17
+  --> $DIR/const-param-before-other-params.rs:10:17
    |
 LL | fn foo<const X: (), T>(_: &T) {}
    |                 ^^
index f1be90cf2e418a62413c151c84e61c9c77b71121..508bb3e6a689ecc28ab5ecb8cce3eec34e13a695 100644 (file)
@@ -1,7 +1,6 @@
 // revisions: full min
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 fn bar<const X: (), 'a>(_: &'a ()) {
     //~^ ERROR lifetime parameters must be declared prior to const parameters
index aa29d61d917b67bc5cc6cb28a816d2d43df4859d..119f932745b3f05670e4c2da7d6d9f9794b8e0ee 100644 (file)
@@ -1,29 +1,29 @@
 error[E0637]: `&` without an explicit lifetime name cannot be used here
-  --> $DIR/const-param-elided-lifetime.rs:11:19
+  --> $DIR/const-param-elided-lifetime.rs:10:19
    |
 LL | struct A<const N: &u8>;
    |                   ^ explicit lifetime name needed here
 
 error[E0637]: `&` without an explicit lifetime name cannot be used here
-  --> $DIR/const-param-elided-lifetime.rs:16:15
+  --> $DIR/const-param-elided-lifetime.rs:15:15
    |
 LL | impl<const N: &u8> A<N> {
    |               ^ explicit lifetime name needed here
 
 error[E0637]: `&` without an explicit lifetime name cannot be used here
-  --> $DIR/const-param-elided-lifetime.rs:19:21
+  --> $DIR/const-param-elided-lifetime.rs:18:21
    |
 LL |     fn foo<const M: &u8>(&self) {}
    |                     ^ explicit lifetime name needed here
 
 error[E0637]: `&` without an explicit lifetime name cannot be used here
-  --> $DIR/const-param-elided-lifetime.rs:24:15
+  --> $DIR/const-param-elided-lifetime.rs:23:15
    |
 LL | impl<const N: &u8> B for A<N> {}
    |               ^ explicit lifetime name needed here
 
 error[E0637]: `&` without an explicit lifetime name cannot be used here
-  --> $DIR/const-param-elided-lifetime.rs:28:17
+  --> $DIR/const-param-elided-lifetime.rs:27:17
    |
 LL | fn bar<const N: &u8>() {}
    |                 ^ explicit lifetime name needed here
index ed30182690a7abb2f1113e9a071a9658136b6bb3..5d3c8f7b2e613ebf65b1b90a0763a04d3a5501e5 100644 (file)
@@ -1,35 +1,35 @@
 error[E0637]: `&` without an explicit lifetime name cannot be used here
-  --> $DIR/const-param-elided-lifetime.rs:11:19
+  --> $DIR/const-param-elided-lifetime.rs:10:19
    |
 LL | struct A<const N: &u8>;
    |                   ^ explicit lifetime name needed here
 
 error[E0637]: `&` without an explicit lifetime name cannot be used here
-  --> $DIR/const-param-elided-lifetime.rs:16:15
+  --> $DIR/const-param-elided-lifetime.rs:15:15
    |
 LL | impl<const N: &u8> A<N> {
    |               ^ explicit lifetime name needed here
 
 error[E0637]: `&` without an explicit lifetime name cannot be used here
-  --> $DIR/const-param-elided-lifetime.rs:19:21
+  --> $DIR/const-param-elided-lifetime.rs:18:21
    |
 LL |     fn foo<const M: &u8>(&self) {}
    |                     ^ explicit lifetime name needed here
 
 error[E0637]: `&` without an explicit lifetime name cannot be used here
-  --> $DIR/const-param-elided-lifetime.rs:24:15
+  --> $DIR/const-param-elided-lifetime.rs:23:15
    |
 LL | impl<const N: &u8> B for A<N> {}
    |               ^ explicit lifetime name needed here
 
 error[E0637]: `&` without an explicit lifetime name cannot be used here
-  --> $DIR/const-param-elided-lifetime.rs:28:17
+  --> $DIR/const-param-elided-lifetime.rs:27:17
    |
 LL | fn bar<const N: &u8>() {}
    |                 ^ explicit lifetime name needed here
 
 error: `&'static u8` is forbidden as the type of a const generic parameter
-  --> $DIR/const-param-elided-lifetime.rs:11:19
+  --> $DIR/const-param-elided-lifetime.rs:10:19
    |
 LL | struct A<const N: &u8>;
    |                   ^^^
@@ -38,7 +38,7 @@ LL | struct A<const N: &u8>;
    = help: more complex types are supported with `#[feature(const_generics)]`
 
 error: `&'static u8` is forbidden as the type of a const generic parameter
-  --> $DIR/const-param-elided-lifetime.rs:16:15
+  --> $DIR/const-param-elided-lifetime.rs:15:15
    |
 LL | impl<const N: &u8> A<N> {
    |               ^^^
@@ -47,7 +47,7 @@ LL | impl<const N: &u8> A<N> {
    = help: more complex types are supported with `#[feature(const_generics)]`
 
 error: `&'static u8` is forbidden as the type of a const generic parameter
-  --> $DIR/const-param-elided-lifetime.rs:24:15
+  --> $DIR/const-param-elided-lifetime.rs:23:15
    |
 LL | impl<const N: &u8> B for A<N> {}
    |               ^^^
@@ -56,7 +56,7 @@ LL | impl<const N: &u8> B for A<N> {}
    = help: more complex types are supported with `#[feature(const_generics)]`
 
 error: `&'static u8` is forbidden as the type of a const generic parameter
-  --> $DIR/const-param-elided-lifetime.rs:28:17
+  --> $DIR/const-param-elided-lifetime.rs:27:17
    |
 LL | fn bar<const N: &u8>() {}
    |                 ^^^
@@ -65,7 +65,7 @@ LL | fn bar<const N: &u8>() {}
    = help: more complex types are supported with `#[feature(const_generics)]`
 
 error: `&'static u8` is forbidden as the type of a const generic parameter
-  --> $DIR/const-param-elided-lifetime.rs:19:21
+  --> $DIR/const-param-elided-lifetime.rs:18:21
    |
 LL |     fn foo<const M: &u8>(&self) {}
    |                     ^^^
index 633e876f1d7dd29c054eed348a3c317a848fc591..89715a7b8e9d4557066577979d8b9fd10f95a876 100644 (file)
@@ -6,7 +6,6 @@
 
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 struct A<const N: &u8>;
 //~^ ERROR `&` without an explicit lifetime name cannot be used here
index 5a126f5c3c696718de3d358021719f6d14881bd9..c2ec7359c9f7be224196ef678fc5d1006c2e8fae 100644 (file)
@@ -1,5 +1,5 @@
 error[E0401]: can't use generic parameters from outer function
-  --> $DIR/const-param-from-outer-fn.rs:9:9
+  --> $DIR/const-param-from-outer-fn.rs:8:9
    |
 LL | fn foo<const X: u32>() {
    |              - const parameter from outer function
index 5a126f5c3c696718de3d358021719f6d14881bd9..c2ec7359c9f7be224196ef678fc5d1006c2e8fae 100644 (file)
@@ -1,5 +1,5 @@
 error[E0401]: can't use generic parameters from outer function
-  --> $DIR/const-param-from-outer-fn.rs:9:9
+  --> $DIR/const-param-from-outer-fn.rs:8:9
    |
 LL | fn foo<const X: u32>() {
    |              - const parameter from outer function
index e1376c6e108b8fc776091d3f6c11e560f08c41d7..27b9ca9c291ec4e6baa0060cbfa4a585b82724a9 100644 (file)
@@ -2,7 +2,6 @@
 
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 fn foo<const X: u32>() {
     fn bar() -> u32 {
index c8cefc36732b278cde4c5171308e8b34dd2e330b..9cafb05fbcb6b8bcc86f1e220b51bce884c74915 100644 (file)
@@ -3,7 +3,6 @@
 
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 macro_rules! bar {
     ($($t:tt)*) => { impl<const N: usize> $($t)* };
index e8601985287bd9c2e2105d3b0634272b395348dd..9dc9c80241d5922a023287011f58953518563d1f 100644 (file)
@@ -3,7 +3,6 @@
 // revisions: full min
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 async fn foo<const N: usize>(arg: [u8; N]) -> usize { arg.len() }
 
diff --git a/src/test/ui/const-generics/const-param-in-trait-ungated.rs b/src/test/ui/const-generics/const-param-in-trait-ungated.rs
deleted file mode 100644 (file)
index 8a81bcc..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-trait Trait<const T: ()> {} //~ ERROR const generics are unstable
-
-fn main() {}
diff --git a/src/test/ui/const-generics/const-param-in-trait-ungated.stderr b/src/test/ui/const-generics/const-param-in-trait-ungated.stderr
deleted file mode 100644 (file)
index d53a4ac..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-error[E0658]: const generics are unstable
-  --> $DIR/const-param-in-trait-ungated.rs:1:19
-   |
-LL | trait Trait<const T: ()> {}
-   |                   ^
-   |
-   = note: see issue #74878 <https://github.com/rust-lang/rust/issues/74878> for more information
-   = help: add `#![feature(min_const_generics)]` to the crate attributes to enable
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0658`.
index 9d31162c1c6f4ec6672fc09fc7280c55a451ad06..79b3ae2037edabf1087dba5794db339d4758b262 100644 (file)
@@ -4,7 +4,6 @@
 
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 
 trait Trait<const T: u8> {}
index 8440e47968e9aea21a91ae4a465600d6be346565..ddd15dbc41bc36c85f19647c8c87fb8206daee00 100644 (file)
@@ -1,5 +1,3 @@
-#![feature(min_const_generics)]
-
 type N = u32;
 struct Foo<const M: usize>;
 fn test<const N: usize>() -> Foo<N> { //~ ERROR type provided when
index df17027802672b08aa2b8161800422315771f3ed..7447ca3ff36315992568a524d80ed0344f585196 100644 (file)
@@ -1,5 +1,5 @@
 error[E0747]: type provided when a constant was expected
-  --> $DIR/const-param-shadowing.rs:5:34
+  --> $DIR/const-param-shadowing.rs:3:34
    |
 LL | fn test<const N: usize>() -> Foo<N> {
    |                                  ^
index f7ad579dbca0bc83cc09fd28fdb0cf9fbfb7670e..f639e276f46683346b33b1d7420e3e70381d46e9 100644 (file)
@@ -1,11 +1,11 @@
 error[E0770]: the type of const parameters must not depend on other generic parameters
-  --> $DIR/const-param-type-depends-on-const-param.rs:12:52
+  --> $DIR/const-param-type-depends-on-const-param.rs:11:52
    |
 LL | pub struct Dependent<const N: usize, const X: [u8; N]>([(); N]);
    |                                                    ^ the type must not depend on the parameter `N`
 
 error[E0770]: the type of const parameters must not depend on other generic parameters
-  --> $DIR/const-param-type-depends-on-const-param.rs:16:40
+  --> $DIR/const-param-type-depends-on-const-param.rs:15:40
    |
 LL | pub struct SelfDependent<const N: [u8; N]>;
    |                                        ^ the type must not depend on the parameter `N`
index 6b7a218ada5ddef7b805b7e354056f63ac8f40d7..d63bc23632096e5ff2145cfed4319848b220b194 100644 (file)
@@ -1,17 +1,17 @@
 error[E0770]: the type of const parameters must not depend on other generic parameters
-  --> $DIR/const-param-type-depends-on-const-param.rs:12:52
+  --> $DIR/const-param-type-depends-on-const-param.rs:11:52
    |
 LL | pub struct Dependent<const N: usize, const X: [u8; N]>([(); N]);
    |                                                    ^ the type must not depend on the parameter `N`
 
 error[E0770]: the type of const parameters must not depend on other generic parameters
-  --> $DIR/const-param-type-depends-on-const-param.rs:16:40
+  --> $DIR/const-param-type-depends-on-const-param.rs:15:40
    |
 LL | pub struct SelfDependent<const N: [u8; N]>;
    |                                        ^ the type must not depend on the parameter `N`
 
 error: `[u8; _]` is forbidden as the type of a const generic parameter
-  --> $DIR/const-param-type-depends-on-const-param.rs:12:47
+  --> $DIR/const-param-type-depends-on-const-param.rs:11:47
    |
 LL | pub struct Dependent<const N: usize, const X: [u8; N]>([(); N]);
    |                                               ^^^^^^^
@@ -20,7 +20,7 @@ LL | pub struct Dependent<const N: usize, const X: [u8; N]>([(); N]);
    = help: more complex types are supported with `#[feature(const_generics)]`
 
 error: `[u8; _]` is forbidden as the type of a const generic parameter
-  --> $DIR/const-param-type-depends-on-const-param.rs:16:35
+  --> $DIR/const-param-type-depends-on-const-param.rs:15:35
    |
 LL | pub struct SelfDependent<const N: [u8; N]>;
    |                                   ^^^^^^^
index 29371eeb21d1cf0721c0370982eb6009d6f1a910..62b146e016a13c7bc8e9dba21d6bce867d50bbbf 100644 (file)
@@ -2,7 +2,6 @@
 
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 // Currently, const parameters cannot depend on other generic parameters,
 // as our current implementation can't really support this.
index ea75a3d04035828c432665eb5786d001261d3ec3..781f50e61734d21e91ff9bff44f3ab9ed7117440 100644 (file)
@@ -3,7 +3,7 @@
 
 use std::marker::PhantomData;
 
-struct B<T, const N: T>(PhantomData<[T; N]>); //~ ERROR const generics are unstable
+struct B<T, const N: T>(PhantomData<[T; N]>);
 //~^ ERROR the type of const parameters must not depend on other generic parameters
 
 fn main() {}
index 5d379ff083ca70642f5ee8925f068e5a84c5fbb0..8e14defd65d99c87ef7c604082b3c816b6ee7ee3 100644 (file)
@@ -4,16 +4,6 @@ error[E0770]: the type of const parameters must not depend on other generic para
 LL | struct B<T, const N: T>(PhantomData<[T; N]>);
    |                      ^ the type must not depend on the parameter `T`
 
-error[E0658]: const generics are unstable
-  --> $DIR/const-param-type-depends-on-type-param-ungated.rs:6:19
-   |
-LL | struct B<T, const N: T>(PhantomData<[T; N]>);
-   |                   ^
-   |
-   = note: see issue #74878 <https://github.com/rust-lang/rust/issues/74878> for more information
-   = help: add `#![feature(min_const_generics)]` to the crate attributes to enable
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
-Some errors have detailed explanations: E0658, E0770.
-For more information about an error, try `rustc --explain E0658`.
+For more information about this error, try `rustc --explain E0770`.
index f860788e778a6f21e8dd7b198106f19edbd842ff..a83ee627187b52e5577ee95e0e21f0ede4d84747 100644 (file)
@@ -1,11 +1,11 @@
 error[E0770]: the type of const parameters must not depend on other generic parameters
-  --> $DIR/const-param-type-depends-on-type-param.rs:12:34
+  --> $DIR/const-param-type-depends-on-type-param.rs:11:34
    |
 LL | pub struct Dependent<T, const X: T>([(); X]);
    |                                  ^ the type must not depend on the parameter `T`
 
 error[E0392]: parameter `T` is never used
-  --> $DIR/const-param-type-depends-on-type-param.rs:12:22
+  --> $DIR/const-param-type-depends-on-type-param.rs:11:22
    |
 LL | pub struct Dependent<T, const X: T>([(); X]);
    |                      ^ unused parameter
index f860788e778a6f21e8dd7b198106f19edbd842ff..a83ee627187b52e5577ee95e0e21f0ede4d84747 100644 (file)
@@ -1,11 +1,11 @@
 error[E0770]: the type of const parameters must not depend on other generic parameters
-  --> $DIR/const-param-type-depends-on-type-param.rs:12:34
+  --> $DIR/const-param-type-depends-on-type-param.rs:11:34
    |
 LL | pub struct Dependent<T, const X: T>([(); X]);
    |                                  ^ the type must not depend on the parameter `T`
 
 error[E0392]: parameter `T` is never used
-  --> $DIR/const-param-type-depends-on-type-param.rs:12:22
+  --> $DIR/const-param-type-depends-on-type-param.rs:11:22
    |
 LL | pub struct Dependent<T, const X: T>([(); X]);
    |                      ^ unused parameter
index 93ae111751236431243c4f7353fed704368d6676..910a964350226555065b2202e5dc04f7786ba293 100644 (file)
@@ -2,7 +2,6 @@
 
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 // Currently, const parameters cannot depend on other generic parameters,
 // as our current implementation can't really support this.
index 0f4f007f9d249911979f35f1723ab38de60b2df5..923964a4070a1d3abb819d3d6a730506a396cf05 100644 (file)
@@ -1,11 +1,11 @@
 error: const parameter `x` should have an upper case name
-  --> $DIR/const-parameter-uppercase-lint.rs:9:15
+  --> $DIR/const-parameter-uppercase-lint.rs:8:15
    |
 LL | fn noop<const x: u32>() {
    |               ^ help: convert the identifier to upper case (notice the capitalization): `X`
    |
 note: the lint level is defined here
-  --> $DIR/const-parameter-uppercase-lint.rs:7:9
+  --> $DIR/const-parameter-uppercase-lint.rs:6:9
    |
 LL | #![deny(non_upper_case_globals)]
    |         ^^^^^^^^^^^^^^^^^^^^^^
index 0f4f007f9d249911979f35f1723ab38de60b2df5..923964a4070a1d3abb819d3d6a730506a396cf05 100644 (file)
@@ -1,11 +1,11 @@
 error: const parameter `x` should have an upper case name
-  --> $DIR/const-parameter-uppercase-lint.rs:9:15
+  --> $DIR/const-parameter-uppercase-lint.rs:8:15
    |
 LL | fn noop<const x: u32>() {
    |               ^ help: convert the identifier to upper case (notice the capitalization): `X`
    |
 note: the lint level is defined here
-  --> $DIR/const-parameter-uppercase-lint.rs:7:9
+  --> $DIR/const-parameter-uppercase-lint.rs:6:9
    |
 LL | #![deny(non_upper_case_globals)]
    |         ^^^^^^^^^^^^^^^^^^^^^^
index b9bd6666af39d06bde3500d52675776e553bbf16..5d97907c2e7fa430fcc7852e82dabc769d1cc1e7 100644 (file)
@@ -2,7 +2,6 @@
 
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 #![deny(non_upper_case_globals)]
 
index cd34cfc0478c7b255d95b221eff644558fbeb6c0..fb150f892edc4ab511878de2db29ff4e9cebf432 100644 (file)
@@ -4,7 +4,6 @@
 
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 #![allow(dead_code, unused_variables)]
 
index b2816367ea107c7b48c598c47c9a3b4aada99d10..d6a54ead13163c2f2cd2850258d326613dcd25aa 100644 (file)
@@ -1,5 +1,5 @@
 error: constant expression depends on a generic parameter
-  --> $DIR/feature-gate-const_evaluatable_checked.rs:9:30
+  --> $DIR/feature-gate-const_evaluatable_checked.rs:8:30
    |
 LL | fn test<const N: usize>() -> Arr<N> where Arr<N>: Default {
    |                              ^^^^^^
index 573bc66b7c7e86afa88c1e272e76aad6806b4d73..7de4bfcdd0587ed2c591da87c63c70a6c018f96d 100644 (file)
@@ -1,5 +1,5 @@
 error: generic parameters may not be used in const operations
-  --> $DIR/feature-gate-const_evaluatable_checked.rs:6:33
+  --> $DIR/feature-gate-const_evaluatable_checked.rs:5:33
    |
 LL | type Arr<const N: usize> = [u8; N - 1];
    |                                 ^ cannot perform const operation using `N`
index 9746adab29bf63c7f89cb3ee1d3b5525dc779415..f49ca0251aa93820e0cb0201dabf2aedd65b2bdc 100644 (file)
@@ -1,7 +1,6 @@
 // revisions: full min
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 type Arr<const N: usize> = [u8; N - 1];
 //[min]~^ ERROR generic parameters may not be used in const operations
index d476a7eb6455cb95882da003faf9c2724d0f480a..9f3d94bbd8abef87c9b89734c5f809b6c095b3ab 100644 (file)
@@ -1,5 +1,5 @@
 error: generic parameters may not be used in const operations
-  --> $DIR/simple.rs:8:53
+  --> $DIR/simple.rs:7:53
    |
 LL | fn test<const N: usize>() -> [u8; N - 1] where [u8; N - 1]: Default {
    |                                                     ^ cannot perform const operation using `N`
@@ -8,7 +8,7 @@ LL | fn test<const N: usize>() -> [u8; N - 1] where [u8; N - 1]: Default {
    = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
-  --> $DIR/simple.rs:8:35
+  --> $DIR/simple.rs:7:35
    |
 LL | fn test<const N: usize>() -> [u8; N - 1] where [u8; N - 1]: Default {
    |                                   ^ cannot perform const operation using `N`
index dcf0071cb29b6eb5898367e390d3200939075243..94ad71b6c1ac9cfa2d31cba6550c71a2dd6f39e2 100644 (file)
@@ -1,7 +1,6 @@
 // [full] run-pass
 // revisions: full min
 #![cfg_attr(full, feature(const_generics))]
-#![cfg_attr(min, feature(min_const_generics))]
 #![feature(const_evaluatable_checked)]
 #![allow(incomplete_features)]
 
index f95d6d2d5709ccaff427531ed56299fb5bca5ddb..c8549f101daf683b2daa451aeba18330b6d3f937 100644 (file)
@@ -1,5 +1,5 @@
 error[E0080]: evaluation of constant value failed
-  --> $DIR/simple_fail.rs:7:33
+  --> $DIR/simple_fail.rs:6:33
    |
 LL | type Arr<const N: usize> = [u8; N - 1];
    |                                 ^^^^^ attempt to compute `0_usize - 1_usize`, which would overflow
index bd81e0bc5a8cfa6d46ba33db138e346df1668d20..df54b4cbca5bd8674786fb97f7fc19936aa7e885 100644 (file)
@@ -1,5 +1,5 @@
 error: generic parameters may not be used in const operations
-  --> $DIR/simple_fail.rs:7:33
+  --> $DIR/simple_fail.rs:6:33
    |
 LL | type Arr<const N: usize> = [u8; N - 1];
    |                                 ^ cannot perform const operation using `N`
index 5e2c080927f8601c282f8c394294b6a01d55a0c1..3cbc077f4f146b2f60c32a454f701f479c1dd0e9 100644 (file)
@@ -1,6 +1,5 @@
 // revisions: full min
 #![cfg_attr(full, feature(const_generics))]
-#![cfg_attr(min, feature(min_const_generics))]
 #![feature(const_evaluatable_checked)]
 #![allow(incomplete_features)]
 
index c4351e059dec6a5ab2e740d7d677fb10b6594380..b6fa478f48df4414aa661e795714823227fd9dbb 100644 (file)
@@ -4,7 +4,6 @@
 
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 struct A<const N: u8>;
 struct B<const N: u16>;
index 30749b8bc6d757bd5ddb3e0aac728022161e202e..1d495c9562ded51c1e75d72eab8ad79d3dd107f3 100644 (file)
@@ -5,7 +5,6 @@
 
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 extern crate crayte;
 
 use crayte::*;
index 0574ddfb2557aff283ee95f3e09a67cf3cac3bb7..cec56d7038a48a193e31615682ce555f4a1ec7d9 100644 (file)
@@ -1,5 +1,5 @@
 error: type parameters must be declared prior to const parameters
-  --> $DIR/complex-unord-param.rs:9:41
+  --> $DIR/complex-unord-param.rs:8:41
    |
 LL | struct NestedArrays<'a, const N: usize, A: 'a, const M: usize, T:'a =u32> {
    |                    ---------------------^----------------------^--------- help: reorder the parameters: lifetimes, then types, then consts: `<'a, A: 'a, T: 'a, const N: usize, const M: usize>`
index e83a96388c1909b60fef5e1e0ff58ee04a7e0cba..82b3627d22ff877d1d42b84c1808029c498e56f8 100644 (file)
@@ -3,7 +3,6 @@
 // Checks a complicated usage of unordered params
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 #![allow(dead_code)]
 
 struct NestedArrays<'a, const N: usize, A: 'a, const M: usize, T:'a =u32> {
index 9cc3e9c0da6658b6b166c6f6e07f5facbd5413a1..98352addaef15618d1a3346829d1365a5e71380a 100644 (file)
@@ -1,11 +1,11 @@
 error: lifetime parameters must be declared prior to const parameters
-  --> $DIR/intermixed-lifetime.rs:7:28
+  --> $DIR/intermixed-lifetime.rs:6:28
    |
 LL | struct Foo<const N: usize, 'a, T = u32>(&'a (), T);
    |           -----------------^^---------- help: reorder the parameters: lifetimes, then consts and types: `<'a, const N: usize, T>`
 
 error: lifetime parameters must be declared prior to type parameters
-  --> $DIR/intermixed-lifetime.rs:11:37
+  --> $DIR/intermixed-lifetime.rs:10:37
    |
 LL | struct Bar<const N: usize, T = u32, 'a>(&'a (), T);
    |           --------------------------^^- help: reorder the parameters: lifetimes, then consts and types: `<'a, const N: usize, T>`
index 4d80fdb5bcbc2454634087fddfbce5b3620efaac..532f6d700b28f7e7fb98ea4540b2fc46be789831 100644 (file)
@@ -1,23 +1,23 @@
 error: lifetime parameters must be declared prior to const parameters
-  --> $DIR/intermixed-lifetime.rs:7:28
+  --> $DIR/intermixed-lifetime.rs:6:28
    |
 LL | struct Foo<const N: usize, 'a, T = u32>(&'a (), T);
    |           -----------------^^---------- help: reorder the parameters: lifetimes, then types, then consts: `<'a, T, const N: usize>`
 
 error: type parameters must be declared prior to const parameters
-  --> $DIR/intermixed-lifetime.rs:7:32
+  --> $DIR/intermixed-lifetime.rs:6:32
    |
 LL | struct Foo<const N: usize, 'a, T = u32>(&'a (), T);
    |           ---------------------^------- help: reorder the parameters: lifetimes, then types, then consts: `<'a, T, const N: usize>`
 
 error: lifetime parameters must be declared prior to const parameters
-  --> $DIR/intermixed-lifetime.rs:11:37
+  --> $DIR/intermixed-lifetime.rs:10:37
    |
 LL | struct Bar<const N: usize, T = u32, 'a>(&'a (), T);
    |           --------------------------^^- help: reorder the parameters: lifetimes, then types, then consts: `<'a, T, const N: usize>`
 
 error: type parameters must be declared prior to const parameters
-  --> $DIR/intermixed-lifetime.rs:11:28
+  --> $DIR/intermixed-lifetime.rs:10:28
    |
 LL | struct Bar<const N: usize, T = u32, 'a>(&'a (), T);
    |           -----------------^----------- help: reorder the parameters: lifetimes, then types, then consts: `<'a, T, const N: usize>`
index cc0d1c6c0c97cbcd79d60f2c71a25e5c5113a2c2..9e83bf92a59b93b68e66b170e11965eddd7ebd37 100644 (file)
@@ -2,7 +2,6 @@
 // Checks that lifetimes cannot be interspersed between consts and types.
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 struct Foo<const N: usize, 'a, T = u32>(&'a (), T);
 //~^ Error lifetime parameters must be declared prior to const parameters
index 7058327fdce15ca12e2e7eb5f5be6c08f9405d13..86d6173fa0273cb5fcfda9d9a3a27f05bddf3799 100644 (file)
@@ -1,5 +1,5 @@
 error: type parameters must be declared prior to const parameters
-  --> $DIR/needs-feature.rs:10:26
+  --> $DIR/needs-feature.rs:9:26
    |
 LL | struct A<const N: usize, T=u32>(T);
    |         -----------------^----- help: reorder the parameters: lifetimes, then types, then consts: `<T, const N: usize>`
index 3b6f63a8efecd7cdbeaac62a34bb82f7b41d593d..86d6173fa0273cb5fcfda9d9a3a27f05bddf3799 100644 (file)
@@ -1,18 +1,8 @@
 error: type parameters must be declared prior to const parameters
-  --> $DIR/needs-feature.rs:10:26
+  --> $DIR/needs-feature.rs:9:26
    |
 LL | struct A<const N: usize, T=u32>(T);
-   |         -----------------^----- help: reorder the parameters: lifetimes, then types: `<T, const N: usize>`
+   |         -----------------^----- help: reorder the parameters: lifetimes, then types, then consts: `<T, const N: usize>`
 
-error[E0658]: const generics are unstable
-  --> $DIR/needs-feature.rs:10:16
-   |
-LL | struct A<const N: usize, T=u32>(T);
-   |                ^
-   |
-   = note: see issue #74878 <https://github.com/rust-lang/rust/issues/74878> for more information
-   = help: add `#![feature(min_const_generics)]` to the crate attributes to enable
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0658`.
index ec02dbf407d6ddb8de1cf75cffb6afefe1fac3f3..7eb7764a64449d0dc2636f2f779be460d6b3b2d5 100644 (file)
@@ -1,16 +1,13 @@
 //[full] run-pass
 // Verifies that having generic parameters after constants is not permitted without the
 // `const_generics` feature.
-// revisions: none min full
+// revisions: min full
 
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 struct A<const N: usize, T=u32>(T);
-//[none]~^ ERROR type parameters must be declared prior
-//[none]~| ERROR const generics are unstable
-//[min]~^^^ ERROR type parameters must be declared prior
+//[min]~^ ERROR type parameters must be declared prior
 
 fn main() {
   let _: A<3> = A(0);
index 59cc6f28af857ffb131fccabc99dba00ff6b788f..01fb4210dd63f5351bf230bb4c70b8dc5f37578d 100644 (file)
@@ -1,5 +1,5 @@
 error: type parameters must be declared prior to const parameters
-  --> $DIR/simple-defaults.rs:9:40
+  --> $DIR/simple-defaults.rs:8:40
    |
 LL | struct FixedOutput<'a, const N: usize, T=u32> {
    |                   ---------------------^----- help: reorder the parameters: lifetimes, then types, then consts: `<'a, T, const N: usize>`
index 78abe3519985b49f95763a5b74dd0dcda767a43f..1f1b6c2260db618b2ff0f0433d6f24c9be0df1b3 100644 (file)
@@ -3,7 +3,6 @@
 // Checks some basic test cases for defaults.
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 #![allow(dead_code)]
 
 struct FixedOutput<'a, const N: usize, T=u32> {
index 99f46309bf6ff37c709a035a2961909a0f67d2e4..96deb4a8b5abb968bfdd951aa2037ea55f6ec271 100644 (file)
@@ -1,5 +1,5 @@
 error: type parameters with a default must be trailing
-  --> $DIR/wrong-order.rs:5:10
+  --> $DIR/wrong-order.rs:4:10
    |
 LL | struct A<T = u32, const N: usize> {
    |          ^
@@ -14,7 +14,6 @@ LL | #![cfg_attr(full, feature(const_generics))]
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-   = help: consider using `min_const_generics` instead, which is more stable and complete
 
 error: aborting due to previous error; 1 warning emitted
 
index 29a46367004d44b3a6185858f5d5a5f0069d38ee..b19da76f415d72be5502c1c69ea42a2387114fa2 100644 (file)
@@ -1,5 +1,5 @@
 error: type parameters with a default must be trailing
-  --> $DIR/wrong-order.rs:5:10
+  --> $DIR/wrong-order.rs:4:10
    |
 LL | struct A<T = u32, const N: usize> {
    |          ^
index cb36d456f3887de7f91e2c6c629649fb7b06b716..4f1c05011b0bfc2d02f08fbc969a51254d651616 100644 (file)
@@ -1,6 +1,5 @@
 // revisions: full min
 #![cfg_attr(full, feature(const_generics))] //[full]~WARN the feature `const_generics` is incomplete
-#![cfg_attr(min, feature(min_const_generics))]
 
 struct A<T = u32, const N: usize> {
     //~^ ERROR type parameters with a default must be trailing
index 13fd87f1e3e574a565606e9ff5be2022d96c69fd..ce1481d97e9b485765aa7c78c57fc00975e3e8e5 100644 (file)
@@ -4,7 +4,6 @@
 
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 #[derive(Debug)]
 struct X<const N: usize> {
index 4463ed7fcdd270cb4aa6c953de8a9427cf34cfe4..d6b32323e2d012240e4d6e1258ef0844ff4170ee 100644 (file)
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/different_byref.rs:13:9
+  --> $DIR/different_byref.rs:12:9
    |
 LL |     x = Const::<{ [4] }> {};
    |         ^^^^^^^^^^^^^^^^^^^ expected `3_usize`, found `4_usize`
index e5b393ffe99ebb5c152685fd456973ecf77fcb95..05720d15404ff45f33f89e743fd454d0c3769278 100644 (file)
@@ -1,5 +1,5 @@
 error: `[usize; 1]` is forbidden as the type of a const generic parameter
-  --> $DIR/different_byref.rs:8:23
+  --> $DIR/different_byref.rs:7:23
    |
 LL | struct Const<const V: [usize; 1]> {}
    |                       ^^^^^^^^^^
index cd3960eeb8e0d16cab324fcfe6468f020ca149cb..7977560ecbcf1edc4827c1b28d6faf72a22f7ccf 100644 (file)
@@ -3,7 +3,6 @@
 
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 struct Const<const V: [usize; 1]> {}
 //[min]~^ ERROR `[usize; 1]` is forbidden
index b6729c852abc320c4a386865f8e19ed660d6999f..027e282c398decac53d5ce3202350573a989d576 100644 (file)
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/different_byref_simple.rs:12:9
+  --> $DIR/different_byref_simple.rs:11:9
    |
 LL |     u = ConstUsize::<4> {};
    |         ^^^^^^^^^^^^^^^^^^ expected `3_usize`, found `4_usize`
index b6729c852abc320c4a386865f8e19ed660d6999f..027e282c398decac53d5ce3202350573a989d576 100644 (file)
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/different_byref_simple.rs:12:9
+  --> $DIR/different_byref_simple.rs:11:9
    |
 LL |     u = ConstUsize::<4> {};
    |         ^^^^^^^^^^^^^^^^^^ expected `3_usize`, found `4_usize`
index 93289f933317ccca2cefe56cebdd621843db8205..b48189fc2cba9210690ec0274ac89c4264c978e9 100644 (file)
@@ -3,7 +3,6 @@
 
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 struct ConstUsize<const V: usize> {}
 
index 0295255d8099cd63b70b210be853f637fe0c18cd..73ed23521c30c57f16306d98e450b249664fd7e8 100644 (file)
@@ -3,7 +3,6 @@
 
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 trait Foo<const N: usize> {
     fn myfun(&self) -> usize;
index fdea1fb0c3ead2327e27d149329c08c397f48969..e0e1423ba0107083d9b9583e57cb6eef12a0810e 100644 (file)
@@ -1,5 +1,5 @@
 error[E0277]: the trait bound `(): Foo<N>` is not satisfied
-  --> $DIR/exhaustive-value.rs:267:5
+  --> $DIR/exhaustive-value.rs:266:5
    |
 LL |     fn test() {}
    |     --------- required by `Foo::test`
index fdea1fb0c3ead2327e27d149329c08c397f48969..e0e1423ba0107083d9b9583e57cb6eef12a0810e 100644 (file)
@@ -1,5 +1,5 @@
 error[E0277]: the trait bound `(): Foo<N>` is not satisfied
-  --> $DIR/exhaustive-value.rs:267:5
+  --> $DIR/exhaustive-value.rs:266:5
    |
 LL |     fn test() {}
    |     --------- required by `Foo::test`
index fce036b0da624dc09ac58982141cf37d14643ab8..921f9a467078b31d76fa5030da9401d12a958edd 100644 (file)
@@ -1,7 +1,6 @@
 // revisions: full min
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 trait Foo<const N: u8> {
     fn test() {}
index f1bd8def9ff161cf89c88289aaf01f5315ab2bba..d984449e6ca6e25da8e5830164d7aef324d79a4a 100644 (file)
@@ -1,11 +1,11 @@
 error: using function pointers as const generic parameters is forbidden
-  --> $DIR/fn-const-param-call.rs:12:25
+  --> $DIR/fn-const-param-call.rs:11:25
    |
 LL | struct Wrapper<const F: fn() -> u32>;
    |                         ^^^^^^^^^^^
 
 error: using function pointers as const generic parameters is forbidden
-  --> $DIR/fn-const-param-call.rs:14:15
+  --> $DIR/fn-const-param-call.rs:13:15
    |
 LL | impl<const F: fn() -> u32> Wrapper<F> {
    |               ^^^^^^^^^^^
index f1bd8def9ff161cf89c88289aaf01f5315ab2bba..d984449e6ca6e25da8e5830164d7aef324d79a4a 100644 (file)
@@ -1,11 +1,11 @@
 error: using function pointers as const generic parameters is forbidden
-  --> $DIR/fn-const-param-call.rs:12:25
+  --> $DIR/fn-const-param-call.rs:11:25
    |
 LL | struct Wrapper<const F: fn() -> u32>;
    |                         ^^^^^^^^^^^
 
 error: using function pointers as const generic parameters is forbidden
-  --> $DIR/fn-const-param-call.rs:14:15
+  --> $DIR/fn-const-param-call.rs:13:15
    |
 LL | impl<const F: fn() -> u32> Wrapper<F> {
    |               ^^^^^^^^^^^
index bba6c1f7a16f42be62249cb86e4bf5b7582235fe..70a104e22227d44142e432eff03792e39979330d 100644 (file)
@@ -3,7 +3,6 @@
 
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 fn function() -> u32 {
     17
index 4bdc9b89af607d25e63f90cbbb4292a034dd1c39..f0767a10994a547bccfefb8904e15464e1bb2ba2 100644 (file)
@@ -1,5 +1,5 @@
 error: using function pointers as const generic parameters is forbidden
-  --> $DIR/fn-const-param-infer.rs:7:25
+  --> $DIR/fn-const-param-infer.rs:6:25
    |
 LL | struct Checked<const F: fn(usize) -> bool>;
    |                         ^^^^^^^^^^^^^^^^^
index 4bdc9b89af607d25e63f90cbbb4292a034dd1c39..f0767a10994a547bccfefb8904e15464e1bb2ba2 100644 (file)
@@ -1,5 +1,5 @@
 error: using function pointers as const generic parameters is forbidden
-  --> $DIR/fn-const-param-infer.rs:7:25
+  --> $DIR/fn-const-param-infer.rs:6:25
    |
 LL | struct Checked<const F: fn(usize) -> bool>;
    |                         ^^^^^^^^^^^^^^^^^
index 3ed75e7b00dd7608a16f771e365537effc938ec2..d090479d4c30b3eb2f50d210120229712afc5f9e 100644 (file)
@@ -2,7 +2,6 @@
 
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 struct Checked<const F: fn(usize) -> bool>;
 //~^ ERROR: using function pointers as const generic parameters
index 950684aaa8dc1959e9ab09f7a0b3e5db967b0312..58c1b95893e74ea6c9c48693eb0333d070651863 100644 (file)
@@ -3,7 +3,6 @@
 
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 use std::fmt::Display;
 
index adcaa75996327c48f99ad482d2024fe9de263b76..5c0f17537fa506c071048506c9c1b92bfca6b0a6 100644 (file)
@@ -1,5 +1,5 @@
 error[E0741]: `C` must be annotated with `#[derive(PartialEq, Eq)]` to be used as the type of a const parameter
-  --> $DIR/forbid-non-structural_match-types.rs:15:19
+  --> $DIR/forbid-non-structural_match-types.rs:14:19
    |
 LL | struct D<const X: C>;
    |                   ^ `C` doesn't derive both `PartialEq` and `Eq`
index 014200178b9ca5ad8a37bac466a364d2d33c8f9b..3912cf577512c97caa088232bbde7542db91b09f 100644 (file)
@@ -1,5 +1,5 @@
 error: `A` is forbidden as the type of a const generic parameter
-  --> $DIR/forbid-non-structural_match-types.rs:10:19
+  --> $DIR/forbid-non-structural_match-types.rs:9:19
    |
 LL | struct B<const X: A>; // ok
    |                   ^
@@ -8,7 +8,7 @@ LL | struct B<const X: A>; // ok
    = help: more complex types are supported with `#[feature(const_generics)]`
 
 error: `C` is forbidden as the type of a const generic parameter
-  --> $DIR/forbid-non-structural_match-types.rs:15:19
+  --> $DIR/forbid-non-structural_match-types.rs:14:19
    |
 LL | struct D<const X: C>;
    |                   ^
@@ -17,7 +17,7 @@ LL | struct D<const X: C>;
    = help: more complex types are supported with `#[feature(const_generics)]`
 
 error[E0741]: `C` must be annotated with `#[derive(PartialEq, Eq)]` to be used as the type of a const parameter
-  --> $DIR/forbid-non-structural_match-types.rs:15:19
+  --> $DIR/forbid-non-structural_match-types.rs:14:19
    |
 LL | struct D<const X: C>;
    |                   ^ `C` doesn't derive both `PartialEq` and `Eq`
index e7356d485dbffa662f21f30259e03e1846598a11..0fdb3ed4a5a7989c4db5247403c94be31936f7dd 100644 (file)
@@ -2,7 +2,6 @@
 
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 #[derive(PartialEq, Eq)]
 struct A;
index 0ac51e8c9e61b460c9ae18fcac3326c38f945f84..b827e482977b4b7f233bb0b73482c7eb5e1e680f 100644 (file)
@@ -1,5 +1,5 @@
 error[E0044]: foreign items may not have const parameters
-  --> $DIR/foreign-item-const-parameter.rs:8:5
+  --> $DIR/foreign-item-const-parameter.rs:7:5
    |
 LL |     fn foo<const X: usize>();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^ can't have const parameters
@@ -7,7 +7,7 @@ LL |     fn foo<const X: usize>();
    = help: replace the const parameters with concrete consts
 
 error[E0044]: foreign items may not have type or const parameters
-  --> $DIR/foreign-item-const-parameter.rs:10:5
+  --> $DIR/foreign-item-const-parameter.rs:9:5
    |
 LL |     fn bar<T, const X: usize>(_: T);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't have type or const parameters
index 0ac51e8c9e61b460c9ae18fcac3326c38f945f84..b827e482977b4b7f233bb0b73482c7eb5e1e680f 100644 (file)
@@ -1,5 +1,5 @@
 error[E0044]: foreign items may not have const parameters
-  --> $DIR/foreign-item-const-parameter.rs:8:5
+  --> $DIR/foreign-item-const-parameter.rs:7:5
    |
 LL |     fn foo<const X: usize>();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^ can't have const parameters
@@ -7,7 +7,7 @@ LL |     fn foo<const X: usize>();
    = help: replace the const parameters with concrete consts
 
 error[E0044]: foreign items may not have type or const parameters
-  --> $DIR/foreign-item-const-parameter.rs:10:5
+  --> $DIR/foreign-item-const-parameter.rs:9:5
    |
 LL |     fn bar<T, const X: usize>(_: T);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't have type or const parameters
index 44b6d0332c3f9026bb7ff65c8f382124bab60a58..83caa89f033009eefd4b2f922809f6bba888ccfd 100644 (file)
@@ -2,7 +2,6 @@
 
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 extern "C" {
     fn foo<const X: usize>(); //~ ERROR foreign items may not have const parameters
index 43b42d82d0c45908219029b6fcbeeacc725561d6..2d19a58a1457b6862d1de6860de86361c2298cc3 100644 (file)
@@ -1,5 +1,5 @@
 error: constant expression depends on a generic parameter
-  --> $DIR/generic-function-call-in-array-length.rs:9:29
+  --> $DIR/generic-function-call-in-array-length.rs:8:29
    |
 LL | fn bar<const N: usize>() -> [u32; foo(N)] {
    |                             ^^^^^^^^^^^^^
index 526f98fe8cd4f3e182b13c636c606df744797baf..d7a3f04a8da854845449a848038830d0a5c3d07c 100644 (file)
@@ -1,5 +1,5 @@
 error: generic parameters may not be used in const operations
-  --> $DIR/generic-function-call-in-array-length.rs:9:39
+  --> $DIR/generic-function-call-in-array-length.rs:8:39
    |
 LL | fn bar<const N: usize>() -> [u32; foo(N)] {
    |                                       ^ cannot perform const operation using `N`
@@ -8,7 +8,7 @@ LL | fn bar<const N: usize>() -> [u32; foo(N)] {
    = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
-  --> $DIR/generic-function-call-in-array-length.rs:12:13
+  --> $DIR/generic-function-call-in-array-length.rs:11:13
    |
 LL |     [0; foo(N)]
    |             ^ cannot perform const operation using `N`
index c838070dc95af4dd7f894e53e5f180985ed884fb..a6d2bbd17eaabcf8c72aa617c83ac6a89e0f80ed 100644 (file)
@@ -2,7 +2,6 @@
 
 #![cfg_attr(full, allow(incomplete_features))]
 #![cfg_attr(full, feature(const_generics))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 const fn foo(n: usize) -> usize { n * 2 }
 
index 6befa9d1f6994a48e11b3d2424a9a552af286499..aff8780fb0d1cdcaea9737ebf63e78b19901aea8 100644 (file)
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/generic-param-mismatch.rs:7:5
+  --> $DIR/generic-param-mismatch.rs:6:5
    |
 LL | fn test<const N: usize, const M: usize>() -> [u8; M] {
    |                                              ------- expected `[u8; M]` because of return type
index 6befa9d1f6994a48e11b3d2424a9a552af286499..aff8780fb0d1cdcaea9737ebf63e78b19901aea8 100644 (file)
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/generic-param-mismatch.rs:7:5
+  --> $DIR/generic-param-mismatch.rs:6:5
    |
 LL | fn test<const N: usize, const M: usize>() -> [u8; M] {
    |                                              ------- expected `[u8; M]` because of return type
index e409094eb734ca20bc19491e72c0a4cca4954a21..22fffe47dcc2f5c91941de8bc901b874a21cafa2 100644 (file)
@@ -1,7 +1,6 @@
 // revisions: full min
 #![cfg_attr(full, allow(incomplete_features))]
 #![cfg_attr(full, feature(const_generics))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 fn test<const N: usize, const M: usize>() -> [u8; M] {
     [0; N] //~ ERROR mismatched types
index d311e1c0bae01c362d61f5cb509dd7ac3e34447e..c13882e7fe11619e1d978a97679dde13fdbedf6a 100644 (file)
@@ -1,5 +1,5 @@
 error: constant expression depends on a generic parameter
-  --> $DIR/generic-sum-in-array-length.rs:7:45
+  --> $DIR/generic-sum-in-array-length.rs:6:45
    |
 LL | fn foo<const A: usize, const B: usize>(bar: [usize; A + B]) {}
    |                                             ^^^^^^^^^^^^^^
index e531b612b5609d5dfe7d5215c578ad7701edd3e1..cff5a62193c379fef3751941e0858cd7c1e75ab5 100644 (file)
@@ -1,5 +1,5 @@
 error: generic parameters may not be used in const operations
-  --> $DIR/generic-sum-in-array-length.rs:7:53
+  --> $DIR/generic-sum-in-array-length.rs:6:53
    |
 LL | fn foo<const A: usize, const B: usize>(bar: [usize; A + B]) {}
    |                                                     ^ cannot perform const operation using `A`
@@ -8,7 +8,7 @@ LL | fn foo<const A: usize, const B: usize>(bar: [usize; A + B]) {}
    = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
-  --> $DIR/generic-sum-in-array-length.rs:7:57
+  --> $DIR/generic-sum-in-array-length.rs:6:57
    |
 LL | fn foo<const A: usize, const B: usize>(bar: [usize; A + B]) {}
    |                                                         ^ cannot perform const operation using `B`
index 84ddfe055dc3fe5644e1ca410a06430cf4b8f0c9..7ee0394ba14ce956ed28b58c277c16ab79605df4 100644 (file)
@@ -2,7 +2,6 @@
 
 #![cfg_attr(full, allow(incomplete_features))]
 #![cfg_attr(full, feature(const_generics))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 fn foo<const A: usize, const B: usize>(bar: [usize; A + B]) {}
 //[min]~^ ERROR generic parameters may not be used in const operations
index 05cabc46baa3479edf32bc6a73ea96b60c5933d6..1aa22698b640502743cf6468da577e0164bbc2d8 100644 (file)
@@ -3,7 +3,6 @@
 
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 struct S<const X: u32>;
 
index a587cb618731a015897b5bb414414ec084f1779c..26b965901a4c4d061f6d526f4918bbf20e480ace 100644 (file)
@@ -1,5 +1,5 @@
 error[E0632]: cannot provide explicit generic arguments when `impl Trait` is used in argument position
-  --> $DIR/impl-trait-with-const-arguments.rs:24:20
+  --> $DIR/impl-trait-with-const-arguments.rs:23:20
    |
 LL |     assert_eq!(f::<4usize>(Usizable), 20usize);
    |                    ^^^^^^ explicit generic argument not allowed
index a587cb618731a015897b5bb414414ec084f1779c..26b965901a4c4d061f6d526f4918bbf20e480ace 100644 (file)
@@ -1,5 +1,5 @@
 error[E0632]: cannot provide explicit generic arguments when `impl Trait` is used in argument position
-  --> $DIR/impl-trait-with-const-arguments.rs:24:20
+  --> $DIR/impl-trait-with-const-arguments.rs:23:20
    |
 LL |     assert_eq!(f::<4usize>(Usizable), 20usize);
    |                    ^^^^^^ explicit generic argument not allowed
index a4c75792ee359bb71ec2494a36f00115b599d23b..2e6e49b9c0aa4fd99fcb19c4d9256f8a29a8b07b 100644 (file)
@@ -2,7 +2,6 @@
 
 #![cfg_attr(full, allow(incomplete_features))]
 #![cfg_attr(full, feature(const_generics))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 trait Usizer {
     fn m(self) -> usize;
index 6b902e2d6585eae96317eccae04cf7c0629e2615..9c8359b08a5c1f1ee5b271e0d52a789e37545387 100644 (file)
@@ -1,11 +1,11 @@
 error[E0107]: wrong number of const arguments: expected 2, found 1
-  --> $DIR/incorrect-number-of-const-args.rs:12:5
+  --> $DIR/incorrect-number-of-const-args.rs:11:5
    |
 LL |     foo::<0>();
    |     ^^^^^^^^ expected 2 const arguments
 
 error[E0107]: wrong number of const arguments: expected 2, found 3
-  --> $DIR/incorrect-number-of-const-args.rs:13:17
+  --> $DIR/incorrect-number-of-const-args.rs:12:17
    |
 LL |     foo::<0, 0, 0>();
    |                 ^ unexpected const argument
index 6b902e2d6585eae96317eccae04cf7c0629e2615..9c8359b08a5c1f1ee5b271e0d52a789e37545387 100644 (file)
@@ -1,11 +1,11 @@
 error[E0107]: wrong number of const arguments: expected 2, found 1
-  --> $DIR/incorrect-number-of-const-args.rs:12:5
+  --> $DIR/incorrect-number-of-const-args.rs:11:5
    |
 LL |     foo::<0>();
    |     ^^^^^^^^ expected 2 const arguments
 
 error[E0107]: wrong number of const arguments: expected 2, found 3
-  --> $DIR/incorrect-number-of-const-args.rs:13:17
+  --> $DIR/incorrect-number-of-const-args.rs:12:17
    |
 LL |     foo::<0, 0, 0>();
    |                 ^ unexpected const argument
index f7bdf761f7d1289882195317d995103aa437e415..3c4290df0564fd10390fccc723a09f5ec76db3ef 100644 (file)
@@ -2,7 +2,6 @@
 
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 fn foo<const X: usize, const Y: usize>() -> usize {
     0
index 05bf67a5ff7c6c1bf16da16dd882f02adc496bb3..e85bf8829aee715f2d2a39627c9161d8fb0888bf 100644 (file)
@@ -1,5 +1,5 @@
 error[E0282]: type annotations needed
-  --> $DIR/cannot-infer-const-args.rs:12:5
+  --> $DIR/cannot-infer-const-args.rs:11:5
    |
 LL |     foo();
    |     ^^^ cannot infer the value of const parameter `X` declared on the function `foo`
index 05bf67a5ff7c6c1bf16da16dd882f02adc496bb3..e85bf8829aee715f2d2a39627c9161d8fb0888bf 100644 (file)
@@ -1,5 +1,5 @@
 error[E0282]: type annotations needed
-  --> $DIR/cannot-infer-const-args.rs:12:5
+  --> $DIR/cannot-infer-const-args.rs:11:5
    |
 LL |     foo();
    |     ^^^ cannot infer the value of const parameter `X` declared on the function `foo`
index 2d74b4788bf4b61c4eab058198a1f4930bfcc891..cc52892bd04b77be911dcecbb19fc4236136f419 100644 (file)
@@ -2,7 +2,6 @@
 
 #![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
index 9a1dd1a825895166d48281ebf29acf9d6e1c1637..fcf7d3282b4398207839265755065337ffdf9e59 100644 (file)
@@ -1,5 +1,3 @@
-#![feature(min_const_generics)]
-
 use std::convert::TryInto;
 
 fn take_array_from_mut<T, const N: usize>(data: &mut [T], start: usize) -> &mut [T; N] {
index 99894173bc8f60c7bf88299def65e2e706b2591e..5857a4211985a0ad44389fc59edbd15ff7ba71e5 100644 (file)
@@ -1,5 +1,5 @@
 error[E0282]: type annotations needed
-  --> $DIR/issue-77092.rs:13:26
+  --> $DIR/issue-77092.rs:11:26
    |
 LL |         println!("{:?}", take_array_from_mut(&mut arr, i));
    |                          ^^^^^^^^^^^^^^^^^^^ cannot infer the value of const parameter `N` declared on the function `take_array_from_mut`
index 7aa3bd44df84436a69d77774e66fb1baec42bd55..f6d9c4a26453c3a5ba159e412e3315deb8ab8025 100644 (file)
@@ -1,5 +1,5 @@
 error[E0282]: type annotations needed
-  --> $DIR/method-chain.rs:21:33
+  --> $DIR/method-chain.rs:20:33
    |
 LL |     Foo.bar().bar().bar().bar().baz();
    |                                 ^^^ cannot infer the value of const parameter `N` declared on the associated function `baz`
index 7aa3bd44df84436a69d77774e66fb1baec42bd55..f6d9c4a26453c3a5ba159e412e3315deb8ab8025 100644 (file)
@@ -1,5 +1,5 @@
 error[E0282]: type annotations needed
-  --> $DIR/method-chain.rs:21:33
+  --> $DIR/method-chain.rs:20:33
    |
 LL |     Foo.bar().bar().bar().bar().baz();
    |                                 ^^^ cannot infer the value of const parameter `N` declared on the associated function `baz`
index 9389ca20d106fd7d54e3c7dc1dc2cfb6bf3bad9b..8ac6a7d6267b7bc8f9920567fec682eaece488ba 100644 (file)
@@ -2,7 +2,6 @@
 
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 struct Foo;
 
index 4be625ba90930f475c8ceff6470a339ea13e3a0f..254a28f70e213cb398183e230584954a99c677d2 100644 (file)
@@ -1,5 +1,5 @@
 error[E0282]: type annotations needed
-  --> $DIR/uninferred-consts.rs:14:9
+  --> $DIR/uninferred-consts.rs:13:9
    |
 LL |     Foo.foo();
    |         ^^^ cannot infer the value of const parameter `A` declared on the associated function `foo`
index 4be625ba90930f475c8ceff6470a339ea13e3a0f..254a28f70e213cb398183e230584954a99c677d2 100644 (file)
@@ -1,5 +1,5 @@
 error[E0282]: type annotations needed
-  --> $DIR/uninferred-consts.rs:14:9
+  --> $DIR/uninferred-consts.rs:13:9
    |
 LL |     Foo.foo();
    |         ^^^ cannot infer the value of const parameter `A` declared on the associated function `foo`
index 00fb6eac9920810466362d7d3bdbb32696a9b8d9..bcd9aadb78af9f0692c1e9702ff0b976289570ee 100644 (file)
@@ -3,7 +3,6 @@
 
 #![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;
index 609fdb35cf18d0b9b2e1338fe823768373a917d1..5e2a3eaff5438ec8c51d7e4dda912679f54d4682 100644 (file)
@@ -5,7 +5,6 @@
 
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 struct A<const N: usize> {
     arr: [u8; N],
index cbf48e3d24997aab5cb1964b8a27b03dd87e4bb6..0273383856fd97dedaba45817d7f0e9e89f657a2 100644 (file)
@@ -5,7 +5,6 @@
 
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 fn as_chunks<const N: usize>() -> [u8; N] {
     loop {}
index bdbf338295cccaa94e58d27004b37c41c1ceb94a..96e5976e44b336b3954e1a84dc19872822cc1ea5 100644 (file)
@@ -3,7 +3,6 @@
 
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 fn takes_closure_of_array_3<F>(f: F) where F: Fn([i32; 3]) {
     f([1, 2, 3]);
index c09d16d0ab05b86f9e95b935b550236174ef50f7..3e90dbeece958e61e916ef22f94a1534fd580ed5 100644 (file)
@@ -1,5 +1,5 @@
 error: constant expression depends on a generic parameter
-  --> $DIR/intrinsics-type_name-as-const-argument.rs:15:8
+  --> $DIR/intrinsics-type_name-as-const-argument.rs:14:8
    |
 LL |     T: Trait<{std::intrinsics::type_name::<T>()}>
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
index 02467df193c39d380ffb3d952dff3959edac3339..4c2aaef349390e12e7ffcaf06c117f7d1aacc44b 100644 (file)
@@ -1,5 +1,5 @@
 error: generic parameters may not be used in const operations
-  --> $DIR/intrinsics-type_name-as-const-argument.rs:15:44
+  --> $DIR/intrinsics-type_name-as-const-argument.rs:14:44
    |
 LL |     T: Trait<{std::intrinsics::type_name::<T>()}>
    |                                            ^ cannot perform const operation using `T`
@@ -8,7 +8,7 @@ LL |     T: Trait<{std::intrinsics::type_name::<T>()}>
    = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error: `&'static str` is forbidden as the type of a const generic parameter
-  --> $DIR/intrinsics-type_name-as-const-argument.rs:10:22
+  --> $DIR/intrinsics-type_name-as-const-argument.rs:9:22
    |
 LL | trait Trait<const S: &'static str> {}
    |                      ^^^^^^^^^^^^
index 8971c00ed5a298d6883d5addaf0e67663dd9d53c..f24dd42eb2da7bc5690956b1b57670ba05082899 100644 (file)
@@ -2,7 +2,6 @@
 
 #![cfg_attr(full, allow(incomplete_features))]
 #![cfg_attr(full, feature(const_generics))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 #![feature(core_intrinsics)]
 #![feature(const_type_name)]
index 8855f187e970324f605b2cf77cf1977eeb80a73b..56deec16548f5c562998c16e15c6d9834c5b7645 100644 (file)
@@ -1,5 +1,5 @@
 error: constant expression depends on a generic parameter
-  --> $DIR/issue-61522-array-len-succ.rs:7:40
+  --> $DIR/issue-61522-array-len-succ.rs:6:40
    |
 LL | pub struct MyArray<const COUNT: usize>([u8; COUNT + 1]);
    |                                        ^^^^^^^^^^^^^^^
@@ -7,7 +7,7 @@ LL | pub struct MyArray<const COUNT: usize>([u8; COUNT + 1]);
    = note: this may fail depending on what value the parameter takes
 
 error: constant expression depends on a generic parameter
-  --> $DIR/issue-61522-array-len-succ.rs:12:24
+  --> $DIR/issue-61522-array-len-succ.rs:11:24
    |
 LL |     fn inner(&self) -> &[u8; COUNT + 1] {
    |                        ^^^^^^^^^^^^^^^^
index 2eaef95c2321607a80a97921dd641b6cec3cdfcc..36a0a37ae9c3f69b2a16bf1bc34a6bd2b2ec7eaf 100644 (file)
@@ -1,5 +1,5 @@
 error: generic parameters may not be used in const operations
-  --> $DIR/issue-61522-array-len-succ.rs:7:45
+  --> $DIR/issue-61522-array-len-succ.rs:6:45
    |
 LL | pub struct MyArray<const COUNT: usize>([u8; COUNT + 1]);
    |                                             ^^^^^ cannot perform const operation using `COUNT`
@@ -8,7 +8,7 @@ LL | pub struct MyArray<const COUNT: usize>([u8; COUNT + 1]);
    = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
-  --> $DIR/issue-61522-array-len-succ.rs:12:30
+  --> $DIR/issue-61522-array-len-succ.rs:11:30
    |
 LL |     fn inner(&self) -> &[u8; COUNT + 1] {
    |                              ^^^^^ cannot perform const operation using `COUNT`
index 8c0a3a0377468f3dbc2fbbc21899af330331b14a..d4a948b92597d5727d01fec5128c578244d81692 100644 (file)
@@ -2,7 +2,6 @@
 
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 pub struct MyArray<const COUNT: usize>([u8; COUNT + 1]);
 //[full]~^ ERROR constant expression depends on a generic parameter
index 1c2e7e069a1819948f57a09462b876647c6a8f16..b6c6e6fe374040b30a542e7c119b93267c4cc661 100644 (file)
@@ -1,5 +1,5 @@
 error: `&'static str` is forbidden as the type of a const generic parameter
-  --> $DIR/issue-66596-impl-trait-for-str-const-arg.rs:9:25
+  --> $DIR/issue-66596-impl-trait-for-str-const-arg.rs:8:25
    |
 LL | trait Trait<const NAME: &'static str> {
    |                         ^^^^^^^^^^^^
index 11d4bf4c3e6aa87f58b688f0f6a20d69457fcade..2a741ba87a980957e337143885379e9b47eed37a 100644 (file)
@@ -3,7 +3,6 @@
 
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 
 trait Trait<const NAME: &'static str> {
index e15d65f197e29b47301bf9913009528bbee7cde2..2f004f75de56c67974c5096cf6c0af559a3c4433 100644 (file)
@@ -1,5 +1,5 @@
 warning: cannot use constants which depend on generic parameters in types
-  --> $DIR/issue-67375.rs:9:12
+  --> $DIR/issue-67375.rs:8:12
    |
 LL |     inner: [(); { [|_: &T| {}; 0].len() }],
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -9,7 +9,7 @@ LL |     inner: [(); { [|_: &T| {}; 0].len() }],
    = note: for more information, see issue #76200 <https://github.com/rust-lang/rust/issues/76200>
 
 error[E0392]: parameter `T` is never used
-  --> $DIR/issue-67375.rs:7:12
+  --> $DIR/issue-67375.rs:6:12
    |
 LL | struct Bug<T> {
    |            ^ unused parameter
index da96b5374a57dfd8acad7e85417099d6cf14dcbf..337e7bc14099d5bcaf4c912168da65da9e0cd9e6 100644 (file)
@@ -1,5 +1,5 @@
 error: generic parameters may not be used in const operations
-  --> $DIR/issue-67375.rs:9:25
+  --> $DIR/issue-67375.rs:8:25
    |
 LL |     inner: [(); { [|_: &T| {}; 0].len() }],
    |                         ^ cannot perform const operation using `T`
@@ -8,7 +8,7 @@ LL |     inner: [(); { [|_: &T| {}; 0].len() }],
    = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error[E0392]: parameter `T` is never used
-  --> $DIR/issue-67375.rs:7:12
+  --> $DIR/issue-67375.rs:6:12
    |
 LL | struct Bug<T> {
    |            ^ unused parameter
index ecc76bcae06c5b8f1e55517ff27ccdf74ee15528..a8875b8b6bfcabf59e148ac2b3917686c2fe627b 100644 (file)
@@ -2,7 +2,6 @@
 
 #![cfg_attr(full, allow(incomplete_features))]
 #![cfg_attr(full, feature(const_generics))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 struct Bug<T> {
     //~^ ERROR parameter `T` is never used
index e79c4f5374e1a511e16cc32f0c7d0a903b640e7c..5cdcefe35015f542d169231d05be2bda5501490b 100644 (file)
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/issue-67945-1.rs:14:20
+  --> $DIR/issue-67945-1.rs:13:20
    |
 LL | struct Bug<S> {
    |            - this type parameter
@@ -13,7 +13,7 @@ LL |         let x: S = MaybeUninit::uninit();
                        found union `MaybeUninit<_>`
 
 error[E0392]: parameter `S` is never used
-  --> $DIR/issue-67945-1.rs:11:12
+  --> $DIR/issue-67945-1.rs:10:12
    |
 LL | struct Bug<S> {
    |            ^ unused parameter
index 8fea130baa57c50afe47fbfded37c471f46c6f1d..a3e086ea95486709445809cce14c07949227285e 100644 (file)
@@ -1,5 +1,5 @@
 error: generic parameters may not be used in const operations
-  --> $DIR/issue-67945-1.rs:14:16
+  --> $DIR/issue-67945-1.rs:13:16
    |
 LL |         let x: S = MaybeUninit::uninit();
    |                ^ cannot perform const operation using `S`
@@ -8,7 +8,7 @@ LL |         let x: S = MaybeUninit::uninit();
    = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
-  --> $DIR/issue-67945-1.rs:17:45
+  --> $DIR/issue-67945-1.rs:16:45
    |
 LL |         let b = &*(&x as *const _ as *const S);
    |                                             ^ cannot perform const operation using `S`
@@ -17,7 +17,7 @@ LL |         let b = &*(&x as *const _ as *const S);
    = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error[E0392]: parameter `S` is never used
-  --> $DIR/issue-67945-1.rs:11:12
+  --> $DIR/issue-67945-1.rs:10:12
    |
 LL | struct Bug<S> {
    |            ^ unused parameter
index 6771603f2594bad3e0af72323e97cd3b9d810e34..84737e4e9857839380f0b6569e9ca132027e0860 100644 (file)
@@ -2,7 +2,6 @@
 
 #![cfg_attr(full, allow(incomplete_features))]
 #![cfg_attr(full, feature(const_generics))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 use std::marker::PhantomData;
 
index 2f54b802df8a497d73bca082bb05452056796066..4d96058b395b2188317ca1594320b3fa9187b485 100644 (file)
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/issue-67945-2.rs:12:20
+  --> $DIR/issue-67945-2.rs:11:20
    |
 LL | struct Bug<S> {
    |            - this type parameter
@@ -13,7 +13,7 @@ LL |         let x: S = MaybeUninit::uninit();
                        found union `MaybeUninit<_>`
 
 error[E0392]: parameter `S` is never used
-  --> $DIR/issue-67945-2.rs:9:12
+  --> $DIR/issue-67945-2.rs:8:12
    |
 LL | struct Bug<S> {
    |            ^ unused parameter
index 50633772b75a91c3062cb9207176f21240c8a5d3..860be4a9b6ac91efe8aa07b4b053b51763789945 100644 (file)
@@ -1,5 +1,5 @@
 error: generic parameters may not be used in const operations
-  --> $DIR/issue-67945-2.rs:12:16
+  --> $DIR/issue-67945-2.rs:11:16
    |
 LL |         let x: S = MaybeUninit::uninit();
    |                ^ cannot perform const operation using `S`
@@ -8,7 +8,7 @@ LL |         let x: S = MaybeUninit::uninit();
    = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
-  --> $DIR/issue-67945-2.rs:15:45
+  --> $DIR/issue-67945-2.rs:14:45
    |
 LL |         let b = &*(&x as *const _ as *const S);
    |                                             ^ cannot perform const operation using `S`
@@ -17,7 +17,7 @@ LL |         let b = &*(&x as *const _ as *const S);
    = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error[E0392]: parameter `S` is never used
-  --> $DIR/issue-67945-2.rs:9:12
+  --> $DIR/issue-67945-2.rs:8:12
    |
 LL | struct Bug<S> {
    |            ^ unused parameter
index 72dbb674e66bd33fd108df58af146dab975d037d..4a46786e9a9bf3c3751f1a1df06d07fb5584a390 100644 (file)
@@ -2,7 +2,6 @@
 
 #![cfg_attr(full, allow(incomplete_features))]
 #![cfg_attr(full, feature(const_generics))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 use std::mem::MaybeUninit;
 
index c33b88588c0d0cf2dd19c0eba2669275a318493c..fa66252bd6946f60b49dd710bde84e70db8908ca 100644 (file)
@@ -1,5 +1,5 @@
 error: constant expression depends on a generic parameter
-  --> $DIR/issue-67945-3.rs:8:8
+  --> $DIR/issue-67945-3.rs:7:8
    |
 LL |       A: [(); {
    |  ________^
index 9c6e101ece868dc40d18a23a2f37282c8f602d5e..5c30429c89581ecbe92ed24a15e64d4b446a3cd7 100644 (file)
@@ -1,5 +1,5 @@
 error: generic `Self` types are currently not permitted in anonymous constants
-  --> $DIR/issue-67945-3.rs:10:27
+  --> $DIR/issue-67945-3.rs:9:27
    |
 LL |         let x: Option<Box<Self>> = None;
    |                           ^^^^
index bca079101e2b30a08f2d964777e6d3df8d7f5d85..5bad61cfc763870a7b562b01260d9eb89b2328ca 100644 (file)
@@ -2,7 +2,6 @@
 
 #![cfg_attr(full, allow(incomplete_features))]
 #![cfg_attr(full, feature(const_generics))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 struct Bug<S: ?Sized> {
     A: [(); {
index eab63d3a6e6ab0563b3d513c5e256966c51bdef8..43c3999133c650b934f34ff5b965565a4b151fc3 100644 (file)
@@ -4,7 +4,6 @@
 
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 extern crate impl_const;
 
index 9cfa57006d5c670adb6f2751caa1e25a0c78b85c..f0554823273a8f478e85fa64b790374d4fca7b08 100644 (file)
@@ -3,7 +3,6 @@
 
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 pub fn works() {
     let array/*: [_; _]*/ = default_array();
index bbde404966ccf04361a3c338e0a2cbfdffd120c1..21cefc09c253a8b27ede78c0d55d42e5690b4d47 100644 (file)
@@ -3,7 +3,6 @@
 
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 fn works() {
     let array/*: [u8; _]*/ = default_byte_array();
index d4c962452d182dae3164eb2a43b85ff954ab34ab..6bfdba5711ef652a62af4e79c680d8ff36dee1d5 100644 (file)
@@ -3,7 +3,6 @@
 
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 pub trait Foo<const B: bool> {}
 pub fn bar<T: Foo<{ true }>>() {}
index 9162d1142b64a81f69d931fe2d1fcfed7978b077..dc3c33736dabfc81b90fa07e856ea461dad89fdf 100644 (file)
@@ -3,7 +3,6 @@
 // revisions: full min
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 const SIZE: usize = 16;
 
index 7ea8d936d6141c1a5589017425a5904aa618d92f..f59eb60cb38f0ed488f5308082b8f29b7cc05e0f 100644 (file)
@@ -1,6 +1,5 @@
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 // All of these three items must be in `lib2` to reproduce the error
 
index 50e914185511297cc9f0ba233e74d45392f6ca32..61fba92c1962e481ff7700d17202bc994e2c901d 100644 (file)
@@ -6,10 +6,9 @@ LL | #![cfg_attr(full, feature(const_generics))]
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-   = help: consider using `min_const_generics` instead, which is more stable and complete
 
 error[E0771]: use of non-static lifetime `'a` in const generic
-  --> $DIR/issue-56445.rs:9:26
+  --> $DIR/issue-56445.rs:8:26
    |
 LL | struct Bug<'a, const S: &'a str>(PhantomData<&'a ()>);
    |                          ^^
index bcb27d8d1e19740a4f1a3c975c01393077b354a2..80702dd4bc33c844d51347659098957a07968c21 100644 (file)
@@ -1,5 +1,5 @@
 error[E0771]: use of non-static lifetime `'a` in const generic
-  --> $DIR/issue-56445.rs:9:26
+  --> $DIR/issue-56445.rs:8:26
    |
 LL | struct Bug<'a, const S: &'a str>(PhantomData<&'a ()>);
    |                          ^^
index 0bcde348b05d5d1ef52d007fe1941481162ae5a3..bc9e1dee853e482c592da4e5c6741e26d54c3ebd 100644 (file)
@@ -1,7 +1,6 @@
 // Regression test for https://github.com/rust-lang/rust/issues/56445#issuecomment-518402995.
 // revisions: full min
 #![cfg_attr(full, feature(const_generics))] //[full]~WARN the feature `const_generics` is incomplete
-#![cfg_attr(min, feature(min_const_generics))]
 #![crate_type = "lib"]
 
 use std::marker::PhantomData;
diff --git a/src/test/ui/const-generics/issues/issue-60263.rs b/src/test/ui/const-generics/issues/issue-60263.rs
deleted file mode 100644 (file)
index 70cbc24..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-struct B<const I: u8>; //~ ERROR const generics are unstable
-
-impl B<0> {
-    fn bug() -> Self {
-        panic!()
-    }
-}
-
-fn main() {}
diff --git a/src/test/ui/const-generics/issues/issue-60263.stderr b/src/test/ui/const-generics/issues/issue-60263.stderr
deleted file mode 100644 (file)
index aeef296..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-error[E0658]: const generics are unstable
-  --> $DIR/issue-60263.rs:1:16
-   |
-LL | struct B<const I: u8>;
-   |                ^
-   |
-   = note: see issue #74878 <https://github.com/rust-lang/rust/issues/74878> for more information
-   = help: add `#![feature(min_const_generics)]` to the crate attributes to enable
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0658`.
index cc014ea429d5c200d4295ea93e1cf2451fde4b12..c03b7252a3c8530895ac946e0fb03026dab57ada 100644 (file)
@@ -6,7 +6,6 @@ LL | #![cfg_attr(full, feature(const_generics))]
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-   = help: consider using `min_const_generics` instead, which is more stable and complete
 
 warning: 1 warning emitted
 
index ae2b0520fb1c1ee47885195a2120fcb9c2f930b6..6e64c78cd8c96979fa135386b1bea79b1cc96b4c 100644 (file)
@@ -1,7 +1,6 @@
 // check-pass
 // revisions: full min
 #![cfg_attr(full, feature(const_generics))] //[full]~WARN the feature `const_generics` is incomplete
-#![cfg_attr(min, feature(min_const_generics))]
 
 struct Generic<const V: usize>;
 
index 3a9f819a6262cb3dac1b580e63383044a09e46c9..f18728eabbb437b7dca909166d01f1197f109da8 100644 (file)
@@ -6,7 +6,6 @@ LL | #![cfg_attr(full, feature(const_generics))]
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-   = help: consider using `min_const_generics` instead, which is more stable and complete
 
 warning: 1 warning emitted
 
index 201c0d039d98f3dab979ece6c25def3d44a86586..c93b296dbb557c8a3ce974278573351beeed0a7e 100644 (file)
@@ -1,7 +1,6 @@
 // build-pass
 // revisions: full min
 #![cfg_attr(full, feature(const_generics))] //[full]~WARN the feature `const_generics` is incomplete
-#![cfg_attr(min, feature(min_const_generics))]
 
 fn f<T: Copy, const N: usize>(x: T) -> [T; N] {
     [x; N]
index 883ebbef3e80dff20f507a0ffcf8620f4e327f48..9f8e68d211dec6200313869d850770cd487a3d2a 100644 (file)
@@ -6,10 +6,9 @@ LL | #![cfg_attr(full, feature(const_generics))]
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-   = help: consider using `min_const_generics` instead, which is more stable and complete
 
 error[E0277]: the trait bound `T: Copy` is not satisfied
-  --> $DIR/issue-61336-2.rs:10:5
+  --> $DIR/issue-61336-2.rs:9:5
    |
 LL |     [x; { N }]
    |     ^^^^^^^^^^ the trait `Copy` is not implemented for `T`
index 40863a4f71860bebcb15364e1b8454a03e8bd814..82d17a87e0af874aeb5e276445eb01596b23f96d 100644 (file)
@@ -1,5 +1,5 @@
 error[E0277]: the trait bound `T: Copy` is not satisfied
-  --> $DIR/issue-61336-2.rs:10:5
+  --> $DIR/issue-61336-2.rs:9:5
    |
 LL |     [x; { N }]
    |     ^^^^^^^^^^ the trait `Copy` is not implemented for `T`
index 44995157cc91fda6a4ed80d6b2d344925dfb3eca..a1cf641ff749f66182fa75f0e34204ce3ab5ed8e 100644 (file)
@@ -1,6 +1,5 @@
 // revisions: full min
 #![cfg_attr(full, feature(const_generics))] //[full]~WARN the feature `const_generics` is incomplete
-#![cfg_attr(min, feature(min_const_generics))]
 
 fn f<T: Copy, const N: usize>(x: T) -> [T; N] {
     [x; { N }]
index 3863da8da05484060e236e17d4e35d0d15c6eba4..974e2af6fd2cf95fadca4e6c8a7db195ba60cfb8 100644 (file)
@@ -6,10 +6,9 @@ LL | #![cfg_attr(full, feature(const_generics))]
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-   = help: consider using `min_const_generics` instead, which is more stable and complete
 
 error[E0277]: the trait bound `T: Copy` is not satisfied
-  --> $DIR/issue-61336.rs:10:5
+  --> $DIR/issue-61336.rs:9:5
    |
 LL |     [x; N]
    |     ^^^^^^ the trait `Copy` is not implemented for `T`
index 6c57f9ccbf511b4c2ac484bc5df1a8ac9122b880..19c7153582cb9650ff107afae290cf5cbc6a6f97 100644 (file)
@@ -1,5 +1,5 @@
 error[E0277]: the trait bound `T: Copy` is not satisfied
-  --> $DIR/issue-61336.rs:10:5
+  --> $DIR/issue-61336.rs:9:5
    |
 LL |     [x; N]
    |     ^^^^^^ the trait `Copy` is not implemented for `T`
index 7c34250e6b2d2e695138128cac3e2eb4fa167913..c0106ee38c206d9849f29dee9e5a480493ff9be5 100644 (file)
@@ -1,6 +1,5 @@
 // revisions: full min
 #![cfg_attr(full, feature(const_generics))] //[full]~WARN the feature `const_generics` is incomplete
-#![cfg_attr(min, feature(min_const_generics))]
 
 fn f<T: Copy, const N: usize>(x: T) -> [T; N] {
     [x; N]
index 294378a66901a4eea5790eda99b9b1c29ca30f4b..ac6c378295d3144ed85071ddbfe38412be0ce3a1 100644 (file)
@@ -6,7 +6,6 @@ LL | #![cfg_attr(full, feature(const_generics))]
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-   = help: consider using `min_const_generics` instead, which is more stable and complete
 
 warning: 1 warning emitted
 
index 649f8b4255b1216adb4d4f5461c4998fe86b9c7c..421f696f3fd8d92eeaf191fd116cd87ba5c8d513 100644 (file)
@@ -1,7 +1,6 @@
 // check-pass
 // revisions: full min
 #![cfg_attr(full, feature(const_generics))] //[full]~WARN the feature `const_generics` is incomplete
-#![cfg_attr(min, feature(min_const_generics))]
 
 use std::mem;
 
index eec1b20254ed780178bc4f944e491e8fa6341b75..82b36de45a2aac033883f54ee5e33b87b3dbc3bd 100644 (file)
@@ -6,7 +6,6 @@ LL | #![cfg_attr(full, feature(const_generics))]
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-   = help: consider using `min_const_generics` instead, which is more stable and complete
 
 warning: 1 warning emitted
 
index 91a4794099c073bd463cc52e84678bceeb5abac8..0e228126d77896c9f2359c05383c2019557184a9 100644 (file)
@@ -1,7 +1,6 @@
 // run-pass
 // revisions: full min
 #![cfg_attr(full, feature(const_generics))] //[full]~WARN the feature `const_generics` is incomplete
-#![cfg_attr(min, feature(min_const_generics))]
 
 fn promote<const N: i32>() {
     // works:
index 3a266c8e97422ae4e3bbaf6a4b8c6e4548e5cffb..b7f66345c4aa3fbb786d9657457ec20eca61d203 100644 (file)
@@ -6,10 +6,9 @@ LL | #![cfg_attr(full, feature(const_generics))]
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-   = help: consider using `min_const_generics` instead, which is more stable and complete
 
 error: constant expression depends on a generic parameter
-  --> $DIR/issue-61747.rs:8:23
+  --> $DIR/issue-61747.rs:7:23
    |
 LL |     fn successor() -> Const<{C + 1}> {
    |                       ^^^^^^^^^^^^^^
index 1de9e71b6eb008021eda8525827033770a8f6907..b85533ccb46fbdc573079c133ec47faa825ad855 100644 (file)
@@ -1,5 +1,5 @@
 error: generic parameters may not be used in const operations
-  --> $DIR/issue-61747.rs:8:30
+  --> $DIR/issue-61747.rs:7:30
    |
 LL |     fn successor() -> Const<{C + 1}> {
    |                              ^ cannot perform const operation using `C`
index 3a4dd1cdd181df9d1db2e4391868d6a2fdc89304..3aa2e6a5c31dc8d996858861816f827e146a4128 100644 (file)
@@ -1,6 +1,5 @@
 // revisions: full min
 #![cfg_attr(full, feature(const_generics))] //[full]~WARN the feature `const_generics` is incomplete
-#![cfg_attr(min, feature(min_const_generics))]
 
 struct Const<const N: usize>;
 
index b805bc0db7e55fb758870abb2ddbc90440de60cf..b970f4e4c8e310d9ee43b1ddeec496c43877a0f7 100644 (file)
@@ -1,5 +1,5 @@
 error: constant expression depends on a generic parameter
-  --> $DIR/issue-61935.rs:10:14
+  --> $DIR/issue-61935.rs:9:14
    |
 LL |         Self:FooImpl<{N==0}>
    |              ^^^^^^^^^^^^^^^
index b1d92056a544c259b0438dd606047f924142386d..9382dca31530e152210d422d5ce5b56de609b78c 100644 (file)
@@ -1,5 +1,5 @@
 error: generic parameters may not be used in const operations
-  --> $DIR/issue-61935.rs:10:23
+  --> $DIR/issue-61935.rs:9:23
    |
 LL |         Self:FooImpl<{N==0}>
    |                       ^ cannot perform const operation using `N`
index 9fa02329a7124c805d82453896e8babfb9f87a72..ed861c63bf1e3b7668ed4c48a22a1e7bf252b59a 100644 (file)
@@ -1,7 +1,6 @@
 // revisions: full min
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 trait Foo {}
 
index a8fa37803566006057ea6f10573c1768fd3876b1..1a0e46e599d95c0f0f4e32056d9b2f0e1f6cb3a1 100644 (file)
@@ -3,7 +3,6 @@
 // revisions: full min
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 pub trait BitLen: Sized {
     const BIT_LEN: usize;
index 120aa8e4af5d2e0a8552e59775dcf24c3796b9b4..373360c7ced6cf7b8307d12752e618997fafa1cb 100644 (file)
@@ -1,5 +1,5 @@
 error: constant expression depends on a generic parameter
-  --> $DIR/issue-62220.rs:13:27
+  --> $DIR/issue-62220.rs:12:27
    |
 LL |     pub fn trunc(self) -> (TruncatedVector<T, { N }>, T) {
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
index b338cdb87e1e5ee03e868329e36c3e5adc68dd11..72311d030cf0bcefc8f30034ff22bc9d56c1c12d 100644 (file)
@@ -1,5 +1,5 @@
 error: generic parameters may not be used in const operations
-  --> $DIR/issue-62220.rs:8:59
+  --> $DIR/issue-62220.rs:7:59
    |
 LL | pub type TruncatedVector<T, const N: usize> = Vector<T, { N - 1 }>;
    |                                                           ^ cannot perform const operation using `N`
index 2017473fa9e24cbb66bc2961685bdc32aa27759b..c26784c9813c56b3f21d049af128b87c45ca14d7 100644 (file)
@@ -1,7 +1,6 @@
 // revisions: full min
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 pub struct Vector<T, const N: usize>([T; N]);
 
index a8d44074db9d14b0fcf3e18641116a80aa0387d9..833e70ca6d386860bb7d6d3a7de48e10f457d9ef 100644 (file)
@@ -1,5 +1,5 @@
 error: constant expression depends on a generic parameter
-  --> $DIR/issue-62456.rs:7:20
+  --> $DIR/issue-62456.rs:6:20
    |
 LL |     let _ = [0u64; N + 1];
    |                    ^^^^^
index a4b501a7bb109f343a1965b020ec9af07f768cea..920318fa0ac344929d6241d3bdffee71b32d7400 100644 (file)
@@ -1,5 +1,5 @@
 error: generic parameters may not be used in const operations
-  --> $DIR/issue-62456.rs:7:20
+  --> $DIR/issue-62456.rs:6:20
    |
 LL |     let _ = [0u64; N + 1];
    |                    ^ cannot perform const operation using `N`
index cbb2a11a931aeabd1df230222a68ef0211fc7884..e24cf36c8ce4e8b3f44e6a21fd7e8d6b6ff134d1 100644 (file)
@@ -1,7 +1,6 @@
 // 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 N: usize>() {
     let _ = [0u64; N + 1];
index 9c84f06ce9f74987aea8f299bcb876e898cde91e..f09af76325e96c9f98906e2acc435667099a00b3 100644 (file)
@@ -1,5 +1,5 @@
 error: constant expression depends on a generic parameter
-  --> $DIR/issue-62504.rs:19:25
+  --> $DIR/issue-62504.rs:18:25
    |
 LL |         ArrayHolder([0; Self::SIZE])
    |                         ^^^^^^^^^^
index 865eaf749326764fd36b94e16d68d45600451d99..5d45e302888d424895cb88f12ac906c75de013ea 100644 (file)
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/issue-62504.rs:19:21
+  --> $DIR/issue-62504.rs:18:21
    |
 LL |         ArrayHolder([0; Self::SIZE])
    |                     ^^^^^^^^^^^^^^^ expected `X`, found `Self::SIZE`
@@ -8,7 +8,7 @@ LL |         ArrayHolder([0; Self::SIZE])
               found array `[u32; _]`
 
 error: constant expression depends on a generic parameter
-  --> $DIR/issue-62504.rs:19:25
+  --> $DIR/issue-62504.rs:18:25
    |
 LL |         ArrayHolder([0; Self::SIZE])
    |                         ^^^^^^^^^^
index 5630962ff53767ca8ff9b156640b464fbb9c5b90..0b95754cab45d48f4db62d05985cd2e0ef04c9ce 100644 (file)
@@ -2,7 +2,6 @@
 #![allow(incomplete_features)]
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 trait HasSize {
     const SIZE: usize;
index 5117e20d6266b5a26dc0ed999d6a6c876fa942d8..a0aee4821c69ebbb19e99fce9ac1c3294f27401d 100644 (file)
@@ -1,5 +1,5 @@
 error: `NoMatch` is forbidden as the type of a const generic parameter
-  --> $DIR/issue-62579-no-match.rs:10:17
+  --> $DIR/issue-62579-no-match.rs:9:17
    |
 LL | fn foo<const T: NoMatch>() -> bool {
    |                 ^^^^^^^
index c9853aa9162e10117028f104f2e95f695f3fa70b..46813f5256e587947c39ffd2da4fad2d5d80cf38 100644 (file)
@@ -2,7 +2,6 @@
 // revisions: full min
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 #[derive(PartialEq, Eq)]
 struct NoMatch;
index dce2e27c71a139536a0b666c407f9aa9eb2244d7..6e6aa196633021b9532d1c8abc3bb94f935a3d7c 100644 (file)
@@ -1,11 +1,11 @@
 error[E0770]: the type of const parameters must not depend on other generic parameters
-  --> $DIR/issue-62878.rs:6:38
+  --> $DIR/issue-62878.rs:5:38
    |
 LL | fn foo<const N: usize, const A: [u8; N]>() {}
    |                                      ^ the type must not depend on the parameter `N`
 
 error[E0747]: type provided when a constant was expected
-  --> $DIR/issue-62878.rs:11:11
+  --> $DIR/issue-62878.rs:10:11
    |
 LL |     foo::<_, {[1]}>();
    |           ^
@@ -13,7 +13,7 @@ LL |     foo::<_, {[1]}>();
    = help: const arguments cannot yet be inferred with `_`
 
 error[E0308]: mismatched types
-  --> $DIR/issue-62878.rs:11:15
+  --> $DIR/issue-62878.rs:10:15
    |
 LL |     foo::<_, {[1]}>();
    |               ^^^ expected `usize`, found array `[{integer}; 1]`
index 9f95e5d88623e13bd21e0d3661a302a30fafa5b5..920d7e43b9b7e6241f75d8bf484879fea36087c5 100644 (file)
@@ -1,11 +1,11 @@
 error[E0770]: the type of const parameters must not depend on other generic parameters
-  --> $DIR/issue-62878.rs:6:38
+  --> $DIR/issue-62878.rs:5:38
    |
 LL | fn foo<const N: usize, const A: [u8; N]>() {}
    |                                      ^ the type must not depend on the parameter `N`
 
 error: `[u8; _]` is forbidden as the type of a const generic parameter
-  --> $DIR/issue-62878.rs:6:33
+  --> $DIR/issue-62878.rs:5:33
    |
 LL | fn foo<const N: usize, const A: [u8; N]>() {}
    |                                 ^^^^^^^
index c087711e5f9adff179f7df24bed53838ef347340..a70606c4a7d3254a2c49b363f5288aade69f0cd4 100644 (file)
@@ -1,7 +1,6 @@
 // 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 N: usize, const A: [u8; N]>() {}
 //~^ ERROR the type of const parameters must not
index a20c7264acfdda5460eb50b281231ed12a88c834..e1c20e6ae781a1769b71397e27c5838e42af7880 100644 (file)
@@ -1,5 +1,5 @@
 error[E0741]: `&'static (dyn A + 'static)` must be annotated with `#[derive(PartialEq, Eq)]` to be used as the type of a const parameter
-  --> $DIR/issue-63322-forbid-dyn.rs:10:18
+  --> $DIR/issue-63322-forbid-dyn.rs:9:18
    |
 LL | fn test<const T: &'static dyn A>() {
    |                  ^^^^^^^^^^^^^^ `&'static (dyn A + 'static)` doesn't derive both `PartialEq` and `Eq`
index 5dbfdc6d652b6708f817ddc15f9890c4d498f0f1..543e4b29a16200d054182fc0abf96e1d62e5ad71 100644 (file)
@@ -1,5 +1,5 @@
 error: `&'static (dyn A + 'static)` is forbidden as the type of a const generic parameter
-  --> $DIR/issue-63322-forbid-dyn.rs:10:18
+  --> $DIR/issue-63322-forbid-dyn.rs:9:18
    |
 LL | fn test<const T: &'static dyn A>() {
    |                  ^^^^^^^^^^^^^^
@@ -8,7 +8,7 @@ LL | fn test<const T: &'static dyn A>() {
    = help: more complex types are supported with `#[feature(const_generics)]`
 
 error[E0741]: `&'static (dyn A + 'static)` must be annotated with `#[derive(PartialEq, Eq)]` to be used as the type of a const parameter
-  --> $DIR/issue-63322-forbid-dyn.rs:10:18
+  --> $DIR/issue-63322-forbid-dyn.rs:9:18
    |
 LL | fn test<const T: &'static dyn A>() {
    |                  ^^^^^^^^^^^^^^ `&'static (dyn A + 'static)` doesn't derive both `PartialEq` and `Eq`
index 2194eb97a410740802c64b8eafc8c761ab3991ed..334e2aac02a4814cd2ea692e86a79ae74097fc19 100644 (file)
@@ -1,7 +1,6 @@
 // revisions: full min
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 trait A {}
 struct B;
index a97ec9308f814f86230bfb8ebf3e681f07c01189..abb26d6cf1753d6c311a43b12058cc8ca055fa30 100644 (file)
@@ -1,5 +1,5 @@
 error: constant expression depends on a generic parameter
-  --> $DIR/issue-64494.rs:16:53
+  --> $DIR/issue-64494.rs:15:53
    |
 LL | impl<T: Foo> MyTrait for T where Is<{T::VAL == 5}>: True {}
    |                                                     ^^^^
@@ -7,7 +7,7 @@ LL | impl<T: Foo> MyTrait for T where Is<{T::VAL == 5}>: True {}
    = note: this may fail depending on what value the parameter takes
 
 error: constant expression depends on a generic parameter
-  --> $DIR/issue-64494.rs:19:53
+  --> $DIR/issue-64494.rs:18:53
    |
 LL | impl<T: Foo> MyTrait for T where Is<{T::VAL == 6}>: True {}
    |                                                     ^^^^
index 681166b1d2b94b7d270dfc9c361913bba2896d83..936ab7f6e7e338ab2dc1ccbd62a2692570149a5b 100644 (file)
@@ -1,5 +1,5 @@
 error: generic parameters may not be used in const operations
-  --> $DIR/issue-64494.rs:16:38
+  --> $DIR/issue-64494.rs:15:38
    |
 LL | impl<T: Foo> MyTrait for T where Is<{T::VAL == 5}>: True {}
    |                                      ^^^^^^ cannot perform const operation using `T`
@@ -8,7 +8,7 @@ LL | impl<T: Foo> MyTrait for T where Is<{T::VAL == 5}>: True {}
    = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
-  --> $DIR/issue-64494.rs:19:38
+  --> $DIR/issue-64494.rs:18:38
    |
 LL | impl<T: Foo> MyTrait for T where Is<{T::VAL == 6}>: True {}
    |                                      ^^^^^^ cannot perform const operation using `T`
@@ -17,7 +17,7 @@ LL | impl<T: Foo> MyTrait for T where Is<{T::VAL == 6}>: True {}
    = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error[E0119]: conflicting implementations of trait `MyTrait`:
-  --> $DIR/issue-64494.rs:19:1
+  --> $DIR/issue-64494.rs:18:1
    |
 LL | impl<T: Foo> MyTrait for T where Is<{T::VAL == 5}>: True {}
    | ------------------------------------ first implementation here
index 014742be03db609f858a3b7ae8f362ba412dfc6f..96d19203109a5761b2cb11717a2c0f44f3b324b0 100644 (file)
@@ -1,7 +1,6 @@
 // revisions: full min
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 trait Foo {
     const VAL: usize;
index 1ca709d09755bc7bc71a0cf82acb1ab3999279cc..8c603b74b90710d8f877e642f050e9b17e23bd0e 100644 (file)
@@ -2,7 +2,6 @@
 // revisions: full min
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 struct Foo<const D: usize> {
     state: Option<[u8; D]>,
index a1520912e4e2bb2930f3c8ec401722043e33616b..7e150f5f6db5ac9d1aa1dec9788e23a4c77e2d95 100644 (file)
@@ -1,5 +1,5 @@
 error: constant expression depends on a generic parameter
-  --> $DIR/issue-66205.rs:8:12
+  --> $DIR/issue-66205.rs:7:12
    |
 LL |     fact::<{ N - 1 }>();
    |            ^^^^^^^^^
index ecd96ac37e404c059329b91d632ff0023a91d563..b41793b62d2dc0f5da7d59b24b1abea32f962108 100644 (file)
@@ -1,5 +1,5 @@
 error: generic parameters may not be used in const operations
-  --> $DIR/issue-66205.rs:8:14
+  --> $DIR/issue-66205.rs:7:14
    |
 LL |     fact::<{ N - 1 }>();
    |              ^ cannot perform const operation using `N`
index 4e37c247d008ed461f3596cdebd3cd08005b4674..14249b62ceed835e6cd768f62cfbfad9259d8bf4 100644 (file)
@@ -1,7 +1,6 @@
 // revisions: full min
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 #![allow(dead_code, unconditional_recursion)]
 
 fn fact<const N: usize>() {
index 3e048593c9b2ca8dc156199c0849b9112b13027b..a871b118dcc5265d3df78752affde7908eefacaf 100644 (file)
@@ -2,7 +2,6 @@
 // revisions: full min
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 pub struct Tuple;
 
index 09d88ef89a308f86998e130d2c9ed42c0641ce91..ed35a5f7c0a879409011988d169205f7d59ea994 100644 (file)
@@ -2,7 +2,6 @@
 // revisions: full min
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 trait Baz {
     type Quaks;
index 78c7ebff059855d658e38177173ffa9953c95327..fa9c680d4b8dd8b67b9528e75bda17cc8f054080 100644 (file)
@@ -1,5 +1,5 @@
 error[E0277]: the trait bound `[u16; 3]: Bar` is not satisfied
-  --> $DIR/issue-67185-2.rs:17:1
+  --> $DIR/issue-67185-2.rs:16:1
    |
 LL | / trait Foo
 LL | |
@@ -17,7 +17,7 @@ LL | | }
    = help: add `#![feature(trivial_bounds)]` to the crate attributes to enable
 
 error[E0277]: the trait bound `[[u16; 3]; 2]: Bar` is not satisfied
-  --> $DIR/issue-67185-2.rs:17:1
+  --> $DIR/issue-67185-2.rs:16:1
    |
 LL | / trait Foo
 LL | |
@@ -35,7 +35,7 @@ LL | | }
    = help: add `#![feature(trivial_bounds)]` to the crate attributes to enable
 
 error[E0277]: the trait bound `[u16; 3]: Bar` is not satisfied
-  --> $DIR/issue-67185-2.rs:27:6
+  --> $DIR/issue-67185-2.rs:26:6
    |
 LL | trait Foo
    |       --- required by a bound in this
@@ -51,7 +51,7 @@ LL | impl Foo for FooImpl {}
              <[u16; 4] as Bar>
 
 error[E0277]: the trait bound `[[u16; 3]; 2]: Bar` is not satisfied
-  --> $DIR/issue-67185-2.rs:27:6
+  --> $DIR/issue-67185-2.rs:26:6
    |
 LL | trait Foo
    |       --- required by a bound in this
@@ -67,7 +67,7 @@ LL | impl Foo for FooImpl {}
              <[u16; 4] as Bar>
 
 error[E0277]: the trait bound `[[u16; 3]; 2]: Bar` is not satisfied
-  --> $DIR/issue-67185-2.rs:31:14
+  --> $DIR/issue-67185-2.rs:30:14
    |
 LL | trait Foo
    |       --- required by a bound in this
@@ -83,7 +83,7 @@ LL | fn f(_: impl Foo) {}
              <[u16; 4] as Bar>
 
 error[E0277]: the trait bound `[u16; 3]: Bar` is not satisfied
-  --> $DIR/issue-67185-2.rs:31:14
+  --> $DIR/issue-67185-2.rs:30:14
    |
 LL | trait Foo
    |       --- required by a bound in this
index 78c7ebff059855d658e38177173ffa9953c95327..fa9c680d4b8dd8b67b9528e75bda17cc8f054080 100644 (file)
@@ -1,5 +1,5 @@
 error[E0277]: the trait bound `[u16; 3]: Bar` is not satisfied
-  --> $DIR/issue-67185-2.rs:17:1
+  --> $DIR/issue-67185-2.rs:16:1
    |
 LL | / trait Foo
 LL | |
@@ -17,7 +17,7 @@ LL | | }
    = help: add `#![feature(trivial_bounds)]` to the crate attributes to enable
 
 error[E0277]: the trait bound `[[u16; 3]; 2]: Bar` is not satisfied
-  --> $DIR/issue-67185-2.rs:17:1
+  --> $DIR/issue-67185-2.rs:16:1
    |
 LL | / trait Foo
 LL | |
@@ -35,7 +35,7 @@ LL | | }
    = help: add `#![feature(trivial_bounds)]` to the crate attributes to enable
 
 error[E0277]: the trait bound `[u16; 3]: Bar` is not satisfied
-  --> $DIR/issue-67185-2.rs:27:6
+  --> $DIR/issue-67185-2.rs:26:6
    |
 LL | trait Foo
    |       --- required by a bound in this
@@ -51,7 +51,7 @@ LL | impl Foo for FooImpl {}
              <[u16; 4] as Bar>
 
 error[E0277]: the trait bound `[[u16; 3]; 2]: Bar` is not satisfied
-  --> $DIR/issue-67185-2.rs:27:6
+  --> $DIR/issue-67185-2.rs:26:6
    |
 LL | trait Foo
    |       --- required by a bound in this
@@ -67,7 +67,7 @@ LL | impl Foo for FooImpl {}
              <[u16; 4] as Bar>
 
 error[E0277]: the trait bound `[[u16; 3]; 2]: Bar` is not satisfied
-  --> $DIR/issue-67185-2.rs:31:14
+  --> $DIR/issue-67185-2.rs:30:14
    |
 LL | trait Foo
    |       --- required by a bound in this
@@ -83,7 +83,7 @@ LL | fn f(_: impl Foo) {}
              <[u16; 4] as Bar>
 
 error[E0277]: the trait bound `[u16; 3]: Bar` is not satisfied
-  --> $DIR/issue-67185-2.rs:31:14
+  --> $DIR/issue-67185-2.rs:30:14
    |
 LL | trait Foo
    |       --- required by a bound in this
index 1176d0c690403901d254de4caf0d356ee800f577..94a713d7cf95e58baa6cdbe8f315a4558e821734 100644 (file)
@@ -1,7 +1,6 @@
 // revisions: full min
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 trait Baz {
     type Quaks;
index 27a56b8eb02b2a0692f28bf6042155c77320600f..dcbe5b94a6281dfc3d70c297b8bb235e45fb0b00 100644 (file)
@@ -1,5 +1,5 @@
 error: constant expression depends on a generic parameter
-  --> $DIR/issue-67739.rs:12:15
+  --> $DIR/issue-67739.rs:11:15
    |
 LL |         [0u8; mem::size_of::<Self::Associated>()];
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
index 27a56b8eb02b2a0692f28bf6042155c77320600f..dcbe5b94a6281dfc3d70c297b8bb235e45fb0b00 100644 (file)
@@ -1,5 +1,5 @@
 error: constant expression depends on a generic parameter
-  --> $DIR/issue-67739.rs:12:15
+  --> $DIR/issue-67739.rs:11:15
    |
 LL |         [0u8; mem::size_of::<Self::Associated>()];
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
index 0f5860f22fdd34310f6132bda694682531ac76fe..e4960e56c9e4ea7ce9e875860b19a5b6c23ab78f 100644 (file)
@@ -1,7 +1,6 @@
 // revisions: full min
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 use std::mem;
 
index ac774f50c74938b23855fcc90a4a188d39589df9..4015fb090b934dc345a6f4ab4754138bf0ed0cf8 100644 (file)
@@ -1,5 +1,5 @@
 error[E0207]: the const parameter `N` is not constrained by the impl trait, self type, or predicates
-  --> $DIR/issue-68366.rs:12:13
+  --> $DIR/issue-68366.rs:11:13
    |
 LL | impl <const N: usize> Collatz<{Some(N)}> {}
    |             ^ unconstrained const parameter
@@ -8,7 +8,7 @@ LL | impl <const N: usize> Collatz<{Some(N)}> {}
    = note: proving the result of expressions other than the parameter are unique is not supported
 
 error[E0207]: the const parameter `N` is not constrained by the impl trait, self type, or predicates
-  --> $DIR/issue-68366.rs:18:12
+  --> $DIR/issue-68366.rs:17:12
    |
 LL | impl<const N: usize> Foo {}
    |            ^ unconstrained const parameter
index acaf4a33ee0a88548c34a6fd72e23f9d0e4009e9..da4cbd3081f894928bfc27222575eb181fa060d5 100644 (file)
@@ -1,5 +1,5 @@
 error: generic parameters may not be used in const operations
-  --> $DIR/issue-68366.rs:12:37
+  --> $DIR/issue-68366.rs:11:37
    |
 LL | impl <const N: usize> Collatz<{Some(N)}> {}
    |                                     ^ cannot perform const operation using `N`
@@ -8,7 +8,7 @@ LL | impl <const N: usize> Collatz<{Some(N)}> {}
    = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error[E0207]: the const parameter `N` is not constrained by the impl trait, self type, or predicates
-  --> $DIR/issue-68366.rs:12:13
+  --> $DIR/issue-68366.rs:11:13
    |
 LL | impl <const N: usize> Collatz<{Some(N)}> {}
    |             ^ unconstrained const parameter
@@ -17,7 +17,7 @@ LL | impl <const N: usize> Collatz<{Some(N)}> {}
    = note: proving the result of expressions other than the parameter are unique is not supported
 
 error[E0207]: the const parameter `N` is not constrained by the impl trait, self type, or predicates
-  --> $DIR/issue-68366.rs:18:12
+  --> $DIR/issue-68366.rs:17:12
    |
 LL | impl<const N: usize> Foo {}
    |            ^ unconstrained const parameter
index 474cdb7258d96478eb2a3f6c30991e970c024738..37afed62327d612b4881e4af24ee05479e698b12 100644 (file)
@@ -5,7 +5,6 @@
 // revisions: full min
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 struct Collatz<const N: Option<usize>>;
 
index 3b27d4d68c5d440bd8954de299fc1c99d503b261..0bb23be1eb4ea3bea13dc7fe5cf876d78a95ea47 100644 (file)
@@ -2,7 +2,6 @@
 // revisions: full min
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 pub struct S(u8);
 
index 59653114a6b61f81582fc39526532c5de1b629ab..2de8ada276610f3eaae8539df0473362ba62e68e 100644 (file)
@@ -1,5 +1,5 @@
 error: `[usize; 0]` is forbidden as the type of a const generic parameter
-  --> $DIR/issue-68615-adt.rs:7:23
+  --> $DIR/issue-68615-adt.rs:6:23
    |
 LL | struct Const<const V: [usize; 0]> {}
    |                       ^^^^^^^^^^
index d616f3ab95a822581724dbae5dc78ab573ef2a38..ddea3e8ab6587d9993eeada78b59cf40ad8e8ed3 100644 (file)
@@ -2,7 +2,6 @@
 // revisions: full min
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 struct Const<const V: [usize; 0]> {}
 //[min]~^ ERROR `[usize; 0]` is forbidden as the type of a const generic parameter
index 1ee881b96ec6037185bae03f24373e21f3ccd244..0d17b04a5cdd97780eaf06012086e59ec97054f0 100644 (file)
@@ -1,5 +1,5 @@
 error: `[usize; 0]` is forbidden as the type of a const generic parameter
-  --> $DIR/issue-68615-array.rs:7:21
+  --> $DIR/issue-68615-array.rs:6:21
    |
 LL | struct Foo<const V: [usize; 0] > {}
    |                     ^^^^^^^^^^
index 24c9a59a1855f04d9ba1d415a5ecc7585cd2bcf3..56afd9b2a154a75539e115026dc3e9163ec0c312 100644 (file)
@@ -2,7 +2,6 @@
 // revisions: full min
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 struct Foo<const V: [usize; 0] > {}
 //[min]~^ ERROR `[usize; 0]` is forbidden as the type of a const generic parameter
index 3690bac3eb342fc1bf2fa732d1422ca70275b052..25dcd88a4afcde81a8a898db52d97fb7797471ec 100644 (file)
@@ -1,5 +1,5 @@
 error: constant expression depends on a generic parameter
-  --> $DIR/issue-68977.rs:35:44
+  --> $DIR/issue-68977.rs:34:44
    |
 LL |     FxpStorageHelper<INT_BITS, FRAC_BITS>: FxpStorage,
    |                                            ^^^^^^^^^^
index ea91df1e0bf4db0c171bcf4a80a4a240188d4eee..0b3d5b9a760f704ab2af18f68bd4bb5df53060be 100644 (file)
@@ -1,5 +1,5 @@
 error: generic parameters may not be used in const operations
-  --> $DIR/issue-68977.rs:29:17
+  --> $DIR/issue-68977.rs:28:17
    |
 LL |     PhantomU8<{(INT_BITS + FRAC_BITS + 7) / 8}>;
    |                 ^^^^^^^^ cannot perform const operation using `INT_BITS`
@@ -8,7 +8,7 @@ LL |     PhantomU8<{(INT_BITS + FRAC_BITS + 7) / 8}>;
    = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
-  --> $DIR/issue-68977.rs:29:28
+  --> $DIR/issue-68977.rs:28:28
    |
 LL |     PhantomU8<{(INT_BITS + FRAC_BITS + 7) / 8}>;
    |                            ^^^^^^^^^ cannot perform const operation using `FRAC_BITS`
index 4fea94cb4652bf5f992a6730cfca6eedab970a57..a0ffcc84c7a37c53c6f5fcb48900d9746d9d3438 100644 (file)
@@ -1,7 +1,6 @@
 // revisions: full min
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 struct PhantomU8<const X: u8>;
 
index 04175089dc069510d4189d5921b4ce145074ffeb..5c118d245a1ec326106db55922ac9b93af357798 100644 (file)
@@ -2,7 +2,6 @@
 // revisions: full min
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 const L: usize = 4;
 
index ceefc2dcb32cfae181b2f75023e78e73d7d24a32..f82131262d6e31017e7b694f78940bf536b5ebea 100644 (file)
@@ -2,7 +2,6 @@
 // revisions: full min
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 fn main() {
     <()>::foo();
index 04c76a4dcaff763bf260db466b384dbf6c17650d..9e912b691773bcbcac6bddb8ab0bc8a136cbf701 100644 (file)
@@ -2,7 +2,6 @@
 // revisions: full min
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 pub trait Trait<const N: usize>: From<<Self as Trait<N>>::Item> {
   type Item;
index b87825d20ce321b1d15c4b299339629acf79885a..7b1a2f98dfeba2b4a1a147ce0de97255a2414116 100644 (file)
@@ -1,11 +1,11 @@
 error[E0770]: the type of const parameters must not depend on other generic parameters
-  --> $DIR/issue-71169.rs:6:43
+  --> $DIR/issue-71169.rs:5:43
    |
 LL | fn foo<const LEN: usize, const DATA: [u8; LEN]>() {}
    |                                           ^^^ the type must not depend on the parameter `LEN`
 
 error: constant expression depends on a generic parameter
-  --> $DIR/issue-71169.rs:11:14
+  --> $DIR/issue-71169.rs:10:14
    |
 LL |     foo::<4, DATA>();
    |              ^^^^
index 9b0a2946ca6cfa14dff6f1593f1d8fd2cb81e2d9..68ac47460b3590c4794d458863369a5049915daa 100644 (file)
@@ -1,11 +1,11 @@
 error[E0770]: the type of const parameters must not depend on other generic parameters
-  --> $DIR/issue-71169.rs:6:43
+  --> $DIR/issue-71169.rs:5:43
    |
 LL | fn foo<const LEN: usize, const DATA: [u8; LEN]>() {}
    |                                           ^^^ the type must not depend on the parameter `LEN`
 
 error: `[u8; _]` is forbidden as the type of a const generic parameter
-  --> $DIR/issue-71169.rs:6:38
+  --> $DIR/issue-71169.rs:5:38
    |
 LL | fn foo<const LEN: usize, const DATA: [u8; LEN]>() {}
    |                                      ^^^^^^^^^
index 7007ec222caa8440baedbcf45ca2e954a53edcda..a574da4b6b31dc7411f6ff2d6ae4914ba64572ba 100644 (file)
@@ -1,7 +1,6 @@
 // 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 LEN: usize, const DATA: [u8; LEN]>() {}
 //~^ ERROR the type of const parameters must not
index 453ef00e6dc1d4976fccae77352a223fc8b51e0e..3950317b3705330e58498bacddfd7c1f5092af43 100644 (file)
@@ -1,23 +1,23 @@
 error[E0770]: the type of const parameters must not depend on other generic parameters
-  --> $DIR/issue-71381.rs:15:82
+  --> $DIR/issue-71381.rs:14:82
    |
 LL |     pub fn call_me<Args: Sized, const IDX: usize, const FN: unsafe extern "C" fn(Args)>(&self) {
    |                                                                                  ^^^^ the type must not depend on the parameter `Args`
 
 error[E0770]: the type of const parameters must not depend on other generic parameters
-  --> $DIR/issue-71381.rs:24:40
+  --> $DIR/issue-71381.rs:23:40
    |
 LL |         const FN: unsafe extern "C" fn(Args),
    |                                        ^^^^ the type must not depend on the parameter `Args`
 
 error: using function pointers as const generic parameters is forbidden
-  --> $DIR/issue-71381.rs:15:61
+  --> $DIR/issue-71381.rs:14:61
    |
 LL |     pub fn call_me<Args: Sized, const IDX: usize, const FN: unsafe extern "C" fn(Args)>(&self) {
    |                                                             ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: using function pointers as const generic parameters is forbidden
-  --> $DIR/issue-71381.rs:24:19
+  --> $DIR/issue-71381.rs:23:19
    |
 LL |         const FN: unsafe extern "C" fn(Args),
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^
index 453ef00e6dc1d4976fccae77352a223fc8b51e0e..3950317b3705330e58498bacddfd7c1f5092af43 100644 (file)
@@ -1,23 +1,23 @@
 error[E0770]: the type of const parameters must not depend on other generic parameters
-  --> $DIR/issue-71381.rs:15:82
+  --> $DIR/issue-71381.rs:14:82
    |
 LL |     pub fn call_me<Args: Sized, const IDX: usize, const FN: unsafe extern "C" fn(Args)>(&self) {
    |                                                                                  ^^^^ the type must not depend on the parameter `Args`
 
 error[E0770]: the type of const parameters must not depend on other generic parameters
-  --> $DIR/issue-71381.rs:24:40
+  --> $DIR/issue-71381.rs:23:40
    |
 LL |         const FN: unsafe extern "C" fn(Args),
    |                                        ^^^^ the type must not depend on the parameter `Args`
 
 error: using function pointers as const generic parameters is forbidden
-  --> $DIR/issue-71381.rs:15:61
+  --> $DIR/issue-71381.rs:14:61
    |
 LL |     pub fn call_me<Args: Sized, const IDX: usize, const FN: unsafe extern "C" fn(Args)>(&self) {
    |                                                             ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: using function pointers as const generic parameters is forbidden
-  --> $DIR/issue-71381.rs:24:19
+  --> $DIR/issue-71381.rs:23:19
    |
 LL |         const FN: unsafe extern "C" fn(Args),
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^
index 65d88e553b9e5dd1ea324d3a41557abf1ce0a617..f015d6946954f57dc3506401d608d3fb1e8bee21 100644 (file)
@@ -1,7 +1,6 @@
 // revisions: full min
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 struct Test(*const usize);
 
index 3da85ee040de9951ecd0ef23f50e8f37dd299900..715037bd5f1e86e94f44ea67c3b79a72869e8686 100644 (file)
@@ -1,5 +1,5 @@
 error: using function pointers as const generic parameters is forbidden
-  --> $DIR/issue-71382.rs:17:23
+  --> $DIR/issue-71382.rs:16:23
    |
 LL |     fn test<const FN: fn()>(&self) {
    |                       ^^^^
index 3da85ee040de9951ecd0ef23f50e8f37dd299900..715037bd5f1e86e94f44ea67c3b79a72869e8686 100644 (file)
@@ -1,5 +1,5 @@
 error: using function pointers as const generic parameters is forbidden
-  --> $DIR/issue-71382.rs:17:23
+  --> $DIR/issue-71382.rs:16:23
    |
 LL |     fn test<const FN: fn()>(&self) {
    |                       ^^^^
index 12a7d08382a371c7d813a966a7e6f3ff7b02b1e9..3a56db937de093befcad095900225a8d1a5fd97d 100644 (file)
@@ -1,7 +1,6 @@
 // revisions: full min
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 struct Test();
 
index 48d4bb361a183a89595985efa5334d6eaf0b7e7f..01a85b745ce395d61e226b92a6dc28db8068efd2 100644 (file)
@@ -1,11 +1,11 @@
 error[E0770]: the type of const parameters must not depend on other generic parameters
-  --> $DIR/issue-71611.rs:6:31
+  --> $DIR/issue-71611.rs:5:31
    |
 LL | fn func<A, const F: fn(inner: A)>(outer: A) {
    |                               ^ the type must not depend on the parameter `A`
 
 error: using function pointers as const generic parameters is forbidden
-  --> $DIR/issue-71611.rs:6:21
+  --> $DIR/issue-71611.rs:5:21
    |
 LL | fn func<A, const F: fn(inner: A)>(outer: A) {
    |                     ^^^^^^^^^^^^
index 48d4bb361a183a89595985efa5334d6eaf0b7e7f..01a85b745ce395d61e226b92a6dc28db8068efd2 100644 (file)
@@ -1,11 +1,11 @@
 error[E0770]: the type of const parameters must not depend on other generic parameters
-  --> $DIR/issue-71611.rs:6:31
+  --> $DIR/issue-71611.rs:5:31
    |
 LL | fn func<A, const F: fn(inner: A)>(outer: A) {
    |                               ^ the type must not depend on the parameter `A`
 
 error: using function pointers as const generic parameters is forbidden
-  --> $DIR/issue-71611.rs:6:21
+  --> $DIR/issue-71611.rs:5:21
    |
 LL | fn func<A, const F: fn(inner: A)>(outer: A) {
    |                     ^^^^^^^^^^^^
index 9b8e8be6bc6fc72124b9f5008a83ba19eeee0fb3..6468d0b6bdae3fa163ebdc8336c1596a43315dd9 100644 (file)
@@ -1,7 +1,6 @@
 // revisions: full min
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 fn func<A, const F: fn(inner: A)>(outer: A) {
     //~^ ERROR: using function pointers as const generic parameters is forbidden
index 51f94678467437a7ac8541da7c419361205e778c..eedd73c4dcc0afd6542f456ace309328876c1381 100644 (file)
@@ -1,5 +1,5 @@
 error: using function pointers as const generic parameters is forbidden
-  --> $DIR/issue-72352.rs:8:42
+  --> $DIR/issue-72352.rs:7:42
    |
 LL | unsafe fn unsafely_do_the_thing<const F: fn(&CStr) -> usize>(ptr: *const i8) -> usize {
    |                                          ^^^^^^^^^^^^^^^^^^
index 51f94678467437a7ac8541da7c419361205e778c..eedd73c4dcc0afd6542f456ace309328876c1381 100644 (file)
@@ -1,5 +1,5 @@
 error: using function pointers as const generic parameters is forbidden
-  --> $DIR/issue-72352.rs:8:42
+  --> $DIR/issue-72352.rs:7:42
    |
 LL | unsafe fn unsafely_do_the_thing<const F: fn(&CStr) -> usize>(ptr: *const i8) -> usize {
    |                                          ^^^^^^^^^^^^^^^^^^
index 1517f3dae4ff4974d3c3210087ff5c16b879ffb8..9cd95c11026d743e1f6d8d703bbee572cad678b7 100644 (file)
@@ -1,7 +1,6 @@
 // revisions: full min
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 use std::ffi::{CStr, CString};
 
index b4c79d4171b7ac79281eb39d8428d309c9beee9b..fbb7ae59bef71b7917e0cab7bb90c2411024f390 100644 (file)
@@ -1,5 +1,5 @@
 error: constant expression depends on a generic parameter
-  --> $DIR/issue-72787.rs:11:32
+  --> $DIR/issue-72787.rs:10:32
    |
 LL |     Condition<{ LHS <= RHS }>: True
    |                                ^^^^
@@ -7,7 +7,7 @@ LL |     Condition<{ LHS <= RHS }>: True
    = note: this may fail depending on what value the parameter takes
 
 error: constant expression depends on a generic parameter
-  --> $DIR/issue-72787.rs:26:42
+  --> $DIR/issue-72787.rs:25:42
    |
 LL |     IsLessOrEqual<{ 8 - I }, { 8 - J }>: True,
    |                                          ^^^^
@@ -15,7 +15,7 @@ LL |     IsLessOrEqual<{ 8 - I }, { 8 - J }>: True,
    = note: this may fail depending on what value the parameter takes
 
 error: constant expression depends on a generic parameter
-  --> $DIR/issue-72787.rs:26:42
+  --> $DIR/issue-72787.rs:25:42
    |
 LL |     IsLessOrEqual<{ 8 - I }, { 8 - J }>: True,
    |                                          ^^^^
@@ -23,7 +23,7 @@ LL |     IsLessOrEqual<{ 8 - I }, { 8 - J }>: True,
    = note: this may fail depending on what value the parameter takes
 
 error: constant expression depends on a generic parameter
-  --> $DIR/issue-72787.rs:26:42
+  --> $DIR/issue-72787.rs:25:42
    |
 LL |     IsLessOrEqual<{ 8 - I }, { 8 - J }>: True,
    |                                          ^^^^
@@ -31,7 +31,7 @@ LL |     IsLessOrEqual<{ 8 - I }, { 8 - J }>: True,
    = note: this may fail depending on what value the parameter takes
 
 error: constant expression depends on a generic parameter
-  --> $DIR/issue-72787.rs:26:42
+  --> $DIR/issue-72787.rs:25:42
    |
 LL |     IsLessOrEqual<{ 8 - I }, { 8 - J }>: True,
    |                                          ^^^^
index 27bbc28011f2e5c9e84fcb69b216d41577dbdfb1..aadf19ba6b6f23eecb9186a7fed66b733ed04176 100644 (file)
@@ -1,5 +1,5 @@
 error: generic parameters may not be used in const operations
-  --> $DIR/issue-72787.rs:11:17
+  --> $DIR/issue-72787.rs:10:17
    |
 LL |     Condition<{ LHS <= RHS }>: True
    |                 ^^^ cannot perform const operation using `LHS`
@@ -8,7 +8,7 @@ LL |     Condition<{ LHS <= RHS }>: True
    = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
-  --> $DIR/issue-72787.rs:11:24
+  --> $DIR/issue-72787.rs:10:24
    |
 LL |     Condition<{ LHS <= RHS }>: True
    |                        ^^^ cannot perform const operation using `RHS`
@@ -17,7 +17,7 @@ LL |     Condition<{ LHS <= RHS }>: True
    = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
-  --> $DIR/issue-72787.rs:26:25
+  --> $DIR/issue-72787.rs:25:25
    |
 LL |     IsLessOrEqual<{ 8 - I }, { 8 - J }>: True,
    |                         ^ cannot perform const operation using `I`
@@ -26,7 +26,7 @@ LL |     IsLessOrEqual<{ 8 - I }, { 8 - J }>: True,
    = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
-  --> $DIR/issue-72787.rs:26:36
+  --> $DIR/issue-72787.rs:25:36
    |
 LL |     IsLessOrEqual<{ 8 - I }, { 8 - J }>: True,
    |                                    ^ cannot perform const operation using `J`
@@ -35,7 +35,7 @@ LL |     IsLessOrEqual<{ 8 - I }, { 8 - J }>: True,
    = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error[E0283]: type annotations needed
-  --> $DIR/issue-72787.rs:22:26
+  --> $DIR/issue-72787.rs:21:26
    |
 LL | pub trait True {}
    | -------------- required by this bound in `True`
@@ -46,7 +46,7 @@ LL |     IsLessOrEqual<I, 8>: True,
    = note: cannot satisfy `IsLessOrEqual<I, 8_u32>: True`
 
 error[E0283]: type annotations needed
-  --> $DIR/issue-72787.rs:22:26
+  --> $DIR/issue-72787.rs:21:26
    |
 LL | pub trait True {}
    | -------------- required by this bound in `True`
index 57572e23aa4dee8a83d7ab9c04ca87caae4be15f..16bc9470470f632cdbd15f4e19f1d62bc7ddba9d 100644 (file)
@@ -1,7 +1,6 @@
 // revisions: full min
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 pub struct IsLessOrEqual<const LHS: u32, const RHS: u32>;
 pub struct Condition<const CONDITION: bool>;
index b499400472153727cffe0974653311db1afe7bc4..82f9b9d346dd899865c80b6be7a5c225f50e3c95 100644 (file)
@@ -1,5 +1,5 @@
 error: constant expression depends on a generic parameter
-  --> $DIR/issue-72819-generic-in-const-eval.rs:9:39
+  --> $DIR/issue-72819-generic-in-const-eval.rs:8:39
    |
 LL | where Assert::<{N < usize::MAX / 2}>: IsTrue,
    |                                       ^^^^^^
index 8df3c85ec1f7749d83cccd11a225976b116896b0..6646be47b31e6d12ca3bd27f55e3c6d7f6e8a18e 100644 (file)
@@ -1,5 +1,5 @@
 error: generic parameters may not be used in const operations
-  --> $DIR/issue-72819-generic-in-const-eval.rs:9:17
+  --> $DIR/issue-72819-generic-in-const-eval.rs:8:17
    |
 LL | where Assert::<{N < usize::MAX / 2}>: IsTrue,
    |                 ^ cannot perform const operation using `N`
index 4c0004795f0dcabfe6e8a537c24afeb47af07d9a..f612d8bd3f6b197cdb743585d2b6e35092918ca2 100644 (file)
@@ -3,7 +3,6 @@
 // revisions: full min
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 struct Arr<const N: usize>
 where Assert::<{N < usize::MAX / 2}>: IsTrue,
index 3ff0563acc77d0281e3be0cd128ff5a33b0cb8f9..aeab9e267728f69c99873a5c4d3004f756fc726c 100644 (file)
@@ -1,5 +1,5 @@
 error: `[u32; _]` is forbidden as the type of a const generic parameter
-  --> $DIR/issue-73491.rs:9:19
+  --> $DIR/issue-73491.rs:8:19
    |
 LL | fn hoge<const IN: [u32; LEN]>() {}
    |                   ^^^^^^^^^^
index 4f6c44ad2cdb0fed2205297405f08dc67dd46480..c7cb92baf30aa47a2c74d60b95408c771b23d44e 100644 (file)
@@ -2,7 +2,6 @@
 // revisions: full min
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 const LEN: usize = 1024;
 
index 0816bad35b2de05dc732a32afa6fd3c5297f88b3..81691a14ef67e52545ba9060588e204f79191a76 100644 (file)
@@ -1,5 +1,5 @@
 error: using raw pointers as const generic parameters is forbidden
-  --> $DIR/issue-73508.rs:6:33
+  --> $DIR/issue-73508.rs:5:33
    |
 LL | pub const fn func_name<const X: *const u32>() {}
    |                                 ^^^^^^^^^^
index 0816bad35b2de05dc732a32afa6fd3c5297f88b3..81691a14ef67e52545ba9060588e204f79191a76 100644 (file)
@@ -1,5 +1,5 @@
 error: using raw pointers as const generic parameters is forbidden
-  --> $DIR/issue-73508.rs:6:33
+  --> $DIR/issue-73508.rs:5:33
    |
 LL | pub const fn func_name<const X: *const u32>() {}
    |                                 ^^^^^^^^^^
index 21b87f7f9014c31457c0f6b639e0133e0e5510b3..f02c4161dc109026c154b9adfd45f03c34907ef1 100644 (file)
@@ -1,7 +1,6 @@
 // revisions: full min
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 pub const fn func_name<const X: *const u32>() {}
 //~^ ERROR using raw pointers
index 1351246667e9bb9802b24898fb1454c243799d46..6561183f7cad42740a8605e395fbc46f4eae3525 100644 (file)
@@ -1,5 +1,5 @@
 error: `[u8; _]` is forbidden as the type of a const generic parameter
-  --> $DIR/issue-74101.rs:7:18
+  --> $DIR/issue-74101.rs:6:18
    |
 LL | fn test<const N: [u8; 1 + 2]>() {}
    |                  ^^^^^^^^^^^
@@ -8,7 +8,7 @@ LL | fn test<const N: [u8; 1 + 2]>() {}
    = help: more complex types are supported with `#[feature(const_generics)]`
 
 error: `[u8; _]` is forbidden as the type of a const generic parameter
-  --> $DIR/issue-74101.rs:10:21
+  --> $DIR/issue-74101.rs:9:21
    |
 LL | struct Foo<const N: [u8; 1 + 2]>;
    |                     ^^^^^^^^^^^
index 2a7d31ac8dd662502b4e87c67afc51face437e70..d4fd72eb6daa3b787d1c5bfe32df9cba16a58892 100644 (file)
@@ -2,7 +2,6 @@
 // revisions: full min
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 fn test<const N: [u8; 1 + 2]>() {}
 //[min]~^ ERROR `[u8; _]` is forbidden as the type of a const generic parameter
index e3e8502ae6349312f0528b86ec1cc2c19f48733b..2b6aa7dad97eec1ab9b732cd7b6b29bb7bded653 100644 (file)
@@ -1,5 +1,5 @@
 error: `IceEnum` is forbidden as the type of a const generic parameter
-  --> $DIR/issue-74255.rs:15:31
+  --> $DIR/issue-74255.rs:14:31
    |
 LL |     fn ice_struct_fn<const I: IceEnum>() {}
    |                               ^^^^^^^
index b277c273461c3ce8c540ea16cd3ba3a91af4267d..75a876c27e59de24f943fdf0978aafe187666af0 100644 (file)
@@ -2,7 +2,6 @@
 // revisions: full min
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 #[derive(PartialEq, Eq)]
 enum IceEnum {
index 12947a2ab37583497d7dd27645b14a6c206be47c..27393d38c6b1c95f9a67fe493b930f8fcdf35d49 100644 (file)
@@ -1,5 +1,5 @@
 error: `Inner` is forbidden as the type of a const generic parameter
-  --> $DIR/issue-74950.rs:18:23
+  --> $DIR/issue-74950.rs:17:23
    |
 LL | struct Outer<const I: Inner>;
    |                       ^^^^^
@@ -8,7 +8,7 @@ LL | struct Outer<const I: Inner>;
    = help: more complex types are supported with `#[feature(const_generics)]`
 
 error: `Inner` is forbidden as the type of a const generic parameter
-  --> $DIR/issue-74950.rs:18:23
+  --> $DIR/issue-74950.rs:17:23
    |
 LL | struct Outer<const I: Inner>;
    |                       ^^^^^
@@ -17,7 +17,7 @@ LL | struct Outer<const I: Inner>;
    = help: more complex types are supported with `#[feature(const_generics)]`
 
 error: `Inner` is forbidden as the type of a const generic parameter
-  --> $DIR/issue-74950.rs:18:23
+  --> $DIR/issue-74950.rs:17:23
    |
 LL | struct Outer<const I: Inner>;
    |                       ^^^^^
@@ -26,7 +26,7 @@ LL | struct Outer<const I: Inner>;
    = help: more complex types are supported with `#[feature(const_generics)]`
 
 error: `Inner` is forbidden as the type of a const generic parameter
-  --> $DIR/issue-74950.rs:18:23
+  --> $DIR/issue-74950.rs:17:23
    |
 LL | struct Outer<const I: Inner>;
    |                       ^^^^^
@@ -35,7 +35,7 @@ LL | struct Outer<const I: Inner>;
    = help: more complex types are supported with `#[feature(const_generics)]`
 
 error: `Inner` is forbidden as the type of a const generic parameter
-  --> $DIR/issue-74950.rs:18:23
+  --> $DIR/issue-74950.rs:17:23
    |
 LL | struct Outer<const I: Inner>;
    |                       ^^^^^
index 39f91f2b83dfbe7a08687457e57a5abf124c57ca..91e5cc776facf0c50122356dbcbee1f58b7b4990 100644 (file)
@@ -2,7 +2,6 @@
 // revisions: full min
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 
 #[derive(PartialEq, Eq)]
index b87bb18a5a6830cdd8d1e904700d02187b25e8ab..4ab90dd1ec6691ec4c0a752e7e8df90c02482206 100644 (file)
@@ -1,5 +1,5 @@
 error: `[u8; _]` is forbidden as the type of a const generic parameter
-  --> $DIR/issue-75047.rs:15:21
+  --> $DIR/issue-75047.rs:14:21
    |
 LL | struct Foo<const N: [u8; Bar::<u32>::value()]>;
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^
index 7bab7cdd0989e4c966dfeda2f418e60c253f01fa..97437748177e45eb6326235d01beddcec5f4065e 100644 (file)
@@ -2,7 +2,6 @@
 // revisions: full min
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 struct Bar<T>(T);
 
index 089937e66ca06bea2e3ff116bfebb0917b01f843..88b8ff89ffe109eab5a73dccf16f8d0f58627475 100644 (file)
@@ -1,5 +1,5 @@
 error: constant expression depends on a generic parameter
-  --> $DIR/issue-76701-ty-param-in-const.rs:6:21
+  --> $DIR/issue-76701-ty-param-in-const.rs:5:21
    |
 LL | fn ty_param<T>() -> [u8; std::mem::size_of::<T>()] {
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -7,7 +7,7 @@ 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
+  --> $DIR/issue-76701-ty-param-in-const.rs:11:37
    |
 LL | fn const_param<const N: usize>() -> [u8; N + 1] {
    |                                     ^^^^^^^^^^^
index 551b8e43e1d4c00298f8f733f4ad74320400a615..32f70fa30072764b142be2729d85e2e88ce6ed6a 100644 (file)
@@ -1,5 +1,5 @@
 error: generic parameters may not be used in const operations
-  --> $DIR/issue-76701-ty-param-in-const.rs:6:46
+  --> $DIR/issue-76701-ty-param-in-const.rs:5:46
    |
 LL | fn ty_param<T>() -> [u8; std::mem::size_of::<T>()] {
    |                                              ^ cannot perform const operation using `T`
@@ -8,7 +8,7 @@ LL | fn ty_param<T>() -> [u8; std::mem::size_of::<T>()] {
    = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
-  --> $DIR/issue-76701-ty-param-in-const.rs:12:42
+  --> $DIR/issue-76701-ty-param-in-const.rs:11:42
    |
 LL | fn const_param<const N: usize>() -> [u8; N + 1] {
    |                                          ^ cannot perform const operation using `N`
index 9051c36fe81f40aa8d5dd2a7c96583b4b7686438..9948982656357ace8b115c758f8f876e5ca9dfb0 100644 (file)
@@ -1,7 +1,6 @@
 // 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
diff --git a/src/test/ui/const-generics/issues/issue-80062.rs b/src/test/ui/const-generics/issues/issue-80062.rs
new file mode 100644 (file)
index 0000000..56dc532
--- /dev/null
@@ -0,0 +1,10 @@
+// Regression test for issue #80062 (fixed by `min_const_generics`)
+
+fn sof<T>() -> T { unimplemented!() }
+
+fn test<T>() {
+    let _: [u8; sof::<T>()];
+    //~^ ERROR generic parameters may not be used in const operations
+}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/issues/issue-80062.stderr b/src/test/ui/const-generics/issues/issue-80062.stderr
new file mode 100644 (file)
index 0000000..aad8907
--- /dev/null
@@ -0,0 +1,11 @@
+error: generic parameters may not be used in const operations
+  --> $DIR/issue-80062.rs:6:23
+   |
+LL |     let _: [u8; sof::<T>()];
+   |                       ^ cannot perform const operation using `T`
+   |
+   = note: type parameters may not be used in const expressions
+   = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/const-generics/issues/issue-80375.rs b/src/test/ui/const-generics/issues/issue-80375.rs
new file mode 100644 (file)
index 0000000..c906bb2
--- /dev/null
@@ -0,0 +1,4 @@
+struct MyArray<const COUNT: usize>([u8; COUNT + 1]);
+//~^ ERROR generic parameters may not be used in const operations
+
+fn main() {}
diff --git a/src/test/ui/const-generics/issues/issue-80375.stderr b/src/test/ui/const-generics/issues/issue-80375.stderr
new file mode 100644 (file)
index 0000000..9765a63
--- /dev/null
@@ -0,0 +1,11 @@
+error: generic parameters may not be used in const operations
+  --> $DIR/issue-80375.rs:1:41
+   |
+LL | struct MyArray<const COUNT: usize>([u8; COUNT + 1]);
+   |                                         ^^^^^ cannot perform const operation using `COUNT`
+   |
+   = help: const parameters may only be used as standalone arguments, i.e. `COUNT`
+   = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
+
+error: aborting due to previous error
+
index 28f80702dcf00c9093c810ab78cb63c3b0c3e5d6..189a32570f76b6245c319e44a0500bc9ab924296 100644 (file)
@@ -2,7 +2,6 @@
 // revisions: full min
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 trait T<const A: usize> {
     fn f();
index 3c9d4c9b4700f24f96be6d2840f46b391b147ea3..1883f454e602164bf7390bfad32e992356cbfd88 100644 (file)
@@ -1,5 +1,5 @@
 error: expressions must be enclosed in braces to be used as const generic arguments
-  --> $DIR/macro_rules-braces.rs:49:17
+  --> $DIR/macro_rules-braces.rs:48:17
    |
 LL |     let _: baz!(m::P);
    |                 ^^^^
@@ -10,7 +10,7 @@ LL |     let _: baz!({ m::P });
    |                 ^      ^
 
 error: expressions must be enclosed in braces to be used as const generic arguments
-  --> $DIR/macro_rules-braces.rs:69:17
+  --> $DIR/macro_rules-braces.rs:68:17
    |
 LL |     let _: baz!(10 + 7);
    |                 ^^^^^^
@@ -21,7 +21,7 @@ LL |     let _: baz!({ 10 + 7 });
    |                 ^        ^
 
 error: constant expression depends on a generic parameter
-  --> $DIR/macro_rules-braces.rs:16:13
+  --> $DIR/macro_rules-braces.rs:15:13
    |
 LL |             [u8; $x]
    |             ^^^^^^^^
@@ -33,7 +33,7 @@ LL |     let _: foo!({{ N }});
    = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: constant expression depends on a generic parameter
-  --> $DIR/macro_rules-braces.rs:21:13
+  --> $DIR/macro_rules-braces.rs:20:13
    |
 LL |             [u8; { $x }]
    |             ^^^^^^^^^^^^
@@ -45,7 +45,7 @@ LL |     let _: bar!({ N });
    = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: constant expression depends on a generic parameter
-  --> $DIR/macro_rules-braces.rs:26:13
+  --> $DIR/macro_rules-braces.rs:25:13
    |
 LL |             Foo<$x>
    |             ^^^^^^^
@@ -57,7 +57,7 @@ LL |     let _: baz!({{ N }});
    = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: constant expression depends on a generic parameter
-  --> $DIR/macro_rules-braces.rs:31:13
+  --> $DIR/macro_rules-braces.rs:30:13
    |
 LL |             Foo<{ $x }>
    |             ^^^^^^^^^^^
index c400e2c814dd70a872ec58e3a18dff04eff140ce..60583d43c0162d18a163f0c2df0d3db4c4e53055 100644 (file)
@@ -1,5 +1,5 @@
 error: expressions must be enclosed in braces to be used as const generic arguments
-  --> $DIR/macro_rules-braces.rs:49:17
+  --> $DIR/macro_rules-braces.rs:48:17
    |
 LL |     let _: baz!(m::P);
    |                 ^^^^
@@ -10,7 +10,7 @@ LL |     let _: baz!({ m::P });
    |                 ^      ^
 
 error: expressions must be enclosed in braces to be used as const generic arguments
-  --> $DIR/macro_rules-braces.rs:69:17
+  --> $DIR/macro_rules-braces.rs:68:17
    |
 LL |     let _: baz!(10 + 7);
    |                 ^^^^^^
@@ -21,7 +21,7 @@ LL |     let _: baz!({ 10 + 7 });
    |                 ^        ^
 
 error: generic parameters may not be used in const operations
-  --> $DIR/macro_rules-braces.rs:37:20
+  --> $DIR/macro_rules-braces.rs:36:20
    |
 LL |     let _: foo!({{ N }});
    |                    ^ cannot perform const operation using `N`
@@ -30,7 +30,7 @@ LL |     let _: foo!({{ N }});
    = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
-  --> $DIR/macro_rules-braces.rs:41:19
+  --> $DIR/macro_rules-braces.rs:40:19
    |
 LL |     let _: bar!({ N });
    |                   ^ cannot perform const operation using `N`
@@ -39,7 +39,7 @@ LL |     let _: bar!({ N });
    = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
-  --> $DIR/macro_rules-braces.rs:46:20
+  --> $DIR/macro_rules-braces.rs:45:20
    |
 LL |     let _: baz!({{ N }});
    |                    ^ cannot perform const operation using `N`
@@ -48,7 +48,7 @@ LL |     let _: baz!({{ N }});
    = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
-  --> $DIR/macro_rules-braces.rs:51:19
+  --> $DIR/macro_rules-braces.rs:50:19
    |
 LL |     let _: biz!({ N });
    |                   ^ cannot perform const operation using `N`
index c6b43bec243f4d46c6a85f805833840d14fed8aa..605a10880bbb178e25a9865bca720fc618fecf09 100644 (file)
@@ -1,7 +1,6 @@
 // revisions: full min
 #![cfg_attr(full, allow(incomplete_features))]
 #![cfg_attr(full, feature(const_generics))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 mod m {
     pub const P: usize = 0;
diff --git a/src/test/ui/const-generics/min-and-full-same-time.rs b/src/test/ui/const-generics/min-and-full-same-time.rs
deleted file mode 100644 (file)
index 2365adc..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-#![feature(const_generics)]
-//~^ ERROR features `const_generics` and `min_const_generics` are incompatible
-#![allow(incomplete_features)]
-#![feature(min_const_generics)]
-
-
-fn main() {}
diff --git a/src/test/ui/const-generics/min-and-full-same-time.stderr b/src/test/ui/const-generics/min-and-full-same-time.stderr
deleted file mode 100644 (file)
index 907fec9..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-error: features `const_generics` and `min_const_generics` are incompatible, using them at the same time is not allowed
-  --> $DIR/min-and-full-same-time.rs:1:12
-   |
-LL | #![feature(const_generics)]
-   |            ^^^^^^^^^^^^^^
-...
-LL | #![feature(min_const_generics)]
-   |            ^^^^^^^^^^^^^^^^^^
-   |
-   = help: remove one of these features
-
-error: aborting due to previous error
-
index fa75613d9ddc1d621394e259ee308dd9e6be4b53..27e971b5b6f9b03eb7eca16f257dcf4a6ebc592a 100644 (file)
@@ -1,6 +1,4 @@
 // check-pass
-#![feature(min_const_generics)]
-
 struct Foo<const N: usize>;
 
 impl<const N: usize> Foo<N> {
index 686ce98fcdff3f88f4a2a50a4ef7ee5e947067e4..7840989cb0814c156799f76b4a1f7bc919ecc313 100644 (file)
@@ -1,5 +1,3 @@
-#![feature(min_const_generics)]
-
 use std::mem::size_of;
 
 fn test<const N: usize>() {}
index 2ea66279d460881ed3c97f73bb90d01f91269a96..176692448491aaa0a4a3c0967808a45c391a5c9d 100644 (file)
@@ -1,5 +1,5 @@
 error: generic parameters may not be used in const operations
-  --> $DIR/complex-expression.rs:11:38
+  --> $DIR/complex-expression.rs:9:38
    |
 LL | struct Break0<const N: usize>([u8; { N + 1 }]);
    |                                      ^ cannot perform const operation using `N`
@@ -8,7 +8,7 @@ LL | struct Break0<const N: usize>([u8; { N + 1 }]);
    = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
-  --> $DIR/complex-expression.rs:14:40
+  --> $DIR/complex-expression.rs:12:40
    |
 LL | struct Break1<const N: usize>([u8; { { N } }]);
    |                                        ^ cannot perform const operation using `N`
@@ -17,7 +17,7 @@ LL | struct Break1<const N: usize>([u8; { { N } }]);
    = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
-  --> $DIR/complex-expression.rs:18:17
+  --> $DIR/complex-expression.rs:16:17
    |
 LL |     let _: [u8; N + 1];
    |                 ^ cannot perform const operation using `N`
@@ -26,7 +26,7 @@ LL |     let _: [u8; N + 1];
    = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
-  --> $DIR/complex-expression.rs:23:17
+  --> $DIR/complex-expression.rs:21:17
    |
 LL |     let _ = [0; N + 1];
    |                 ^ cannot perform const operation using `N`
@@ -35,7 +35,7 @@ LL |     let _ = [0; N + 1];
    = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
-  --> $DIR/complex-expression.rs:27:45
+  --> $DIR/complex-expression.rs:25:45
    |
 LL | struct BreakTy0<T>(T, [u8; { size_of::<*mut T>() }]);
    |                                             ^ cannot perform const operation using `T`
@@ -44,7 +44,7 @@ LL | struct BreakTy0<T>(T, [u8; { size_of::<*mut T>() }]);
    = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
-  --> $DIR/complex-expression.rs:30:47
+  --> $DIR/complex-expression.rs:28:47
    |
 LL | struct BreakTy1<T>(T, [u8; { { size_of::<*mut T>() } }]);
    |                                               ^ cannot perform const operation using `T`
@@ -53,7 +53,7 @@ LL | struct BreakTy1<T>(T, [u8; { { size_of::<*mut T>() } }]);
    = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
-  --> $DIR/complex-expression.rs:34:32
+  --> $DIR/complex-expression.rs:32:32
    |
 LL |     let _: [u8; size_of::<*mut T>() + 1];
    |                                ^ cannot perform const operation using `T`
@@ -62,7 +62,7 @@ LL |     let _: [u8; size_of::<*mut T>() + 1];
    = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 warning: cannot use constants which depend on generic parameters in types
-  --> $DIR/complex-expression.rs:39:17
+  --> $DIR/complex-expression.rs:37:17
    |
 LL |     let _ = [0; size_of::<*mut T>() + 1];
    |                 ^^^^^^^^^^^^^^^^^^^^^^^
index 2aaf2c39875583ca9ec703a4ad04e5d9b103013b..057bd5af89ef70480d8fd41f30f327b73ec1b7e9 100644 (file)
@@ -1,4 +1,3 @@
-#![feature(min_const_generics)]
 #![feature(never_type)]
 
 struct Foo<const N: [u8; 0]>;
index 5d473f1f8769fa8d477fd7770b888a3a57296d9b..20d498f9c93be77bca9db7f07f80025917110180 100644 (file)
@@ -1,5 +1,5 @@
 error: `[u8; 0]` is forbidden as the type of a const generic parameter
-  --> $DIR/complex-types.rs:4:21
+  --> $DIR/complex-types.rs:3:21
    |
 LL | struct Foo<const N: [u8; 0]>;
    |                     ^^^^^^^
@@ -8,7 +8,7 @@ LL | struct Foo<const N: [u8; 0]>;
    = help: more complex types are supported with `#[feature(const_generics)]`
 
 error: `()` is forbidden as the type of a const generic parameter
-  --> $DIR/complex-types.rs:7:21
+  --> $DIR/complex-types.rs:6:21
    |
 LL | struct Bar<const N: ()>;
    |                     ^^
@@ -17,7 +17,7 @@ LL | struct Bar<const N: ()>;
    = help: more complex types are supported with `#[feature(const_generics)]`
 
 error: `No` is forbidden as the type of a const generic parameter
-  --> $DIR/complex-types.rs:12:21
+  --> $DIR/complex-types.rs:11:21
    |
 LL | struct Fez<const N: No>;
    |                     ^^
@@ -26,7 +26,7 @@ LL | struct Fez<const N: No>;
    = help: more complex types are supported with `#[feature(const_generics)]`
 
 error: `&'static u8` is forbidden as the type of a const generic parameter
-  --> $DIR/complex-types.rs:15:21
+  --> $DIR/complex-types.rs:14:21
    |
 LL | struct Faz<const N: &'static u8>;
    |                     ^^^^^^^^^^^
@@ -35,7 +35,7 @@ LL | struct Faz<const N: &'static u8>;
    = help: more complex types are supported with `#[feature(const_generics)]`
 
 error: `!` is forbidden as the type of a const generic parameter
-  --> $DIR/complex-types.rs:18:21
+  --> $DIR/complex-types.rs:17:21
    |
 LL | struct Fiz<const N: !>;
    |                     ^
@@ -44,7 +44,7 @@ LL | struct Fiz<const N: !>;
    = help: more complex types are supported with `#[feature(const_generics)]`
 
 error: `()` is forbidden as the type of a const generic parameter
-  --> $DIR/complex-types.rs:21:19
+  --> $DIR/complex-types.rs:20:19
    |
 LL | enum Goo<const N: ()> { A, B }
    |                   ^^
@@ -53,7 +53,7 @@ LL | enum Goo<const N: ()> { A, B }
    = help: more complex types are supported with `#[feature(const_generics)]`
 
 error: `()` is forbidden as the type of a const generic parameter
-  --> $DIR/complex-types.rs:24:20
+  --> $DIR/complex-types.rs:23:20
    |
 LL | union Boo<const N: ()> { a: () }
    |                    ^^
index dd82be33a8e80b7be29d5c4c1da7641f28bcd49d..71d13ca61c9b3bfc634166ee31a47c4088933eaf 100644 (file)
@@ -1,5 +1,4 @@
 // check-pass
-#![feature(min_const_generics)]
 #![allow(dead_code)]
 
 fn foo<T>() {
index 4d0cab012f99e1fef4c9ab31b4c6422d4dfa89d0..f9f6660f6b823f4e67cc3d2edff4977b20eaaf01 100644 (file)
@@ -1,5 +1,5 @@
 warning: cannot use constants which depend on generic parameters in types
-  --> $DIR/const-evaluatable-unchecked.rs:6:9
+  --> $DIR/const-evaluatable-unchecked.rs:5:9
    |
 LL |     [0; std::mem::size_of::<*mut T>()];
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -9,7 +9,7 @@ LL |     [0; std::mem::size_of::<*mut T>()];
    = note: for more information, see issue #76200 <https://github.com/rust-lang/rust/issues/76200>
 
 warning: cannot use constants which depend on generic parameters in types
-  --> $DIR/const-evaluatable-unchecked.rs:17:21
+  --> $DIR/const-evaluatable-unchecked.rs:16:21
    |
 LL |         let _ = [0; Self::ASSOC];
    |                     ^^^^^^^^^^^
@@ -18,7 +18,7 @@ LL |         let _ = [0; Self::ASSOC];
    = note: for more information, see issue #76200 <https://github.com/rust-lang/rust/issues/76200>
 
 warning: cannot use constants which depend on generic parameters in types
-  --> $DIR/const-evaluatable-unchecked.rs:29:21
+  --> $DIR/const-evaluatable-unchecked.rs:28:21
    |
 LL |         let _ = [0; Self::ASSOC];
    |                     ^^^^^^^^^^^
index 13742238a201aa47a48d000dd9e58c56fc4a8fa9..beea0acac600a1c808094245c8e0f75514dd687e 100644 (file)
@@ -1,5 +1,5 @@
 error: comparison operators cannot be chained
-  --> $DIR/const-expression-suggest-missing-braces-without-turbofish.rs:8:8
+  --> $DIR/const-expression-suggest-missing-braces-without-turbofish.rs:6:8
    |
 LL |     foo<BAR + 3>();
    |        ^       ^
@@ -10,7 +10,7 @@ LL |     foo::<BAR + 3>();
    |        ^^
 
 error: comparison operators cannot be chained
-  --> $DIR/const-expression-suggest-missing-braces-without-turbofish.rs:11:8
+  --> $DIR/const-expression-suggest-missing-braces-without-turbofish.rs:9:8
    |
 LL |     foo<BAR + BAR>();
    |        ^         ^
@@ -21,7 +21,7 @@ LL |     foo::<BAR + BAR>();
    |        ^^
 
 error: comparison operators cannot be chained
-  --> $DIR/const-expression-suggest-missing-braces-without-turbofish.rs:14:8
+  --> $DIR/const-expression-suggest-missing-braces-without-turbofish.rs:12:8
    |
 LL |     foo<3 + 3>();
    |        ^     ^
@@ -32,7 +32,7 @@ LL |     foo::<3 + 3>();
    |        ^^
 
 error: comparison operators cannot be chained
-  --> $DIR/const-expression-suggest-missing-braces-without-turbofish.rs:17:8
+  --> $DIR/const-expression-suggest-missing-braces-without-turbofish.rs:15:8
    |
 LL |     foo<BAR - 3>();
    |        ^       ^
@@ -43,7 +43,7 @@ LL |     foo::<BAR - 3>();
    |        ^^
 
 error: comparison operators cannot be chained
-  --> $DIR/const-expression-suggest-missing-braces-without-turbofish.rs:20:8
+  --> $DIR/const-expression-suggest-missing-braces-without-turbofish.rs:18:8
    |
 LL |     foo<BAR - BAR>();
    |        ^         ^
@@ -54,7 +54,7 @@ LL |     foo::<BAR - BAR>();
    |        ^^
 
 error: comparison operators cannot be chained
-  --> $DIR/const-expression-suggest-missing-braces-without-turbofish.rs:23:8
+  --> $DIR/const-expression-suggest-missing-braces-without-turbofish.rs:21:8
    |
 LL |     foo<100 - BAR>();
    |        ^         ^
@@ -65,7 +65,7 @@ LL |     foo::<100 - BAR>();
    |        ^^
 
 error: comparison operators cannot be chained
-  --> $DIR/const-expression-suggest-missing-braces-without-turbofish.rs:26:8
+  --> $DIR/const-expression-suggest-missing-braces-without-turbofish.rs:24:8
    |
 LL |     foo<bar<i32>()>();
    |        ^   ^
@@ -76,13 +76,13 @@ LL |     foo::<bar<i32>()>();
    |        ^^
 
 error: expected one of `;` or `}`, found `>`
-  --> $DIR/const-expression-suggest-missing-braces-without-turbofish.rs:26:19
+  --> $DIR/const-expression-suggest-missing-braces-without-turbofish.rs:24:19
    |
 LL |     foo<bar<i32>()>();
    |                   ^ expected one of `;` or `}`
 
 error: comparison operators cannot be chained
-  --> $DIR/const-expression-suggest-missing-braces-without-turbofish.rs:30:8
+  --> $DIR/const-expression-suggest-missing-braces-without-turbofish.rs:28:8
    |
 LL |     foo<bar::<i32>()>();
    |        ^            ^
@@ -93,7 +93,7 @@ LL |     foo::<bar::<i32>()>();
    |        ^^
 
 error: comparison operators cannot be chained
-  --> $DIR/const-expression-suggest-missing-braces-without-turbofish.rs:33:8
+  --> $DIR/const-expression-suggest-missing-braces-without-turbofish.rs:31:8
    |
 LL |     foo<bar::<i32>() + BAR>();
    |        ^                  ^
@@ -104,7 +104,7 @@ LL |     foo::<bar::<i32>() + BAR>();
    |        ^^
 
 error: comparison operators cannot be chained
-  --> $DIR/const-expression-suggest-missing-braces-without-turbofish.rs:36:8
+  --> $DIR/const-expression-suggest-missing-braces-without-turbofish.rs:34:8
    |
 LL |     foo<bar::<i32>() - BAR>();
    |        ^                  ^
@@ -115,7 +115,7 @@ LL |     foo::<bar::<i32>() - BAR>();
    |        ^^
 
 error: comparison operators cannot be chained
-  --> $DIR/const-expression-suggest-missing-braces-without-turbofish.rs:39:8
+  --> $DIR/const-expression-suggest-missing-braces-without-turbofish.rs:37:8
    |
 LL |     foo<BAR - bar::<i32>()>();
    |        ^                  ^
@@ -126,7 +126,7 @@ LL |     foo::<BAR - bar::<i32>()>();
    |        ^^
 
 error: comparison operators cannot be chained
-  --> $DIR/const-expression-suggest-missing-braces-without-turbofish.rs:42:8
+  --> $DIR/const-expression-suggest-missing-braces-without-turbofish.rs:40:8
    |
 LL |     foo<BAR - bar::<i32>()>();
    |        ^                  ^
index 6adcf6a3e36d804359b2334ad4f6ee81a0595852..ad451fcf65df7ae583dde7037eeb828241998ce0 100644 (file)
@@ -1,5 +1,5 @@
 error: expected one of `,` or `>`, found `3`
-  --> $DIR/const-expression-suggest-missing-braces.rs:8:17
+  --> $DIR/const-expression-suggest-missing-braces.rs:6:17
    |
 LL |     foo::<BAR + 3>();
    |                 ^ expected one of `,` or `>`
@@ -10,7 +10,7 @@ LL |     foo::<{ BAR + 3 }>();
    |           ^         ^
 
 error: expressions must be enclosed in braces to be used as const generic arguments
-  --> $DIR/const-expression-suggest-missing-braces.rs:20:11
+  --> $DIR/const-expression-suggest-missing-braces.rs:18:11
    |
 LL |     foo::<3 + 3>();
    |           ^^^^^
@@ -21,7 +21,7 @@ LL |     foo::<{ 3 + 3 }>();
    |           ^       ^
 
 error: expected one of `,` or `>`, found `-`
-  --> $DIR/const-expression-suggest-missing-braces.rs:23:15
+  --> $DIR/const-expression-suggest-missing-braces.rs:21:15
    |
 LL |     foo::<BAR - 3>();
    |               ^ expected one of `,` or `>`
@@ -32,7 +32,7 @@ LL |     foo::<{ BAR - 3 }>();
    |           ^         ^
 
 error: expected one of `,` or `>`, found `-`
-  --> $DIR/const-expression-suggest-missing-braces.rs:26:15
+  --> $DIR/const-expression-suggest-missing-braces.rs:24:15
    |
 LL |     foo::<BAR - BAR>();
    |               ^ expected one of `,` or `>`
@@ -43,7 +43,7 @@ LL |     foo::<{ BAR - BAR }>();
    |           ^           ^
 
 error: expressions must be enclosed in braces to be used as const generic arguments
-  --> $DIR/const-expression-suggest-missing-braces.rs:29:11
+  --> $DIR/const-expression-suggest-missing-braces.rs:27:11
    |
 LL |     foo::<100 - BAR>();
    |           ^^^^^^^^^
@@ -54,7 +54,7 @@ LL |     foo::<{ 100 - BAR }>();
    |           ^           ^
 
 error: expected one of `,` or `>`, found `(`
-  --> $DIR/const-expression-suggest-missing-braces.rs:32:19
+  --> $DIR/const-expression-suggest-missing-braces.rs:30:19
    |
 LL |     foo::<bar<i32>()>();
    |                   ^ expected one of `,` or `>`
@@ -65,7 +65,7 @@ LL |     foo::<{ bar<i32>() }>();
    |           ^            ^
 
 error: expected one of `,` or `>`, found `(`
-  --> $DIR/const-expression-suggest-missing-braces.rs:35:21
+  --> $DIR/const-expression-suggest-missing-braces.rs:33:21
    |
 LL |     foo::<bar::<i32>()>();
    |                     ^ expected one of `,` or `>`
@@ -76,7 +76,7 @@ LL |     foo::<{ bar::<i32>() }>();
    |           ^              ^
 
 error: expected one of `,` or `>`, found `(`
-  --> $DIR/const-expression-suggest-missing-braces.rs:38:21
+  --> $DIR/const-expression-suggest-missing-braces.rs:36:21
    |
 LL |     foo::<bar::<i32>() + BAR>();
    |                     ^ expected one of `,` or `>`
@@ -87,7 +87,7 @@ LL |     foo::<{ bar::<i32>() + BAR }>();
    |           ^                    ^
 
 error: expected one of `,` or `>`, found `(`
-  --> $DIR/const-expression-suggest-missing-braces.rs:41:21
+  --> $DIR/const-expression-suggest-missing-braces.rs:39:21
    |
 LL |     foo::<bar::<i32>() - BAR>();
    |                     ^ expected one of `,` or `>`
@@ -98,7 +98,7 @@ LL |     foo::<{ bar::<i32>() - BAR }>();
    |           ^                    ^
 
 error: expected one of `,` or `>`, found `-`
-  --> $DIR/const-expression-suggest-missing-braces.rs:44:15
+  --> $DIR/const-expression-suggest-missing-braces.rs:42:15
    |
 LL |     foo::<BAR - bar::<i32>()>();
    |               ^ expected one of `,` or `>`
@@ -109,7 +109,7 @@ LL |     foo::<{ BAR - bar::<i32>() }>();
    |           ^                    ^
 
 error: expected one of `,` or `>`, found `-`
-  --> $DIR/const-expression-suggest-missing-braces.rs:47:15
+  --> $DIR/const-expression-suggest-missing-braces.rs:45:15
    |
 LL |     foo::<BAR - bar::<i32>()>();
    |               ^ expected one of `,` or `>`
@@ -120,19 +120,19 @@ LL |     foo::<{ BAR - bar::<i32>() }>();
    |           ^                    ^
 
 error[E0404]: expected trait, found constant `BAR`
-  --> $DIR/const-expression-suggest-missing-braces.rs:13:11
+  --> $DIR/const-expression-suggest-missing-braces.rs:11:11
    |
 LL |     foo::<BAR + BAR>();
    |           ^^^ not a trait
 
 error[E0404]: expected trait, found constant `BAR`
-  --> $DIR/const-expression-suggest-missing-braces.rs:13:17
+  --> $DIR/const-expression-suggest-missing-braces.rs:11:17
    |
 LL |     foo::<BAR + BAR>();
    |                 ^^^ not a trait
 
 warning: trait objects without an explicit `dyn` are deprecated
-  --> $DIR/const-expression-suggest-missing-braces.rs:13:11
+  --> $DIR/const-expression-suggest-missing-braces.rs:11:11
    |
 LL |     foo::<BAR + BAR>();
    |           ^^^^^^^^^ help: use `dyn`: `dyn BAR + BAR`
@@ -140,7 +140,7 @@ LL |     foo::<BAR + BAR>();
    = note: `#[warn(bare_trait_objects)]` on by default
 
 error[E0747]: type provided when a constant was expected
-  --> $DIR/const-expression-suggest-missing-braces.rs:13:11
+  --> $DIR/const-expression-suggest-missing-braces.rs:11:11
    |
 LL |     foo::<BAR + BAR>();
    |           ^^^^^^^^^
index 3370666cc5cd0450a21dcfc90c30b048f07fff95..0c10af6c43f560527c125a22d34d79ea59a44b05 100644 (file)
@@ -1,7 +1,5 @@
 // run-pass
 
-#![feature(min_const_generics)]
-
 const fn identity<const T: u32>() -> u32 { T }
 
 #[derive(Eq, PartialEq, Debug)]
index 7e0c1c2ed9fa0cd45fe3b7abfaab1466fcefaf43..d7918a73ab8b3726f06c618190f014019710e478 100644 (file)
@@ -1,5 +1,3 @@
-#![feature(min_const_generics)]
-
 fn foo<const SIZE: usize = 5>() {}
                       //~^ ERROR expected one of `!`, `(`, `+`, `,`, `::`, `<`, or `>`, found `=`
 
index ed1a83b6a4dd5b5b5cce919d4998e3b15856e224..8eb796d9bb7a8aa679012de4411d0a524e65cf4a 100644 (file)
@@ -1,5 +1,5 @@
 error: expected one of `!`, `(`, `+`, `,`, `::`, `<`, or `>`, found `=`
-  --> $DIR/default_function_param.rs:3:26
+  --> $DIR/default_function_param.rs:1:26
    |
 LL | fn foo<const SIZE: usize = 5>() {}
    |                          ^ expected one of 7 possible tokens
index 322ddccbf18994bc5fce14ec59c04f4e6138295c..c8003ad5d44d830466a0b67feb1f48cb118df5a5 100644 (file)
@@ -1,5 +1,3 @@
-#![feature(min_const_generics)]
-
 trait Foo<const KIND: bool = true> {}
                         //~^ ERROR expected one of `!`, `(`, `+`, `,`, `::`, `<`, or `>`, found `=`
 
index 49c3ac86744a0a33a468e54aaa3c855570c49295..6d112ef1de03302bec3e9e391cdae4643842501b 100644 (file)
@@ -1,5 +1,5 @@
 error: expected one of `!`, `(`, `+`, `,`, `::`, `<`, or `>`, found `=`
-  --> $DIR/default_trait_param.rs:3:28
+  --> $DIR/default_trait_param.rs:1:28
    |
 LL | trait Foo<const KIND: bool = true> {}
    |                            ^ expected one of 7 possible tokens
diff --git a/src/test/ui/const-generics/min_const_generics/feature-gate-min_const_generics.rs b/src/test/ui/const-generics/min_const_generics/feature-gate-min_const_generics.rs
deleted file mode 100644 (file)
index 423deae..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-fn test<const N: usize>() {}
-//~^ ERROR const generics are unstable
-
-fn main() {}
diff --git a/src/test/ui/const-generics/min_const_generics/feature-gate-min_const_generics.stderr b/src/test/ui/const-generics/min_const_generics/feature-gate-min_const_generics.stderr
deleted file mode 100644 (file)
index 7f82a96..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-error[E0658]: const generics are unstable
-  --> $DIR/feature-gate-min_const_generics.rs:1:15
-   |
-LL | fn test<const N: usize>() {}
-   |               ^
-   |
-   = note: see issue #74878 <https://github.com/rust-lang/rust/issues/74878> for more information
-   = help: add `#![feature(min_const_generics)]` to the crate attributes to enable
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0658`.
index 02944e2bff2f5e6c64961c54d81c15f2cd4f04a6..881f8b98aad086bb870e19068b0aa1bcd1849ca7 100644 (file)
@@ -1,5 +1,3 @@
-#![feature(min_const_generics)]
-
 // This test checks that non-static lifetimes are prohibited under `min_const_generics`. It
 // currently emits an error with `min_const_generics`. This will ICE under `const_generics`.
 
index cdfd491e39541bcf34742c12824e39f90b02c1ca..5def54ca26d978dff81e7bb13d456aa0eb0313d8 100644 (file)
@@ -1,5 +1,5 @@
 error[E0658]: a non-static lifetime is not allowed in a `const`
-  --> $DIR/forbid-non-static-lifetimes.rs:9:22
+  --> $DIR/forbid-non-static-lifetimes.rs:7:22
    |
 LL |     test::<{ let _: &'a (); 3 },>();
    |                      ^^
@@ -8,7 +8,7 @@ LL |     test::<{ let _: &'a (); 3 },>();
    = help: add `#![feature(const_generics)]` to the crate attributes to enable
 
 error[E0658]: a non-static lifetime is not allowed in a `const`
-  --> $DIR/forbid-non-static-lifetimes.rs:23:16
+  --> $DIR/forbid-non-static-lifetimes.rs:21:16
    |
 LL |     [(); (|_: &'a u8| (), 0).1];
    |                ^^
index e59b97922bea131e931791cbff303f0bdd21c185..a120eee67ee40b618e74f1b8cdf353950c6775cc 100644 (file)
@@ -1,4 +1,3 @@
-#![feature(min_const_generics)]
 use std::mem::transmute;
 
 fn get_flag<const FlagSet: bool, const ShortName: char>() -> Option<char> {
index a3157c6b5644d12f747d55bea5923fcccb66d2cf..04f716fa73351ce9fb36459119ee7ae4add9af68 100644 (file)
@@ -1,29 +1,29 @@
 error[E0308]: mismatched types
-  --> $DIR/invalid-patterns.rs:29:21
+  --> $DIR/invalid-patterns.rs:28:21
    |
 LL |   get_flag::<false, 0xFF>();
    |                     ^^^^ expected `char`, found `u8`
 
 error[E0308]: mismatched types
-  --> $DIR/invalid-patterns.rs:31:14
+  --> $DIR/invalid-patterns.rs:30:14
    |
 LL |   get_flag::<7, 'c'>();
    |              ^ expected `bool`, found integer
 
 error[E0308]: mismatched types
-  --> $DIR/invalid-patterns.rs:33:14
+  --> $DIR/invalid-patterns.rs:32:14
    |
 LL |   get_flag::<42, 0x5ad>();
    |              ^^ expected `bool`, found integer
 
 error[E0308]: mismatched types
-  --> $DIR/invalid-patterns.rs:33:18
+  --> $DIR/invalid-patterns.rs:32:18
    |
 LL |   get_flag::<42, 0x5ad>();
    |                  ^^^^^ expected `char`, found `u8`
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/invalid-patterns.rs:38:21
+  --> $DIR/invalid-patterns.rs:37:21
    |
 LL |   get_flag::<false, { unsafe { char_raw.character } }>();
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`)
@@ -31,7 +31,7 @@ LL |   get_flag::<false, { unsafe { char_raw.character } }>();
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/invalid-patterns.rs:40:14
+  --> $DIR/invalid-patterns.rs:39:14
    |
 LL |   get_flag::<{ unsafe { bool_raw.boolean } }, 'z'>();
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x42, but expected a boolean
@@ -39,7 +39,7 @@ LL |   get_flag::<{ unsafe { bool_raw.boolean } }, 'z'>();
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/invalid-patterns.rs:42:14
+  --> $DIR/invalid-patterns.rs:41:14
    |
 LL |   get_flag::<{ unsafe { bool_raw.boolean } }, { unsafe { char_raw.character } }>();
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x42, but expected a boolean
@@ -47,7 +47,7 @@ LL |   get_flag::<{ unsafe { bool_raw.boolean } }, { unsafe { char_raw.character
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/invalid-patterns.rs:42:47
+  --> $DIR/invalid-patterns.rs:41:47
    |
 LL |   get_flag::<{ unsafe { bool_raw.boolean } }, { unsafe { char_raw.character } }>();
    |                                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`)
index 1bd0c46f55e2ddf5e9835d33d66017ccac357ecb..f83518fc9d4763afd152e38e632577abead52f44 100644 (file)
@@ -1,5 +1,3 @@
-#![feature(min_const_generics)]
-
 struct Example<const N: usize>;
 
 macro_rules! external_macro {
index a5dedf6fe2053ef2b7d8474091bda36860b4dd92..22930a352a869115a353aa05dff7373353e7e039 100644 (file)
@@ -1,5 +1,5 @@
 error: expected type, found `{`
-  --> $DIR/macro-fail.rs:31:27
+  --> $DIR/macro-fail.rs:29:27
    |
 LL | fn make_marker() -> impl Marker<gimme_a_const!(marker)> {
    |                                 ----------------------
@@ -13,7 +13,7 @@ LL |       ($rusty: ident) => {{ let $rusty = 3; *&$rusty }}
    = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: expected type, found `{`
-  --> $DIR/macro-fail.rs:31:27
+  --> $DIR/macro-fail.rs:29:27
    |
 LL |   Example::<gimme_a_const!(marker)>
    |             ----------------------
@@ -27,7 +27,7 @@ LL |       ($rusty: ident) => {{ let $rusty = 3; *&$rusty }}
    = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: expected type, found `{`
-  --> $DIR/macro-fail.rs:6:10
+  --> $DIR/macro-fail.rs:4:10
    |
 LL |     () => {{
    |  __________^
@@ -46,7 +46,7 @@ LL |     let _fail = Example::<external_macro!()>;
    = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: unexpected end of macro invocation
-  --> $DIR/macro-fail.rs:41:25
+  --> $DIR/macro-fail.rs:39:25
    |
 LL |     macro_rules! gimme_a_const {
    |     -------------------------- when calling this macro
@@ -55,25 +55,25 @@ LL |   let _fail = Example::<gimme_a_const!()>;
    |                         ^^^^^^^^^^^^^^^^ missing tokens in macro arguments
 
 error[E0747]: type provided when a constant was expected
-  --> $DIR/macro-fail.rs:16:33
+  --> $DIR/macro-fail.rs:14:33
    |
 LL | fn make_marker() -> impl Marker<gimme_a_const!(marker)> {
    |                                 ^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0747]: type provided when a constant was expected
-  --> $DIR/macro-fail.rs:18:13
+  --> $DIR/macro-fail.rs:16:13
    |
 LL |   Example::<gimme_a_const!(marker)>
    |             ^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0747]: type provided when a constant was expected
-  --> $DIR/macro-fail.rs:38:25
+  --> $DIR/macro-fail.rs:36:25
    |
 LL |   let _fail = Example::<external_macro!()>;
    |                         ^^^^^^^^^^^^^^^^^
 
 error[E0747]: type provided when a constant was expected
-  --> $DIR/macro-fail.rs:41:25
+  --> $DIR/macro-fail.rs:39:25
    |
 LL |   let _fail = Example::<gimme_a_const!()>;
    |                         ^^^^^^^^^^^^^^^^
index 575fbd33572f094f5a284faf76ab9bb5499a68fa..9b63f76987a05e0fa2ccf9cfa7de2a50f49e695f 100644 (file)
@@ -1,6 +1,4 @@
 // run-pass
-#![feature(min_const_generics)]
-
 struct Example<const N: usize>;
 
 macro_rules! external_macro {
index 0973b373c122c6cc42b5862f4cb2f3d13b080f51..9ef619365a08c71765ee5007ede8f656242fb638 100644 (file)
@@ -1,5 +1,3 @@
-#![feature(min_const_generics)]
-
 trait Foo {
     fn t1() -> [u8; std::mem::size_of::<Self>()]; //~ERROR generic parameters
 }
index 40c73f0b95136bdb9114fa69939eef0c5591afe5..4fdfb5fbcb1a76eaa739584cb08f6bc132e4a46f 100644 (file)
@@ -1,5 +1,5 @@
 error: generic parameters may not be used in const operations
-  --> $DIR/self-ty-in-const-1.rs:4:41
+  --> $DIR/self-ty-in-const-1.rs:2:41
    |
 LL |     fn t1() -> [u8; std::mem::size_of::<Self>()];
    |                                         ^^^^ cannot perform const operation using `Self`
@@ -8,13 +8,13 @@ LL |     fn t1() -> [u8; std::mem::size_of::<Self>()];
    = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error: generic `Self` types are currently not permitted in anonymous constants
-  --> $DIR/self-ty-in-const-1.rs:14:41
+  --> $DIR/self-ty-in-const-1.rs:12:41
    |
 LL |     fn t3() -> [u8; std::mem::size_of::<Self>()] {}
    |                                         ^^^^
    |
 note: not a concrete type
-  --> $DIR/self-ty-in-const-1.rs:13:9
+  --> $DIR/self-ty-in-const-1.rs:11:9
    |
 LL | impl<T> Bar<T> {
    |         ^^^^^^
index e7f80d50082b367755cd94feab63b2aa64f780be..286ec2d24508416b73b5c82b873496f4c48104c3 100644 (file)
@@ -1,5 +1,3 @@
-#![feature(min_const_generics)]
-
 struct Bar<T>(T);
 
 trait Baz {
index 9ac6410a290a525978058ed3dfb49adc5269db15..41546292c47d1d847d57724dab6a1e853af4eade 100644 (file)
@@ -1,11 +1,11 @@
 error: generic `Self` types are currently not permitted in anonymous constants
-  --> $DIR/self-ty-in-const-2.rs:17:41
+  --> $DIR/self-ty-in-const-2.rs:15:41
    |
 LL |         let _: [u8; std::mem::size_of::<Self>()];
    |                                         ^^^^
    |
 note: not a concrete type
-  --> $DIR/self-ty-in-const-2.rs:15:17
+  --> $DIR/self-ty-in-const-2.rs:13:17
    |
 LL | impl<T> Baz for Bar<T> {
    |                 ^^^^^^
index 0ef17109bed40333528f57bc90f1cbb6181a53b5..7518dc59e599c89ee05a5a4531638f46d7010b94 100644 (file)
@@ -1,5 +1,3 @@
-#![feature(min_const_generics)]
-
 fn a<const X: &'static [u32]>() {}
 //~^ ERROR `&'static [u32]` is forbidden as the type of a const generic parameter
 
index 6c39f6b4c1dc3b8c9f623f0bc3a400fb20e4a480..05939b05bba3d6879d00ed6ad75d83eac57690a9 100644 (file)
@@ -1,5 +1,5 @@
 error: `&'static [u32]` is forbidden as the type of a const generic parameter
-  --> $DIR/static-reference-array-const-param.rs:3:15
+  --> $DIR/static-reference-array-const-param.rs:1:15
    |
 LL | fn a<const X: &'static [u32]>() {}
    |               ^^^^^^^^^^^^^^
index dfa1ece2f36578df3095ed52b37a4bce8136f347..560795a51f58ea645921a89c5b35ce18f6be35fb 100644 (file)
@@ -1,5 +1,3 @@
-#![feature(min_const_generics)]
-
 struct Const<const P: &'static ()>;
 //~^ ERROR `&'static ()` is forbidden as the type of a const generic parameter
 
index 6b90329b72cee19b193cfe3ea3e0776ecd96119d..8724c7e33b1cc9556c520e68598a0a8c900ce78e 100644 (file)
@@ -1,5 +1,5 @@
 error: `&'static ()` is forbidden as the type of a const generic parameter
-  --> $DIR/transmute-const-param-static-reference.rs:3:23
+  --> $DIR/transmute-const-param-static-reference.rs:1:23
    |
 LL | struct Const<const P: &'static ()>;
    |                       ^^^^^^^^^^^
index cf24cbe7e82bae335920d968727f3f53fcbcf15a..6a5739db3aefbfeb0a6befa0f89a6947787879d7 100644 (file)
@@ -3,7 +3,6 @@
 
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 
 use std::ops::AddAssign;
index 06ab9a6ff2910b26ee20a4223f92b58a8d6081bf..9d7ca36545c9c650a2f931a7a5950045fa49c9aa 100644 (file)
@@ -1,5 +1,5 @@
 error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants
-  --> $DIR/nested-type.rs:16:5
+  --> $DIR/nested-type.rs:15:5
    |
 LL |     Foo::<17>::value()
    |     ^^^^^^^^^^^^^^^^^^
index 369e387508e9fc46275fa292dd4362a582f4182d..dabb3f245f5b2c51c4983f76a6101bc7bb266a8f 100644 (file)
@@ -1,5 +1,5 @@
 error: `[u8; _]` is forbidden as the type of a const generic parameter
-  --> $DIR/nested-type.rs:7:21
+  --> $DIR/nested-type.rs:6:21
    |
 LL |   struct Foo<const N: [u8; {
    |  _____________________^
@@ -15,7 +15,7 @@ LL | | }]>;
    = help: more complex types are supported with `#[feature(const_generics)]`
 
 error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants
-  --> $DIR/nested-type.rs:16:5
+  --> $DIR/nested-type.rs:15:5
    |
 LL |     Foo::<17>::value()
    |     ^^^^^^^^^^^^^^^^^^
index c5660983985c3f81588fae000a61672fbc0108ac..be8ebb7f401f276c545cc1fd28e37f6faa3195bf 100644 (file)
@@ -2,7 +2,6 @@
 
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 struct Foo<const N: [u8; { //[min]~ ERROR `[u8; _]` is forbidden
     struct Foo<const N: usize>;
index 8a1462c59e810fffdef71afb4d87655b667829a7..671f1103dccad7fcfeb56f35c067cb35b5d5ca72 100644 (file)
@@ -6,7 +6,6 @@ LL | #![feature(const_generics)]
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-   = help: consider using `min_const_generics` instead, which is more stable and complete
 
 error: constant expression depends on a generic parameter
   --> $DIR/unify-fixpoint.rs:9:32
index 3dccfd73dcccb66ce94fe4a55dd18ffaa3061433..debb272da360848f2076c0fc8ab1782a31bc58bc 100644 (file)
@@ -1,5 +1,5 @@
 error: type parameters with a default must be trailing
-  --> $DIR/params-in-ct-in-ty-param-lazy-norm.rs:12:12
+  --> $DIR/params-in-ct-in-ty-param-lazy-norm.rs:11:12
    |
 LL | struct Bar<T = [u8; N], const N: usize>(T);
    |            ^
@@ -7,13 +7,13 @@ LL | struct Bar<T = [u8; N], const N: usize>(T);
    = note: using type defaults and const parameters in the same parameter list is currently not permitted
 
 error: constant values inside of type parameter defaults must not depend on generic parameters
-  --> $DIR/params-in-ct-in-ty-param-lazy-norm.rs:7:44
+  --> $DIR/params-in-ct-in-ty-param-lazy-norm.rs:6:44
    |
 LL | struct Foo<T, U = [u8; std::mem::size_of::<T>()]>(T, U);
    |                                            ^ the anonymous constant must not depend on the parameter `T`
 
 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
+  --> $DIR/params-in-ct-in-ty-param-lazy-norm.rs:11:21
    |
 LL | struct Bar<T = [u8; N], const N: usize>(T);
    |                     ^ the anonymous constant must not depend on the parameter `N`
index 9e0837a0a620c656254809b597f0d020f4f260b7..171efca19383135c679690482355b3864bd8b390 100644 (file)
@@ -1,5 +1,5 @@
 error: type parameters with a default must be trailing
-  --> $DIR/params-in-ct-in-ty-param-lazy-norm.rs:12:12
+  --> $DIR/params-in-ct-in-ty-param-lazy-norm.rs:11:12
    |
 LL | struct Bar<T = [u8; N], const N: usize>(T);
    |            ^
@@ -7,7 +7,7 @@ LL | struct Bar<T = [u8; N], const N: usize>(T);
    = note: using type defaults and const parameters in the same parameter list is currently not permitted
 
 error: generic parameters may not be used in const operations
-  --> $DIR/params-in-ct-in-ty-param-lazy-norm.rs:7:44
+  --> $DIR/params-in-ct-in-ty-param-lazy-norm.rs:6:44
    |
 LL | struct Foo<T, U = [u8; std::mem::size_of::<T>()]>(T, U);
    |                                            ^ cannot perform const operation using `T`
@@ -16,7 +16,7 @@ LL | struct Foo<T, U = [u8; std::mem::size_of::<T>()]>(T, U);
    = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 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
+  --> $DIR/params-in-ct-in-ty-param-lazy-norm.rs:11:21
    |
 LL | struct Bar<T = [u8; N], const N: usize>(T);
    |                     ^ the anonymous constant must not depend on the parameter `N`
index 51f0cff3f215e61e8f1da9cb07071cd932387464..845c6111b59683e51e2c6a0021ee339fc1355421 100644 (file)
@@ -2,7 +2,6 @@
 
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 struct Foo<T, U = [u8; std::mem::size_of::<T>()]>(T, U);
 //[full]~^ ERROR constant values inside of type parameter defaults
index ac568bb75f002c08576e3e2ddade3c77f0402fe1..ce9a1a0feb42070c573ae3dd7b2b2b2b964c749f 100644 (file)
@@ -1,7 +1,5 @@
 // run-pass
 // tests that promoting expressions containing const parameters is allowed.
-#![feature(min_const_generics)]
-
 fn promotion_test<const N: usize>() -> &'static usize {
     &(3 + N)
 }
index ffaab51f766d8d8b264c03f9096935041fc9a7cc..04bc46cb4ab12547bee30c4f95e71442e50e8c23 100644 (file)
@@ -1,11 +1,11 @@
 error: using raw pointers as const generic parameters is forbidden
-  --> $DIR/raw-ptr-const-param-deref.rs:10:23
+  --> $DIR/raw-ptr-const-param-deref.rs:9:23
    |
 LL | struct Const<const P: *const u32>;
    |                       ^^^^^^^^^^
 
 error: using raw pointers as const generic parameters is forbidden
-  --> $DIR/raw-ptr-const-param-deref.rs:12:15
+  --> $DIR/raw-ptr-const-param-deref.rs:11:15
    |
 LL | impl<const P: *const u32> Const<P> {
    |               ^^^^^^^^^^
index ffaab51f766d8d8b264c03f9096935041fc9a7cc..04bc46cb4ab12547bee30c4f95e71442e50e8c23 100644 (file)
@@ -1,11 +1,11 @@
 error: using raw pointers as const generic parameters is forbidden
-  --> $DIR/raw-ptr-const-param-deref.rs:10:23
+  --> $DIR/raw-ptr-const-param-deref.rs:9:23
    |
 LL | struct Const<const P: *const u32>;
    |                       ^^^^^^^^^^
 
 error: using raw pointers as const generic parameters is forbidden
-  --> $DIR/raw-ptr-const-param-deref.rs:12:15
+  --> $DIR/raw-ptr-const-param-deref.rs:11:15
    |
 LL | impl<const P: *const u32> Const<P> {
    |               ^^^^^^^^^^
index 20cc62ebc17cd408a4c48430cccbf1ed4ff047b0..ca7d33c0eb98496300f9640298aab3db90925d4b 100644 (file)
@@ -3,7 +3,6 @@
 
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 const A: u32 = 3;
 
index d317aa0f585cf9c616ae74b02b5f952ee24a5faa..310422aafcd352d05c6adc7a0f2cee6d74ca5b70 100644 (file)
@@ -1,5 +1,5 @@
 error: using raw pointers as const generic parameters is forbidden
-  --> $DIR/raw-ptr-const-param.rs:7:23
+  --> $DIR/raw-ptr-const-param.rs:6:23
    |
 LL | struct Const<const P: *const u32>;
    |                       ^^^^^^^^^^
index d317aa0f585cf9c616ae74b02b5f952ee24a5faa..310422aafcd352d05c6adc7a0f2cee6d74ca5b70 100644 (file)
@@ -1,5 +1,5 @@
 error: using raw pointers as const generic parameters is forbidden
-  --> $DIR/raw-ptr-const-param.rs:7:23
+  --> $DIR/raw-ptr-const-param.rs:6:23
    |
 LL | struct Const<const P: *const u32>;
    |                       ^^^^^^^^^^
index 36e593aa210223d8a85eb1a9f35298c5f5ee117e..a04c6d5e64e1983afe735d761038228bee262d43 100644 (file)
@@ -2,7 +2,6 @@
 
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 struct Const<const P: *const u32>; //~ ERROR: using raw pointers as const generic parameters
 
index d06da2ef0630a103210489cef75f82ec344dce56..80dd1be33c2416c54e71468f0c6ee3f1d89cdad6 100644 (file)
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/slice-const-param-mismatch.rs:15:35
+  --> $DIR/slice-const-param-mismatch.rs:14:35
    |
 LL |     let _: ConstString<"Hello"> = ConstString::<"World">;
    |            --------------------   ^^^^^^^^^^^^^^^^^^^^^^ expected `"Hello"`, found `"World"`
@@ -10,7 +10,7 @@ LL |     let _: ConstString<"Hello"> = ConstString::<"World">;
               found struct `ConstString<"World">`
 
 error[E0308]: mismatched types
-  --> $DIR/slice-const-param-mismatch.rs:17:33
+  --> $DIR/slice-const-param-mismatch.rs:16:33
    |
 LL |     let _: ConstString<"ℇ㇈↦"> = ConstString::<"ℇ㇈↥">;
    |            -------------------   ^^^^^^^^^^^^^^^^^^^^^ expected `"ℇ㇈↦"`, found `"ℇ㇈↥"`
@@ -21,7 +21,7 @@ LL |     let _: ConstString<"ℇ㇈↦"> = ConstString::<"ℇ㇈↥">;
               found struct `ConstString<"ℇ㇈↥">`
 
 error[E0308]: mismatched types
-  --> $DIR/slice-const-param-mismatch.rs:19:33
+  --> $DIR/slice-const-param-mismatch.rs:18:33
    |
 LL |     let _: ConstBytes<b"AAA"> = ConstBytes::<b"BBB">;
    |            ------------------   ^^^^^^^^^^^^^^^^^^^^ expected `b"AAA"`, found `b"BBB"`
index 46997fed770ac34fb0390fc647d9df383eb337ad..13d0b217ed29859eb027f97f998d71e175a48847 100644 (file)
@@ -1,5 +1,5 @@
 error: `&'static str` is forbidden as the type of a const generic parameter
-  --> $DIR/slice-const-param-mismatch.rs:8:29
+  --> $DIR/slice-const-param-mismatch.rs:7:29
    |
 LL | struct ConstString<const T: &'static str>;
    |                             ^^^^^^^^^^^^
@@ -8,7 +8,7 @@ LL | struct ConstString<const T: &'static str>;
    = help: more complex types are supported with `#[feature(const_generics)]`
 
 error: `&'static [u8]` is forbidden as the type of a const generic parameter
-  --> $DIR/slice-const-param-mismatch.rs:10:28
+  --> $DIR/slice-const-param-mismatch.rs:9:28
    |
 LL | struct ConstBytes<const T: &'static [u8]>;
    |                            ^^^^^^^^^^^^^
index 0f8ae9bac4a3ce24898c8f761c26f4fa2e865080..f020e2bf66fb066a073ec43e1e6429787660b9c9 100644 (file)
@@ -2,7 +2,6 @@
 
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 
 struct ConstString<const T: &'static str>;
index 7a9f65233e7937d3b82858313dca05bb0cd4a513..821c6e3995aa324140021fbd115743376749fb76 100644 (file)
@@ -1,5 +1,5 @@
 error: `&'static str` is forbidden as the type of a const generic parameter
-  --> $DIR/slice-const-param.rs:8:40
+  --> $DIR/slice-const-param.rs:7:40
    |
 LL | pub fn function_with_str<const STRING: &'static str>() -> &'static str {
    |                                        ^^^^^^^^^^^^
@@ -8,7 +8,7 @@ LL | pub fn function_with_str<const STRING: &'static str>() -> &'static str {
    = help: more complex types are supported with `#[feature(const_generics)]`
 
 error: `&'static [u8]` is forbidden as the type of a const generic parameter
-  --> $DIR/slice-const-param.rs:13:41
+  --> $DIR/slice-const-param.rs:12:41
    |
 LL | pub fn function_with_bytes<const BYTES: &'static [u8]>() -> &'static [u8] {
    |                                         ^^^^^^^^^^^^^
index f76e948c4af2b81ef0fce0735719e073ff6d8ccd..bf1bf8af9222c424d88b362772417c68191a9804 100644 (file)
@@ -3,7 +3,6 @@
 
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 pub fn function_with_str<const STRING: &'static str>() -> &'static str {
     //[min]~^ ERROR `&'static str` is forbidden
index 9274ccd2b921a9965a621ee0676168c58f6bf4a3..d7d2a8447e902c341285c0154e81036e4f7c2da6 100644 (file)
@@ -1,5 +1,5 @@
 error: `std::ops::Range<usize>` is forbidden as the type of a const generic parameter
-  --> $DIR/const-generics-range.rs:8:24
+  --> $DIR/const-generics-range.rs:7:24
    |
 LL | struct _Range<const R: std::ops::Range<usize>>;
    |                        ^^^^^^^^^^^^^^^^^^^^^^
@@ -8,7 +8,7 @@ LL | struct _Range<const R: std::ops::Range<usize>>;
    = help: more complex types are supported with `#[feature(const_generics)]`
 
 error: `RangeFrom<usize>` is forbidden as the type of a const generic parameter
-  --> $DIR/const-generics-range.rs:13:28
+  --> $DIR/const-generics-range.rs:12:28
    |
 LL | struct _RangeFrom<const R: std::ops::RangeFrom<usize>>;
    |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -17,7 +17,7 @@ LL | struct _RangeFrom<const R: std::ops::RangeFrom<usize>>;
    = help: more complex types are supported with `#[feature(const_generics)]`
 
 error: `RangeFull` is forbidden as the type of a const generic parameter
-  --> $DIR/const-generics-range.rs:18:28
+  --> $DIR/const-generics-range.rs:17:28
    |
 LL | struct _RangeFull<const R: std::ops::RangeFull>;
    |                            ^^^^^^^^^^^^^^^^^^^
@@ -26,7 +26,7 @@ LL | struct _RangeFull<const R: std::ops::RangeFull>;
    = help: more complex types are supported with `#[feature(const_generics)]`
 
 error: `RangeInclusive<usize>` is forbidden as the type of a const generic parameter
-  --> $DIR/const-generics-range.rs:24:33
+  --> $DIR/const-generics-range.rs:23:33
    |
 LL | struct _RangeInclusive<const R: std::ops::RangeInclusive<usize>>;
    |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -35,7 +35,7 @@ LL | struct _RangeInclusive<const R: std::ops::RangeInclusive<usize>>;
    = help: more complex types are supported with `#[feature(const_generics)]`
 
 error: `RangeTo<usize>` is forbidden as the type of a const generic parameter
-  --> $DIR/const-generics-range.rs:29:26
+  --> $DIR/const-generics-range.rs:28:26
    |
 LL | struct _RangeTo<const R: std::ops::RangeTo<usize>>;
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -44,7 +44,7 @@ LL | struct _RangeTo<const R: std::ops::RangeTo<usize>>;
    = help: more complex types are supported with `#[feature(const_generics)]`
 
 error: `RangeToInclusive<usize>` is forbidden as the type of a const generic parameter
-  --> $DIR/const-generics-range.rs:34:35
+  --> $DIR/const-generics-range.rs:33:35
    |
 LL | struct _RangeToInclusive<const R: std::ops::RangeToInclusive<usize>>;
    |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
index 136ac35289024c684fb8bf0445a12ad6b678df5a..deaab830e91d30e354cedf3cd5cb6cd8fd4e3739 100644 (file)
@@ -2,7 +2,6 @@
 // revisions: full min
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 // `Range` should be usable within const generics:
 struct _Range<const R: std::ops::Range<usize>>;
index e73a297c878f88f4e6ada939f54292ac7a43739b..db998033c0a2f803834e3c6e9a1606ade312ad65 100644 (file)
@@ -1,5 +1,5 @@
 error[E0573]: expected type, found const parameter `C`
-  --> $DIR/struct-with-invalid-const-param.rs:8:23
+  --> $DIR/struct-with-invalid-const-param.rs:7:23
    |
 LL | struct S<const C: u8>(C);
    |                       ^ not a type
index e73a297c878f88f4e6ada939f54292ac7a43739b..db998033c0a2f803834e3c6e9a1606ade312ad65 100644 (file)
@@ -1,5 +1,5 @@
 error[E0573]: expected type, found const parameter `C`
-  --> $DIR/struct-with-invalid-const-param.rs:8:23
+  --> $DIR/struct-with-invalid-const-param.rs:7:23
    |
 LL | struct S<const C: u8>(C);
    |                       ^ not a type
index f0122ace3aec3a5c97e71a69d918c5a79b299746..32970ccaa5dbc3d2c2a7067df3867a8753396079 100644 (file)
@@ -3,7 +3,6 @@
 
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 struct S<const C: u8>(C); //~ ERROR expected type, found const parameter
 
index b66d79845f971581f821b702ea1e88a8790c1bcf..30d05c708e14f3936cbacc00744df8f8964ef95b 100644 (file)
@@ -3,7 +3,6 @@
 
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 struct Const<const N: usize>;
 trait Foo<const N: usize> {}
index e041e9709d0ec56204caad2ebd7505736f22b63a..bf855d4dcaac87d7a7d33e3da12b48ebabd7d477 100644 (file)
@@ -3,7 +3,6 @@
 
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 use std::mem::MaybeUninit;
 
index 67a44d2c5b4ada4624ecc4ecb7033c182630d562..ad38754c7412e74057a30e76d75284f969e9db4c 100644 (file)
@@ -1,5 +1,5 @@
 error: type parameters must be declared prior to const parameters
-  --> $DIR/type-after-const-ok.rs:9:26
+  --> $DIR/type-after-const-ok.rs:8:26
    |
 LL | struct A<const N: usize, T>(T);
    |         -----------------^- help: reorder the parameters: lifetimes, then types, then consts: `<T, const N: usize>`
index 69227cdf19c33a64c383cbaf8d9872cf8e83c333..920c067dc1a726fd46da4a74b0bead3b862119eb 100644 (file)
@@ -3,7 +3,6 @@
 // Verifies that having generic parameters after constants is permitted
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 #[allow(dead_code)]
 struct A<const N: usize, T>(T);
index aa85376bf0d75268a0a898bca3423d317acc705c..cd9c3ae7bbc09ef3521aaf7e99c6d43912c3e181 100644 (file)
@@ -1,6 +1,5 @@
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 pub struct Struct<const N: usize>(());
 
index 3ccdd472613728351b030ba9bff54bce1f3aa9a8..4997d493bbb4a9e1d69afcadbe0a82f3f095e84b 100644 (file)
@@ -1,7 +1,6 @@
 // run-pass
 // revisions: full min
 #![cfg_attr(full, feature(const_generics))]
-#![cfg_attr(min, feature(min_const_generics))]
 #![allow(incomplete_features)]
 
 struct Foo;
index f3b19109a7c80e14cd49faf608ae1cb7966f8802..417fe2501ae3ef1a22961f2f0d9e978d00d894e3 100644 (file)
@@ -2,7 +2,6 @@
 // revisions: full min
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 trait SliceExt<T: Clone> {
     fn array_windows_example<'a, const N: usize>(&'a self) -> ArrayWindowsExample<'a, T, N>;
index 465b66b09ce22c85bd654fbe6b401e754585f159..2ece25bb41b2c1fedeed4f40bea837ac10bf3b74 100644 (file)
@@ -2,7 +2,6 @@
 // revisions: full min
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 trait T {
     fn test<const A: i32>(&self) -> i32 { A }
index 3d4910e9e4b40bf97590818953e968dfc5491b81..4a2c303095e55c6d221c69a391492eb1d7bfcd65 100644 (file)
@@ -2,7 +2,6 @@
 // revisions: full min
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 struct X;
 
index 0868d309b337d67ef0fa43200ddbbf38f51e5649..a1163fca8d4e221fc00c99d5cfaac1608e385e6d 100644 (file)
@@ -2,7 +2,6 @@
 // revisions: full min
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 struct A<const N: usize>;
 
index 4a374dc1db60be03b4857418d9fca9b8d85b6dab..75ddd839f664d069d39ebc339d4d67539ceec759 100644 (file)
@@ -2,7 +2,6 @@
 // revisions: full min
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 trait IterExt: Sized + Iterator {
     fn default_for_size<const N: usize>(self) -> [Self::Item; N]
index ba5a42e47e92da9e7b352f1952e2dc8d3355384a..b3585d5fc10753e1e297136765d34f9a3000a4b4 100644 (file)
@@ -3,7 +3,6 @@
 
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 struct Struct<const N: usize>;
 
index 234c09e04ae6d35a543fab83a3b7d7ecd374611d..df7c277f605baac155341eb896698b0198b62621 100644 (file)
@@ -2,7 +2,6 @@
 // revisions: full min
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 trait ConstChunksExactTrait<T> {
     fn const_chunks_exact<const N: usize>(&self) -> ConstChunksExact<'_, T, {N}>;
index fd52373cee218cb5ed7a6944850acd5b374dddb2..5fb571f2394dfa854ee7f269522579e62f4c48aa 100644 (file)
@@ -2,7 +2,6 @@
 // revisions: full min
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 use std::marker::PhantomData;
 
index 8f240f0d930a4ba7d2bcb04e58b02c91f5f59018..92f5d815a0fe8a3327d42e425291799fe1893427 100644 (file)
@@ -1,5 +1,5 @@
 error: `&'static str` is forbidden as the type of a const generic parameter
-  --> $DIR/issue-71348.rs:11:24
+  --> $DIR/issue-71348.rs:10:24
    |
 LL | trait Get<'a, const N: &'static str> {
    |                        ^^^^^^^^^^^^
@@ -8,7 +8,7 @@ LL | trait Get<'a, const N: &'static str> {
    = help: more complex types are supported with `#[feature(const_generics)]`
 
 error: `&'static str` is forbidden as the type of a const generic parameter
-  --> $DIR/issue-71348.rs:19:25
+  --> $DIR/issue-71348.rs:18:25
    |
 LL |     fn ask<'a, const N: &'static str>(&'a self) -> &'a <Self as Get<N>>::Target
    |                         ^^^^^^^^^^^^
index 772e179746ddb5e0df14837b7d9d645df847e0d2..33735ef87c5a394108a378e93339475c1dbcc24c 100644 (file)
@@ -2,7 +2,6 @@
 // revisions: full min
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 struct Foo {
     i: i32,
index da1d3270b7cccc2c678be8ccae8249089a6f2213..8ac9bab63208fc04f1452bedc479797322213bab 100644 (file)
@@ -1,5 +1,5 @@
 error: using function pointers as const generic parameters is forbidden
-  --> $DIR/issue-71382.rs:17:23
+  --> $DIR/issue-71382.rs:16:23
    |
 LL |     fn test<const FN: fn() -> u8>(&self) -> u8 {
    |                       ^^^^^^^^^^
index da1d3270b7cccc2c678be8ccae8249089a6f2213..8ac9bab63208fc04f1452bedc479797322213bab 100644 (file)
@@ -1,5 +1,5 @@
 error: using function pointers as const generic parameters is forbidden
-  --> $DIR/issue-71382.rs:17:23
+  --> $DIR/issue-71382.rs:16:23
    |
 LL |     fn test<const FN: fn() -> u8>(&self) -> u8 {
    |                       ^^^^^^^^^^
index 497fd1381de7f3d3901326e70182e3ecd68e687e..b3677613dbc8c7d5ac3795c45f7c1f1096cca084 100644 (file)
@@ -1,7 +1,6 @@
 // revisions: full min
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 struct Test;
 
index 2aaf12cea4f8c0fb252c569ec99f234f52b4a5ec..3701e14eadcfc1ecb3d824c09a646036c3702088 100644 (file)
@@ -2,7 +2,6 @@
 // revisions: full min
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 use std::mem::MaybeUninit;
 
index 3e53190ee48692117a500bd60d2f81916fa76434..5d7dcb9c458ab3398eef1d82dfdd09cebc3a0ae8 100644 (file)
@@ -2,7 +2,6 @@
 // revisions: full min
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 trait Foo<'a, A>: Iterator<Item=A> {
     fn bar<const N: usize>(&mut self) -> *const [A; N];
index 747664a0962997d365b2216ec69764420424690a..9e4afba311403fab2e6810ef9b26f1ad9267aa5f 100644 (file)
@@ -3,7 +3,6 @@
 // revisions: full min
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 extern crate type_dependent_lib;
 
index ec23ff1d2212273ac68ba935cf3cce89ae40bf3f..b61e970cfb37076ffc6c848ea127c518b8a29694 100644 (file)
@@ -2,7 +2,6 @@
 // revisions: full min
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 struct A;
 impl A {
index 70af65509231015197c622acaec2bc3765f6f575..a4776a43b21160d892cbe0c00468f092eb88b344 100644 (file)
@@ -2,7 +2,6 @@
 // revisions: full min
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 struct R;
 
index a530e63449d4038958472f80b23eedd3beac8622..b942c397a8d2b4280c0d2ef2ed994bda36ef27c9 100644 (file)
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/type-mismatch.rs:12:27
+  --> $DIR/type-mismatch.rs:11:27
    |
 LL |     assert_eq!(R.method::<1u16>(), 1);
    |                           ^^^^ expected `u8`, found `u16`
index a530e63449d4038958472f80b23eedd3beac8622..b942c397a8d2b4280c0d2ef2ed994bda36ef27c9 100644 (file)
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/type-mismatch.rs:12:27
+  --> $DIR/type-mismatch.rs:11:27
    |
 LL |     assert_eq!(R.method::<1u16>(), 1);
    |                           ^^^^ expected `u8`, found `u16`
index 67d80973f0397a46ab239ea019a4af092c78ce1b..7fba1afe9189f06b1a3b0fba782719ea70671777 100644 (file)
@@ -1,7 +1,6 @@
 // revisions: full min
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 struct R;
 
index f424fd03341fec6945058f72f9aa72c277ab21ce..9a2e9f09319d8a15667e3c025081944b9eb65c83 100644 (file)
@@ -3,7 +3,6 @@
 
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 trait T<const A: usize> {
     fn l<const N: bool>() -> usize;
index 265e9ee618be14d8e99f93eebf25c1e8a93027f3..480ecdb387346e06e044f399eb401fd70f30ebb6 100644 (file)
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/types-mismatch-const-args.rs:15:41
+  --> $DIR/types-mismatch-const-args.rs:14:41
    |
 LL |     let _: A<'a, u32, {2u32}, {3u32}> = A::<'a, u32, {4u32}, {3u32}> { data: PhantomData };
    |                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `2_u32`, found `4_u32`
@@ -8,7 +8,7 @@ LL |     let _: A<'a, u32, {2u32}, {3u32}> = A::<'a, u32, {4u32}, {3u32}> { data
               found type `4_u32`
 
 error[E0308]: mismatched types
-  --> $DIR/types-mismatch-const-args.rs:17:41
+  --> $DIR/types-mismatch-const-args.rs:16:41
    |
 LL |     let _: A<'a, u16, {2u32}, {3u32}> = A::<'b, u32, {2u32}, {3u32}> { data: PhantomData };
    |            --------------------------   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `u16`, found `u32`
index 27277f0c0befad0bab38dc682686de4c1a1565b3..c19c8db737a191be7d8822c9a808e923dc2df31a 100644 (file)
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/types-mismatch-const-args.rs:15:41
+  --> $DIR/types-mismatch-const-args.rs:14:41
    |
 LL |     let _: A<'a, u32, {2u32}, {3u32}> = A::<'a, u32, {4u32}, {3u32}> { data: PhantomData };
    |            --------------------------   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `2_u32`, found `4_u32`
@@ -10,7 +10,7 @@ LL |     let _: A<'a, u32, {2u32}, {3u32}> = A::<'a, u32, {4u32}, {3u32}> { data
               found struct `A<'_, _, 4_u32, _>`
 
 error[E0308]: mismatched types
-  --> $DIR/types-mismatch-const-args.rs:17:41
+  --> $DIR/types-mismatch-const-args.rs:16:41
    |
 LL |     let _: A<'a, u16, {2u32}, {3u32}> = A::<'b, u32, {2u32}, {3u32}> { data: PhantomData };
    |            --------------------------   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `u16`, found `u32`
index 34b85304cc4d1a90185d4df1ff76eca2b5f36578..14cef083d8373e393e7a9e4fcd7615b8b987a4cf 100644 (file)
@@ -1,7 +1,6 @@
 // revisions: full min
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 // tests the diagnostic output of type mismatches for types that have const generics arguments.
 
index 45afbdc9ab10556d11ad202bbd99186bc36029e9..9592f26623070ab8390458a022a0244e4786ecf4 100644 (file)
@@ -2,7 +2,6 @@
 // revisions: full min
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 use std::fmt;
 
index 65ae05e11982609398e2966f55410b2ee60738bf..4bab2bb5a77f57cf0bc34fc64634d944448874d8 100644 (file)
@@ -2,7 +2,6 @@
 // revisions: full min
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 use std::fmt;
 
index 94f3165eaec3106d5776e2948aea8f1c52edd971..b8b2e90aa66c6ae1a65a4a6796a55a58f4167b8d 100644 (file)
@@ -1,5 +1,5 @@
 error[E0412]: cannot find type `UnknownStruct` in this scope
-  --> $DIR/unknown_adt.rs:8:12
+  --> $DIR/unknown_adt.rs:7:12
    |
 LL |     let _: UnknownStruct<7>;
    |            ^^^^^^^^^^^^^ not found in this scope
index 94f3165eaec3106d5776e2948aea8f1c52edd971..b8b2e90aa66c6ae1a65a4a6796a55a58f4167b8d 100644 (file)
@@ -1,5 +1,5 @@
 error[E0412]: cannot find type `UnknownStruct` in this scope
-  --> $DIR/unknown_adt.rs:8:12
+  --> $DIR/unknown_adt.rs:7:12
    |
 LL |     let _: UnknownStruct<7>;
    |            ^^^^^^^^^^^^^ not found in this scope
index c6131402aeb6cb60dc73c775db65f644d6573f4a..977f90aad116d1a12c28047198a846d2578398ce 100644 (file)
@@ -2,7 +2,6 @@
 
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 fn main() {
     let _: UnknownStruct<7>;
index 3c305167b4b64d12bbc5525b2cab68b7eeaf1f6c..2918e399dc8ee7e8f7fc37416118457d84b1c0eb 100644 (file)
@@ -3,7 +3,6 @@
 
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 struct A<const N: usize>; // ok
 
index 1b075ade16a06cf3b560b5011bb6695eb27f1b1c..46d57e0dcfca8138b689fccddb23dd45638f4b9f 100644 (file)
@@ -4,7 +4,6 @@
 
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 #![warn(unused_braces)]
 
 
index 1752779a60a3a7e23a00d41046a88af094b75aa9..8899139aa6bb75a938e27f305963a989f189f1da 100644 (file)
@@ -1,11 +1,11 @@
 warning: unnecessary braces around const expression
-  --> $DIR/unused_braces.rs:15:14
+  --> $DIR/unused_braces.rs:14:14
    |
 LL |     let _: A<{ 7 }>;
    |              ^^^^^ help: remove these braces
    |
 note: the lint level is defined here
-  --> $DIR/unused_braces.rs:8:9
+  --> $DIR/unused_braces.rs:7:9
    |
 LL | #![warn(unused_braces)]
    |         ^^^^^^^^^^^^^
index 1b075ade16a06cf3b560b5011bb6695eb27f1b1c..46d57e0dcfca8138b689fccddb23dd45638f4b9f 100644 (file)
@@ -4,7 +4,6 @@
 
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 #![warn(unused_braces)]
 
 
index 1752779a60a3a7e23a00d41046a88af094b75aa9..8899139aa6bb75a938e27f305963a989f189f1da 100644 (file)
@@ -1,11 +1,11 @@
 warning: unnecessary braces around const expression
-  --> $DIR/unused_braces.rs:15:14
+  --> $DIR/unused_braces.rs:14:14
    |
 LL |     let _: A<{ 7 }>;
    |              ^^^^^ help: remove these braces
    |
 note: the lint level is defined here
-  --> $DIR/unused_braces.rs:8:9
+  --> $DIR/unused_braces.rs:7:9
    |
 LL | #![warn(unused_braces)]
    |         ^^^^^^^^^^^^^
index 31c4caf7ab8509037adfcc07f7e6fbb8f6413b54..0348bbacaabd2496f024a3d64604a450a394e1c9 100644 (file)
@@ -4,7 +4,6 @@
 
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 #![warn(unused_braces)]
 
 
index 4af48fa1590907a37ee96c93833d965719e467f5..dfb593a9507d5f5a03c84589583cf592f12bbb28 100644 (file)
@@ -1,5 +1,5 @@
 error: constant expression depends on a generic parameter
-  --> $DIR/wf-misc.rs:9:12
+  --> $DIR/wf-misc.rs:8:12
    |
 LL |     let _: [u8; N + 1];
    |            ^^^^^^^^^^^
@@ -7,7 +7,7 @@ LL |     let _: [u8; N + 1];
    = note: this may fail depending on what value the parameter takes
 
 error: constant expression depends on a generic parameter
-  --> $DIR/wf-misc.rs:17:12
+  --> $DIR/wf-misc.rs:16:12
    |
 LL |     let _: Const::<{N + 1}>;
    |            ^^^^^^^^^^^^^^^^
index 99142cb6ce7a585d959109023fb87942596d6796..9967a2218f6ec8967eda23a0b65c06c34f35493c 100644 (file)
@@ -1,5 +1,5 @@
 error: generic parameters may not be used in const operations
-  --> $DIR/wf-misc.rs:9:17
+  --> $DIR/wf-misc.rs:8:17
    |
 LL |     let _: [u8; N + 1];
    |                 ^ cannot perform const operation using `N`
@@ -8,7 +8,7 @@ LL |     let _: [u8; N + 1];
    = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
-  --> $DIR/wf-misc.rs:17:21
+  --> $DIR/wf-misc.rs:16:21
    |
 LL |     let _: Const::<{N + 1}>;
    |                     ^ cannot perform const operation using `N`
index 103c580f28fc44985d2c154fa619c339bbe511aa..8a5b6ddfe2668c9d83a4147da325d15246b0bad2 100644 (file)
@@ -3,7 +3,6 @@
 
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 pub fn arr_len<const N: usize>() {
     let _: [u8; N + 1];
index cdcaf25094240e586c4f3329eed37d38eb84b1ef..dc09cad3180bfbf6f8d3603c1f52b2596870818a 100644 (file)
@@ -2,7 +2,6 @@
 // revisions: full min
 #![cfg_attr(full, feature(const_generics))]
 #![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
 
 trait Bar<const N: usize> { fn bar() {} }
 trait Foo<const N: usize>: Bar<N> {}
diff --git a/src/test/ui/const-ptr/out_of_bounds_read.rs b/src/test/ui/const-ptr/out_of_bounds_read.rs
new file mode 100644 (file)
index 0000000..183aa9e
--- /dev/null
@@ -0,0 +1,16 @@
+// error-pattern: any use of this value will cause an error
+
+#![feature(const_ptr_read)]
+#![feature(const_ptr_offset)]
+
+fn main() {
+    use std::ptr;
+
+    const DATA: [u32; 1] = [42];
+
+    const PAST_END_PTR: *const u32 = unsafe { DATA.as_ptr().add(1) };
+
+    const _READ: u32 = unsafe { ptr::read(PAST_END_PTR) };
+    const _CONST_READ: u32 = unsafe { PAST_END_PTR.read() };
+    const _MUT_READ: u32 = unsafe { (PAST_END_PTR as *mut u32).read() };
+}
diff --git a/src/test/ui/const-ptr/out_of_bounds_read.stderr b/src/test/ui/const-ptr/out_of_bounds_read.stderr
new file mode 100644 (file)
index 0000000..ca65a07
--- /dev/null
@@ -0,0 +1,54 @@
+error: any use of this value will cause an error
+  --> $SRC_DIR/core/src/intrinsics.rs:LL:COL
+   |
+LL |     unsafe { copy_nonoverlapping(src, dst, count) }
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |              |
+   |              memory access failed: pointer must be in-bounds at offset 8, but is outside bounds of alloc6 which has size 4
+   |              inside `copy_nonoverlapping::<u32>` at $SRC_DIR/core/src/intrinsics.rs:LL:COL
+   |              inside `std::ptr::read::<u32>` at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+   |              inside `_READ` at $DIR/out_of_bounds_read.rs:13:33
+   | 
+  ::: $DIR/out_of_bounds_read.rs:13:5
+   |
+LL |     const _READ: u32 = unsafe { ptr::read(PAST_END_PTR) };
+   |     ------------------------------------------------------
+   |
+   = note: `#[deny(const_err)]` on by default
+
+error: any use of this value will cause an error
+  --> $SRC_DIR/core/src/intrinsics.rs:LL:COL
+   |
+LL |     unsafe { copy_nonoverlapping(src, dst, count) }
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |              |
+   |              memory access failed: pointer must be in-bounds at offset 8, but is outside bounds of alloc6 which has size 4
+   |              inside `copy_nonoverlapping::<u32>` at $SRC_DIR/core/src/intrinsics.rs:LL:COL
+   |              inside `std::ptr::read::<u32>` at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+   |              inside `ptr::const_ptr::<impl *const u32>::read` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+   |              inside `_CONST_READ` at $DIR/out_of_bounds_read.rs:14:39
+   | 
+  ::: $DIR/out_of_bounds_read.rs:14:5
+   |
+LL |     const _CONST_READ: u32 = unsafe { PAST_END_PTR.read() };
+   |     --------------------------------------------------------
+
+error: any use of this value will cause an error
+  --> $SRC_DIR/core/src/intrinsics.rs:LL:COL
+   |
+LL |     unsafe { copy_nonoverlapping(src, dst, count) }
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |              |
+   |              memory access failed: pointer must be in-bounds at offset 8, but is outside bounds of alloc6 which has size 4
+   |              inside `copy_nonoverlapping::<u32>` at $SRC_DIR/core/src/intrinsics.rs:LL:COL
+   |              inside `std::ptr::read::<u32>` at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+   |              inside `ptr::mut_ptr::<impl *mut u32>::read` at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL
+   |              inside `_MUT_READ` at $DIR/out_of_bounds_read.rs:15:37
+   | 
+  ::: $DIR/out_of_bounds_read.rs:15:5
+   |
+LL |     const _MUT_READ: u32 = unsafe { (PAST_END_PTR as *mut u32).read() };
+   |     --------------------------------------------------------------------
+
+error: aborting due to 3 previous errors
+
diff --git a/src/test/ui/consts/const-fn-error.rs b/src/test/ui/consts/const-fn-error.rs
new file mode 100644 (file)
index 0000000..68a4d41
--- /dev/null
@@ -0,0 +1,21 @@
+#![feature(const_fn)]
+
+const X : usize = 2;
+
+const fn f(x: usize) -> usize {
+    let mut sum = 0;
+    for i in 0..x {
+        //~^ ERROR mutable references
+        //~| ERROR calls in constant functions
+        //~| ERROR calls in constant functions
+        //~| ERROR E0080
+        //~| ERROR E0744
+        sum += i;
+    }
+    sum
+}
+
+#[allow(unused_variables)]
+fn main() {
+    let a : [i32; f(X)];
+}
diff --git a/src/test/ui/consts/const-fn-error.stderr b/src/test/ui/consts/const-fn-error.stderr
new file mode 100644 (file)
index 0000000..86b1eeb
--- /dev/null
@@ -0,0 +1,49 @@
+error[E0744]: `for` is not allowed in a `const fn`
+  --> $DIR/const-fn-error.rs:7:5
+   |
+LL | /     for i in 0..x {
+LL | |
+LL | |
+LL | |
+...  |
+LL | |         sum += i;
+LL | |     }
+   | |_____^
+
+error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+  --> $DIR/const-fn-error.rs:7:14
+   |
+LL |     for i in 0..x {
+   |              ^^^^
+
+error[E0658]: mutable references are not allowed in constant functions
+  --> $DIR/const-fn-error.rs:7:14
+   |
+LL |     for i in 0..x {
+   |              ^^^^
+   |
+   = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
+   = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+
+error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+  --> $DIR/const-fn-error.rs:7:14
+   |
+LL |     for i in 0..x {
+   |              ^^^^
+
+error[E0080]: evaluation of constant value failed
+  --> $DIR/const-fn-error.rs:7:14
+   |
+LL |     for i in 0..x {
+   |              ^^^^
+   |              |
+   |              calling non-const function `<std::ops::Range<usize> as IntoIterator>::into_iter`
+   |              inside `f` at $DIR/const-fn-error.rs:7:14
+...
+LL |     let a : [i32; f(X)];
+   |                   ---- inside `main::{constant#0}` at $DIR/const-fn-error.rs:20:19
+
+error: aborting due to 5 previous errors
+
+Some errors have detailed explanations: E0015, E0080, E0658, E0744.
+For more information about an error, try `rustc --explain E0015`.
index e8e6f1d390099a3974db7fd85f12aed64aeaef58..5c0d7d94d64f1bf061f4e5ca3e0c22309e957c32 100644 (file)
@@ -1,6 +1,7 @@
 // run-pass
 
 #![feature(const_size_of_val, const_align_of_val)]
+#![feature(const_size_of_val_raw, const_align_of_val_raw, layout_for_ptr)]
 
 use std::mem;
 
@@ -32,6 +33,9 @@ union Ugh {
 
 const SIZE_OF_SLICE: usize = mem::size_of_val("foobar".as_bytes());
 
+const SIZE_OF_DANGLING: usize = unsafe { mem::size_of_val_raw(0x100 as *const i32) };
+const ALIGN_OF_DANGLING: usize = unsafe { mem::align_of_val_raw(0x100 as *const i16) };
+
 fn main() {
     assert_eq!(SIZE_OF_FOO, mem::size_of::<Foo>());
     assert_eq!(SIZE_OF_BAR, mem::size_of::<Bar>());
@@ -41,5 +45,8 @@ fn main() {
     assert_eq!(ALIGN_OF_BAR, mem::align_of::<Bar>());
     assert_eq!(ALIGN_OF_UGH, mem::align_of::<Ugh>());
 
+    assert_eq!(SIZE_OF_DANGLING, mem::size_of::<i32>());
+    assert_eq!(ALIGN_OF_DANGLING, mem::align_of::<i16>());
+
     assert_eq!(SIZE_OF_SLICE, "foobar".len());
 }
diff --git a/src/test/ui/consts/issue-44415.rs b/src/test/ui/consts/issue-44415.rs
new file mode 100644 (file)
index 0000000..71e7646
--- /dev/null
@@ -0,0 +1,11 @@
+#![feature(core_intrinsics)]
+
+use std::intrinsics;
+
+struct Foo {
+    bytes: [u8; unsafe { intrinsics::size_of::<Foo>() }],
+    //~^ ERROR cycle detected when simplifying constant for the type system
+    x: usize,
+}
+
+fn main() {}
diff --git a/src/test/ui/consts/issue-44415.stderr b/src/test/ui/consts/issue-44415.stderr
new file mode 100644 (file)
index 0000000..38841e9
--- /dev/null
@@ -0,0 +1,28 @@
+error[E0391]: cycle detected when simplifying constant for the type system `Foo::bytes::{constant#0}`
+  --> $DIR/issue-44415.rs:6:17
+   |
+LL |     bytes: [u8; unsafe { intrinsics::size_of::<Foo>() }],
+   |                 ^^^^^^
+   |
+note: ...which requires simplifying constant for the type system `Foo::bytes::{constant#0}`...
+  --> $DIR/issue-44415.rs:6:17
+   |
+LL |     bytes: [u8; unsafe { intrinsics::size_of::<Foo>() }],
+   |                 ^^^^^^
+note: ...which requires const-evaluating + checking `Foo::bytes::{constant#0}`...
+  --> $DIR/issue-44415.rs:6:17
+   |
+LL |     bytes: [u8; unsafe { intrinsics::size_of::<Foo>() }],
+   |                 ^^^^^^
+   = note: ...which requires computing layout of `Foo`...
+   = note: ...which requires normalizing `[u8; _]`...
+   = note: ...which again requires simplifying constant for the type system `Foo::bytes::{constant#0}`, completing the cycle
+note: cycle used when checking that `Foo` is well-formed
+  --> $DIR/issue-44415.rs:5:1
+   |
+LL | struct Foo {
+   | ^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0391`.
diff --git a/src/test/ui/consts/issue-55878.rs b/src/test/ui/consts/issue-55878.rs
new file mode 100644 (file)
index 0000000..c1c5464
--- /dev/null
@@ -0,0 +1,8 @@
+// build-fail
+// normalize-stderr-64bit "18446744073709551615" -> "SIZE"
+// normalize-stderr-32bit "4294967295" -> "SIZE"
+
+// error-pattern: are too big for the current architecture
+fn main() {
+    println!("Size: {}", std::mem::size_of::<[u8; u64::MAX as usize]>());
+}
diff --git a/src/test/ui/consts/issue-55878.stderr b/src/test/ui/consts/issue-55878.stderr
new file mode 100644 (file)
index 0000000..924910e
--- /dev/null
@@ -0,0 +1,25 @@
+error[E0080]: values of the type `[u8; SIZE]` are too big for the current architecture
+  --> $SRC_DIR/core/src/mem/mod.rs:LL:COL
+   |
+LL |     intrinsics::size_of::<T>()
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |     |
+   |     inside `std::mem::size_of::<[u8; SIZE]>` at $SRC_DIR/core/src/mem/mod.rs:LL:COL
+   |     inside `main` at $DIR/issue-55878.rs:7:26
+   | 
+  ::: $DIR/issue-55878.rs:7:26
+   |
+LL |     println!("Size: {}", std::mem::size_of::<[u8; u64::MAX as usize]>());
+   |                          ----------------------------------------------
+
+error: erroneous constant used
+  --> $DIR/issue-55878.rs:7:26
+   |
+LL |     println!("Size: {}", std::mem::size_of::<[u8; u64::MAX as usize]>());
+   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ referenced constant has errors
+   |
+   = note: `#[deny(const_err)]` on by default
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/src/test/ui/crate-loading/auxiliary/crateresolve1-1.rs b/src/test/ui/crate-loading/auxiliary/crateresolve1-1.rs
new file mode 100644 (file)
index 0000000..a00a19e
--- /dev/null
@@ -0,0 +1,5 @@
+// compile-flags:-C extra-filename=-1
+#![crate_name = "crateresolve1"]
+#![crate_type = "lib"]
+
+pub fn f() -> isize { 10 }
diff --git a/src/test/ui/crate-loading/auxiliary/crateresolve1-2.rs b/src/test/ui/crate-loading/auxiliary/crateresolve1-2.rs
new file mode 100644 (file)
index 0000000..71cc0a1
--- /dev/null
@@ -0,0 +1,5 @@
+// compile-flags:-C extra-filename=-2
+#![crate_name = "crateresolve1"]
+#![crate_type = "lib"]
+
+pub fn f() -> isize { 20 }
diff --git a/src/test/ui/crate-loading/auxiliary/crateresolve1-3.rs b/src/test/ui/crate-loading/auxiliary/crateresolve1-3.rs
new file mode 100644 (file)
index 0000000..921687d
--- /dev/null
@@ -0,0 +1,5 @@
+// compile-flags:-C extra-filename=-3
+#![crate_name = "crateresolve1"]
+#![crate_type = "lib"]
+
+pub fn f() -> isize { 30 }
diff --git a/src/test/ui/crate-loading/crateresolve1.rs b/src/test/ui/crate-loading/crateresolve1.rs
new file mode 100644 (file)
index 0000000..49e47da
--- /dev/null
@@ -0,0 +1,10 @@
+// dont-check-compiler-stderr
+// aux-build:crateresolve1-1.rs
+// aux-build:crateresolve1-2.rs
+// aux-build:crateresolve1-3.rs
+// error-pattern:multiple matching crates for `crateresolve1`
+
+extern crate crateresolve1;
+
+fn main() {
+}
index bea77dc9f5c4fdabaea3d8bd818502345a4d5e48..be6ec3e4ed1a9d26555c165ea2915f54e0b3d3f7 100644 (file)
@@ -1,7 +1,7 @@
 // Reject mixing cyclic structure and Drop when using trait
 // objects to hide the cross-references.
 //
-// (Compare against compile-fail/dropck_vec_cycle_checked.rs)
+// (Compare against ui/span/dropck_vec_cycle_checked.rs)
 
 use std::cell::Cell;
 use id::Id;
index 02e8665cd2e3be1a67aa06a3b880cc4a87a6be42..c9599f6e805bb0a13499a713d17c7a236976cbe7 100644 (file)
@@ -1,7 +1,5 @@
 // Issue 8142: Test that Drop impls cannot be specialized beyond the
 // predicates attached to the type definition itself.
-#![feature(min_const_generics)]
-
 trait Bound { fn foo(&self) { } }
 struct K<'l1,'l2> { x: &'l1 i8, y: &'l2 u8 }
 struct L<'l1,'l2> { x: &'l1 i8, y: &'l2 u8 }
index 284cf59c822bd2b34a88eb25542ee899c98f9f63..cb4d97a8b2023355bf2949db73d20e919a128700 100644 (file)
 error[E0367]: `Drop` impl requires `'adds_bnd: 'al` but the struct it is implemented for does not
-  --> $DIR/reject-specialized-drops-8142.rs:26:20
+  --> $DIR/reject-specialized-drops-8142.rs:24:20
    |
 LL | impl<'al,'adds_bnd:'al> Drop for K<'al,'adds_bnd> {                        // REJECT
    |                    ^^^
    |
 note: the implementor must specify the same requirement
-  --> $DIR/reject-specialized-drops-8142.rs:6:1
+  --> $DIR/reject-specialized-drops-8142.rs:4:1
    |
 LL | struct K<'l1,'l2> { x: &'l1 i8, y: &'l2 u8 }
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0367]: `Drop` impl requires `'adds_bnd: 'al` but the struct it is implemented for does not
-  --> $DIR/reject-specialized-drops-8142.rs:30:67
+  --> $DIR/reject-specialized-drops-8142.rs:28:67
    |
 LL | impl<'al,'adds_bnd>     Drop for L<'al,'adds_bnd> where 'adds_bnd:'al {    // REJECT
    |                                                                   ^^^
    |
 note: the implementor must specify the same requirement
-  --> $DIR/reject-specialized-drops-8142.rs:7:1
+  --> $DIR/reject-specialized-drops-8142.rs:5:1
    |
 LL | struct L<'l1,'l2> { x: &'l1 i8, y: &'l2 u8 }
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0308]: mismatched types
-  --> $DIR/reject-specialized-drops-8142.rs:36:1
+  --> $DIR/reject-specialized-drops-8142.rs:34:1
    |
 LL | impl                    Drop for N<'static>     { fn drop(&mut self) { } } // REJECT
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch
    |
    = note: expected struct `N<'n>`
               found struct `N<'static>`
-note: the lifetime `'n` as defined on the struct at 9:10...
-  --> $DIR/reject-specialized-drops-8142.rs:9:10
+note: the lifetime `'n` as defined on the struct at 7:10...
+  --> $DIR/reject-specialized-drops-8142.rs:7:10
    |
 LL | struct N<'n> { x: &'n i8 }
    |          ^^
    = note: ...does not necessarily outlive the static lifetime
 
 error[E0366]: `Drop` impls cannot be specialized
-  --> $DIR/reject-specialized-drops-8142.rs:43:1
+  --> $DIR/reject-specialized-drops-8142.rs:41:1
    |
 LL | impl              Drop for P<i8>          { fn drop(&mut self) { } } // REJECT
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: use the same sequence of generic type, lifetime and const parameters as the struct definition
-  --> $DIR/reject-specialized-drops-8142.rs:11:1
+  --> $DIR/reject-specialized-drops-8142.rs:9:1
    |
 LL | struct P<Tp> { x: *const Tp }
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0367]: `Drop` impl requires `AddsBnd: Bound` but the struct it is implemented for does not
-  --> $DIR/reject-specialized-drops-8142.rs:46:14
+  --> $DIR/reject-specialized-drops-8142.rs:44:14
    |
 LL | impl<AddsBnd:Bound> Drop for Q<AddsBnd> { fn drop(&mut self) { } } // REJECT
    |              ^^^^^
    |
 note: the implementor must specify the same requirement
-  --> $DIR/reject-specialized-drops-8142.rs:12:1
+  --> $DIR/reject-specialized-drops-8142.rs:10:1
    |
 LL | struct Q<Tq> { x: *const Tq }
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0367]: `Drop` impl requires `AddsRBnd: 'rbnd` but the struct it is implemented for does not
-  --> $DIR/reject-specialized-drops-8142.rs:49:21
+  --> $DIR/reject-specialized-drops-8142.rs:47:21
    |
 LL | impl<'rbnd,AddsRBnd:'rbnd> Drop for R<AddsRBnd> { fn drop(&mut self) { } } // REJECT
    |                     ^^^^^
    |
 note: the implementor must specify the same requirement
-  --> $DIR/reject-specialized-drops-8142.rs:13:1
+  --> $DIR/reject-specialized-drops-8142.rs:11:1
    |
 LL | struct R<Tr> { x: *const Tr }
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0366]: `Drop` impls cannot be specialized
-  --> $DIR/reject-specialized-drops-8142.rs:58:1
+  --> $DIR/reject-specialized-drops-8142.rs:56:1
    |
 LL | impl<One>         Drop for V<One,One>     { fn drop(&mut self) { } } // REJECT
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: use the same sequence of generic type, lifetime and const parameters as the struct definition
-  --> $DIR/reject-specialized-drops-8142.rs:17:1
+  --> $DIR/reject-specialized-drops-8142.rs:15:1
    |
 LL | struct V<Tva, Tvb> { x: *const Tva, y: *const Tvb }
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'lw` due to conflicting requirements
-  --> $DIR/reject-specialized-drops-8142.rs:61:1
+  --> $DIR/reject-specialized-drops-8142.rs:59:1
    |
 LL | impl<'lw>         Drop for W<'lw,'lw>     { fn drop(&mut self) { } } // REJECT
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-note: first, the lifetime cannot outlive the lifetime `'l1` as defined on the struct at 18:10...
-  --> $DIR/reject-specialized-drops-8142.rs:18:10
+note: first, the lifetime cannot outlive the lifetime `'l1` as defined on the struct at 16:10...
+  --> $DIR/reject-specialized-drops-8142.rs:16:10
    |
 LL | struct W<'l1, 'l2> { x: &'l1 i8, y: &'l2 u8 }
    |          ^^^
-note: ...but the lifetime must also be valid for the lifetime `'l2` as defined on the struct at 18:15...
-  --> $DIR/reject-specialized-drops-8142.rs:18:15
+note: ...but the lifetime must also be valid for the lifetime `'l2` as defined on the struct at 16:15...
+  --> $DIR/reject-specialized-drops-8142.rs:16:15
    |
 LL | struct W<'l1, 'l2> { x: &'l1 i8, y: &'l2 u8 }
    |               ^^^
 note: ...so that the types are compatible
-  --> $DIR/reject-specialized-drops-8142.rs:61:1
+  --> $DIR/reject-specialized-drops-8142.rs:59:1
    |
 LL | impl<'lw>         Drop for W<'lw,'lw>     { fn drop(&mut self) { } } // REJECT
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -110,61 +110,61 @@ LL | impl<'lw>         Drop for W<'lw,'lw>     { fn drop(&mut self) { } } // REJ
               found `W<'_, '_>`
 
 error[E0366]: `Drop` impls cannot be specialized
-  --> $DIR/reject-specialized-drops-8142.rs:64:1
+  --> $DIR/reject-specialized-drops-8142.rs:62:1
    |
 LL | impl              Drop for X<3>           { fn drop(&mut self) { } } // REJECT
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: use the same sequence of generic type, lifetime and const parameters as the struct definition
-  --> $DIR/reject-specialized-drops-8142.rs:19:1
+  --> $DIR/reject-specialized-drops-8142.rs:17:1
    |
 LL | struct X<const Ca: usize>;
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0366]: `Drop` impls cannot be specialized
-  --> $DIR/reject-specialized-drops-8142.rs:67:1
+  --> $DIR/reject-specialized-drops-8142.rs:65:1
    |
 LL | impl<const Ca: usize> Drop for Y<Ca, Ca>     { fn drop(&mut self) { } } // REJECT
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: use the same sequence of generic type, lifetime and const parameters as the struct definition
-  --> $DIR/reject-specialized-drops-8142.rs:20:1
+  --> $DIR/reject-specialized-drops-8142.rs:18:1
    |
 LL | struct Y<const Ca: usize, const Cb: usize>;
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0367]: `Drop` impl requires `AddsBnd: Bound` but the enum it is implemented for does not
-  --> $DIR/reject-specialized-drops-8142.rs:70:14
+  --> $DIR/reject-specialized-drops-8142.rs:68:14
    |
 LL | impl<AddsBnd:Bound> Drop for Enum<AddsBnd> { fn drop(&mut self) { } } // REJECT
    |              ^^^^^
    |
 note: the implementor must specify the same requirement
-  --> $DIR/reject-specialized-drops-8142.rs:22:1
+  --> $DIR/reject-specialized-drops-8142.rs:20:1
    |
 LL | enum Enum<T> { Variant(T) }
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0367]: `Drop` impl requires `AddsBnd: Bound` but the struct it is implemented for does not
-  --> $DIR/reject-specialized-drops-8142.rs:73:14
+  --> $DIR/reject-specialized-drops-8142.rs:71:14
    |
 LL | impl<AddsBnd:Bound> Drop for TupleStruct<AddsBnd> { fn drop(&mut self) { } } // REJECT
    |              ^^^^^
    |
 note: the implementor must specify the same requirement
-  --> $DIR/reject-specialized-drops-8142.rs:23:1
+  --> $DIR/reject-specialized-drops-8142.rs:21:1
    |
 LL | struct TupleStruct<T>(T);
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0367]: `Drop` impl requires `AddsBnd: Bound` but the union it is implemented for does not
-  --> $DIR/reject-specialized-drops-8142.rs:76:21
+  --> $DIR/reject-specialized-drops-8142.rs:74:21
    |
 LL | impl<AddsBnd:Copy + Bound> Drop for Union<AddsBnd> { fn drop(&mut self) { } } // REJECT
    |                     ^^^^^
    |
 note: the implementor must specify the same requirement
-  --> $DIR/reject-specialized-drops-8142.rs:24:1
+  --> $DIR/reject-specialized-drops-8142.rs:22:1
    |
 LL | union Union<T: Copy> { f: T }
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
index 0cfb93d466835adc95d29a8337d8fdab578eadda..f927dd189038abad765c4db97cea107e9a8e30ca 100644 (file)
@@ -7,7 +7,7 @@
 enum MyWeirdOption<T> {
     None = 0,
     Some(T) = std::mem::size_of::<T>(),
-    //~^ ERROR constant expression depends on a generic parameter
+    //~^ ERROR generic parameters may not be used in const operations
 }
 
 fn main() {
index 91d488a07cc6df61575be045f6ab1d7fd06dac89..4d57765e13f5adcc3f4cebbf631a8ffe85a45733 100644 (file)
@@ -1,10 +1,11 @@
-error: constant expression depends on a generic parameter
-  --> $DIR/issue-70453-generics-in-discr-ice-2.rs:9:15
+error: generic parameters may not be used in const operations
+  --> $DIR/issue-70453-generics-in-discr-ice-2.rs:9:35
    |
 LL |     Some(T) = std::mem::size_of::<T>(),
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^
+   |                                   ^ cannot perform const operation using `T`
    |
-   = note: this may fail depending on what value the parameter takes
+   = note: type parameters may not be used in const expressions
+   = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error: aborting due to previous error
 
index 676f1115dde01cd8e8ee574c8810d98c5796bc21..a0fb788a5109c67a91cc1a307e07d51712c99d07 100644 (file)
@@ -8,7 +8,7 @@ enum MyWeirdOption<T> {
 //~^ ERROR parameter `T` is never used
     None = 0,
     Some = std::mem::size_of::<T>(),
-    //~^ ERROR constant expression depends on a generic parameter
+    //~^ ERROR generic parameters may not be used in const operations
 }
 
 fn main() {
index 0dc5432d28c08334af8731929e4e936e7430e999..1d43903928bef7394c2e5156289d5afd549c1935 100644 (file)
@@ -1,10 +1,11 @@
-error: constant expression depends on a generic parameter
-  --> $DIR/issue-70453-generics-in-discr-ice.rs:10:12
+error: generic parameters may not be used in const operations
+  --> $DIR/issue-70453-generics-in-discr-ice.rs:10:32
    |
 LL |     Some = std::mem::size_of::<T>(),
-   |            ^^^^^^^^^^^^^^^^^^^^^^^^
+   |                                ^ cannot perform const operation using `T`
    |
-   = note: this may fail depending on what value the parameter takes
+   = note: type parameters may not be used in const expressions
+   = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error[E0392]: parameter `T` is never used
   --> $DIR/issue-70453-generics-in-discr-ice.rs:7:20
index cdc1db4c0b48203e3adfad7d21c1b263147db072..e62582fb5161aa44f9444cf73402765552ab8bc0 100644 (file)
@@ -1,4 +1,3 @@
-// run-pass
 #![feature(arbitrary_enum_discriminant, core_intrinsics)]
 
 extern crate core;
@@ -8,8 +7,7 @@
 enum MyWeirdOption<T> {
     None = 0,
     Some(T) = core::mem::size_of::<*mut T>(),
-    //~^ WARN cannot use constants which depend on generic parameters in types
-    //~| WARN this was previously accepted by the compiler but is being phased out
+    //~^ ERROR generic parameters may not be used
 }
 
 fn main() {
index 906927e705ee8cbb75212d6f0fc4cf9e310bede6..8c97af263b287f98e4bac301370513fcd0a643cd 100644 (file)
@@ -1,12 +1,11 @@
-warning: cannot use constants which depend on generic parameters in types
-  --> $DIR/issue-70453-polymorphic-ctfe.rs:10:15
+error: generic parameters may not be used in const operations
+  --> $DIR/issue-70453-polymorphic-ctfe.rs:9:41
    |
 LL |     Some(T) = core::mem::size_of::<*mut T>(),
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                                         ^ cannot perform const operation using `T`
    |
-   = note: `#[warn(const_evaluatable_unchecked)]` 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 #76200 <https://github.com/rust-lang/rust/issues/76200>
+   = note: type parameters may not be used in const expressions
+   = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
-warning: 1 warning emitted
+error: aborting due to previous error
 
index 7977bddae7bcb39dc5efd61290baddfc4189142d..f4697344cc7a41943adb906b07f4b2a41d49b25b 100644 (file)
@@ -1,6 +1,6 @@
-enum Bug<S> {
+enum Bug<S> { //~ ERROR parameter `S` is never used
     Var = {
-        let x: S = 0; //~ ERROR: mismatched types
+        let x: S = 0; //~ ERROR generic parameters may not be used
         0
     },
 }
index 6583fe13d0c6345524cc3a3e805b46c2eea72cc7..32ca94203e630ce935a36927a0384ee4f56616ac 100644 (file)
@@ -1,17 +1,20 @@
-error[E0308]: mismatched types
-  --> $DIR/issue-67945-1.rs:3:20
+error: generic parameters may not be used in const operations
+  --> $DIR/issue-67945-1.rs:3:16
    |
-LL | enum Bug<S> {
-   |          - this type parameter
-LL |     Var = {
 LL |         let x: S = 0;
-   |                -   ^ expected type parameter `S`, found integer
-   |                |
-   |                expected due to this
+   |                ^ cannot perform const operation using `S`
+   |
+   = note: type parameters may not be used in const expressions
+   = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
+
+error[E0392]: parameter `S` is never used
+  --> $DIR/issue-67945-1.rs:1:10
+   |
+LL | enum Bug<S> {
+   |          ^ unused parameter
    |
-   = note: expected type parameter `S`
-                        found type `{integer}`
+   = help: consider removing `S`, referring to it in a field, or using a marker such as `PhantomData`
 
-error: aborting due to previous error
+error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0308`.
+For more information about this error, try `rustc --explain E0392`.
index 16bd8530ab38c47a32220219c01cffd0d8f48f75..e5044468da12929266ca65867b6911295d6622fb 100644 (file)
@@ -1,9 +1,8 @@
 #![feature(type_ascription)]
 
-enum Bug<S> {
+enum Bug<S> { //~ ERROR parameter `S` is never used
     Var = 0: S,
-    //~^ ERROR: mismatched types
-    //~| ERROR: mismatched types
+    //~^ ERROR generic parameters may not be used
 }
 
 fn main() {}
index c40506d59edd9ec8d76bb29ca7843b92b078d8bc..a738d3b15a5574d803e706b4d2b451b9b18d6d2f 100644 (file)
@@ -1,25 +1,20 @@
-error[E0308]: mismatched types
-  --> $DIR/issue-67945-2.rs:4:11
+error: generic parameters may not be used in const operations
+  --> $DIR/issue-67945-2.rs:4:14
    |
-LL | enum Bug<S> {
-   |          - this type parameter
 LL |     Var = 0: S,
-   |           ^ expected type parameter `S`, found integer
+   |              ^ cannot perform const operation using `S`
    |
-   = note: expected type parameter `S`
-                        found type `{integer}`
+   = note: type parameters may not be used in const expressions
+   = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
-error[E0308]: mismatched types
-  --> $DIR/issue-67945-2.rs:4:11
+error[E0392]: parameter `S` is never used
+  --> $DIR/issue-67945-2.rs:3:10
    |
 LL | enum Bug<S> {
-   |          - this type parameter
-LL |     Var = 0: S,
-   |           ^^^^ expected `isize`, found type parameter `S`
+   |          ^ unused parameter
    |
-   = note:        expected type `isize`
-           found type parameter `S`
+   = help: consider removing `S`, referring to it in a field, or using a marker such as `PhantomData`
 
 error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0308`.
+For more information about this error, try `rustc --explain E0392`.
index 356e4f36042ae5005c7bcf051a36f4d7e2d497c9..f915f6edef52b974c652b106e903b77eeaad96d3 100644 (file)
@@ -6,7 +6,6 @@ LL | #![feature(const_generics)]
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-   = help: consider using `min_const_generics` instead, which is more stable and complete
 
 error[E0730]: cannot pattern-match on an array without a fixed length
   --> $DIR/E0730.rs:6:9
index b184b59981701acd5ed4f5cfec2a754ca936f826..60220be6b57ba55e1667c790aa3dfd05b723c0f5 100644 (file)
@@ -6,7 +6,6 @@ LL | #![feature(const_generics)]
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-   = help: consider using `min_const_generics` instead, which is more stable and complete
 
 error[E0771]: use of non-static lifetime `'a` in const generic
   --> $DIR/E0771.rs:4:41
diff --git a/src/test/ui/extern-flag/empty-extern-arg.rs b/src/test/ui/extern-flag/empty-extern-arg.rs
new file mode 100644 (file)
index 0000000..d3cb5aa
--- /dev/null
@@ -0,0 +1,4 @@
+// compile-flags: --extern std=
+// error-pattern: extern location for std does not exist
+
+fn main() {}
diff --git a/src/test/ui/extern-flag/empty-extern-arg.stderr b/src/test/ui/extern-flag/empty-extern-arg.stderr
new file mode 100644 (file)
index 0000000..199c4fb
--- /dev/null
@@ -0,0 +1,4 @@
+error: extern location for std does not exist: 
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/feature-gates/feature-gate-const_generics-ptr.rs b/src/test/ui/feature-gates/feature-gate-const_generics-ptr.rs
deleted file mode 100644 (file)
index dc602ba..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-struct ConstFn<const F: fn()>;
-//~^ ERROR const generics are unstable
-//~^^ ERROR using function pointers as const generic parameters is forbidden
-
-struct ConstPtr<const P: *const u32>;
-//~^ ERROR const generics are unstable
-//~^^ ERROR using raw pointers as const generic parameters is forbidden
-
-fn main() {}
diff --git a/src/test/ui/feature-gates/feature-gate-const_generics-ptr.stderr b/src/test/ui/feature-gates/feature-gate-const_generics-ptr.stderr
deleted file mode 100644 (file)
index eef4653..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-error[E0658]: const generics are unstable
-  --> $DIR/feature-gate-const_generics-ptr.rs:1:22
-   |
-LL | struct ConstFn<const F: fn()>;
-   |                      ^
-   |
-   = note: see issue #74878 <https://github.com/rust-lang/rust/issues/74878> for more information
-   = help: add `#![feature(min_const_generics)]` to the crate attributes to enable
-
-error[E0658]: const generics are unstable
-  --> $DIR/feature-gate-const_generics-ptr.rs:5:23
-   |
-LL | struct ConstPtr<const P: *const u32>;
-   |                       ^
-   |
-   = note: see issue #74878 <https://github.com/rust-lang/rust/issues/74878> for more information
-   = help: add `#![feature(min_const_generics)]` to the crate attributes to enable
-
-error: using function pointers as const generic parameters is forbidden
-  --> $DIR/feature-gate-const_generics-ptr.rs:1:25
-   |
-LL | struct ConstFn<const F: fn()>;
-   |                         ^^^^
-
-error: using raw pointers as const generic parameters is forbidden
-  --> $DIR/feature-gate-const_generics-ptr.rs:5:26
-   |
-LL | struct ConstPtr<const P: *const u32>;
-   |                          ^^^^^^^^^^
-
-error: aborting due to 4 previous errors
-
-For more information about this error, try `rustc --explain E0658`.
index fe1ded1c4bbc4bba7e8b86d954a113a51a1d59ad..06364eebef91c8b786f03e603ff9f08ae0633cf2 100644 (file)
@@ -1,5 +1,5 @@
-fn foo<const X: ()>() {} //~ ERROR const generics are unstable
+fn foo<const X: ()>() {} //~ ERROR `()` is forbidden as the type of a const generic parameter
 
-struct Foo<const X: usize>([(); X]); //~ ERROR const generics are unstable
+struct Foo<const X: usize>([(); X]);
 
 fn main() {}
index f80362252f9236cfb09ea62ad58fd65124c9dfe5..b2b7e4576bf7dc043c6829d8dcdbb04b76afcede 100644 (file)
@@ -1,21 +1,11 @@
-error[E0658]: const generics are unstable
-  --> $DIR/feature-gate-const_generics.rs:1:14
+error: `()` is forbidden as the type of a const generic parameter
+  --> $DIR/feature-gate-const_generics.rs:1:17
    |
 LL | fn foo<const X: ()>() {}
-   |              ^
+   |                 ^^
    |
-   = note: see issue #74878 <https://github.com/rust-lang/rust/issues/74878> for more information
-   = help: add `#![feature(min_const_generics)]` to the crate attributes to enable
+   = note: the only supported types are integers, `bool` and `char`
+   = help: more complex types are supported with `#[feature(const_generics)]`
 
-error[E0658]: const generics are unstable
-  --> $DIR/feature-gate-const_generics.rs:3:18
-   |
-LL | struct Foo<const X: usize>([(); X]);
-   |                  ^
-   |
-   = note: see issue #74878 <https://github.com/rust-lang/rust/issues/74878> for more information
-   = help: add `#![feature(min_const_generics)]` to the crate attributes to enable
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/fn/issue-80179.rs b/src/test/ui/fn/issue-80179.rs
new file mode 100644 (file)
index 0000000..7609b15
--- /dev/null
@@ -0,0 +1,27 @@
+// Functions with a type placeholder `_` as the return type should
+// show a function pointer suggestion when given a function item
+// and suggest how to return closures correctly from a function.
+// This is a regression test of #80179
+
+fn returns_i32() -> i32 {
+    0
+}
+
+fn returns_fn_ptr() -> _ {
+//~^ ERROR the type placeholder `_` is not allowed within types on item signatures [E0121]
+//~| NOTE not allowed in type signatures
+//~| HELP replace with the correct return type
+//~| SUGGESTION fn() -> i32
+    returns_i32
+}
+
+fn returns_closure() -> _ {
+//~^ ERROR the type placeholder `_` is not allowed within types on item signatures [E0121]
+//~| NOTE not allowed in type signatures
+//~| HELP consider using an `Fn`, `FnMut`, or `FnOnce` trait bound
+//~| NOTE for more information on `Fn` traits and closure types, see
+//        https://doc.rust-lang.org/book/ch13-01-closures.html
+    || 0
+}
+
+fn main() {}
diff --git a/src/test/ui/fn/issue-80179.stderr b/src/test/ui/fn/issue-80179.stderr
new file mode 100644 (file)
index 0000000..63571e7
--- /dev/null
@@ -0,0 +1,21 @@
+error[E0121]: the type placeholder `_` is not allowed within types on item signatures
+  --> $DIR/issue-80179.rs:10:24
+   |
+LL | fn returns_fn_ptr() -> _ {
+   |                        ^
+   |                        |
+   |                        not allowed in type signatures
+   |                        help: replace with the correct return type: `fn() -> i32`
+
+error[E0121]: the type placeholder `_` is not allowed within types on item signatures
+  --> $DIR/issue-80179.rs:18:25
+   |
+LL | fn returns_closure() -> _ {
+   |                         ^ not allowed in type signatures
+   |
+   = help: consider using an `Fn`, `FnMut`, or `FnOnce` trait bound
+   = note: for more information on `Fn` traits and closure types, see https://doc.rust-lang.org/book/ch13-01-closures.html
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0121`.
index c41bcc73fa50611b3301e8f1509bb8c2295913f1..6a0b4ed17b96294866da32d19b3cc142f78e88fa 100644 (file)
@@ -36,7 +36,7 @@ impl Drop for DropMoveFoo { fn drop(&mut self) { } }
 fn test0() {
     // just copy implicitly copyable fields from `f`, no moves
     // (and thus it is okay that these are Drop; compare against
-    // compile-fail test: borrowck-struct-update-with-dtor.rs).
+    // test ui/borrowck/borrowck-struct-update-with-dtor.rs).
 
     // Case 1: Nocopyable
     let f = DropNoFoo::new(1, 2);
index fd493e1ff37d6e6b31faa1cdca506d19ff99e6ff..11d2c9b7fb7641af6fc915f3fd41e93a3f2718a5 100644 (file)
@@ -5,4 +5,4 @@ inputs. This investigation was kicked off by #38714, which revealed
 some pretty deep flaws in the ad-hoc way that we were doing things
 before.
 
-See also `src/test/compile-fail/closure-expected-type`.
+See also `src/test/ui/closure-expected-type`.
diff --git a/src/test/ui/generic-associated-types/issue-74824.rs b/src/test/ui/generic-associated-types/issue-74824.rs
new file mode 100644 (file)
index 0000000..00761a9
--- /dev/null
@@ -0,0 +1,27 @@
+#![feature(generic_associated_types)]
+#![feature(associated_type_defaults)]
+#![allow(incomplete_features)]
+
+use std::ops::Deref;
+
+trait UnsafeCopy {
+    type Copy<T>: Copy = Box<T>;
+    //~^ ERROR the trait bound `Box<T>: Copy` is not satisfied
+    //~^^ ERROR the trait bound `T: Clone` is not satisfied
+    fn copy<T>(x: &Self::Copy<T>) -> Self::Copy<T> {
+        *x
+    }
+}
+
+impl<T> UnsafeCopy for T {}
+
+fn main() {
+    let b = Box::new(42usize);
+    let copy = <()>::copy(&b);
+
+    let raw_b = Box::deref(&b) as *const _;
+    let raw_copy = Box::deref(&copy) as *const _;
+
+    // assert the addresses.
+    assert_eq!(raw_b, raw_copy);
+}
diff --git a/src/test/ui/generic-associated-types/issue-74824.stderr b/src/test/ui/generic-associated-types/issue-74824.stderr
new file mode 100644 (file)
index 0000000..34a2c19
--- /dev/null
@@ -0,0 +1,27 @@
+error[E0277]: the trait bound `Box<T>: Copy` is not satisfied
+  --> $DIR/issue-74824.rs:8:5
+   |
+LL |     type Copy<T>: Copy = Box<T>;
+   |     ^^^^^^^^^^^^^^----^^^^^^^^^^
+   |     |             |
+   |     |             required by this bound in `UnsafeCopy::Copy`
+   |     the trait `Copy` is not implemented for `Box<T>`
+
+error[E0277]: the trait bound `T: Clone` is not satisfied
+  --> $DIR/issue-74824.rs:8:5
+   |
+LL |     type Copy<T>: Copy = Box<T>;
+   |     ^^^^^^^^^^^^^^----^^^^^^^^^^
+   |     |             |
+   |     |             required by this bound in `UnsafeCopy::Copy`
+   |     the trait `Clone` is not implemented for `T`
+   |
+   = note: required because of the requirements on the impl of `Clone` for `Box<T>`
+help: consider restricting type parameter `T`
+   |
+LL |     type Copy<T: Clone>: Copy = Box<T>;
+   |                ^^^^^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
index dd89bc0f7a0ff856feba1e555509b6fe48b84127..3c62e47381c0b7abc44519f1efc8329f73cb71ad 100644 (file)
@@ -1,4 +1,4 @@
 struct Foo<T, U = [u8; std::mem::size_of::<T>()]>(T, U);
-//~^ ERROR constant values inside of type parameter defaults
+//~^ ERROR generic parameters may not be used in const operations
 
 fn main() {}
index ea867240269efdd3bf0de265687cc543d4eaf5d3..41a0a03ff6688ea8f1d943b5a55b3bda2d8bb994 100644 (file)
@@ -1,8 +1,11 @@
-error: constant values inside of type parameter defaults must not depend on generic parameters
+error: generic parameters may not be used in const operations
   --> $DIR/param-in-ct-in-ty-param-default.rs:1:44
    |
 LL | struct Foo<T, U = [u8; std::mem::size_of::<T>()]>(T, U);
-   |                                            ^ the anonymous constant must not depend on the parameter `T`
+   |                                            ^ cannot perform const operation using `T`
+   |
+   = note: type parameters may not be used in const expressions
+   = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error: aborting due to previous error
 
index 6de36deb5976480b97cb25ef2630a1f1f3d80ec6..4ca6d1998353f882ae2119a921e1de8bcc86afa1 100644 (file)
@@ -6,7 +6,6 @@ LL | #![feature(decl_macro, rustc_attrs, const_generics)]
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-   = help: consider using `min_const_generics` instead, which is more stable and complete
 
 warning: 1 warning emitted
 
index 3f85383eb33fa05b49245fe3c31c17471c8e5a9b..b351b8b73a0e58b6e8fab3ae419f9b2738958861 100644 (file)
@@ -6,7 +6,6 @@ LL | #![feature(const_generics)]
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-   = help: consider using `min_const_generics` instead, which is more stable and complete
 
 warning: 1 warning emitted
 
index 3f7226c79bf2afecf421bd3b4aef361b291c0d9a..5fed02164b5b704b482f1026f53e7024ceaeb6f4 100644 (file)
@@ -4,7 +4,7 @@ error[E0277]: the size for values of type `[i32]` cannot be known at compilation
 LL |     fn iceman(c: Vec<[i32]>) {}
    |                  ^^^^^^^^^^ doesn't have a size known at compile-time
    | 
-  ::: $SRC_DIR/alloc/src/vec.rs:LL:COL
+  ::: $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
    |
 LL | pub struct Vec<T, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global> {
    |                - required by this bound in `Vec`
index ab0a18869632a986e9253cba7c7e506b9163506a..b028fcae0775bca8a33ef8459995b3ffe09e2f20 100644 (file)
@@ -1,5 +1,5 @@
 // run-pass
-#![allow(unused_imports, overlapping_patterns)]
+#![allow(unused_imports, overlapping_range_endpoints)]
 // pretty-expanded FIXME #23616
 
 use m::{START, END};
index ce3bffe602ca06721078a9f98297ac05d3e285d9..ff7e884ea6f83d8558377a2df6bbea7406da1b61 100644 (file)
@@ -1,11 +1,10 @@
-error[E0275]: overflow evaluating the requirement `<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<T as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next: Sized`
+error[E0275]: overflow evaluating the requirement `<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<T as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next`
   --> $DIR/issue-23122-2.rs:9:5
    |
 LL |     type Next = <GetNext<T::Next> as Next>::Next;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`issue_23122_2`)
-   = note: required because of the requirements on the impl of `Next` for `GetNext<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<T as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next>`
 
 error: aborting due to previous error
 
index edb06fea8ad5333db9322141654ee1cbd24ca6e5..a3e26a41232c7b382d9545dc33a92949c73ed539 100644 (file)
@@ -1,5 +1,5 @@
 // run-pass
-#![allow(overlapping_patterns)]
+#![allow(overlapping_range_endpoints)]
 
 fn main() {
     let x = 'a';
index 04382be27d7a5d1786a85401178786b605e3f406..84037b72a274698e44db70cfef41c9996c101854 100644 (file)
@@ -1,6 +1,6 @@
 // run-pass
 
-// This test is bogus (i.e., should be compile-fail) during the period
+// This test is bogus (i.e., should be check-fail) during the period
 // where #54986 is implemented and #54987 is *not* implemented. For
 // now: just ignore it
 //
index 30551375450825a9ede851354086852bab4a368b..ef3b114a5fa2a084d3b19222262cc88858540514 100644 (file)
@@ -1,6 +1,6 @@
 // run-pass
 
-// This test is bogus (i.e., should be compile-fail) during the period
+// This test is bogus (i.e., should be check-fail) during the period
 // where #54986 is implemented and #54987 is *not* implemented. For
 // now: just ignore it
 //
index aea9fde5309e24350b8a486f6283e3367ca6d8f8..43c0bfb26cd8137dd63e776cc510df4ab5cccf26 100644 (file)
@@ -3,7 +3,7 @@
 // Demonstrate the use of the unguarded escape hatch with a lifetime param
 // to assert that destructor will not access any dead data.
 //
-// Compare with compile-fail/issue28498-reject-lifetime-param.rs
+// Compare with ui/span/issue28498-reject-lifetime-param.rs
 
 #![feature(dropck_eyepatch)]
 
index 91ef5a7c98d6dbc7ed93ff1036453772c119b7dc..23fd86a093b59fd99604ff4a636d1aed03a1d898 100644 (file)
@@ -3,7 +3,7 @@
 // Demonstrate the use of the unguarded escape hatch with a type param in negative position
 // to assert that destructor will not access any dead data.
 //
-// Compare with compile-fail/issue28498-reject-lifetime-param.rs
+// Compare with ui/span/issue28498-reject-lifetime-param.rs
 
 // Demonstrate that a type param in negative position causes dropck to reject code
 // that might indirectly access previously dropped value.
index 808f3b6e81e52582e32ef15d7a94e43445100768..61d11cf38347eae04c40cc1f3fc6e0b2fd1bd977 100644 (file)
@@ -3,7 +3,7 @@
 // Demonstrate the use of the unguarded escape hatch with a trait bound
 // to assert that destructor will not access any dead data.
 //
-// Compare with compile-fail/issue28498-reject-trait-bound.rs
+// Compare with ui/span/issue28498-reject-trait-bound.rs
 
 #![feature(dropck_eyepatch)]
 
index 3a75956af528012fdc8a16fb3db0b5d5925f6dd1..58d25940733ced12546d2842451ae8b274d4b708 100644 (file)
@@ -12,7 +12,7 @@ fn dim() -> usize {
 
 pub struct Vector<T, D: Dim> {
     entries: [T; D::dim()],
-    //~^ ERROR no function or associated item named `dim` found
+    //~^ ERROR generic parameters may not be used
     _dummy: D,
 }
 
index 5e8d487f41658571ab75b7a5971307c84b0d110d..91e31ca0bd8b1d885b52b54c4e522a026a87b5e9 100644 (file)
@@ -1,11 +1,11 @@
-error[E0599]: no function or associated item named `dim` found for type parameter `D` in the current scope
-  --> $DIR/issue-39559.rs:14:21
+error: generic parameters may not be used in const operations
+  --> $DIR/issue-39559.rs:14:18
    |
 LL |     entries: [T; D::dim()],
-   |                     ^^^ function or associated item not found in `D`
+   |                  ^^^^^^ cannot perform const operation using `D`
    |
-   = help: items from traits can only be used if the type parameter is bounded by the trait
+   = note: type parameters may not be used in const expressions
+   = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0599`.
diff --git a/src/test/ui/issues/issue-43733.rs b/src/test/ui/issues/issue-43733.rs
deleted file mode 100644 (file)
index a602d76..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-#![feature(const_fn)]
-#![feature(thread_local)]
-#![feature(cfg_target_thread_local, thread_local_internals)]
-
-type Foo = std::cell::RefCell<String>;
-
-#[cfg(target_thread_local)]
-#[thread_local]
-static __KEY: std::thread::__FastLocalKeyInner<Foo> =
-    std::thread::__FastLocalKeyInner::new();
-
-#[cfg(not(target_thread_local))]
-static __KEY: std::thread::__OsLocalKeyInner<Foo> =
-    std::thread::__OsLocalKeyInner::new();
-
-fn __getit() -> std::option::Option<&'static Foo>
-{
-    __KEY.get(Default::default) //~ ERROR call to unsafe function is unsafe
-}
-
-static FOO: std::thread::LocalKey<Foo> =
-    std::thread::LocalKey::new(__getit);
-//~^ ERROR call to unsafe function is unsafe
-
-fn main() {
-    FOO.with(|foo| println!("{}", foo.borrow()));
-    std::thread::spawn(|| {
-        FOO.with(|foo| *foo.borrow_mut() += "foo");
-    }).join().unwrap();
-    FOO.with(|foo| println!("{}", foo.borrow()));
-}
diff --git a/src/test/ui/issues/issue-43733.stderr b/src/test/ui/issues/issue-43733.stderr
deleted file mode 100644 (file)
index ee6a3b0..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
-  --> $DIR/issue-43733.rs:18:5
-   |
-LL |     __KEY.get(Default::default)
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function
-   |
-   = note: consult the function's documentation for information on how to avoid undefined behavior
-
-error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
-  --> $DIR/issue-43733.rs:22:5
-   |
-LL |     std::thread::LocalKey::new(__getit);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function
-   |
-   = note: consult the function's documentation for information on how to avoid undefined behavior
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0133`.
index 697a160b4ecb44a110998844923be5741b3c9bd6..e3ffa8e7c6ef6b39c6ec099a6c05739696a053f0 100644 (file)
@@ -2,7 +2,7 @@
 #![feature(test)]
 #![allow(unused_mut)] // under NLL we get warning about `x` below: rust-lang/rust#54499
 
-// This test is bogus (i.e., should be compile-fail) during the period
+// This test is bogus (i.e., should be check-fail) during the period
 // where #54986 is implemented and #54987 is *not* implemented. For
 // now: just ignore it
 //
index 2a4ccda8929191b881dcca193b19ccb847397876..5e97339f148c5cbcaa97e0140d240e1359296411 100644 (file)
@@ -12,7 +12,6 @@ LL | #![feature(const_generics)]
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-   = help: consider using `min_const_generics` instead, which is more stable and complete
 
 error: aborting due to previous error; 1 warning emitted
 
index c0fdb2ef34ac4efd38db83c27af1e81fc6a9b33b..33e967cebffccd0be1d36165406d158012888cdf 100644 (file)
@@ -2,7 +2,7 @@ error: lifetime parameters must be declared prior to type parameters
   --> $DIR/issue-59508.rs:10:25
    |
 LL |     pub fn do_things<T, 'a, 'b: 'a>() {
-   |                     ----^^--^^----- help: reorder the parameters: lifetimes, then types: `<'a, 'b: 'a, T>`
+   |                     ----^^--^^----- help: reorder the parameters: lifetimes, then types, then consts: `<'a, 'b: 'a, T>`
 
 error: aborting due to previous error
 
index 44cb74815c6a04555c3a091281fd04275e7383ce..46ae9403c03ceca08d12b6a89088576ed75abea4 100644 (file)
@@ -4,7 +4,7 @@ pub const fn sof<T>() -> usize {
 
 fn test<T>() {
     let _: [u8; sof::<T>()];
-    //~^ ERROR the size for values of type `T`
+    //~^ ERROR generic parameters may not be used in const operations
 }
 
 fn main() {}
index 5a6c86d133ba338296d22325cebc7e665e1b645e..5c167ea083423a372fe16141fe5fd56b13be1bf2 100644 (file)
@@ -1,19 +1,11 @@
-error[E0277]: the size for values of type `T` cannot be known at compilation time
+error: generic parameters may not be used in const operations
   --> $DIR/feature-gate-lazy_normalization_consts.rs:6:23
    |
-LL | pub const fn sof<T>() -> usize {
-   |                  - required by this bound in `sof`
-...
-LL | fn test<T>() {
-   |         - this type parameter needs to be `Sized`
 LL |     let _: [u8; sof::<T>()];
-   |                       ^ doesn't have a size known at compile-time
+   |                       ^ cannot perform const operation using `T`
    |
-help: consider relaxing the implicit `Sized` restriction
-   |
-LL | pub const fn sof<T: ?Sized>() -> usize {
-   |                   ^^^^^^^^
+   = note: type parameters may not be used in const expressions
+   = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0277`.
index 76d7d0f024d65ce7d2f63b044ededc19d9fcf5c5..047bc7f6d9009246e6c5c358c246fe67245f9242 100644 (file)
@@ -2,25 +2,25 @@ error: lifetime parameters must be declared prior to type parameters
   --> $DIR/lifetime-before-type-params.rs:2:13
    |
 LL | fn first<T, 'a, 'b>() {}
-   |         ----^^--^^- help: reorder the parameters: lifetimes, then types: `<'a, 'b, T>`
+   |         ----^^--^^- help: reorder the parameters: lifetimes, then types, then consts: `<'a, 'b, T>`
 
 error: lifetime parameters must be declared prior to type parameters
   --> $DIR/lifetime-before-type-params.rs:4:18
    |
 LL | fn second<'a, T, 'b>() {}
-   |          --------^^- help: reorder the parameters: lifetimes, then types: `<'a, 'b, T>`
+   |          --------^^- help: reorder the parameters: lifetimes, then types, then consts: `<'a, 'b, T>`
 
 error: lifetime parameters must be declared prior to type parameters
   --> $DIR/lifetime-before-type-params.rs:6:16
    |
 LL | fn third<T, U, 'a>() {}
-   |         -------^^- help: reorder the parameters: lifetimes, then types: `<'a, T, U>`
+   |         -------^^- help: reorder the parameters: lifetimes, then types, then consts: `<'a, T, U>`
 
 error: lifetime parameters must be declared prior to type parameters
   --> $DIR/lifetime-before-type-params.rs:8:18
    |
 LL | fn fourth<'a, T, 'b, U, 'c, V>() {}
-   |          --------^^-----^^---- help: reorder the parameters: lifetimes, then types: `<'a, 'b, 'c, T, U, V>`
+   |          --------^^-----^^---- help: reorder the parameters: lifetimes, then types, then consts: `<'a, 'b, 'c, T, U, V>`
 
 error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/linkage-attr/invalid-link-args.rs b/src/test/ui/linkage-attr/invalid-link-args.rs
new file mode 100644 (file)
index 0000000..5eb1c63
--- /dev/null
@@ -0,0 +1,14 @@
+// build-fail
+// dont-check-compiler-stderr
+// ignore-msvc due to linker-flavor=ld
+// error-pattern:aFdEfSeVEEE
+// compile-flags: -C linker-flavor=ld
+
+/* Make sure invalid link_args are printed to stderr. */
+
+#![feature(link_args)]
+
+#[link_args = "aFdEfSeVEEE"]
+extern {}
+
+fn main() { }
diff --git a/src/test/ui/linkage-attr/issue-10755.rs b/src/test/ui/linkage-attr/issue-10755.rs
new file mode 100644 (file)
index 0000000..5ce69bc
--- /dev/null
@@ -0,0 +1,7 @@
+// build-fail
+// dont-check-compiler-stderr
+// compile-flags: -C linker=llllll -C linker-flavor=ld
+// error-pattern: linker `llllll` not found
+
+fn main() {
+}
index a9c7ac363b0b31261b0993c550d84dc99c5badb7..f23c7cb0dca1415d2a8c77fc3e2f54128f9512d1 100644 (file)
@@ -5,6 +5,10 @@ macro_rules! foo {
     ( $($i:ident)* ) => { $($i)+ }; //~ WARN meta-variable repeats with different Kleene operator
 }
 
+#[warn(missing_fragment_specifier)]
+macro_rules! m { ($i) => {} } //~ WARN missing fragment specifier
+                              //~| WARN this was previously accepted
+
 #[warn(soft_unstable)]
 mod benches {
     #[bench] //~ WARN use of unstable library feature 'test'
index 24e2733064e48029f0be9f6eab9977db04e861b3..b0fc1f8e5eec76161fb2e708b5826b7ce97a469a 100644 (file)
@@ -12,14 +12,28 @@ note: the lint level is defined here
 LL | #[warn(meta_variable_misuse)]
    |        ^^^^^^^^^^^^^^^^^^^^
 
+warning: missing fragment specifier
+  --> $DIR/expansion-time.rs:9:19
+   |
+LL | macro_rules! m { ($i) => {} }
+   |                   ^^
+   |
+note: the lint level is defined here
+  --> $DIR/expansion-time.rs:8:8
+   |
+LL | #[warn(missing_fragment_specifier)]
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = 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 #40107 <https://github.com/rust-lang/rust/issues/40107>
+
 warning: use of unstable library feature 'test': `bench` is a part of custom test frameworks which are unstable
-  --> $DIR/expansion-time.rs:10:7
+  --> $DIR/expansion-time.rs:14:7
    |
 LL |     #[bench]
    |       ^^^^^
    |
 note: the lint level is defined here
-  --> $DIR/expansion-time.rs:8:8
+  --> $DIR/expansion-time.rs:12:8
    |
 LL | #[warn(soft_unstable)]
    |        ^^^^^^^^^^^^^
@@ -33,10 +47,10 @@ LL | 2
    | ^
    |
 note: the lint level is defined here
-  --> $DIR/expansion-time.rs:25:8
+  --> $DIR/expansion-time.rs:29:8
    |
 LL | #[warn(incomplete_include)]
    |        ^^^^^^^^^^^^^^^^^^
 
-warning: 3 warnings emitted
+warning: 4 warnings emitted
 
index 5f7f5e66eaa9f220d4b004b151fe6edb29832b2a..05213f4ed4bc81d901983383144671a368ce028e 100644 (file)
@@ -1,5 +1,5 @@
 // check-pass
-#![feature(c_variadic, min_const_generics)]
+#![feature(c_variadic)]
 #![warn(function_item_references)]
 use std::fmt::Pointer;
 use std::fmt::Formatter;
index 74505eeb987c6613ad82e514dedfcb5413ab50a2..3973af540c81f181ecd929386cc312e2b7f766f2 100644 (file)
@@ -107,7 +107,7 @@ LL |     VEC.push(0);
    = 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
 note: mutable reference created due to call to this method
-  --> $SRC_DIR/alloc/src/vec.rs:LL:COL
+  --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
    |
 LL | /     pub fn push(&mut self, value: T) {
 LL | |         // This will panic or abort if we would allocate > isize::MAX bytes
diff --git a/src/test/ui/lint/must_use-in-stdlib-traits.rs b/src/test/ui/lint/must_use-in-stdlib-traits.rs
new file mode 100644 (file)
index 0000000..70dddf6
--- /dev/null
@@ -0,0 +1,47 @@
+#![deny(unused_must_use)]
+#![feature(arbitrary_self_types)]
+
+use std::iter::Iterator;
+use std::future::Future;
+
+use std::task::{Context, Poll};
+use std::pin::Pin;
+use std::unimplemented;
+
+struct MyFuture;
+
+impl Future for MyFuture {
+   type Output = u32;
+
+   fn poll(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<u32> {
+      Poll::Pending
+   }
+}
+
+fn iterator() -> impl Iterator {
+   std::iter::empty::<u32>()
+}
+
+fn future() -> impl Future {
+   MyFuture
+}
+
+fn square_fn_once() -> impl FnOnce(u32) -> u32 {
+   |x| x * x
+}
+
+fn square_fn_mut() -> impl FnMut(u32) -> u32 {
+   |x| x * x
+}
+
+fn square_fn() -> impl Fn(u32) -> u32 {
+   |x| x * x
+}
+
+fn main() {
+   iterator(); //~ ERROR unused implementer of `Iterator` that must be used
+   future(); //~ ERROR unused implementer of `Future` that must be used
+   square_fn_once(); //~ ERROR unused implementer of `FnOnce` that must be used
+   square_fn_mut(); //~ ERROR unused implementer of `FnMut` that must be used
+   square_fn(); //~ ERROR unused implementer of `Fn` that must be used
+}
diff --git a/src/test/ui/lint/must_use-in-stdlib-traits.stderr b/src/test/ui/lint/must_use-in-stdlib-traits.stderr
new file mode 100644 (file)
index 0000000..76978d2
--- /dev/null
@@ -0,0 +1,47 @@
+error: unused implementer of `Iterator` that must be used
+  --> $DIR/must_use-in-stdlib-traits.rs:42:4
+   |
+LL |    iterator();
+   |    ^^^^^^^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/must_use-in-stdlib-traits.rs:1:9
+   |
+LL | #![deny(unused_must_use)]
+   |         ^^^^^^^^^^^^^^^
+   = note: iterators are lazy and do nothing unless consumed
+
+error: unused implementer of `Future` that must be used
+  --> $DIR/must_use-in-stdlib-traits.rs:43:4
+   |
+LL |    future();
+   |    ^^^^^^^^^
+   |
+   = note: futures do nothing unless you `.await` or poll them
+
+error: unused implementer of `FnOnce` that must be used
+  --> $DIR/must_use-in-stdlib-traits.rs:44:4
+   |
+LL |    square_fn_once();
+   |    ^^^^^^^^^^^^^^^^^
+   |
+   = note: closures are lazy and do nothing unless called
+
+error: unused implementer of `FnMut` that must be used
+  --> $DIR/must_use-in-stdlib-traits.rs:45:4
+   |
+LL |    square_fn_mut();
+   |    ^^^^^^^^^^^^^^^^
+   |
+   = note: closures are lazy and do nothing unless called
+
+error: unused implementer of `Fn` that must be used
+  --> $DIR/must_use-in-stdlib-traits.rs:46:4
+   |
+LL |    square_fn();
+   |    ^^^^^^^^^^^^
+   |
+   = note: closures are lazy and do nothing unless called
+
+error: aborting due to 5 previous errors
+
index 4592bc31a39769cabd0fa86892ce296c66a8c0fd..8c79630b7fd2cb5fb9776ae49f8be6843b63e894 100644 (file)
@@ -1,10 +1,6 @@
-// check-pass
-// This test should stop compiling
-// we decide to enable this lint for item statements.
-
 #![deny(redundant_semicolons)]
 
 fn main() {
-    fn inner() {};
-    struct Bar {};
+    fn inner() {}; //~ ERROR unnecessary
+    struct Bar {}; //~ ERROR unnecessary
 }
diff --git a/src/test/ui/lint/redundant-semicolon/item-stmt-semi.stderr b/src/test/ui/lint/redundant-semicolon/item-stmt-semi.stderr
new file mode 100644 (file)
index 0000000..451b152
--- /dev/null
@@ -0,0 +1,20 @@
+error: unnecessary trailing semicolon
+  --> $DIR/item-stmt-semi.rs:4:18
+   |
+LL |     fn inner() {};
+   |                  ^ help: remove this semicolon
+   |
+note: the lint level is defined here
+  --> $DIR/item-stmt-semi.rs:1:9
+   |
+LL | #![deny(redundant_semicolons)]
+   |         ^^^^^^^^^^^^^^^^^^^^
+
+error: unnecessary trailing semicolon
+  --> $DIR/item-stmt-semi.rs:5:18
+   |
+LL |     struct Bar {};
+   |                  ^ help: remove this semicolon
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/llvm-asm/asm-src-loc-codegen-units.rs b/src/test/ui/llvm-asm/asm-src-loc-codegen-units.rs
new file mode 100644 (file)
index 0000000..387822d
--- /dev/null
@@ -0,0 +1,12 @@
+// build-fail
+// dont-check-compiler-stderr
+// compile-flags: -C codegen-units=2
+// ignore-emscripten
+
+#![feature(llvm_asm)]
+
+fn main() {
+    unsafe {
+        llvm_asm!("nowayisthisavalidinstruction"); //~ ERROR instruction
+    }
+}
diff --git a/src/test/ui/llvm-asm/asm-src-loc.rs b/src/test/ui/llvm-asm/asm-src-loc.rs
new file mode 100644 (file)
index 0000000..063066d
--- /dev/null
@@ -0,0 +1,11 @@
+// build-fail
+// dont-check-compiler-stderr
+// ignore-emscripten
+
+#![feature(llvm_asm)]
+
+fn main() {
+    unsafe {
+        llvm_asm!("nowayisthisavalidinstruction"); //~ ERROR instruction
+    }
+}
index 054958ba00b8db227dca1df607abf3022eac54bc..2229f2c3900c30220584e5b59d38b3015b990420 100644 (file)
@@ -2,5 +2,6 @@
 
 macro_rules! m { ($i) => {} }
 //~^ ERROR missing fragment specifier
+//~| WARN previously accepted
 
 fn main() {}
index 645f06e59d8176be382d166d2f20d4ac9fab478d..d2f2a823c2a6b47af00eb8b0d3aed999abb2831a 100644 (file)
@@ -3,6 +3,10 @@ error: missing fragment specifier
    |
 LL | macro_rules! m { ($i) => {} }
    |                   ^^
+   |
+   = note: `#[deny(missing_fragment_specifier)]` 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 #40107 <https://github.com/rust-lang/rust/issues/40107>
 
 error: aborting due to previous error
 
index e5e656de6fa7f339b968f53acb1cc9d68f49e287..c46274d59b65810cc39531ddb7b2b266972bbc33 100644 (file)
@@ -8,7 +8,7 @@
 // to it being e.g., a place where the addition of an argument
 // causes it to go down a code path with subtly different behavior).
 //
-// There is a companion test in compile-fail.
+// There is a companion failing test.
 
 // compile-flags: --test -C debug_assertions=yes
 // revisions: std core
@@ -68,26 +68,26 @@ fn to_format_or_not_to_format() {
 
     assert!(true, "{}",);
 
-    // assert_eq!(1, 1, "{}",); // see compile-fail
-    // assert_ne!(1, 2, "{}",); // see compile-fail
+    // assert_eq!(1, 1, "{}",); // see check-fail
+    // assert_ne!(1, 2, "{}",); // see check-fail
 
     debug_assert!(true, "{}",);
 
-    // debug_assert_eq!(1, 1, "{}",); // see compile-fail
-    // debug_assert_ne!(1, 2, "{}",); // see compile-fail
-    // eprint!("{}",); // see compile-fail
-    // eprintln!("{}",); // see compile-fail
-    // format!("{}",); // see compile-fail
-    // format_args!("{}",); // see compile-fail
+    // debug_assert_eq!(1, 1, "{}",); // see check-fail
+    // debug_assert_ne!(1, 2, "{}",); // see check-fail
+    // eprint!("{}",); // see check-fail
+    // eprintln!("{}",); // see check-fail
+    // format!("{}",); // see check-fail
+    // format_args!("{}",); // see check-fail
 
     if falsum() { panic!("{}",); }
 
-    // print!("{}",); // see compile-fail
-    // println!("{}",); // see compile-fail
-    // unimplemented!("{}",); // see compile-fail
+    // print!("{}",); // see check-fail
+    // println!("{}",); // see check-fail
+    // unimplemented!("{}",); // see check-fail
 
     if falsum() { unreachable!("{}",); }
 
-    // write!(&mut stdout, "{}",); // see compile-fail
-    // writeln!(&mut stdout, "{}",); // see compile-fail
+    // write!(&mut stdout, "{}",); // see check-fail
+    // writeln!(&mut stdout, "{}",); // see check-fail
 }
index dd0cac659fd312a1e4ccc8a96b3ceee10d58ab2a..ac15e9fa8ea837ac3410294d534bc0e3f2497f71 100644 (file)
@@ -23,22 +23,28 @@ LL |     debug_assert_ne!(1, 2, "{}",);
    |                             ^^
 
 error: 1 positional argument in format string, but no arguments were given
-  --> $DIR/macro-comma-behavior.rs:54:19
+  --> $DIR/macro-comma-behavior.rs:52:19
    |
 LL |     format_args!("{}",);
    |                   ^^
 
 error: 1 positional argument in format string, but no arguments were given
-  --> $DIR/macro-comma-behavior.rs:72:21
+  --> $DIR/macro-comma-behavior.rs:68:21
    |
 LL |     unimplemented!("{}",);
    |                     ^^
 
 error: 1 positional argument in format string, but no arguments were given
-  --> $DIR/macro-comma-behavior.rs:81:24
+  --> $DIR/macro-comma-behavior.rs:77:24
    |
 LL |             write!(f, "{}",)?;
    |                        ^^
 
-error: aborting due to 7 previous errors
+error: 1 positional argument in format string, but no arguments were given
+  --> $DIR/macro-comma-behavior.rs:81:26
+   |
+LL |             writeln!(f, "{}",)?;
+   |                          ^^
+
+error: aborting due to 8 previous errors
 
index 0bfe06830783278e7a57ce63c7fcf2a1520ca031..27d50ff3d57eacda6cdd1a5c650ad0d54f2cf131 100644 (file)
@@ -40,10 +40,8 @@ fn to_format_or_not_to_format() {
     }
 
     #[cfg(std)] {
-        // FIXME: compile-fail says "expected error not found" even though
-        //        rustc does emit an error
-        // eprintln!("{}",);
-        // <DISABLED> [std]~^ ERROR no arguments
+        eprintln!("{}",);
+        //[std]~^ ERROR no arguments
     }
 
     #[cfg(std)] {
@@ -63,10 +61,8 @@ fn to_format_or_not_to_format() {
     }
 
     #[cfg(std)] {
-        // FIXME: compile-fail says "expected error not found" even though
-        //        rustc does emit an error
-        // println!("{}",);
-        // <DISABLED> [std]~^ ERROR no arguments
+        println!("{}",);
+        //[std]~^ ERROR no arguments
     }
 
     unimplemented!("{}",);
@@ -82,11 +78,9 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
             //[core]~^ ERROR no arguments
             //[std]~^^ ERROR no arguments
 
-            // FIXME: compile-fail says "expected error not found" even though
-            //        rustc does emit an error
-            // writeln!(f, "{}",)?;
-            // <DISABLED> [core]~^ ERROR no arguments
-            // <DISABLED> [std]~^^ ERROR no arguments
+            writeln!(f, "{}",)?;
+            //[core]~^ ERROR no arguments
+            //[std]~^^ ERROR no arguments
             Ok(())
         }
     }
index 4372d89fbf5220170906f086313b8fcdf45ab7c6..7fd060e222498b405b7d621e23900eb32ed17beb 100644 (file)
@@ -29,34 +29,52 @@ LL |         eprint!("{}",);
    |                  ^^
 
 error: 1 positional argument in format string, but no arguments were given
-  --> $DIR/macro-comma-behavior.rs:50:18
+  --> $DIR/macro-comma-behavior.rs:43:20
+   |
+LL |         eprintln!("{}",);
+   |                    ^^
+
+error: 1 positional argument in format string, but no arguments were given
+  --> $DIR/macro-comma-behavior.rs:48:18
    |
 LL |         format!("{}",);
    |                  ^^
 
 error: 1 positional argument in format string, but no arguments were given
-  --> $DIR/macro-comma-behavior.rs:54:19
+  --> $DIR/macro-comma-behavior.rs:52:19
    |
 LL |     format_args!("{}",);
    |                   ^^
 
 error: 1 positional argument in format string, but no arguments were given
-  --> $DIR/macro-comma-behavior.rs:61:17
+  --> $DIR/macro-comma-behavior.rs:59:17
    |
 LL |         print!("{}",);
    |                 ^^
 
 error: 1 positional argument in format string, but no arguments were given
-  --> $DIR/macro-comma-behavior.rs:72:21
+  --> $DIR/macro-comma-behavior.rs:64:19
+   |
+LL |         println!("{}",);
+   |                   ^^
+
+error: 1 positional argument in format string, but no arguments were given
+  --> $DIR/macro-comma-behavior.rs:68:21
    |
 LL |     unimplemented!("{}",);
    |                     ^^
 
 error: 1 positional argument in format string, but no arguments were given
-  --> $DIR/macro-comma-behavior.rs:81:24
+  --> $DIR/macro-comma-behavior.rs:77:24
    |
 LL |             write!(f, "{}",)?;
    |                        ^^
 
-error: aborting due to 10 previous errors
+error: 1 positional argument in format string, but no arguments were given
+  --> $DIR/macro-comma-behavior.rs:81:26
+   |
+LL |             writeln!(f, "{}",)?;
+   |                          ^^
+
+error: aborting due to 13 previous errors
 
index 50c0ef3451d3d834f5af038eb8bdfd14ef2e2586..f6c4f896d67c1ea4b6987e10f80d6f83a204fca3 100644 (file)
@@ -68,7 +68,7 @@ fn column() {
     let _ = column!();
 }
 
-// compile_error! is in a companion to this test in compile-fail
+// compile_error! is in a check-fail companion to this test
 
 #[test]
 fn concat() {
index 6b023e41372745de4ed0e3f1b76ee92a3d574464..b23e5c71c03f06e29245481dbfa775b0b3c57874 100644 (file)
@@ -2,6 +2,7 @@ macro_rules! test {
     ($a, $b) => {
         //~^ ERROR missing fragment
         //~| ERROR missing fragment
+        //~| WARN this was previously accepted
         ()
     };
 }
index 334d62812cdab9c4d2a1206143498cfa86709527..674ce3434aac63fd9446e23a30c91f34fe2c3271 100644 (file)
@@ -9,6 +9,10 @@ error: missing fragment specifier
    |
 LL |     ($a, $b) => {
    |          ^^
+   |
+   = note: `#[deny(missing_fragment_specifier)]` 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 #40107 <https://github.com/rust-lang/rust/issues/40107>
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/macros/not-utf8.bin b/src/test/ui/macros/not-utf8.bin
new file mode 100644 (file)
index 0000000..4148e5b
Binary files /dev/null and b/src/test/ui/macros/not-utf8.bin differ
diff --git a/src/test/ui/macros/not-utf8.rs b/src/test/ui/macros/not-utf8.rs
new file mode 100644 (file)
index 0000000..1cb1fdc
--- /dev/null
@@ -0,0 +1,5 @@
+// error-pattern: did not contain valid UTF-8
+
+fn foo() {
+    include!("not-utf8.bin")
+}
diff --git a/src/test/ui/macros/not-utf8.stderr b/src/test/ui/macros/not-utf8.stderr
new file mode 100644 (file)
index 0000000..f47be14
--- /dev/null
@@ -0,0 +1,10 @@
+error: couldn't read $DIR/not-utf8.bin: stream did not contain valid UTF-8
+  --> $DIR/not-utf8.rs:4:5
+   |
+LL |     include!("not-utf8.bin")
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/meta/meta-expected-error-wrong-rev.a.stderr b/src/test/ui/meta/meta-expected-error-wrong-rev.a.stderr
new file mode 100644 (file)
index 0000000..583b2c4
--- /dev/null
@@ -0,0 +1,16 @@
+error[E0308]: mismatched types
+  --> $DIR/meta-expected-error-wrong-rev.rs:13:18
+   |
+LL |     let x: u32 = 22_usize;
+   |            ---   ^^^^^^^^ expected `u32`, found `usize`
+   |            |
+   |            expected due to this
+   |
+help: change the type of the numeric literal from `usize` to `u32`
+   |
+LL |     let x: u32 = 22_u32;
+   |                  ^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/meta/meta-expected-error-wrong-rev.rs b/src/test/ui/meta/meta-expected-error-wrong-rev.rs
new file mode 100644 (file)
index 0000000..7e49434
--- /dev/null
@@ -0,0 +1,16 @@
+// ignore-compare-mode-nll
+
+// revisions: a
+// should-fail
+
+// This is a "meta-test" of the compilertest framework itself.  In
+// particular, it includes the right error message, but the message
+// targets the wrong revision, so we expect the execution to fail.
+// See also `meta-expected-error-correct-rev.rs`.
+
+#[cfg(a)]
+fn foo() {
+    let x: u32 = 22_usize; //[b]~ ERROR mismatched types
+}
+
+fn main() { }
index 8a96303e6b904e3d389ef4ed3966d3a12039db2b..eec0a4599c30c1798ebfd9b65ea063af889db199 100644 (file)
@@ -3,8 +3,6 @@
 //
 // build-pass
 // compile-flags: -Zmir-opt-level=2 -Zvalidate-mir
-#![feature(min_const_generics)]
-
 #[derive(Clone)]
 struct Array<T, const N: usize>([T; N]);
 
diff --git a/src/test/ui/never_type/issue-52443.rs b/src/test/ui/never_type/issue-52443.rs
new file mode 100644 (file)
index 0000000..4519833
--- /dev/null
@@ -0,0 +1,14 @@
+fn main() {
+    [(); & { loop { continue } } ]; //~ ERROR mismatched types
+
+    [(); loop { break }]; //~ ERROR mismatched types
+
+    [(); {while true {break}; 0}];
+    //~^ WARN denote infinite loops with
+
+    [(); { for _ in 0usize.. {}; 0}];
+    //~^ ERROR `for` is not allowed in a `const`
+    //~| ERROR calls in constants are limited to constant functions
+    //~| ERROR mutable references are not allowed in constants
+    //~| ERROR calls in constants are limited to constant functions
+}
diff --git a/src/test/ui/never_type/issue-52443.stderr b/src/test/ui/never_type/issue-52443.stderr
new file mode 100644 (file)
index 0000000..051896c
--- /dev/null
@@ -0,0 +1,57 @@
+warning: denote infinite loops with `loop { ... }`
+  --> $DIR/issue-52443.rs:6:11
+   |
+LL |     [(); {while true {break}; 0}];
+   |           ^^^^^^^^^^ help: use `loop`
+   |
+   = note: `#[warn(while_true)]` on by default
+
+error[E0744]: `for` is not allowed in a `const`
+  --> $DIR/issue-52443.rs:9:12
+   |
+LL |     [(); { for _ in 0usize.. {}; 0}];
+   |            ^^^^^^^^^^^^^^^^^^^^
+
+error[E0308]: mismatched types
+  --> $DIR/issue-52443.rs:2:10
+   |
+LL |     [(); & { loop { continue } } ];
+   |          ^^^^^^^^^^^^^^^^^^^^^^^
+   |          |
+   |          expected `usize`, found reference
+   |          help: consider removing the borrow: `{ loop { continue } }`
+   |
+   = note:   expected type `usize`
+           found reference `&_`
+
+error[E0308]: mismatched types
+  --> $DIR/issue-52443.rs:4:17
+   |
+LL |     [(); loop { break }];
+   |                 ^^^^^
+   |                 |
+   |                 expected `usize`, found `()`
+   |                 help: give it a value of the expected type: `break 42`
+
+error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants
+  --> $DIR/issue-52443.rs:9:21
+   |
+LL |     [(); { for _ in 0usize.. {}; 0}];
+   |                     ^^^^^^^^
+
+error[E0764]: mutable references are not allowed in constants
+  --> $DIR/issue-52443.rs:9:21
+   |
+LL |     [(); { for _ in 0usize.. {}; 0}];
+   |                     ^^^^^^^^ `&mut` is only allowed in `const fn`
+
+error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants
+  --> $DIR/issue-52443.rs:9:21
+   |
+LL |     [(); { for _ in 0usize.. {}; 0}];
+   |                     ^^^^^^^^
+
+error: aborting due to 6 previous errors; 1 warning emitted
+
+Some errors have detailed explanations: E0015, E0308, E0744, E0764.
+For more information about an error, try `rustc --explain E0015`.
index 37638a93d77f1db41cfe2271c405a5abc8118916..2f134f83ced193ff188cdca97145dc8ad10830cc 100644 (file)
@@ -15,7 +15,7 @@ error[E0499]: cannot borrow `x` as mutable more than once at a time
 LL |         v.push(|| x = String::new());
    |                ^^ - borrows occur due to use of `x` in closure
    |                |
-   |                mutable borrow starts here in previous iteration of loop
+   |                `x` was mutably borrowed here in the previous iteration of the loop
 
 error[E0524]: two closures require unique access to `x` at the same time
   --> $DIR/closures-in-loops.rs:20:16
index 758a14d0177055b7d1d045aa386787c3f88a6595..0db9fe62c3869d409c76cdb697b8b5015d35cff1 100644 (file)
@@ -5,7 +5,7 @@ LL | fn to_refs<T>(mut list: [&mut List<T>; 2]) -> Vec<&mut T> {
    |                          - let's call the lifetime of this reference `'1`
 ...
 LL |         result.push(&mut list[0].value);
-   |                     ^^^^^^^^^^^^^^^^^^ mutable borrow starts here in previous iteration of loop
+   |                     ^^^^^^^^^^^^^^^^^^ `list[_].value` was mutably borrowed here in the previous iteration of the loop
 ...
 LL |             return result;
    |                    ------ returning this value requires that `list[_].value` is borrowed for `'1`
@@ -19,7 +19,7 @@ LL | fn to_refs<T>(mut list: [&mut List<T>; 2]) -> Vec<&mut T> {
 LL |         if let Some(n) = list[0].next.as_mut() {
    |                          ^^^^^^^^^^^^---------
    |                          |
-   |                          mutable borrow starts here in previous iteration of loop
+   |                          `list[_].next` was mutably borrowed here in the previous iteration of the loop
    |                          argument requires that `list[_].next` is borrowed for `'1`
 
 error: aborting due to 2 previous errors
index f942d7628b5078b89cae1ae5d49ff0a022751db8..f1af2e855afe6c5fd501fc7054d496a579c3bdd6 100644 (file)
@@ -5,7 +5,7 @@ LL | fn to_refs<'a, T>(mut list: (&'a mut List<T>, &'a mut List<T>)) -> Vec<&'a
    |            -- lifetime `'a` defined here
 ...
 LL |         result.push(&mut (list.0).value);
-   |                     ^^^^^^^^^^^^^^^^^^^ mutable borrow starts here in previous iteration of loop
+   |                     ^^^^^^^^^^^^^^^^^^^ `list.0.value` was mutably borrowed here in the previous iteration of the loop
 ...
 LL |             return result;
    |                    ------ returning this value requires that `list.0.value` is borrowed for `'a`
@@ -19,7 +19,7 @@ LL | fn to_refs<'a, T>(mut list: (&'a mut List<T>, &'a mut List<T>)) -> Vec<&'a
 LL |         if let Some(n) = (list.0).next.as_mut() {
    |                          ^^^^^^^^^^^^^---------
    |                          |
-   |                          mutable borrow starts here in previous iteration of loop
+   |                          `list.0.next` was mutably borrowed here in the previous iteration of the loop
    |                          argument requires that `list.0.next` is borrowed for `'a`
 
 error: aborting due to 2 previous errors
index 07ca021b53bce5b8ebadc036173f2139c8b17206..2fe6a53a49aefc47ad35a4c1b4f33191f3cba393 100644 (file)
@@ -5,7 +5,7 @@ LL | fn assignment_to_field_projection<'a, T>(
    |                                   -- lifetime `'a` defined here
 ...
 LL |         result.push(&mut (list.0).value);
-   |                     ^^^^^^^^^^^^^^^^^^^ mutable borrow starts here in previous iteration of loop
+   |                     ^^^^^^^^^^^^^^^^^^^ `list.0.value` was mutably borrowed here in the previous iteration of the loop
 ...
 LL |             return result;
    |                    ------ returning this value requires that `list.0.value` is borrowed for `'a`
@@ -19,7 +19,7 @@ LL | fn assignment_to_field_projection<'a, T>(
 LL |         if let Some(n) = (list.0).next.as_mut() {
    |                          ^^^^^^^^^^^^^---------
    |                          |
-   |                          mutable borrow starts here in previous iteration of loop
+   |                          `list.0.next` was mutably borrowed here in the previous iteration of the loop
    |                          argument requires that `list.0.next` is borrowed for `'a`
 
 error[E0499]: cannot borrow `list.0.0.0.0.0.value` as mutable more than once at a time
@@ -29,7 +29,7 @@ LL | fn assignment_through_projection_chain<'a, T>(
    |                                        -- lifetime `'a` defined here
 ...
 LL |         result.push(&mut ((((list.0).0).0).0).0.value);
-   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ mutable borrow starts here in previous iteration of loop
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `list.0.0.0.0.0.value` was mutably borrowed here in the previous iteration of the loop
 ...
 LL |             return result;
    |                    ------ returning this value requires that `list.0.0.0.0.0.value` is borrowed for `'a`
@@ -43,7 +43,7 @@ LL | fn assignment_through_projection_chain<'a, T>(
 LL |         if let Some(n) = ((((list.0).0).0).0).0.next.as_mut() {
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^---------
    |                          |
-   |                          mutable borrow starts here in previous iteration of loop
+   |                          `list.0.0.0.0.0.next` was mutably borrowed here in the previous iteration of the loop
    |                          argument requires that `list.0.0.0.0.0.next` is borrowed for `'a`
 
 error: aborting due to 4 previous errors
index 8ac45b3db71b32fd0df5ee2262672d4fa48ed890..b61083078ccdbc0d4d58561aa9c489c45cc33825 100644 (file)
@@ -23,7 +23,7 @@ fn b<'a>(t: &'a Box<dyn Test>, mut ss: SomeStruct<'a>) {
     ss.u = t;
 }
 
-// see also compile-fail/object-lifetime-default-from-rptr-box-error.rs
+// see also ui/object-lifetime/object-lifetime-default-from-rptr-box-error.rs
 
 fn d<'a>(t: &'a Box<dyn Test+'a>, mut ss: SomeStruct<'a>) {
     ss.u = t;
diff --git a/src/test/ui/panic-handler/auxiliary/weak-lang-items.rs b/src/test/ui/panic-handler/auxiliary/weak-lang-items.rs
new file mode 100644 (file)
index 0000000..7a698cf
--- /dev/null
@@ -0,0 +1,22 @@
+// no-prefer-dynamic
+
+// This aux-file will require the eh_personality function to be codegen'd, but
+// it hasn't been defined just yet. Make sure we don't explode.
+
+#![no_std]
+#![crate_type = "rlib"]
+
+struct A;
+
+impl core::ops::Drop for A {
+    fn drop(&mut self) {}
+}
+
+pub fn foo() {
+    let _a = A;
+    panic!("wut");
+}
+
+mod std {
+    pub use core::{option, fmt};
+}
diff --git a/src/test/ui/panic-handler/panic-handler-missing.rs b/src/test/ui/panic-handler/panic-handler-missing.rs
new file mode 100644 (file)
index 0000000..6bb062b
--- /dev/null
@@ -0,0 +1,9 @@
+// dont-check-compiler-stderr
+// error-pattern: `#[panic_handler]` function required, but not found
+
+#![feature(lang_items)]
+#![no_main]
+#![no_std]
+
+#[lang = "eh_personality"]
+fn eh() {}
diff --git a/src/test/ui/panic-handler/panic-handler-twice.rs b/src/test/ui/panic-handler/panic-handler-twice.rs
new file mode 100644 (file)
index 0000000..05bef66
--- /dev/null
@@ -0,0 +1,19 @@
+// dont-check-compiler-stderr
+// aux-build:some-panic-impl.rs
+
+#![feature(lang_items)]
+#![no_std]
+#![no_main]
+
+extern crate some_panic_impl;
+
+use core::panic::PanicInfo;
+
+#[panic_handler]
+fn panic(info: &PanicInfo) -> ! {
+    //~^ ERROR found duplicate lang item `panic_impl`
+    loop {}
+}
+
+#[lang = "eh_personality"]
+fn eh() {}
diff --git a/src/test/ui/panic-handler/weak-lang-item.rs b/src/test/ui/panic-handler/weak-lang-item.rs
new file mode 100644 (file)
index 0000000..3fa3822
--- /dev/null
@@ -0,0 +1,11 @@
+// aux-build:weak-lang-items.rs
+// error-pattern: `#[panic_handler]` function required, but not found
+// error-pattern: language item required, but not found: `eh_personality`
+// ignore-emscripten compiled with panic=abort, personality not required
+
+#![no_std]
+
+extern crate core;
+extern crate weak_lang_items;
+
+fn main() {}
diff --git a/src/test/ui/panic-handler/weak-lang-item.stderr b/src/test/ui/panic-handler/weak-lang-item.stderr
new file mode 100644 (file)
index 0000000..b7c040c
--- /dev/null
@@ -0,0 +1,19 @@
+error[E0259]: the name `core` is defined multiple times
+  --> $DIR/weak-lang-item.rs:8:1
+   |
+LL | extern crate core;
+   | ^^^^^^^^^^^^^^^^^^ `core` reimported here
+   |
+   = note: `core` must be defined only once in the type namespace of this module
+help: you can use `as` to change the binding name of the import
+   |
+LL | extern crate core as other_core;
+   |
+
+error: `#[panic_handler]` function required, but not found
+
+error: language item required, but not found: `eh_personality`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0259`.
diff --git a/src/test/ui/panic-runtime/auxiliary/depends.rs b/src/test/ui/panic-runtime/auxiliary/depends.rs
new file mode 100644 (file)
index 0000000..e9bc2f4
--- /dev/null
@@ -0,0 +1,8 @@
+// no-prefer-dynamic
+
+#![feature(panic_runtime)]
+#![crate_type = "rlib"]
+#![panic_runtime]
+#![no_std]
+
+extern crate needs_panic_runtime;
diff --git a/src/test/ui/panic-runtime/auxiliary/needs-panic-runtime.rs b/src/test/ui/panic-runtime/auxiliary/needs-panic-runtime.rs
new file mode 100644 (file)
index 0000000..3f030c1
--- /dev/null
@@ -0,0 +1,6 @@
+// no-prefer-dynamic
+
+#![feature(needs_panic_runtime)]
+#![crate_type = "rlib"]
+#![needs_panic_runtime]
+#![no_std]
diff --git a/src/test/ui/panic-runtime/runtime-depend-on-needs-runtime.rs b/src/test/ui/panic-runtime/runtime-depend-on-needs-runtime.rs
new file mode 100644 (file)
index 0000000..d57f164
--- /dev/null
@@ -0,0 +1,8 @@
+// dont-check-compiler-stderr
+// aux-build:needs-panic-runtime.rs
+// aux-build:depends.rs
+// error-pattern:cannot depend on a crate that needs a panic runtime
+
+extern crate depends;
+
+fn main() {}
diff --git a/src/test/ui/panic-runtime/two-panic-runtimes.rs b/src/test/ui/panic-runtime/two-panic-runtimes.rs
new file mode 100644 (file)
index 0000000..c968b5e
--- /dev/null
@@ -0,0 +1,16 @@
+// build-fail
+// dont-check-compiler-stderr
+// error-pattern:cannot link together two panic runtimes: panic_runtime_unwind and panic_runtime_unwind2
+// ignore-tidy-linelength
+// aux-build:panic-runtime-unwind.rs
+// aux-build:panic-runtime-unwind2.rs
+// aux-build:panic-runtime-lang-items.rs
+
+#![no_std]
+#![no_main]
+
+extern crate panic_runtime_unwind;
+extern crate panic_runtime_unwind2;
+extern crate panic_runtime_lang_items;
+
+fn main() {}
diff --git a/src/test/ui/panic-runtime/unwind-tables-panic-required.rs b/src/test/ui/panic-runtime/unwind-tables-panic-required.rs
new file mode 100644 (file)
index 0000000..6393a27
--- /dev/null
@@ -0,0 +1,11 @@
+// Tests that the compiler errors if the user tries to turn off unwind tables
+// when they are required.
+//
+// dont-check-compiler-stderr
+// compile-flags: -C panic=unwind -C force-unwind-tables=no
+// ignore-tidy-linelength
+//
+// error-pattern: panic=unwind requires unwind tables, they cannot be disabled with `-C force-unwind-tables=no`.
+
+pub fn main() {
+}
diff --git a/src/test/ui/panic-runtime/unwind-tables-target-required.rs b/src/test/ui/panic-runtime/unwind-tables-target-required.rs
new file mode 100644 (file)
index 0000000..14c1789
--- /dev/null
@@ -0,0 +1,11 @@
+// Tests that the compiler errors if the user tries to turn off unwind tables
+// when they are required.
+//
+// only-x86_64-windows-msvc
+// compile-flags: -C force-unwind-tables=no
+// ignore-tidy-linelength
+//
+// error-pattern: target requires unwind tables, they cannot be disabled with `-C force-unwind-tables=no`.
+
+pub fn main() {
+}
diff --git a/src/test/ui/panic-runtime/want-abort-got-unwind.rs b/src/test/ui/panic-runtime/want-abort-got-unwind.rs
new file mode 100644 (file)
index 0000000..e33c3bc
--- /dev/null
@@ -0,0 +1,9 @@
+// build-fail
+// dont-check-compiler-stderr
+// error-pattern:is not compiled with this crate's panic strategy `abort`
+// aux-build:panic-runtime-unwind.rs
+// compile-flags:-C panic=abort
+
+extern crate panic_runtime_unwind;
+
+fn main() {}
diff --git a/src/test/ui/panic-runtime/want-abort-got-unwind2.rs b/src/test/ui/panic-runtime/want-abort-got-unwind2.rs
new file mode 100644 (file)
index 0000000..438f1d8
--- /dev/null
@@ -0,0 +1,10 @@
+// build-fail
+// dont-check-compiler-stderr
+// error-pattern:is not compiled with this crate's panic strategy `abort`
+// aux-build:panic-runtime-unwind.rs
+// aux-build:wants-panic-runtime-unwind.rs
+// compile-flags:-C panic=abort
+
+extern crate wants_panic_runtime_unwind;
+
+fn main() {}
diff --git a/src/test/ui/parser/incorrect-move-async-order-issue-79694.fixed b/src/test/ui/parser/incorrect-move-async-order-issue-79694.fixed
new file mode 100644 (file)
index 0000000..055800d
--- /dev/null
@@ -0,0 +1,8 @@
+// run-rustfix
+// edition:2018
+
+// Regression test for issue 79694
+
+fn main() {
+    let _ = async move { }; //~ ERROR 7:13: 7:23: the order of `move` and `async` is incorrect
+}
diff --git a/src/test/ui/parser/incorrect-move-async-order-issue-79694.rs b/src/test/ui/parser/incorrect-move-async-order-issue-79694.rs
new file mode 100644 (file)
index 0000000..e8be165
--- /dev/null
@@ -0,0 +1,8 @@
+// run-rustfix
+// edition:2018
+
+// Regression test for issue 79694
+
+fn main() {
+    let _ = move async { }; //~ ERROR 7:13: 7:23: the order of `move` and `async` is incorrect
+}
diff --git a/src/test/ui/parser/incorrect-move-async-order-issue-79694.stderr b/src/test/ui/parser/incorrect-move-async-order-issue-79694.stderr
new file mode 100644 (file)
index 0000000..2add9fb
--- /dev/null
@@ -0,0 +1,13 @@
+error: the order of `move` and `async` is incorrect
+  --> $DIR/incorrect-move-async-order-issue-79694.rs:7:13
+   |
+LL |     let _ = move async { };
+   |             ^^^^^^^^^^
+   |
+help: try switching the order
+   |
+LL |     let _ = async move { };
+   |             ^^^^^^^^^^
+
+error: aborting due to previous error
+
index 46f16ea0cc41cbd286b43c84b33c7e0e9504287f..bcecd75b1abbad33e772bf4e1042befd4dfba493 100644 (file)
@@ -2,7 +2,7 @@ error: lifetime parameters must be declared prior to type parameters
   --> $DIR/issue-14303-enum.rs:1:15
    |
 LL | enum X<'a, T, 'b> {
-   |       --------^^- help: reorder the parameters: lifetimes, then types: `<'a, 'b, T>`
+   |       --------^^- help: reorder the parameters: lifetimes, then types, then consts: `<'a, 'b, T>`
 
 error: aborting due to previous error
 
index 8cbab4b9653a0b67b12ba7a223dfde2d77785fbb..082c37e0be7956e8789126a54c1dcaf7d4452add 100644 (file)
@@ -2,7 +2,7 @@ error: lifetime parameters must be declared prior to type parameters
   --> $DIR/issue-14303-fn-def.rs:1:15
    |
 LL | fn foo<'a, T, 'b>(x: &'a T) {}
-   |       --------^^- help: reorder the parameters: lifetimes, then types: `<'a, 'b, T>`
+   |       --------^^- help: reorder the parameters: lifetimes, then types, then consts: `<'a, 'b, T>`
 
 error: aborting due to previous error
 
index 56cd4fb381038090802bee4966c071706464a20f..3b5615d2a9ecab7e55415c4924b1ce5c9c88ea71 100644 (file)
@@ -2,7 +2,7 @@ error: lifetime parameters must be declared prior to type parameters
   --> $DIR/issue-14303-impl.rs:3:13
    |
 LL | impl<'a, T, 'b> X<T> {}
-   |     --------^^- help: reorder the parameters: lifetimes, then types: `<'a, 'b, T>`
+   |     --------^^- help: reorder the parameters: lifetimes, then types, then consts: `<'a, 'b, T>`
 
 error: aborting due to previous error
 
index f31cb92ad66ce2924f62b3db1f643f22a434d224..dbd0b987dd1901bfaba0b6e650949fc4c9799408 100644 (file)
@@ -2,7 +2,7 @@ error: lifetime parameters must be declared prior to type parameters
   --> $DIR/issue-14303-struct.rs:1:17
    |
 LL | struct X<'a, T, 'b> {
-   |         --------^^- help: reorder the parameters: lifetimes, then types: `<'a, 'b, T>`
+   |         --------^^- help: reorder the parameters: lifetimes, then types, then consts: `<'a, 'b, T>`
 
 error: aborting due to previous error
 
index 0e7399102bf177d2d2737bd50255e64d2003189c..7dfa62d823fd8754c7f3873797b2a401b73ac7c3 100644 (file)
@@ -2,7 +2,7 @@ error: lifetime parameters must be declared prior to type parameters
   --> $DIR/issue-14303-trait.rs:1:18
    |
 LL | trait Foo<'a, T, 'b> {}
-   |          --------^^- help: reorder the parameters: lifetimes, then types: `<'a, 'b, T>`
+   |          --------^^- help: reorder the parameters: lifetimes, then types, then consts: `<'a, 'b, T>`
 
 error: aborting due to previous error
 
index cf81f0480a2a7e1a0d880c1c676548781185fea6..80e2d7c6545ba277512e0c9c2ad7ee0a0c70be40 100644 (file)
@@ -2,7 +2,6 @@ macro_rules! foo {
     { $+ } => { //~ ERROR expected identifier, found `+`
                 //~^ ERROR missing fragment specifier
         $(x)(y) //~ ERROR expected one of: `*`, `+`, or `?`
-       //~^ ERROR attempted to repeat an expression containing no syntax variables
     }
 }
 
index f54efaa6996f283caef7fa32daebe1fcb8258f40..b4d38d3ce4806ca8c5a6d9bf50241a3c01bdb684 100644 (file)
@@ -4,23 +4,17 @@ error: expected identifier, found `+`
 LL |     { $+ } => {
    |        ^
 
-error: missing fragment specifier
-  --> $DIR/issue-33569.rs:2:8
-   |
-LL |     { $+ } => {
-   |        ^
-
 error: expected one of: `*`, `+`, or `?`
   --> $DIR/issue-33569.rs:4:13
    |
 LL |         $(x)(y)
    |             ^^^
 
-error: attempted to repeat an expression containing no syntax variables matched as repeating at this depth
-  --> $DIR/issue-33569.rs:4:10
+error: missing fragment specifier
+  --> $DIR/issue-33569.rs:2:8
    |
-LL |         $(x)(y)
-   |          ^^^
+LL |     { $+ } => {
+   |        ^
 
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/parser/multibyte-char-use-seperator-issue-80134.rs b/src/test/ui/parser/multibyte-char-use-seperator-issue-80134.rs
new file mode 100644 (file)
index 0000000..f3ae3ab
--- /dev/null
@@ -0,0 +1,12 @@
+// Regression test for #80134.
+
+fn main() {
+    (()é);
+    //~^ ERROR: expected one of `)`, `,`, `.`, `?`, or an operator
+    //~| ERROR: cannot find value `é` in this scope
+    //~| ERROR: non-ascii idents are not fully supported
+    (()æ°·);
+    //~^ ERROR: expected one of `)`, `,`, `.`, `?`, or an operator
+    //~| ERROR: cannot find value `æ°·` in this scope
+    //~| ERROR: non-ascii idents are not fully supported
+}
diff --git a/src/test/ui/parser/multibyte-char-use-seperator-issue-80134.stderr b/src/test/ui/parser/multibyte-char-use-seperator-issue-80134.stderr
new file mode 100644 (file)
index 0000000..892cc92
--- /dev/null
@@ -0,0 +1,52 @@
+error: expected one of `)`, `,`, `.`, `?`, or an operator, found `é`
+  --> $DIR/multibyte-char-use-seperator-issue-80134.rs:4:8
+   |
+LL |     (()é);
+   |        ^
+   |        |
+   |        expected one of `)`, `,`, `.`, `?`, or an operator
+   |        help: missing `,`
+
+error: expected one of `)`, `,`, `.`, `?`, or an operator, found `æ°·`
+  --> $DIR/multibyte-char-use-seperator-issue-80134.rs:8:8
+   |
+LL |     (()æ°·);
+   |        -^
+   |        |
+   |        expected one of `)`, `,`, `.`, `?`, or an operator
+   |        help: missing `,`
+
+error[E0425]: cannot find value `é` in this scope
+  --> $DIR/multibyte-char-use-seperator-issue-80134.rs:4:8
+   |
+LL |     (()é);
+   |        ^ not found in this scope
+
+error[E0425]: cannot find value `æ°·` in this scope
+  --> $DIR/multibyte-char-use-seperator-issue-80134.rs:8:8
+   |
+LL |     (()æ°·);
+   |        ^^ not found in this scope
+
+error[E0658]: non-ascii idents are not fully supported
+  --> $DIR/multibyte-char-use-seperator-issue-80134.rs:4:8
+   |
+LL |     (()é);
+   |        ^
+   |
+   = note: see issue #55467 <https://github.com/rust-lang/rust/issues/55467> for more information
+   = help: add `#![feature(non_ascii_idents)]` to the crate attributes to enable
+
+error[E0658]: non-ascii idents are not fully supported
+  --> $DIR/multibyte-char-use-seperator-issue-80134.rs:8:8
+   |
+LL |     (()æ°·);
+   |        ^^
+   |
+   = note: see issue #55467 <https://github.com/rust-lang/rust/issues/55467> for more information
+   = help: add `#![feature(non_ascii_idents)]` to the crate attributes to enable
+
+error: aborting due to 6 previous errors
+
+Some errors have detailed explanations: E0425, E0658.
+For more information about an error, try `rustc --explain E0425`.
index f87f96e34fccdc373f5ca237d60b2596caa5bf5f..ca4fcd85bb6df2f6b15dac79c5fd874997e2bf4b 100644 (file)
@@ -25,10 +25,6 @@ enum Baz {
 impl Eq for Baz {}
 const BAZ: Baz = Baz::Baz1;
 
-type Quux = fn(usize, usize) -> usize;
-fn quux(a: usize, b: usize) -> usize { a + b }
-const QUUX: Quux = quux;
-
 fn main() {
     match FOO {
         FOO => {}
@@ -106,9 +102,44 @@ fn main() {
         //~^ ERROR unreachable pattern
     }
 
+    type Quux = fn(usize, usize) -> usize;
+    fn quux(a: usize, b: usize) -> usize { a + b }
+    const QUUX: Quux = quux;
+
     match QUUX {
         QUUX => {}
         QUUX => {}
         _ => {}
     }
+
+    #[derive(PartialEq, Eq)]
+    struct Wrap<T>(T);
+    const WRAPQUUX: Wrap<Quux> = Wrap(quux);
+
+    match WRAPQUUX {
+        WRAPQUUX => {}
+        WRAPQUUX => {}
+        Wrap(_) => {}
+    }
+
+    match WRAPQUUX {
+        Wrap(_) => {}
+        WRAPQUUX => {} // detected unreachable because we do inspect the `Wrap` layer
+        //~^ ERROR unreachable pattern
+    }
+
+    #[derive(PartialEq, Eq)]
+    enum WhoKnows<T> {
+        Yay(T),
+        Nope,
+    };
+    const WHOKNOWSQUUX: WhoKnows<Quux> = WhoKnows::Yay(quux);
+
+    match WHOKNOWSQUUX {
+        WHOKNOWSQUUX => {}
+        WhoKnows::Yay(_) => {}
+        WHOKNOWSQUUX => {} // detected unreachable because we do inspect the `WhoKnows` layer
+        //~^ ERROR unreachable pattern
+        WhoKnows::Nope => {}
+    }
 }
index f10166d5a35801cae7b9a33a5e32d672ad706d0e..68451043cf5403918670794bb2c4cd63d298628f 100644 (file)
@@ -1,11 +1,11 @@
 error: to use a constant of type `Foo` in a pattern, `Foo` must be annotated with `#[derive(PartialEq, Eq)]`
-  --> $DIR/consts-opaque.rs:34:9
+  --> $DIR/consts-opaque.rs:30:9
    |
 LL |         FOO => {}
    |         ^^^
 
 error: unreachable pattern
-  --> $DIR/consts-opaque.rs:36:9
+  --> $DIR/consts-opaque.rs:32:9
    |
 LL |         _ => {} // should not be emitting unreachable warning
    |         ^
@@ -17,19 +17,19 @@ LL | #![deny(unreachable_patterns)]
    |         ^^^^^^^^^^^^^^^^^^^^
 
 error: to use a constant of type `Foo` in a pattern, `Foo` must be annotated with `#[derive(PartialEq, Eq)]`
-  --> $DIR/consts-opaque.rs:41:9
+  --> $DIR/consts-opaque.rs:37:9
    |
 LL |         FOO_REF => {}
    |         ^^^^^^^
 
 error: unreachable pattern
-  --> $DIR/consts-opaque.rs:43:9
+  --> $DIR/consts-opaque.rs:39:9
    |
 LL |         Foo(_) => {} // should not be emitting unreachable warning
    |         ^^^^^^
 
 warning: to use a constant of type `Foo` in a pattern, `Foo` must be annotated with `#[derive(PartialEq, Eq)]`
-  --> $DIR/consts-opaque.rs:49:9
+  --> $DIR/consts-opaque.rs:45:9
    |
 LL |         FOO_REF_REF => {}
    |         ^^^^^^^^^^^
@@ -39,13 +39,13 @@ LL |         FOO_REF_REF => {}
    = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/62411>
 
 error: to use a constant of type `Bar` in a pattern, `Bar` must be annotated with `#[derive(PartialEq, Eq)]`
-  --> $DIR/consts-opaque.rs:57:9
+  --> $DIR/consts-opaque.rs:53:9
    |
 LL |         BAR => {} // should not be emitting unreachable warning
    |         ^^^
 
 error: unreachable pattern
-  --> $DIR/consts-opaque.rs:57:9
+  --> $DIR/consts-opaque.rs:53:9
    |
 LL |         Bar => {}
    |         --- matches any value
@@ -53,7 +53,7 @@ LL |         BAR => {} // should not be emitting unreachable warning
    |         ^^^ unreachable pattern
 
 error: unreachable pattern
-  --> $DIR/consts-opaque.rs:60:9
+  --> $DIR/consts-opaque.rs:56:9
    |
 LL |         Bar => {}
    |         --- matches any value
@@ -62,19 +62,19 @@ LL |         _ => {}
    |         ^ unreachable pattern
 
 error: to use a constant of type `Bar` in a pattern, `Bar` must be annotated with `#[derive(PartialEq, Eq)]`
-  --> $DIR/consts-opaque.rs:65:9
+  --> $DIR/consts-opaque.rs:61:9
    |
 LL |         BAR => {}
    |         ^^^
 
 error: unreachable pattern
-  --> $DIR/consts-opaque.rs:67:9
+  --> $DIR/consts-opaque.rs:63:9
    |
 LL |         Bar => {} // should not be emitting unreachable warning
    |         ^^^
 
 error: unreachable pattern
-  --> $DIR/consts-opaque.rs:69:9
+  --> $DIR/consts-opaque.rs:65:9
    |
 LL |         Bar => {} // should not be emitting unreachable warning
    |         --- matches any value
@@ -83,76 +83,88 @@ LL |         _ => {}
    |         ^ unreachable pattern
 
 error: to use a constant of type `Bar` in a pattern, `Bar` must be annotated with `#[derive(PartialEq, Eq)]`
-  --> $DIR/consts-opaque.rs:74:9
+  --> $DIR/consts-opaque.rs:70:9
    |
 LL |         BAR => {}
    |         ^^^
 
 error: to use a constant of type `Bar` in a pattern, `Bar` must be annotated with `#[derive(PartialEq, Eq)]`
-  --> $DIR/consts-opaque.rs:76:9
+  --> $DIR/consts-opaque.rs:72:9
    |
 LL |         BAR => {} // should not be emitting unreachable warning
    |         ^^^
 
 error: unreachable pattern
-  --> $DIR/consts-opaque.rs:76:9
+  --> $DIR/consts-opaque.rs:72:9
    |
 LL |         BAR => {} // should not be emitting unreachable warning
    |         ^^^
 
 error: unreachable pattern
-  --> $DIR/consts-opaque.rs:79:9
+  --> $DIR/consts-opaque.rs:75:9
    |
 LL |         _ => {} // should not be emitting unreachable warning
    |         ^
 
 error: to use a constant of type `Baz` in a pattern, `Baz` must be annotated with `#[derive(PartialEq, Eq)]`
-  --> $DIR/consts-opaque.rs:84:9
+  --> $DIR/consts-opaque.rs:80:9
    |
 LL |         BAZ => {}
    |         ^^^
 
 error: unreachable pattern
-  --> $DIR/consts-opaque.rs:86:9
+  --> $DIR/consts-opaque.rs:82:9
    |
 LL |         Baz::Baz1 => {} // should not be emitting unreachable warning
    |         ^^^^^^^^^
 
 error: unreachable pattern
-  --> $DIR/consts-opaque.rs:88:9
+  --> $DIR/consts-opaque.rs:84:9
    |
 LL |         _ => {}
    |         ^
 
 error: to use a constant of type `Baz` in a pattern, `Baz` must be annotated with `#[derive(PartialEq, Eq)]`
-  --> $DIR/consts-opaque.rs:94:9
+  --> $DIR/consts-opaque.rs:90:9
    |
 LL |         BAZ => {}
    |         ^^^
 
 error: unreachable pattern
-  --> $DIR/consts-opaque.rs:96:9
+  --> $DIR/consts-opaque.rs:92:9
    |
 LL |         _ => {}
    |         ^
 
 error: to use a constant of type `Baz` in a pattern, `Baz` must be annotated with `#[derive(PartialEq, Eq)]`
-  --> $DIR/consts-opaque.rs:101:9
+  --> $DIR/consts-opaque.rs:97:9
    |
 LL |         BAZ => {}
    |         ^^^
 
 error: unreachable pattern
-  --> $DIR/consts-opaque.rs:103:9
+  --> $DIR/consts-opaque.rs:99:9
    |
 LL |         Baz::Baz2 => {} // should not be emitting unreachable warning
    |         ^^^^^^^^^
 
 error: unreachable pattern
-  --> $DIR/consts-opaque.rs:105:9
+  --> $DIR/consts-opaque.rs:101:9
    |
 LL |         _ => {} // should not be emitting unreachable warning
    |         ^
 
-error: aborting due to 22 previous errors; 1 warning emitted
+error: unreachable pattern
+  --> $DIR/consts-opaque.rs:127:9
+   |
+LL |         WRAPQUUX => {} // detected unreachable because we do inspect the `Wrap` layer
+   |         ^^^^^^^^
+
+error: unreachable pattern
+  --> $DIR/consts-opaque.rs:141:9
+   |
+LL |         WHOKNOWSQUUX => {} // detected unreachable because we do inspect the `WhoKnows` layer
+   |         ^^^^^^^^^^^^
+
+error: aborting due to 24 previous errors; 1 warning emitted
 
index 5a44dfc28bb45200787cb5cf0d85f3f4e072297f..ef573db8210469a38dab99a9fc3b12c2a0bd8f9d 100644 (file)
@@ -1,5 +1,6 @@
 #![feature(exclusive_range_pattern)]
 #![feature(assoc_char_consts)]
+#![allow(overlapping_range_endpoints)]
 #![deny(unreachable_patterns)]
 
 macro_rules! m {
index 2e0023348e4d837f526c7c81018f7d484b3335a5..b1440375494b1697c19200a6335d54fb7ad2f8be 100644 (file)
@@ -1,5 +1,5 @@
 error[E0004]: non-exhaustive patterns: `u8::MAX` not covered
-  --> $DIR/exhaustiveness.rs:47:8
+  --> $DIR/exhaustiveness.rs:48:8
    |
 LL |     m!(0u8, 0..255);
    |        ^^^ pattern `u8::MAX` not covered
@@ -8,7 +8,7 @@ LL |     m!(0u8, 0..255);
    = note: the matched value is of type `u8`
 
 error[E0004]: non-exhaustive patterns: `u8::MAX` not covered
-  --> $DIR/exhaustiveness.rs:48:8
+  --> $DIR/exhaustiveness.rs:49:8
    |
 LL |     m!(0u8, 0..=254);
    |        ^^^ pattern `u8::MAX` not covered
@@ -17,7 +17,7 @@ LL |     m!(0u8, 0..=254);
    = note: the matched value is of type `u8`
 
 error[E0004]: non-exhaustive patterns: `0_u8` not covered
-  --> $DIR/exhaustiveness.rs:49:8
+  --> $DIR/exhaustiveness.rs:50:8
    |
 LL |     m!(0u8, 1..=255);
    |        ^^^ pattern `0_u8` not covered
@@ -26,7 +26,7 @@ LL |     m!(0u8, 1..=255);
    = note: the matched value is of type `u8`
 
 error[E0004]: non-exhaustive patterns: `42_u8` not covered
-  --> $DIR/exhaustiveness.rs:50:8
+  --> $DIR/exhaustiveness.rs:51:8
    |
 LL |     m!(0u8, 0..42 | 43..=255);
    |        ^^^ pattern `42_u8` not covered
@@ -35,7 +35,7 @@ LL |     m!(0u8, 0..42 | 43..=255);
    = note: the matched value is of type `u8`
 
 error[E0004]: non-exhaustive patterns: `i8::MAX` not covered
-  --> $DIR/exhaustiveness.rs:51:8
+  --> $DIR/exhaustiveness.rs:52:8
    |
 LL |     m!(0i8, -128..127);
    |        ^^^ pattern `i8::MAX` not covered
@@ -44,7 +44,7 @@ LL |     m!(0i8, -128..127);
    = note: the matched value is of type `i8`
 
 error[E0004]: non-exhaustive patterns: `i8::MAX` not covered
-  --> $DIR/exhaustiveness.rs:52:8
+  --> $DIR/exhaustiveness.rs:53:8
    |
 LL |     m!(0i8, -128..=126);
    |        ^^^ pattern `i8::MAX` not covered
@@ -53,7 +53,7 @@ LL |     m!(0i8, -128..=126);
    = note: the matched value is of type `i8`
 
 error[E0004]: non-exhaustive patterns: `i8::MIN` not covered
-  --> $DIR/exhaustiveness.rs:53:8
+  --> $DIR/exhaustiveness.rs:54:8
    |
 LL |     m!(0i8, -127..=127);
    |        ^^^ pattern `i8::MIN` not covered
@@ -62,7 +62,7 @@ LL |     m!(0i8, -127..=127);
    = note: the matched value is of type `i8`
 
 error[E0004]: non-exhaustive patterns: `0_i8` not covered
-  --> $DIR/exhaustiveness.rs:54:11
+  --> $DIR/exhaustiveness.rs:55:11
    |
 LL |     match 0i8 {
    |           ^^^ pattern `0_i8` not covered
@@ -71,7 +71,7 @@ LL |     match 0i8 {
    = note: the matched value is of type `i8`
 
 error[E0004]: non-exhaustive patterns: `u128::MAX` not covered
-  --> $DIR/exhaustiveness.rs:59:8
+  --> $DIR/exhaustiveness.rs:60:8
    |
 LL |     m!(0u128, 0..=ALMOST_MAX);
    |        ^^^^^ pattern `u128::MAX` not covered
@@ -80,7 +80,7 @@ LL |     m!(0u128, 0..=ALMOST_MAX);
    = note: the matched value is of type `u128`
 
 error[E0004]: non-exhaustive patterns: `5_u128..=u128::MAX` not covered
-  --> $DIR/exhaustiveness.rs:60:8
+  --> $DIR/exhaustiveness.rs:61:8
    |
 LL |     m!(0u128, 0..=4);
    |        ^^^^^ pattern `5_u128..=u128::MAX` not covered
@@ -89,7 +89,7 @@ LL |     m!(0u128, 0..=4);
    = note: the matched value is of type `u128`
 
 error[E0004]: non-exhaustive patterns: `0_u128` not covered
-  --> $DIR/exhaustiveness.rs:61:8
+  --> $DIR/exhaustiveness.rs:62:8
    |
 LL |     m!(0u128, 1..=u128::MAX);
    |        ^^^^^ pattern `0_u128` not covered
@@ -98,7 +98,7 @@ LL |     m!(0u128, 1..=u128::MAX);
    = note: the matched value is of type `u128`
 
 error[E0004]: non-exhaustive patterns: `(126_u8..=127_u8, false)` not covered
-  --> $DIR/exhaustiveness.rs:69:11
+  --> $DIR/exhaustiveness.rs:70:11
    |
 LL |     match (0u8, true) {
    |           ^^^^^^^^^^^ pattern `(126_u8..=127_u8, false)` not covered
index af720a056932208ed385db8f8ae84b40c31264ac..5ea92b07081afda2889b3363ab7630d718d01494 100644 (file)
@@ -1,5 +1,5 @@
 #![feature(exclusive_range_pattern)]
-#![deny(overlapping_patterns)]
+#![deny(overlapping_range_endpoints)]
 
 macro_rules! m {
     ($s:expr, $t1:pat, $t2:pat) => {
@@ -12,27 +12,33 @@ macro_rules! m {
 }
 
 fn main() {
-    m!(0u8, 20..=30, 30..=40); //~ ERROR multiple patterns covering the same range
-    m!(0u8, 30..=40, 20..=30); //~ ERROR multiple patterns covering the same range
+    m!(0u8, 20..=30, 30..=40); //~ ERROR multiple patterns overlap on their endpoints
+    m!(0u8, 30..=40, 20..=30); //~ ERROR multiple patterns overlap on their endpoints
     m!(0u8, 20..=30, 31..=40);
     m!(0u8, 20..=30, 29..=40);
-    m!(0u8, 20.. 30, 29..=40); //~ ERROR multiple patterns covering the same range
+    m!(0u8, 20.. 30, 29..=40); //~ ERROR multiple patterns overlap on their endpoints
     m!(0u8, 20.. 30, 28..=40);
     m!(0u8, 20.. 30, 30..=40);
     m!(0u8, 20..=30, 30..=30);
-    m!(0u8, 20..=30, 30..=31); //~ ERROR multiple patterns covering the same range
+    m!(0u8, 20..=30, 30..=31); //~ ERROR multiple patterns overlap on their endpoints
     m!(0u8, 20..=30, 29..=30);
     m!(0u8, 20..=30, 20..=20);
     m!(0u8, 20..=30, 20..=21);
-    m!(0u8, 20..=30, 19..=20); //~ ERROR multiple patterns covering the same range
+    m!(0u8, 20..=30, 19..=20); //~ ERROR multiple patterns overlap on their endpoints
     m!(0u8, 20..=30, 20);
     m!(0u8, 20..=30, 25);
     m!(0u8, 20..=30, 30);
     m!(0u8, 20.. 30, 29);
-    m!(0u8, 20, 20..=30); //~ ERROR multiple patterns covering the same range
+    m!(0u8, 20, 20..=30);
     m!(0u8, 25, 20..=30);
-    m!(0u8, 30, 20..=30); //~ ERROR multiple patterns covering the same range
+    m!(0u8, 30, 20..=30);
 
+    match 0u8 {
+        0..=10 => {}
+        20..=30 => {}
+        10..=20 => {} //~ ERROR multiple patterns overlap on their endpoints
+        _ => {}
+    }
     match (0u8, true) {
         (0..=10, true) => {}
         (10..20, true) => {} // not detected
@@ -41,13 +47,13 @@ fn main() {
     }
     match (true, 0u8) {
         (true, 0..=10) => {}
-        (true, 10..20) => {} //~ ERROR multiple patterns covering the same range
+        (true, 10..20) => {} //~ ERROR multiple patterns overlap on their endpoints
         (false, 10..20) => {}
         _ => {}
     }
     match Some(0u8) {
         Some(0..=10) => {}
-        Some(10..20) => {} //~ ERROR multiple patterns covering the same range
+        Some(10..20) => {} //~ ERROR multiple patterns overlap on their endpoints
         _ => {}
     }
 }
index 7bb747cdf6fc12409763e9faa53cc7819bb85530..24c0419e1dde3e2f36d32e3244403ed42d71ff62 100644 (file)
@@ -1,80 +1,89 @@
-error: multiple patterns covering the same range
+error: multiple patterns overlap on their endpoints
   --> $DIR/overlapping_range_endpoints.rs:15:22
    |
 LL |     m!(0u8, 20..=30, 30..=40);
-   |             -------  ^^^^^^^ overlapping patterns
+   |             -------  ^^^^^^^ ... with this range
    |             |
-   |             this range overlaps on `30_u8`
+   |             this range overlaps on `30_u8`...
    |
 note: the lint level is defined here
   --> $DIR/overlapping_range_endpoints.rs:2:9
    |
-LL | #![deny(overlapping_patterns)]
-   |         ^^^^^^^^^^^^^^^^^^^^
+LL | #![deny(overlapping_range_endpoints)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: you likely meant to write mutually exclusive ranges
 
-error: multiple patterns covering the same range
+error: multiple patterns overlap on their endpoints
   --> $DIR/overlapping_range_endpoints.rs:16:22
    |
 LL |     m!(0u8, 30..=40, 20..=30);
-   |             -------  ^^^^^^^ overlapping patterns
+   |             -------  ^^^^^^^ ... with this range
    |             |
-   |             this range overlaps on `30_u8`
+   |             this range overlaps on `30_u8`...
+   |
+   = note: you likely meant to write mutually exclusive ranges
 
-error: multiple patterns covering the same range
+error: multiple patterns overlap on their endpoints
   --> $DIR/overlapping_range_endpoints.rs:19:22
    |
 LL |     m!(0u8, 20.. 30, 29..=40);
-   |             -------  ^^^^^^^ overlapping patterns
+   |             -------  ^^^^^^^ ... with this range
    |             |
-   |             this range overlaps on `29_u8`
+   |             this range overlaps on `29_u8`...
+   |
+   = note: you likely meant to write mutually exclusive ranges
 
-error: multiple patterns covering the same range
+error: multiple patterns overlap on their endpoints
   --> $DIR/overlapping_range_endpoints.rs:23:22
    |
 LL |     m!(0u8, 20..=30, 30..=31);
-   |             -------  ^^^^^^^ overlapping patterns
+   |             -------  ^^^^^^^ ... with this range
    |             |
-   |             this range overlaps on `30_u8`
+   |             this range overlaps on `30_u8`...
+   |
+   = note: you likely meant to write mutually exclusive ranges
 
-error: multiple patterns covering the same range
+error: multiple patterns overlap on their endpoints
   --> $DIR/overlapping_range_endpoints.rs:27:22
    |
 LL |     m!(0u8, 20..=30, 19..=20);
-   |             -------  ^^^^^^^ overlapping patterns
+   |             -------  ^^^^^^^ ... with this range
    |             |
-   |             this range overlaps on `20_u8`
-
-error: multiple patterns covering the same range
-  --> $DIR/overlapping_range_endpoints.rs:32:17
+   |             this range overlaps on `20_u8`...
    |
-LL |     m!(0u8, 20, 20..=30);
-   |             --  ^^^^^^^ overlapping patterns
-   |             |
-   |             this range overlaps on `20_u8`
+   = note: you likely meant to write mutually exclusive ranges
 
-error: multiple patterns covering the same range
-  --> $DIR/overlapping_range_endpoints.rs:34:17
+error: multiple patterns overlap on their endpoints
+  --> $DIR/overlapping_range_endpoints.rs:39:9
    |
-LL |     m!(0u8, 30, 20..=30);
-   |             --  ^^^^^^^ overlapping patterns
-   |             |
-   |             this range overlaps on `30_u8`
+LL |         0..=10 => {}
+   |         ------ this range overlaps on `10_u8`...
+LL |         20..=30 => {}
+   |         ------- this range overlaps on `20_u8`...
+LL |         10..=20 => {}
+   |         ^^^^^^^ ... with this range
+   |
+   = note: you likely meant to write mutually exclusive ranges
 
-error: multiple patterns covering the same range
-  --> $DIR/overlapping_range_endpoints.rs:44:16
+error: multiple patterns overlap on their endpoints
+  --> $DIR/overlapping_range_endpoints.rs:50:16
    |
 LL |         (true, 0..=10) => {}
-   |                ------ this range overlaps on `10_u8`
+   |                ------ this range overlaps on `10_u8`...
 LL |         (true, 10..20) => {}
-   |                ^^^^^^ overlapping patterns
+   |                ^^^^^^ ... with this range
+   |
+   = note: you likely meant to write mutually exclusive ranges
 
-error: multiple patterns covering the same range
-  --> $DIR/overlapping_range_endpoints.rs:50:14
+error: multiple patterns overlap on their endpoints
+  --> $DIR/overlapping_range_endpoints.rs:56:14
    |
 LL |         Some(0..=10) => {}
-   |              ------ this range overlaps on `10_u8`
+   |              ------ this range overlaps on `10_u8`...
 LL |         Some(10..20) => {}
-   |              ^^^^^^ overlapping patterns
+   |              ^^^^^^ ... with this range
+   |
+   = note: you likely meant to write mutually exclusive ranges
 
-error: aborting due to 9 previous errors
+error: aborting due to 8 previous errors
 
index 6516925e93918b76679f7cf5ce6a48c358319113..fb4d59b05780e20570ec531b8d190cfa9f7553be 100644 (file)
@@ -1,4 +1,5 @@
 #![feature(exclusive_range_pattern)]
+#![allow(overlapping_range_endpoints)]
 #![deny(unreachable_patterns)]
 
 macro_rules! m {
index e6878d950d62561e48fd7024ef545479559656b0..9a02fac6a75dd47f6a14e6e2a60d73efa50f70da 100644 (file)
 error: unreachable pattern
-  --> $DIR/reachability.rs:16:17
+  --> $DIR/reachability.rs:17:17
    |
 LL |     m!(0u8, 42, 42);
    |                 ^^
    |
 note: the lint level is defined here
-  --> $DIR/reachability.rs:2:9
+  --> $DIR/reachability.rs:3:9
    |
 LL | #![deny(unreachable_patterns)]
    |         ^^^^^^^^^^^^^^^^^^^^
 
 error: unreachable pattern
-  --> $DIR/reachability.rs:20:22
+  --> $DIR/reachability.rs:21:22
    |
 LL |     m!(0u8, 20..=30, 20);
    |                      ^^
 
 error: unreachable pattern
-  --> $DIR/reachability.rs:21:22
+  --> $DIR/reachability.rs:22:22
    |
 LL |     m!(0u8, 20..=30, 21);
    |                      ^^
 
 error: unreachable pattern
-  --> $DIR/reachability.rs:22:22
+  --> $DIR/reachability.rs:23:22
    |
 LL |     m!(0u8, 20..=30, 25);
    |                      ^^
 
 error: unreachable pattern
-  --> $DIR/reachability.rs:23:22
+  --> $DIR/reachability.rs:24:22
    |
 LL |     m!(0u8, 20..=30, 29);
    |                      ^^
 
 error: unreachable pattern
-  --> $DIR/reachability.rs:24:22
+  --> $DIR/reachability.rs:25:22
    |
 LL |     m!(0u8, 20..=30, 30);
    |                      ^^
 
 error: unreachable pattern
-  --> $DIR/reachability.rs:27:21
+  --> $DIR/reachability.rs:28:21
    |
 LL |     m!(0u8, 20..30, 20);
    |                     ^^
 
 error: unreachable pattern
-  --> $DIR/reachability.rs:28:21
+  --> $DIR/reachability.rs:29:21
    |
 LL |     m!(0u8, 20..30, 21);
    |                     ^^
 
 error: unreachable pattern
-  --> $DIR/reachability.rs:29:21
+  --> $DIR/reachability.rs:30:21
    |
 LL |     m!(0u8, 20..30, 25);
    |                     ^^
 
 error: unreachable pattern
-  --> $DIR/reachability.rs:30:21
+  --> $DIR/reachability.rs:31:21
    |
 LL |     m!(0u8, 20..30, 29);
    |                     ^^
 
 error: unreachable pattern
-  --> $DIR/reachability.rs:34:22
+  --> $DIR/reachability.rs:35:22
    |
 LL |     m!(0u8, 20..=30, 20..=30);
    |                      ^^^^^^^
 
 error: unreachable pattern
-  --> $DIR/reachability.rs:35:22
+  --> $DIR/reachability.rs:36:22
    |
 LL |     m!(0u8, 20.. 30, 20.. 30);
    |                      ^^^^^^^
 
 error: unreachable pattern
-  --> $DIR/reachability.rs:36:22
+  --> $DIR/reachability.rs:37:22
    |
 LL |     m!(0u8, 20..=30, 20.. 30);
    |                      ^^^^^^^
 
 error: unreachable pattern
-  --> $DIR/reachability.rs:38:22
+  --> $DIR/reachability.rs:39:22
    |
 LL |     m!(0u8, 20..=30, 21..=30);
    |                      ^^^^^^^
 
 error: unreachable pattern
-  --> $DIR/reachability.rs:39:22
+  --> $DIR/reachability.rs:40:22
    |
 LL |     m!(0u8, 20..=30, 20..=29);
    |                      ^^^^^^^
 
 error: unreachable pattern
-  --> $DIR/reachability.rs:41:24
+  --> $DIR/reachability.rs:42:24
    |
 LL |     m!('a', 'A'..='z', 'a'..='z');
    |                        ^^^^^^^^^
 
 error: unreachable pattern
-  --> $DIR/reachability.rs:48:9
+  --> $DIR/reachability.rs:49:9
    |
 LL |         5..=8 => {},
    |         ^^^^^
 
 error: unreachable pattern
-  --> $DIR/reachability.rs:54:9
+  --> $DIR/reachability.rs:55:9
    |
 LL |         5..15 => {},
    |         ^^^^^
 
 error: unreachable pattern
-  --> $DIR/reachability.rs:61:9
+  --> $DIR/reachability.rs:62:9
    |
 LL |         5..25 => {},
    |         ^^^^^
 
 error: unreachable pattern
-  --> $DIR/reachability.rs:69:9
+  --> $DIR/reachability.rs:70:9
    |
 LL |         5..25 => {},
    |         ^^^^^
 
 error: unreachable pattern
-  --> $DIR/reachability.rs:75:9
+  --> $DIR/reachability.rs:76:9
    |
 LL |         5..15 => {},
    |         ^^^^^
 
 error: unreachable pattern
-  --> $DIR/reachability.rs:82:9
+  --> $DIR/reachability.rs:83:9
    |
 LL |         '\u{D7FF}'..='\u{E000}' => {},
    |         ^^^^^^^^^^^^^^^^^^^^^^^
 
 error: unreachable pattern
-  --> $DIR/reachability.rs:103:9
+  --> $DIR/reachability.rs:104:9
    |
 LL |         &FOO => {}
    |         ^^^^
 
 error: unreachable pattern
-  --> $DIR/reachability.rs:104:9
+  --> $DIR/reachability.rs:105:9
    |
 LL |         BAR => {}
    |         ^^^
index 63335586b765ce85b763f076765e6ea340a2a6de..266b6e62afd0bf930050b14dd4ac72f5e5763237 100644 (file)
@@ -6,7 +6,6 @@ LL | #![feature(const_generics, rustc_attrs)]
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-   = help: consider using `min_const_generics` instead, which is more stable and complete
 
 error: item has unused generic parameters
   --> $DIR/closures.rs:19:19
index c976a5b62aa308ea11106862b2c06bb36f16eade..e379e32c1fceb11cbc9ef4e4a6e259f5da0b80f2 100644 (file)
@@ -6,7 +6,6 @@ LL | #![feature(const_generics, rustc_attrs)]
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-   = help: consider using `min_const_generics` instead, which is more stable and complete
 
 error: item has unused generic parameters
   --> $DIR/functions.rs:15:8
index b2b32db045d6a78e4f4e9239b951c4a5120f51fc..c59055ba9d65473ff191d5463825056a64bde007 100644 (file)
@@ -6,7 +6,6 @@ LL | #![feature(const_generics, generators, generator_trait, rustc_attrs)]
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-   = help: consider using `min_const_generics` instead, which is more stable and complete
 
 error: item has unused generic parameters
   --> $DIR/generators.rs:36:5
diff --git a/src/test/ui/privacy/issue-46209-private-enum-variant-reexport.rs b/src/test/ui/privacy/issue-46209-private-enum-variant-reexport.rs
new file mode 100644 (file)
index 0000000..d54c993
--- /dev/null
@@ -0,0 +1,41 @@
+#![feature(crate_visibility_modifier)]
+
+mod rank {
+    pub use self::Professor::*;
+    //~^ ERROR enum is private and its variants cannot be re-exported
+    pub use self::Lieutenant::{JuniorGrade, Full};
+    //~^ ERROR variant `JuniorGrade` is private and cannot be re-exported
+    //~| ERROR variant `Full` is private and cannot be re-exported
+    pub use self::PettyOfficer::*;
+    //~^ ERROR enum is private and its variants cannot be re-exported
+    pub use self::Crewman::*;
+    //~^ ERROR enum is private and its variants cannot be re-exported
+
+    enum Professor {
+        Adjunct,
+        Assistant,
+        Associate,
+        Full
+    }
+
+    enum Lieutenant {
+        JuniorGrade,
+        Full,
+    }
+
+    pub(in rank) enum PettyOfficer {
+        SecondClass,
+        FirstClass,
+        Chief,
+        MasterChief
+    }
+
+    crate enum Crewman {
+        Recruit,
+        Apprentice,
+        Full
+    }
+
+}
+
+fn main() {}
diff --git a/src/test/ui/privacy/issue-46209-private-enum-variant-reexport.stderr b/src/test/ui/privacy/issue-46209-private-enum-variant-reexport.stderr
new file mode 100644 (file)
index 0000000..b876bab
--- /dev/null
@@ -0,0 +1,44 @@
+error: variant `JuniorGrade` is private and cannot be re-exported
+  --> $DIR/issue-46209-private-enum-variant-reexport.rs:6:32
+   |
+LL |     pub use self::Lieutenant::{JuniorGrade, Full};
+   |                                ^^^^^^^^^^^
+...
+LL |     enum Lieutenant {
+   |     --------------- help: consider making the enum public: `pub enum Lieutenant`
+
+error: variant `Full` is private and cannot be re-exported
+  --> $DIR/issue-46209-private-enum-variant-reexport.rs:6:45
+   |
+LL |     pub use self::Lieutenant::{JuniorGrade, Full};
+   |                                             ^^^^
+
+error: enum is private and its variants cannot be re-exported
+  --> $DIR/issue-46209-private-enum-variant-reexport.rs:4:13
+   |
+LL |     pub use self::Professor::*;
+   |             ^^^^^^^^^^^^^^^^^^
+...
+LL |     enum Professor {
+   |     -------------- help: consider making the enum public: `pub enum Professor`
+
+error: enum is private and its variants cannot be re-exported
+  --> $DIR/issue-46209-private-enum-variant-reexport.rs:9:13
+   |
+LL |     pub use self::PettyOfficer::*;
+   |             ^^^^^^^^^^^^^^^^^^^^^
+...
+LL |     pub(in rank) enum PettyOfficer {
+   |     ------------------------------ help: consider making the enum public: `pub enum PettyOfficer`
+
+error: enum is private and its variants cannot be re-exported
+  --> $DIR/issue-46209-private-enum-variant-reexport.rs:11:13
+   |
+LL |     pub use self::Crewman::*;
+   |             ^^^^^^^^^^^^^^^^
+...
+LL |     crate enum Crewman {
+   |     ------------------ help: consider making the enum public: `pub enum Crewman`
+
+error: aborting due to 5 previous errors
+
index cc2bde78d8594b3a6d488a9b75acd9d603455398..276a64b8e9a7bb537ddf85549d93d2815f706a64 100644 (file)
@@ -117,7 +117,7 @@ pub fn main() {
     let m : Box<dyn Trait> = make_val();
     // assert_eq!(object_invoke1(&*m), (4,5));
     //            ~~~~~~~~~~~~~~~~~~~
-    // this call yields a compilation error; see compile-fail/dropck-object-cycle.rs
+    // this call yields a compilation error; see ui/span/dropck-object-cycle.rs
     // for details.
     assert_eq!(object_invoke2(&*m), 5);
 
index f10d5a25f162847d76f66af8174d63cb689659b1..e6377867018c067ec426b13ed86bf5252bc60e8a 100644 (file)
@@ -4,7 +4,7 @@
 // Test that a type which is contravariant with respect to its region
 // parameter compiles successfully when used in a contravariant way.
 //
-// Note: see compile-fail/variance-regions-*.rs for the tests that check that the
+// Note: see ui/variance/variance-regions-*.rs for the tests that check that the
 // variance inference works in the first place.
 
 // pretty-expanded FIXME #23616
index 9316aa15d32a31a329b7253cbeb1941f5ecb0b30..c5c80ce54f12fde453c5128d452ded1866cab767 100644 (file)
@@ -3,7 +3,7 @@
 // Test that a type which is covariant with respect to its region
 // parameter is successful when used in a covariant way.
 //
-// Note: see compile-fail/variance-regions-*.rs for the tests that
+// Note: see ui/variance/variance-regions-*.rs for the tests that
 // check that the variance inference works in the first place.
 
 // This is covariant with respect to 'a, meaning that
index 5de8eb215821a4a8afb879ae19568a6a03ac5f01..7f8151db06f5b8a8ca55699fc564754c6f35465d 100644 (file)
@@ -48,7 +48,6 @@ LL | #![feature(const_generics)]
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-   = help: consider using `min_const_generics` instead, which is more stable and complete
 
 error: aborting due to 5 previous errors; 1 warning emitted
 
index 11155038a91393954fc962dd54de80c8ed441f82..861a4a80ad6521c8dd8ea634d45c5e5928a9c818 100644 (file)
@@ -521,7 +521,6 @@ LL | #![feature(const_generics)]
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-   = help: consider using `min_const_generics` instead, which is more stable and complete
 
 warning: the feature `let_chains` is incomplete and may not be safe to use and/or cause compiler crashes
   --> $DIR/disallowed-positions.rs:22:12
index e84186a42adfff75eb840060e7ad633270154efe..7d66395a3c80f3f3f4ff1f7bef744dcbc297300a 100644 (file)
@@ -3,7 +3,7 @@
 
 // pretty-expanded FIXME #23616
 
-#![feature(repr_simd, platform_intrinsics, min_const_generics)]
+#![feature(repr_simd, platform_intrinsics)]
 
 #[repr(simd)]
 #[derive(Copy, Clone)]
index dedca6276cda90b501421a5a5fc7cc55486893aa..50a4bfd9f518aa784fbc099c5c306c8a1e11172a 100644 (file)
@@ -1,6 +1,6 @@
 // run-pass
 #![allow(non_camel_case_types)]
-#![feature(repr_simd, platform_intrinsics, min_const_generics)]
+#![feature(repr_simd, platform_intrinsics)]
 
 use std::ops;
 
index 4c459fa4bc80155c86f9f4ab77d9140bf353f77d..c11d14b99d482bf526c889345c997701921a0358 100644 (file)
@@ -2,7 +2,7 @@
 // ignore-emscripten
 
 #![allow(non_camel_case_types)]
-#![feature(repr_simd, platform_intrinsics, min_const_generics)]
+#![feature(repr_simd, platform_intrinsics)]
 
 #[repr(simd)]
 #[derive(Copy, Clone, PartialEq, Debug)]
index 5b0ff88432ed9b0965692dd6db7967ef2985db17..96c2c6c5399270ff1d2535a644f781eb9e32cd83 100644 (file)
@@ -3,7 +3,7 @@
 
 // ignore-emscripten FIXME(#45351) hits an LLVM assert
 
-#![feature(repr_simd, platform_intrinsics, min_const_generics)]
+#![feature(repr_simd, platform_intrinsics)]
 
 #[repr(simd)]
 #[derive(Copy, Clone)]
diff --git a/src/test/ui/similar-tokens.fixed b/src/test/ui/similar-tokens.fixed
deleted file mode 100644 (file)
index addba76..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-// run-rustfix
-
-#![allow(unused_imports)]
-
-pub mod x {
-    pub struct A;
-    pub struct B;
-}
-
-// `.` is similar to `,` so list parsing should continue to closing `}`
-use x::{A, B}; //~ ERROR expected one of `,`, `::`, `as`, or `}`, found `.`
-
-fn main() {}
index 3d1bf5fe54ae1132fd2ef05ec9cd309670a4468e..e3024c61ad2bd800da819675c749d809a5df53df 100644 (file)
@@ -1,5 +1,3 @@
-// run-rustfix
-
 #![allow(unused_imports)]
 
 pub mod x {
index 6a8d09ebae668083a8d2006ff3d6124982814509..90acfc052ddd45b90ed8786619ac3009dfd6d7fb 100644 (file)
@@ -1,5 +1,5 @@
 error: expected one of `,`, `::`, `as`, or `}`, found `.`
-  --> $DIR/similar-tokens.rs:11:10
+  --> $DIR/similar-tokens.rs:9:10
    |
 LL | use x::{A. B};
    |          ^
index ac31e4910d5a69c13efd7e9bacf6df9e640fe67a..a14db5ff08966f86e8fb1ea2f66adf74194dbd32 100644 (file)
@@ -1,7 +1,7 @@
 // Reject mixing cyclic structure and Drop when using fixed length
 // arrays.
 //
-// (Compare against compile-fail/dropck_vec_cycle_checked.rs)
+// (Compare against ui/span/dropck_vec_cycle_checked.rs)
 
 
 
index bacd99c68254fb28268883fbbbd075a3461afcb6..c5d21507d76ce09c3cfeca8ddf98baa64a55dae0 100644 (file)
@@ -1,6 +1,6 @@
 // Reject mixing cyclic structure and Drop when using Vec.
 //
-// (Compare against compile-fail/dropck_arr_cycle_checked.rs)
+// (Compare against ui/span/dropck_arr_cycle_checked.rs)
 
 use std::cell::Cell;
 use id::Id;
index 4a9140969324dd46b94ae8cc22ef55313e8b844e..f19c55b043b4b7779c29e237f56d658b8b8f1da8 100644 (file)
@@ -4,7 +4,7 @@
 #![feature(specialization)] //~ WARN the feature `specialization` is incomplete
 
 // Make sure we *can* project non-defaulted associated types
-// cf compile-fail/specialization-default-projection.rs
+// cf ui/specialization/specialization-default-projection.rs
 
 // First, do so without any use of specialization
 
diff --git a/src/test/ui/specialization/issue-50452-fail.rs b/src/test/ui/specialization/issue-50452-fail.rs
new file mode 100644 (file)
index 0000000..fe21e9b
--- /dev/null
@@ -0,0 +1,21 @@
+#![feature(specialization)]
+//~^ WARN the feature `specialization` is incomplete
+
+pub trait Foo {
+    fn foo();
+}
+
+impl Foo for i32 {}
+impl Foo for i64 {
+    fn foo() {}
+    //~^ERROR `foo` specializes an item from a parent `impl`
+}
+impl<T> Foo for T {
+    fn foo() {}
+}
+
+fn main() {
+    i32::foo();
+    i64::foo();
+    u8::foo();
+}
diff --git a/src/test/ui/specialization/issue-50452-fail.stderr b/src/test/ui/specialization/issue-50452-fail.stderr
new file mode 100644 (file)
index 0000000..8e7c503
--- /dev/null
@@ -0,0 +1,26 @@
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/issue-50452-fail.rs:1:12
+   |
+LL | #![feature(specialization)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+   = help: consider using `min_specialization` instead, which is more stable and complete
+
+error[E0520]: `foo` specializes an item from a parent `impl`, but that item is not marked `default`
+  --> $DIR/issue-50452-fail.rs:10:5
+   |
+LL |       fn foo() {}
+   |       ^^^^^^^^^^^ cannot specialize default item `foo`
+...
+LL | / impl<T> Foo for T {
+LL | |     fn foo() {}
+LL | | }
+   | |_- parent `impl` is here
+   |
+   = note: to specialize, `foo` in the parent `impl` must be marked `default`
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0520`.
index 700975e3b828f3e1ab739360f9610e67569ac584..78afe7a949547148f22730c0491e1d8c214fda83 100644 (file)
@@ -4,7 +4,7 @@
 #![feature(specialization)] //~ WARN the feature `specialization` is incomplete
 
 // Make sure we *can* project non-defaulted associated types
-// cf compile-fail/specialization-default-projection.rs
+// cf ui/specialization/specialization-default-projection.rs
 
 // First, do so without any use of specialization
 
index af7ab865e3222512cc9b45a3b41831e6daaacd20..e17025e9e88ccadbf2e0c1019f63ed9a2c409a08 100644 (file)
@@ -2,7 +2,7 @@
 // Issue 23030: Workaround overflowing discriminant
 // with explicit assignments.
 
-// See also compile-fail/overflow-discrim.rs, which shows what
+// See also ui/discrim/discrim-overflow.rs, which shows what
 // happens if you leave the OhNo explicit cases out here.
 
 fn f_i8() {
index 1fc52ead48e0e54d421210e9283e444d859c3a37..d3e92e1624696199884548d13e400d9d61b64399 100644 (file)
@@ -27,7 +27,7 @@ fn b<'a>(t: &'a MyBox<dyn Test>, mut ss: SomeStruct<'a>) {
     ss.u = t;
 }
 
-// see also compile-fail/object-lifetime-default-from-rptr-box-error.rs
+// see also ui/object-lifetime/object-lifetime-default-from-rptr-box-error.rs
 
 fn d<'a>(t: &'a MyBox<dyn Test+'a>, mut ss: SomeStruct<'a>) {
     ss.u = t;
index 1851c8deaa8b4dbb14e99d744d8125858b2d3f10..657914d1c8c0c766f04ca0037fd2a8978006671a 100644 (file)
@@ -2,25 +2,25 @@ error: lifetime parameters must be declared prior to type parameters
   --> $DIR/suggest-move-lifetimes.rs:1:13
    |
 LL | struct A<T, 'a> {
-   |         ----^^- help: reorder the parameters: lifetimes, then types: `<'a, T>`
+   |         ----^^- help: reorder the parameters: lifetimes, then types, then consts: `<'a, T>`
 
 error: lifetime parameters must be declared prior to type parameters
   --> $DIR/suggest-move-lifetimes.rs:5:13
    |
 LL | struct B<T, 'a, U> {
-   |         ----^^---- help: reorder the parameters: lifetimes, then types: `<'a, T, U>`
+   |         ----^^---- help: reorder the parameters: lifetimes, then types, then consts: `<'a, T, U>`
 
 error: lifetime parameters must be declared prior to type parameters
   --> $DIR/suggest-move-lifetimes.rs:10:16
    |
 LL | struct C<T, U, 'a> {
-   |         -------^^- help: reorder the parameters: lifetimes, then types: `<'a, T, U>`
+   |         -------^^- help: reorder the parameters: lifetimes, then types, then consts: `<'a, T, U>`
 
 error: lifetime parameters must be declared prior to type parameters
   --> $DIR/suggest-move-lifetimes.rs:15:16
    |
 LL | struct D<T, U, 'a, 'b, V, 'c> {
-   |         -------^^--^^-----^^- help: reorder the parameters: lifetimes, then types: `<'a, 'b, 'c, T, U, V>`
+   |         -------^^--^^-----^^- help: reorder the parameters: lifetimes, then types, then consts: `<'a, 'b, 'c, T, U, V>`
 
 error: aborting due to 4 previous errors
 
index c138f1a5ba84c8020b4a2148687f9146e74d650a..221a096e08312b19175d54f6b6e46f2cf68fc3e0 100644 (file)
@@ -1,4 +1,4 @@
-//! "compile-fail/svh-uta-trait.rs" is checking that we detect a
+//! "svh-uta-trait.rs" is checking that we detect a
 //! change from `use foo::TraitB` to use `foo::TraitB` in the hash
 //! (SVH) computation (#14132), since that will affect method
 //! resolution.
index 76a472b5b26b16a4b96ea7725d0b19907bedd017..823d29571aa88d42ccaf15b39d62e57b8de1176f 100644 (file)
@@ -1,4 +1,4 @@
-//! "compile-fail/svh-uta-trait.rs" is checking that we detect a
+//! "svh-uta-trait.rs" is checking that we detect a
 //! change from `use foo::TraitB` to use `foo::TraitB` in the hash
 //! (SVH) computation (#14132), since that will affect method
 //! resolution.
index 2f27e99a961aec0e95c4df7874aac2faa2a6cd1e..a03e29dcedc422773a75a3089b672e2d5188a1d4 100644 (file)
@@ -1,4 +1,4 @@
-//! "compile-fail/svh-uta-trait.rs" is checking that we detect a
+//! "svh-uta-trait.rs" is checking that we detect a
 //! change from `use foo::TraitB` to use `foo::TraitB` in the hash
 //! (SVH) computation (#14132), since that will affect method
 //! resolution.
index 93daca034c067484d9437d45d762e1cf73f80e2e..e5c427e096a724b72576ee8089658a611046dac9 100644 (file)
@@ -6,7 +6,7 @@
 // aux-build:svh-uta-change-use-trait.rs
 // normalize-stderr-test: "(crate `(\w+)`:) .*" -> "$1 $$PATH_$2"
 
-//! "compile-fail/svh-uta-trait.rs" is checking that we detect a
+//! "svh-uta-trait.rs" is checking that we detect a
 //! change from `use foo::TraitB` to use `foo::TraitB` in the hash
 //! (SVH) computation (#14132), since that will affect method
 //! resolution.
index e002124059f83dd322a1cb9f5e14b6202e5a9303..55ab17fcd5a9a1b42175ba3bf3d3e3f24bca1dd7 100644 (file)
@@ -1,7 +1,6 @@
 // build-fail
 // compile-flags: -Z symbol-mangling-version=v0
-
-#![feature(min_const_generics, rustc_attrs)]
+#![feature(rustc_attrs)]
 
 pub struct Unsigned<const F: u8>;
 
index 022b3188373c935f56cc691e6db2dbb0fc9091cf..a9574cacea3e7a3eabc180c8ee40b1d385b907ab 100644 (file)
@@ -1,71 +1,71 @@
 error: symbol-name(_RMCs4fqI2P2rA04_25const_generics_demanglingINtB0_8UnsignedKhb_E)
-  --> $DIR/const-generics-demangling.rs:8:1
+  --> $DIR/const-generics-demangling.rs:7:1
    |
 LL | #[rustc_symbol_name]
    | ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<const_generics_demangling[317d481089b8c8fe]::Unsigned<11: u8>>)
-  --> $DIR/const-generics-demangling.rs:8:1
+  --> $DIR/const-generics-demangling.rs:7:1
    |
 LL | #[rustc_symbol_name]
    | ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<const_generics_demangling::Unsigned<11>>)
-  --> $DIR/const-generics-demangling.rs:8:1
+  --> $DIR/const-generics-demangling.rs:7:1
    |
 LL | #[rustc_symbol_name]
    | ^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RMs_Cs4fqI2P2rA04_25const_generics_demanglingINtB2_6SignedKsn98_E)
-  --> $DIR/const-generics-demangling.rs:16:1
+  --> $DIR/const-generics-demangling.rs:15:1
    |
 LL | #[rustc_symbol_name]
    | ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<const_generics_demangling[317d481089b8c8fe]::Signed<-152: i16>>)
-  --> $DIR/const-generics-demangling.rs:16:1
+  --> $DIR/const-generics-demangling.rs:15:1
    |
 LL | #[rustc_symbol_name]
    | ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<const_generics_demangling::Signed<-152>>)
-  --> $DIR/const-generics-demangling.rs:16:1
+  --> $DIR/const-generics-demangling.rs:15:1
    |
 LL | #[rustc_symbol_name]
    | ^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RMs0_Cs4fqI2P2rA04_25const_generics_demanglingINtB3_4BoolKb1_E)
-  --> $DIR/const-generics-demangling.rs:24:1
+  --> $DIR/const-generics-demangling.rs:23:1
    |
 LL | #[rustc_symbol_name]
    | ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<const_generics_demangling[317d481089b8c8fe]::Bool<true: bool>>)
-  --> $DIR/const-generics-demangling.rs:24:1
+  --> $DIR/const-generics-demangling.rs:23:1
    |
 LL | #[rustc_symbol_name]
    | ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<const_generics_demangling::Bool<true>>)
-  --> $DIR/const-generics-demangling.rs:24:1
+  --> $DIR/const-generics-demangling.rs:23:1
    |
 LL | #[rustc_symbol_name]
    | ^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RMs1_Cs4fqI2P2rA04_25const_generics_demanglingINtB3_4CharKc2202_E)
-  --> $DIR/const-generics-demangling.rs:32:1
+  --> $DIR/const-generics-demangling.rs:31:1
    |
 LL | #[rustc_symbol_name]
    | ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<const_generics_demangling[317d481089b8c8fe]::Char<'∂': char>>)
-  --> $DIR/const-generics-demangling.rs:32:1
+  --> $DIR/const-generics-demangling.rs:31:1
    |
 LL | #[rustc_symbol_name]
    | ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<const_generics_demangling::Char<'∂'>>)
-  --> $DIR/const-generics-demangling.rs:32:1
+  --> $DIR/const-generics-demangling.rs:31:1
    |
 LL | #[rustc_symbol_name]
    | ^^^^^^^^^^^^^^^^^^^^
index 823995e5be3afb147998943bbe306744aae90bf8..2d136e6a99a831f5badae45f34e16b27e54abbd3 100644 (file)
@@ -1,87 +1,85 @@
 // check-pass
 // revisions: legacy v0
 //[legacy]compile-flags: -Z symbol-mangling-version=legacy --crate-type=lib
-    //[v0]compile-flags: -Z symbol-mangling-version=v0 --crate-type=lib
+//[v0]compile-flags: -Z symbol-mangling-version=v0 --crate-type=lib
 
-    #![feature(min_const_generics)]
+// `char`
+pub struct Char<const F: char>;
 
-    // `char`
-    pub struct Char<const F: char>;
+impl Char<'A'> {
+    pub fn foo() {}
+}
 
-    impl Char<'A'> {
-        pub fn foo() {}
-    }
+impl<const F: char> Char<F> {
+    pub fn bar() {}
+}
 
-    impl<const F: char> Char<F> {
-        pub fn bar() {}
-    }
+// `i8`
+pub struct I8<const F: i8>;
 
-    // `i8`
-    pub struct I8<const F: i8>;
+impl I8<{i8::MIN}> {
+    pub fn foo() {}
+}
 
-    impl I8<{i8::MIN}> {
-        pub fn foo() {}
-    }
+impl I8<{i8::MAX}> {
+    pub fn foo() {}
+}
 
-    impl I8<{i8::MAX}> {
-        pub fn foo() {}
-    }
+impl<const F: i8> I8<F> {
+    pub fn bar() {}
+}
 
-    impl<const F: i8> I8<F> {
-        pub fn bar() {}
-    }
+// `i16`
+pub struct I16<const F: i16>;
 
-    // `i16`
-    pub struct I16<const F: i16>;
+impl I16<{i16::MIN}> {
+    pub fn foo() {}
+}
 
-    impl I16<{i16::MIN}> {
-        pub fn foo() {}
-    }
+impl<const F: i16> I16<F> {
+    pub fn bar() {}
+}
 
-    impl<const F: i16> I16<F> {
-        pub fn bar() {}
-    }
+// `i32`
+pub struct I32<const F: i32>;
 
-    // `i32`
-    pub struct I32<const F: i32>;
+impl I32<{i32::MIN}> {
+    pub fn foo() {}
+}
 
-    impl I32<{i32::MIN}> {
-        pub fn foo() {}
-    }
+impl<const F: i32> I32<F> {
+    pub fn bar() {}
+}
 
-    impl<const F: i32> I32<F> {
-        pub fn bar() {}
-    }
+// `i64`
+pub struct I64<const F: i64>;
 
-    // `i64`
-    pub struct I64<const F: i64>;
+impl I64<{i64::MIN}> {
+    pub fn foo() {}
+}
 
-    impl I64<{i64::MIN}> {
-        pub fn foo() {}
-    }
+impl<const F: i64> I64<F> {
+    pub fn bar() {}
+}
 
-    impl<const F: i64> I64<F> {
-        pub fn bar() {}
-    }
+// `i128`
+pub struct I128<const F: i128>;
 
-    // `i128`
-    pub struct I128<const F: i128>;
+impl I128<{i128::MIN}> {
+    pub fn foo() {}
+}
 
-    impl I128<{i128::MIN}> {
-        pub fn foo() {}
-    }
+impl<const F: i128> I128<F> {
+    pub fn bar() {}
+}
 
-    impl<const F: i128> I128<F> {
-        pub fn bar() {}
-    }
+// `isize`
+pub struct ISize<const F: isize>;
 
-    // `isize`
-    pub struct ISize<const F: isize>;
+impl ISize<3> {
+    pub fn foo() {}
+}
 
-    impl ISize<3> {
-        pub fn foo() {}
-    }
-
-    impl<const F: isize> ISize<F> {
-        pub fn bar() {}
-    }
+impl<const F: isize> ISize<F> {
+    pub fn bar() {}
+}
index 61ba255dac04d78d0453617b59161e38a5eb0f30..c2e9f92f7b539c28635ee83de38d80185607619d 100644 (file)
@@ -1,9 +1,8 @@
 // check-pass
 // revisions: legacy v0
 //[legacy]compile-flags: -Z symbol-mangling-version=legacy --crate-type=lib
-    //[v0]compile-flags: -Z symbol-mangling-version=v0 --crate-type=lib
+//[v0]compile-flags: -Z symbol-mangling-version=v0 --crate-type=lib
 
-#![feature(min_const_generics)]
 
 pub struct Bar<const F: bool>;
 
diff --git a/src/test/ui/threads-sendsync/issue-43733-2.rs b/src/test/ui/threads-sendsync/issue-43733-2.rs
new file mode 100644 (file)
index 0000000..21ea8e9
--- /dev/null
@@ -0,0 +1,30 @@
+// dont-check-compiler-stderr
+
+#![feature(cfg_target_thread_local, thread_local_internals)]
+
+// On platforms *without* `#[thread_local]`, use
+// a custom non-`Sync` type to fake the same error.
+#[cfg(not(target_thread_local))]
+struct Key<T> {
+    _data: std::cell::UnsafeCell<Option<T>>,
+    _flag: std::cell::Cell<()>,
+}
+
+#[cfg(not(target_thread_local))]
+impl<T> Key<T> {
+    const fn new() -> Self {
+        Key {
+            _data: std::cell::UnsafeCell::new(None),
+            _flag: std::cell::Cell::new(()),
+        }
+    }
+}
+
+#[cfg(target_thread_local)]
+use std::thread::__FastLocalKeyInner as Key;
+
+static __KEY: Key<()> = Key::new();
+//~^ ERROR `UnsafeCell<Option<()>>` cannot be shared between threads
+//~| ERROR cannot be shared between threads safely [E0277]
+
+fn main() {}
diff --git a/src/test/ui/threads-sendsync/issue-43733.rs b/src/test/ui/threads-sendsync/issue-43733.rs
new file mode 100644 (file)
index 0000000..a602d76
--- /dev/null
@@ -0,0 +1,31 @@
+#![feature(const_fn)]
+#![feature(thread_local)]
+#![feature(cfg_target_thread_local, thread_local_internals)]
+
+type Foo = std::cell::RefCell<String>;
+
+#[cfg(target_thread_local)]
+#[thread_local]
+static __KEY: std::thread::__FastLocalKeyInner<Foo> =
+    std::thread::__FastLocalKeyInner::new();
+
+#[cfg(not(target_thread_local))]
+static __KEY: std::thread::__OsLocalKeyInner<Foo> =
+    std::thread::__OsLocalKeyInner::new();
+
+fn __getit() -> std::option::Option<&'static Foo>
+{
+    __KEY.get(Default::default) //~ ERROR call to unsafe function is unsafe
+}
+
+static FOO: std::thread::LocalKey<Foo> =
+    std::thread::LocalKey::new(__getit);
+//~^ ERROR call to unsafe function is unsafe
+
+fn main() {
+    FOO.with(|foo| println!("{}", foo.borrow()));
+    std::thread::spawn(|| {
+        FOO.with(|foo| *foo.borrow_mut() += "foo");
+    }).join().unwrap();
+    FOO.with(|foo| println!("{}", foo.borrow()));
+}
diff --git a/src/test/ui/threads-sendsync/issue-43733.stderr b/src/test/ui/threads-sendsync/issue-43733.stderr
new file mode 100644 (file)
index 0000000..ee6a3b0
--- /dev/null
@@ -0,0 +1,19 @@
+error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
+  --> $DIR/issue-43733.rs:18:5
+   |
+LL |     __KEY.get(Default::default)
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function
+   |
+   = note: consult the function's documentation for information on how to avoid undefined behavior
+
+error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
+  --> $DIR/issue-43733.rs:22:5
+   |
+LL |     std::thread::LocalKey::new(__getit);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function
+   |
+   = note: consult the function's documentation for information on how to avoid undefined behavior
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0133`.
index 391d19c4385586c7277447c8d32eea66e6cfd036..339f9c37eeae8ada2c476a2046f1c3a366e9b717 100644 (file)
@@ -2,7 +2,7 @@
 // Test a case of a trait which extends the same supertrait twice, but
 // with difference type parameters. Test that we can invoke the
 // various methods in various ways successfully.
-// See also `compile-fail/trait-repeated-supertrait-ambig.rs`.
+// See also `ui/traits/trait-repeated-supertrait-ambig.rs`.
 
 
 trait CompareTo<T> {
index c5b22f0026de438b206bd25410f08181963c4c1b..e0c1b023861278b69a07989c53c0dd367693ae14 100644 (file)
@@ -6,7 +6,6 @@ LL | #![feature(const_generics)]
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-   = help: consider using `min_const_generics` instead, which is more stable and complete
 
 warning: 1 warning emitted
 
index 38271cc3c78b509dee1ec70f9b16f2e798c86697..3713a7065f5e5bd057bf8333c6c5cfab5db75759 100644 (file)
@@ -2,7 +2,7 @@
 
 #![allow(dead_code)]
 //
-// See also: compile-fail/unsafe-fn-called-from-safe.rs
+// See also: ui/unsafe/unsafe-fn-called-from-safe.rs
 
 // pretty-expanded FIXME #23616
 
index 26acc913e872ae06d4307405e56dc1e356bd6623..5e953107686f2ce6ce8c0240d8dbc0217fd0d9ed 100644 (file)
@@ -2,7 +2,7 @@
 
 #![allow(dead_code)]
 //
-// See also: compile-fail/unsafe-fn-called-from-safe.rs
+// See also: ui/unsafe/unsafe-fn-called-from-safe.rs
 
 // pretty-expanded FIXME #23616
 
index 0462efaa9b001fe5946c134db9c33a6abe4e4846..73a4cbd07924f4eec588ac496d00ad7620f753f1 100644 (file)
@@ -299,6 +299,7 @@ fn add_packages_to(&mut self, manifest: &mut Manifest) {
         let mut package = |name, targets| self.package(name, &mut manifest.pkg, targets);
         package("rustc", HOSTS);
         package("rustc-dev", HOSTS);
+        package("reproducible-artifacts", HOSTS);
         package("rustc-docs", HOSTS);
         package("cargo", HOSTS);
         package("rust-mingw", MINGW);
index a3c2627fbc2f5391c65ba45ab53b81bf71fa323c..75d5d8cffe3464631f82dcd3c470b78dc1dda8bb 160000 (submodule)
@@ -1 +1 @@
-Subproject commit a3c2627fbc2f5391c65ba45ab53b81bf71fa323c
+Subproject commit 75d5d8cffe3464631f82dcd3c470b78dc1dda8bb
index 7f9d22e594b9c0f4af731ae72e91219b85bd819e..a765390c6032d4c83694367683988b4b1c5e3bc0 100644 (file)
@@ -20,6 +20,7 @@ publish = false
 
 [[bin]]
 name = "cargo-clippy"
+test = false
 path = "src/main.rs"
 
 [[bin]]
index dc931963726b26723495db2c50a8e6bad75c7e64..aaa55e11c7db1b1ee9086584b3b9c581aabad966 100644 (file)
@@ -208,6 +208,7 @@ the lint(s) you are interested in:
 ```terminal
 cargo clippy -- -A clippy::all -W clippy::useless_format -W clippy::...
 ```
+Note that if you've run clippy before, this may only take effect after you've modified a file or ran `cargo clean`.
 
 ### Specifying the minimum supported Rust version
 
index 4d737b3f49b0351e2222fe950807d948e60c2d43..e84c8b4e5b3e0317e7006e84abd689f1dca56d4b 100644 (file)
@@ -501,7 +501,7 @@ impl<'tcx> Visitor<'tcx> for BodyLifetimeChecker {
 
     // for lifetimes as parameters of generics
     fn visit_lifetime(&mut self, lifetime: &'tcx Lifetime) {
-        if lifetime.name.ident().name != kw::Invalid && lifetime.name.ident().name != kw::StaticLifetime {
+        if lifetime.name.ident().name != kw::Empty && lifetime.name.ident().name != kw::StaticLifetime {
             self.lifetimes_used_in_body = true;
         }
     }
index 40f1b802e60e6aeeabec3fa11539c672c4a97cdd..e490ee54c0be0c25d960b0a53c47823a36eaf510 100644 (file)
@@ -1,6 +1,5 @@
 #![feature(rustc_private)]
 #![feature(once_cell)]
-#![feature(bool_to_option)]
 #![cfg_attr(feature = "deny-warnings", deny(warnings))]
 // warn on lints, that are included in `rust-lang/rust`s bootstrap
 #![warn(rust_2018_idioms, unused_lifetimes)]
@@ -20,7 +19,6 @@
 
 use std::borrow::Cow;
 use std::env;
-use std::iter;
 use std::lazy::SyncLazy;
 use std::ops::Deref;
 use std::panic;
@@ -49,6 +47,20 @@ fn arg_value<'a, T: Deref<Target = str>>(
     None
 }
 
+#[test]
+fn test_arg_value() {
+    let args = &["--bar=bar", "--foobar", "123", "--foo"];
+
+    assert_eq!(arg_value(&[] as &[&str], "--foobar", |_| true), None);
+    assert_eq!(arg_value(args, "--bar", |_| false), None);
+    assert_eq!(arg_value(args, "--bar", |_| true), Some("bar"));
+    assert_eq!(arg_value(args, "--bar", |p| p == "bar"), Some("bar"));
+    assert_eq!(arg_value(args, "--bar", |p| p == "foo"), None);
+    assert_eq!(arg_value(args, "--foobar", |p| p == "foo"), None);
+    assert_eq!(arg_value(args, "--foobar", |p| p == "123"), Some("123"));
+    assert_eq!(arg_value(args, "--foo", |_| true), None);
+}
+
 struct DefaultCallbacks;
 impl rustc_driver::Callbacks for DefaultCallbacks {}
 
@@ -170,28 +182,6 @@ fn toolchain_path(home: Option<String>, toolchain: Option<String>) -> Option<Pat
     })
 }
 
-fn remove_clippy_args<'a, T, U, I>(args: &mut Vec<T>, clippy_args: I)
-where
-    T: AsRef<str>,
-    U: AsRef<str> + ?Sized + 'a,
-    I: Iterator<Item = &'a U> + Clone,
-{
-    let args_iter = clippy_args.map(AsRef::as_ref);
-    let args_count = args_iter.clone().count();
-
-    if args_count > 0 {
-        if let Some(start) = args.windows(args_count).enumerate().find_map(|(current, window)| {
-            window
-                .iter()
-                .map(AsRef::as_ref)
-                .eq(args_iter.clone())
-                .then_some(current)
-        }) {
-            args.drain(start..start + args_count);
-        }
-    }
-}
-
 #[allow(clippy::too_many_lines)]
 pub fn main() {
     rustc_driver::init_rustc_env_logger();
@@ -288,9 +278,20 @@ pub fn main() {
             args.extend(vec!["--sysroot".into(), sys_root]);
         };
 
-        let clippy_args = env::var("CLIPPY_ARGS").unwrap_or_default();
-        let clippy_args = clippy_args.split_whitespace();
-        let no_deps = clippy_args.clone().any(|flag| flag == "--no-deps");
+        let mut no_deps = false;
+        let clippy_args = env::var("CLIPPY_ARGS")
+            .unwrap_or_default()
+            .split("__CLIPPY_HACKERY__")
+            .filter_map(|s| match s {
+                "" => None,
+                "--no-deps" => {
+                    no_deps = true;
+                    None
+                },
+                _ => Some(s.to_string()),
+            })
+            .chain(vec!["--cfg".into(), r#"feature="cargo-clippy""#.into()])
+            .collect::<Vec<String>>();
 
         // We enable Clippy if one of the following conditions is met
         // - IF Clippy is run on its test suite OR
@@ -303,11 +304,7 @@ pub fn main() {
 
         let clippy_enabled = clippy_tests_set || (!cap_lints_allow && (!no_deps || in_primary_package));
         if clippy_enabled {
-            remove_clippy_args(&mut args, iter::once("--no-deps"));
-            args.extend(vec!["--cfg".into(), r#"feature="cargo-clippy""#.into()]);
-        } else {
-            // Remove all flags passed through RUSTFLAGS if Clippy is not enabled.
-            remove_clippy_args(&mut args, clippy_args);
+            args.extend(clippy_args);
         }
 
         let mut clippy = ClippyCallbacks;
@@ -318,58 +315,3 @@ pub fn main() {
         rustc_driver::RunCompiler::new(&args, callbacks).run()
     }))
 }
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-
-    #[test]
-    fn test_arg_value() {
-        let args = &["--bar=bar", "--foobar", "123", "--foo"];
-
-        assert_eq!(arg_value(&[] as &[&str], "--foobar", |_| true), None);
-        assert_eq!(arg_value(args, "--bar", |_| false), None);
-        assert_eq!(arg_value(args, "--bar", |_| true), Some("bar"));
-        assert_eq!(arg_value(args, "--bar", |p| p == "bar"), Some("bar"));
-        assert_eq!(arg_value(args, "--bar", |p| p == "foo"), None);
-        assert_eq!(arg_value(args, "--foobar", |p| p == "foo"), None);
-        assert_eq!(arg_value(args, "--foobar", |p| p == "123"), Some("123"));
-        assert_eq!(arg_value(args, "--foo", |_| true), None);
-    }
-
-    #[test]
-    fn removes_clippy_args_from_start() {
-        let mut args = vec!["-D", "clippy::await_holding_lock", "--cfg", r#"feature="some_feat""#];
-        let clippy_args = ["-D", "clippy::await_holding_lock"].iter();
-
-        remove_clippy_args(&mut args, clippy_args);
-        assert_eq!(args, &["--cfg", r#"feature="some_feat""#]);
-    }
-
-    #[test]
-    fn removes_clippy_args_from_end() {
-        let mut args = vec!["-Zui-testing", "-A", "clippy::empty_loop", "--no-deps"];
-        let clippy_args = ["-A", "clippy::empty_loop", "--no-deps"].iter();
-
-        remove_clippy_args(&mut args, clippy_args);
-        assert_eq!(args, &["-Zui-testing"]);
-    }
-
-    #[test]
-    fn removes_clippy_args_from_middle() {
-        let mut args = vec!["-Zui-testing", "-W", "clippy::filter_map", "-L", "serde"];
-        let clippy_args = ["-W", "clippy::filter_map"].iter();
-
-        remove_clippy_args(&mut args, clippy_args);
-        assert_eq!(args, &["-Zui-testing", "-L", "serde"]);
-    }
-
-    #[test]
-    fn no_clippy_args_to_remove() {
-        let mut args = vec!["-Zui-testing", "-L", "serde"];
-        let clippy_args: [&str; 0] = [];
-
-        remove_clippy_args(&mut args, clippy_args.iter());
-        assert_eq!(args, &["-Zui-testing", "-L", "serde"]);
-    }
-}
index 1c0e04689a9fe495edbfc7ef1a276a9d524ba2b6..ea06743394d1075ba270830ba5e49b0c783cc3bf 100644 (file)
@@ -1,5 +1,3 @@
-#![feature(bool_to_option)]
-#![feature(command_access)]
 #![cfg_attr(feature = "deny-warnings", deny(warnings))]
 // warn on lints, that are included in `rust-lang/rust`s bootstrap
 #![warn(rust_2018_idioms, unused_lifetimes)]
@@ -64,7 +62,7 @@ struct ClippyCmd {
     unstable_options: bool,
     cargo_subcommand: &'static str,
     args: Vec<String>,
-    clippy_args: Option<String>,
+    clippy_args: Vec<String>,
 }
 
 impl ClippyCmd {
@@ -101,17 +99,16 @@ fn new<I>(mut old_args: I) -> Self
             args.insert(0, "+nightly".to_string());
         }
 
-        let mut clippy_args = old_args.collect::<Vec<String>>().join(" ");
-        if cargo_subcommand == "fix" && !clippy_args.contains("--no-deps") {
-            clippy_args = format!("{} --no-deps", clippy_args);
+        let mut clippy_args: Vec<String> = old_args.collect();
+        if cargo_subcommand == "fix" && !clippy_args.iter().any(|arg| arg == "--no-deps") {
+            clippy_args.push("--no-deps".into());
         }
 
-        let has_args = !clippy_args.is_empty();
         ClippyCmd {
             unstable_options,
             cargo_subcommand,
             args,
-            clippy_args: has_args.then_some(clippy_args),
+            clippy_args,
         }
     }
 
@@ -151,24 +148,20 @@ fn target_dir() -> Option<(&'static str, OsString)> {
             .map(|p| ("CARGO_TARGET_DIR", p))
     }
 
-    fn into_std_cmd(self, rustflags: Option<String>) -> Command {
+    fn into_std_cmd(self) -> Command {
         let mut cmd = Command::new("cargo");
+        let clippy_args: String = self
+            .clippy_args
+            .iter()
+            .map(|arg| format!("{}__CLIPPY_HACKERY__", arg))
+            .collect();
 
         cmd.env(self.path_env(), Self::path())
             .envs(ClippyCmd::target_dir())
+            .env("CLIPPY_ARGS", clippy_args)
             .arg(self.cargo_subcommand)
             .args(&self.args);
 
-        // HACK: pass Clippy args to the driver *also* through RUSTFLAGS.
-        // This guarantees that new builds will be triggered when Clippy flags change.
-        if let Some(clippy_args) = self.clippy_args {
-            cmd.env(
-                "RUSTFLAGS",
-                rustflags.map_or(clippy_args.clone(), |flags| format!("{} {}", clippy_args, flags)),
-            );
-            cmd.env("CLIPPY_ARGS", clippy_args);
-        }
-
         cmd
     }
 }
@@ -179,7 +172,7 @@ fn process<I>(old_args: I) -> Result<(), i32>
 {
     let cmd = ClippyCmd::new(old_args);
 
-    let mut cmd = cmd.into_std_cmd(env::var("RUSTFLAGS").ok());
+    let mut cmd = cmd.into_std_cmd();
 
     let exit_status = cmd
         .spawn()
@@ -197,7 +190,6 @@ fn process<I>(old_args: I) -> Result<(), i32>
 #[cfg(test)]
 mod tests {
     use super::ClippyCmd;
-    use std::ffi::OsStr;
 
     #[test]
     #[should_panic]
@@ -212,7 +204,6 @@ fn fix_unstable() {
             .split_whitespace()
             .map(ToString::to_string);
         let cmd = ClippyCmd::new(args);
-
         assert_eq!("fix", cmd.cargo_subcommand);
         assert_eq!("RUSTC_WORKSPACE_WRAPPER", cmd.path_env());
         assert!(cmd.args.iter().any(|arg| arg.ends_with("unstable-options")));
@@ -224,8 +215,7 @@ fn fix_implies_no_deps() {
             .split_whitespace()
             .map(ToString::to_string);
         let cmd = ClippyCmd::new(args);
-
-        assert!(cmd.clippy_args.unwrap().contains("--no-deps"));
+        assert!(cmd.clippy_args.iter().any(|arg| arg == "--no-deps"));
     }
 
     #[test]
@@ -234,15 +224,13 @@ fn no_deps_not_duplicated_with_fix() {
             .split_whitespace()
             .map(ToString::to_string);
         let cmd = ClippyCmd::new(args);
-
-        assert_eq!(1, cmd.clippy_args.unwrap().matches("--no-deps").count());
+        assert_eq!(cmd.clippy_args.iter().filter(|arg| *arg == "--no-deps").count(), 1);
     }
 
     #[test]
     fn check() {
         let args = "cargo clippy".split_whitespace().map(ToString::to_string);
         let cmd = ClippyCmd::new(args);
-
         assert_eq!("check", cmd.cargo_subcommand);
         assert_eq!("RUSTC_WRAPPER", cmd.path_env());
     }
@@ -253,63 +241,7 @@ fn check_unstable() {
             .split_whitespace()
             .map(ToString::to_string);
         let cmd = ClippyCmd::new(args);
-
         assert_eq!("check", cmd.cargo_subcommand);
         assert_eq!("RUSTC_WORKSPACE_WRAPPER", cmd.path_env());
     }
-
-    #[test]
-    fn clippy_args_into_rustflags() {
-        let args = "cargo clippy -- -W clippy::as_conversions"
-            .split_whitespace()
-            .map(ToString::to_string);
-        let cmd = ClippyCmd::new(args);
-
-        let rustflags = None;
-        let cmd = cmd.into_std_cmd(rustflags);
-
-        assert!(cmd
-            .get_envs()
-            .any(|(key, val)| key == "RUSTFLAGS" && val == Some(OsStr::new("-W clippy::as_conversions"))));
-    }
-
-    #[test]
-    fn clippy_args_respect_existing_rustflags() {
-        let args = "cargo clippy -- -D clippy::await_holding_lock"
-            .split_whitespace()
-            .map(ToString::to_string);
-        let cmd = ClippyCmd::new(args);
-
-        let rustflags = Some(r#"--cfg feature="some_feat""#.into());
-        let cmd = cmd.into_std_cmd(rustflags);
-
-        assert!(cmd.get_envs().any(|(key, val)| key == "RUSTFLAGS"
-            && val == Some(OsStr::new(r#"-D clippy::await_holding_lock --cfg feature="some_feat""#))));
-    }
-
-    #[test]
-    fn no_env_change_if_no_clippy_args() {
-        let args = "cargo clippy".split_whitespace().map(ToString::to_string);
-        let cmd = ClippyCmd::new(args);
-
-        let rustflags = Some(r#"--cfg feature="some_feat""#.into());
-        let cmd = cmd.into_std_cmd(rustflags);
-
-        assert!(!cmd
-            .get_envs()
-            .any(|(key, _)| key == "RUSTFLAGS" || key == "CLIPPY_ARGS"));
-    }
-
-    #[test]
-    fn no_env_change_if_no_clippy_args_nor_rustflags() {
-        let args = "cargo clippy".split_whitespace().map(ToString::to_string);
-        let cmd = ClippyCmd::new(args);
-
-        let rustflags = None;
-        let cmd = cmd.into_std_cmd(rustflags);
-
-        assert!(!cmd
-            .get_envs()
-            .any(|(key, _)| key == "RUSTFLAGS" || key == "CLIPPY_ARGS"))
-    }
 }
index fda1413868e82549eb76bfc2ce699fe0aa419f46..052223d6d6ff7f4156f17b0562a4d72335a875cb 100644 (file)
@@ -23,7 +23,7 @@ fn dogfood_clippy() {
         .current_dir(root_dir)
         .env("CLIPPY_DOGFOOD", "1")
         .env("CARGO_INCREMENTAL", "0")
-        .arg("clippy")
+        .arg("clippy-preview")
         .arg("--all-targets")
         .arg("--all-features")
         .arg("--")
index 7f4ebf566733a6e8df6d300f10a7d919671c982a..84981a52597327992a772f61ceff6ea23dcd59be 100644 (file)
@@ -39,7 +39,7 @@ fn main() {
         B(i32),
         C,
         D,
-    };
+    }
     let x = E::A(2);
     {
         // lint
index aee56dd4a5ef474e478dc2a72acdb950368796d2..94c7c3cadacf749799ba4a32510e28466e560001 100644 (file)
@@ -51,7 +51,7 @@ enum E {
         B(i32),
         C,
         D,
-    };
+    }
     let x = E::A(2);
     {
         // lint
index 80fbb06b9469109fb3efd1a80603faa9e3d460f7..43dbaeb46555cf8b3a495a7db80adaf107227520 100644 (file)
@@ -10,8 +10,6 @@
 
 #[derive(Clone, Copy, PartialEq, Debug)]
 pub enum Mode {
-    CompileFail,
-    RunFail,
     RunPassValgrind,
     Pretty,
     DebugInfo,
@@ -42,8 +40,6 @@ impl FromStr for Mode {
     type Err = ();
     fn from_str(s: &str) -> Result<Mode, ()> {
         match s {
-            "compile-fail" => Ok(CompileFail),
-            "run-fail" => Ok(RunFail),
             "run-pass-valgrind" => Ok(RunPassValgrind),
             "pretty" => Ok(Pretty),
             "debuginfo" => Ok(DebugInfo),
@@ -65,8 +61,6 @@ fn from_str(s: &str) -> Result<Mode, ()> {
 impl fmt::Display for Mode {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         let s = match *self {
-            CompileFail => "compile-fail",
-            RunFail => "run-fail",
             RunPassValgrind => "run-pass-valgrind",
             Pretty => "pretty",
             DebugInfo => "debuginfo",
@@ -230,7 +224,7 @@ pub struct Config {
     /// The name of the stage being built (stage1, etc)
     pub stage_id: String,
 
-    /// The test mode, compile-fail, run-fail, ui
+    /// The test mode, e.g. ui or debuginfo.
     pub mode: Mode,
 
     /// The test suite (essentially which directory is running, but without the
index a1be0a19f68546be500721d6a8586d13b4b803af..2eba91fd1f4cf6ef72e191d78398db2c66105212 100644 (file)
@@ -542,10 +542,7 @@ fn load_from(&mut self, testfile: &Path, cfg: Option<&str>, config: &Config) {
         }
 
         if self.failure_status == -1 {
-            self.failure_status = match config.mode {
-                Mode::RunFail => 101,
-                _ => 1,
-            };
+            self.failure_status = 1;
         }
         if self.should_ice {
             self.failure_status = 101;
index c63bbaf70d3c14cced5e2d7080eba585da930d3f..aefcfe222e509b63a132bad75a46c6655723b3b1 100644 (file)
@@ -71,7 +71,7 @@ pub fn parse_config(args: Vec<String>) -> Config {
             "",
             "mode",
             "which sort of compile tests to run",
-            "compile-fail | run-fail | run-pass-valgrind | pretty | debug-info | codegen | rustdoc \
+            "run-pass-valgrind | pretty | debug-info | codegen | rustdoc \
             | rustdoc-json | codegen-units | incremental | run-make | ui | js-doc-test | mir-opt | assembly",
         )
         .reqopt(
index 828c4e89f0b1fd20e6740a3cc66afd234c3ab928..9f31b3ae1b1a6d154f18ca910e8961907cb9a50c 100644 (file)
@@ -5,8 +5,8 @@
 use crate::common::{Assembly, Incremental, JsDocTest, MirOpt, RunMake, RustdocJson, Ui};
 use crate::common::{Codegen, CodegenUnits, DebugInfo, Debugger, Rustdoc};
 use crate::common::{CompareMode, FailMode, PassMode};
-use crate::common::{CompileFail, Pretty, RunFail, RunPassValgrind};
 use crate::common::{Config, TestPaths};
+use crate::common::{Pretty, RunPassValgrind};
 use crate::common::{UI_RUN_STDERR, UI_RUN_STDOUT};
 use crate::errors::{self, Error, ErrorKind};
 use crate::header::TestProps;
@@ -330,13 +330,11 @@ impl<'test> TestCx<'test> {
     /// revisions, exactly once, with revision == None).
     fn run_revision(&self) {
         if self.props.should_ice {
-            if self.config.mode != CompileFail && self.config.mode != Incremental {
+            if self.config.mode != Incremental {
                 self.fatal("cannot use should-ice in a test that is not cfail");
             }
         }
         match self.config.mode {
-            CompileFail => self.run_cfail_test(),
-            RunFail => self.run_rfail_test(),
             RunPassValgrind => self.run_valgrind_test(),
             Pretty => self.run_pretty_test(),
             DebugInfo => self.run_debuginfo_test(),
@@ -377,7 +375,6 @@ fn should_run_successfully(&self, pm: Option<PassMode>) -> bool {
 
     fn should_compile_successfully(&self, pm: Option<PassMode>) -> bool {
         match self.config.mode {
-            CompileFail => false,
             JsDocTest => true,
             Ui => pm.is_some() || self.props.fail_mode > Some(FailMode::Build),
             Incremental => {
@@ -1537,8 +1534,8 @@ fn compile_test_general(
         };
 
         let allow_unused = match self.config.mode {
-            CompileFail | Ui => {
-                // compile-fail and ui tests tend to have tons of unused code as
+            Ui => {
+                // UI tests tend to have tons of unused code as
                 // it's just testing various pieces of the compile, but we don't
                 // want to actually assert warnings about all this code. Instead
                 // let's just ignore unused code warnings by defaults and tests
@@ -1940,7 +1937,7 @@ fn make_compile_args(
         }
 
         match self.config.mode {
-            CompileFail | Incremental => {
+            Incremental => {
                 // If we are extracting and matching errors in the new
                 // fashion, then you want JSON mode. Old-skool error
                 // patterns still match the raw compiler output.
@@ -1975,8 +1972,8 @@ fn make_compile_args(
 
                 rustc.arg(dir_opt);
             }
-            RunFail | RunPassValgrind | Pretty | DebugInfo | Codegen | Rustdoc | RustdocJson
-            | RunMake | CodegenUnits | JsDocTest | Assembly => {
+            RunPassValgrind | Pretty | DebugInfo | Codegen | Rustdoc | RustdocJson | RunMake
+            | CodegenUnits | JsDocTest | Assembly => {
                 // do not use JSON output
             }
         }
index 0a69b18a3325413a4aa4b8642ca2e37152f3edb9..e8fd19a63812b4d03f8350d8f77388c1e5251cbe 100644 (file)
@@ -116,13 +116,23 @@ fn make_groups_table(
         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",
+            let lint_def = match lints.iter().find(|l| l.name == lint_name.replace("-", "_")) {
+                Some(def) => def,
+                None => {
+                    let msg = format!(
+                        "`rustc -W help` defined lint `{}` but that lint does not \
+                        appear to exist\n\
+                        Check that the lint definition includes the appropriate doc comments.",
                         lint_name
-                    )
-                })?;
+                    );
+                    if self.validate {
+                        return Err(msg.into());
+                    } else {
+                        eprintln!("warning: {}", msg);
+                        continue;
+                    }
+                }
+            };
             write!(
                 result,
                 "[{}]: listing/{}#{}\n",
index d66f476b4d5e7fdf1ec215c9ac16c923dc292324..5254dbfd25d5284728ab624dca1969d61427a0db 160000 (submodule)
@@ -1 +1 @@
-Subproject commit d66f476b4d5e7fdf1ec215c9ac16c923dc292324
+Subproject commit 5254dbfd25d5284728ab624dca1969d61427a0db
index 11b175f9e80ed3320d846be02d9eadbc29ee0b07..1cde0e25cedca87062182ee5ad23370ee7a7711d 100644 (file)
@@ -65,6 +65,8 @@ byteorder = { version = "1", features = ['default', 'std'] }
 curl-sys = { version = "0.4.13", features = ["http2", "libnghttp2-sys"], optional = true }
 crossbeam-utils = { version = "0.7.2", features = ["nightly"] }
 libc = { version = "0.2.79", features = ["align"] }
+# Ensure default features of libz-sys, which are disabled in some scenarios.
+libz-sys = { version = "1.1.2" }
 proc-macro2 = { version = "1", features = ["default"] }
 quote = { version = "1", features = ["default"] }
 serde = { version = "1.0.82", features = ['derive'] }
index 70ce18255f429caf0d75ecfed8c1464535ee779b..acd94866fd0ff5eacb7e184ae21c19e5440fc5fb 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 70ce18255f429caf0d75ecfed8c1464535ee779b
+Subproject commit acd94866fd0ff5eacb7e184ae21c19e5440fc5fb
index d78af2cd6164c7b844f7830bdca285694e67b846..384a291a777cd3292c805edf107d7d63927e9bf5 100644 (file)
@@ -85,11 +85,7 @@ pub fn check(
     assert!(!lib_features.is_empty());
 
     super::walk_many(
-        &[
-            &src_path.join("test/ui"),
-            &src_path.join("test/ui-fulldeps"),
-            &src_path.join("test/compile-fail"),
-        ],
+        &[&src_path.join("test/ui"), &src_path.join("test/ui-fulldeps")],
         &mut |path| super::filter_dirs(path),
         &mut |entry, contents| {
             let file = entry.path();
index 3b3cf2847c2005af1235bc0da562c3ac82c2f303..80bf02e8a0ef5027d5e18408a99200dbae3cce38 100644 (file)
@@ -1,3 +1,10 @@
 # x
 
 `x` invokes `x.py` from any subdirectory.
+
+To install, run the following commands:
+
+```
+$ cd rust/src/tools/x/
+$ cargo install --path .
+```
index 5a5c7211dc68eef95f4a70b06921bde691afe888..ba0a719118ceed4c88b35e7b67cb77ea38bf3883 100644 (file)
@@ -1 +1 @@
-1.50.0
+1.51.0
index fc733b9e45f1875a1cf90f518a209852f0bace66..c0cf50e516700b1d86aff94d8c6d0b3fc90ba51c 100644 (file)
@@ -90,7 +90,7 @@ exclude_labels = [
 
 [notify-zulip."I-prioritize"]
 zulip_stream = 245100 # #t-compiler/wg-prioritization/alerts
-topic = "I-prioritize #{number} {title}"
+topic = "#{number} {title}"
 message_on_add = """\
 @*WG-prioritization/alerts* issue #{number} has been requested for prioritization.